Como contornar o limite da class de casos Scala de 22 campos?

As classs de casos do Scala possuem um limite de 22 campos no construtor. Eu quero exceder esse limite, existe uma maneira de fazê-lo com inheritance ou composição que funciona com classs de casos?

Mais recentemente (outubro de 2016, seis anos após o OP), o post do blog ” Scala and 22 ” de Richard Dallaway explora esse limite:

Em 2014, quando o Scala 2.11 foi lançado, uma importante limitação foi removida:

Case classs with > 22 parameters are now allowed. 

Isso pode levar você a pensar que não há 22 limites em Scala, mas esse não é o caso. O limite permanece em funções e tuplas .

A correção ( PR 2305 ) introduzida no Scala 2.11 removeu a limitação para os cenários comuns acima: construção de classs de casos, access a campos (incluindo cópia) e correspondência de padrões ( casos de borda de baring ).

Isso foi feito omitindo-se o não- unapply e a unapply para as classs de casos acima de 22 campos.
Em outras palavras, o limite para Function22 e Tuple22 ainda existe.

Trabalhando em torno do limite (pós Scala 2.11)

Existem dois truques comuns para contornar esse limite.

  • O primeiro é usar tuplas aninhadas .
    Embora seja verdade que uma tupla não pode conter mais de 22 elementos, cada elemento em si pode ser uma tupla

  • O outro truque comum é usar listas heterogêneas (HLists), onde não há limite de 22.

Se você quiser fazer uso de classs de casos, talvez seja melhor usar a implementação HList sem forma. Criamos a biblioteca do Slickless para facilitar isso. Em particular, o método mappedWith recente mappedWith convertido entre HLists sem HLists e classs de casos. Se parece com isso:

 import slick.driver.H2Driver.api._ import shapeless._ import slickless._ class LargeTable(tag: Tag) extends Table[Large](tag, "large") { def a = column[Int]("a") def b = column[Int]("b") def c = column[Int]("c") /* etc */ def u = column[Int]("u") def v = column[Int]("v") def w = column[Int]("w") def * = (a :: b :: c :: /* etc */ :: u :: v :: w :: HNil) .mappedWith(Generic[Large]) } 

Há um exemplo completo com 26 colunas na base de código do Slickless.

Esse problema será corrigido no Scala 2.11.

Construa uma class normal que atue como uma class de caso.

Eu ainda uso o scala 2.10.X, já que é o mais recente suportado pelo Spark, e no Spark-SQL eu uso muito as classs de casos.

A solução alternativa para as case classs com mais de 22 campos:

 class Demo(val field1: String, val field2: Int, // .. and so on .. val field23: String) extends Product //For Spark it has to be Serializable with Serializable { def canEqual(that: Any) = that.isInstanceOf[Demo] def productArity = 23 // number of columns def productElement(idx: Int) = idx match { case 0 => field1 case 1 => field2 // .. and so on .. case 22 => field23 } } 

É interessante que seu construtor seja carregado, mas você poderia empacotar valores relacionados em uma class de caso própria.

Então, enquanto você pode ter

 case class MyClass(street: String, city: String, state: String, zip: Integer) 

você consegue fazer isso

 case class MyClass(address: Address) 

Você tem outras opções também:

  • Agrupar itens em tuplas
  • Crie seu próprio atributo Function23 (ou qualquer outro)
  • Use currying

ATUALIZAÇÃO: Como outros já notaram, isso não é mais um problema após o lançamento do Scala 2.11 – embora eu hesite em usar o termo “consertar”. No entanto, o “Catch 22”, se você quiser, às vezes ainda aparece em bibliotecas Scala de terceiros.

Quando você tem muitos valores, geralmente é um sinal de que seu design precisa ser retrabalhado de qualquer maneira.

Forme classs de casos intermitentes que, em seguida, agregam no maior. Isso também torna o código muito mais fácil de entender, raciocinar e manter. Bem como contornar esse problema que você está tendo.

Por exemplo, se eu quisesse armazenar dados do usuário, poderia fazer isso ….

 case class User(name: Name, email: String) case class Name(first: String, last: String) 

Com tão poucas coisas, isso obviamente não seria necessário. Mas se você tem 22 coisas que você está tentando empinar em uma class, você vai querer fazer este tipo de trabalho de class de caso intermitente de qualquer maneira.

Intereting Posts