Класовете на Scala case имат ограничение от 22 полета в конструктора. Искам да надвиша това ограничение, има ли начин да го направя с наследяване или композиция, която работи с класове case?
Как да заобиколите ограничението на класа на случай на Scala от 22 полета?
Отговори (5)
Съвсем наскоро (октомври 2016 г., шест години след OP), публикацията в блога „Ричард Далауей a> изследва това ограничение:
Още през 2014 г., когато беше пусната Scala 2.11, важно ограничение беше премахнато:
Case classes with > 22 parameters are now allowed.
Въпреки това все още съществува ограничение за броя на полетата за класове на случай, моля, вижте https://stackoverflow.com/a/55498135/1586965
Това може да ви накара да мислите, че в Scala няма 22 ограничения, но това не е така. Ограничението продължава да съществува във функции и кортежи.
Корекцията (PR 2305), въведена в Scala 2.11, премахна ограничението за горните общи сценарии: конструиране на класове казуси, достъп до поле (включително копиране) и съвпадение на шаблони (случаи с оголени ръбове).
Той направи това, като пропусна
unapply
иtupled
за класове на казуси над 22 полета.
С други думи, ограничението доFunction22
иTuple22
все още съществува.Работа около лимита (след Scala 2.11)
Има два често срещани трика за заобикаляне на това ограничение.
Първият е да използвате вложени кортежи.
Въпреки че е вярно, че кортежът не може да съдържа повече от 22 елемента, всеки елемент сам по себе си може да бъде кортежДругият често срещан трик е да се използват разнородни списъци (HLists), където няма ограничение от 22.
Ако искате да използвате класове case, може би е по-добре да използвате безформената реализация на HList. Създадохме Slickless библиотеката, за да улесним това. По-специално скорошният
mappedWith
метод преобразува между безформениHLists
и case класове. Изглежда така:
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])
}
Има пълен пример с 26 колони в кодовата база Slickless.
Този проблем ще бъде отстранен в Scala 2.11.
Изградете нормален клас, който действа като клас case.
Все още използвам scala 2.10.X, тъй като това е най-новото, поддържано от Spark, а в Spark-SQL използвам интензивно класове case.
Заобиколното решение за case classes
с повече от 22 полета:
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
}
}
Интересно е, че вашият конструктор е толкова зареден, но можете да пакетирате свързани стойности в собствен клас case.
Така че докато може да имате
case class MyClass(street: String, city: String, state: String, zip: Integer)
можете да направите това
case class MyClass(address: Address)
Имате и други опции:
- Групирайте елементи в кортежи
- Създайте своя собствена черта
Function23
(или каквото и да е) - Използвайте currying
АКТУАЛИЗАЦИЯ: Както други отбелязаха, това вече не е проблем след пускането на Scala 2.11 – въпреки че бих се поколебал да използвам термина „поправка“. Въпреки това, „Catch 22“, ако желаете, понякога все още се показва в Scala библиотеки на трети страни.
Когато имате толкова много стойности, това обикновено е знак, че дизайнът ви така или иначе трябва да бъде преработен.
Формирайте периодични класове от случаи, които след това се агрегират в по-големия. Това също прави кода много по-лесен за разбиране, разсъждение и поддръжка. Както и заобикалянето на този проблем, който имате.
Например, ако исках да съхранявам потребителски данни, можех да направя това....
case class User(name: Name, email: String)
case class Name(first: String, last: String)
С толкова малко неща това, разбира се, не би било необходимо. Но ако имате 22 неща, които се опитвате да натъпчете в един клас, така или иначе ще искате да правите този вид периодична работа в клас.