Классы case Scala имеют ограничение в 22 поля в конструкторе. Я хочу превысить этот предел, есть ли способ сделать это с наследованием или композицией, которая работает с классами case?
Как обойти ограничение класса Scala в 22 поля?
Ответы (5)
Совсем недавно (октябрь 2016 г., через шесть лет после ОП) сообщение в блоге «Scala и 22" от Ричарда Даллауэя a> исследует этот предел:
Еще в 2014 году, когда вышла версия Scala 2.11, было снято важное ограничение:
Case classes with > 22 parameters are now allowed.
Тем не менее, по-прежнему существует ограничение на количество полей класса case, см. 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
(или любую другую) - Используйте каррирование
ОБНОВЛЕНИЕ: как уже отмечали другие, это больше не проблема после выпуска Scala 2.11, хотя я бы не стал использовать термин «исправление». Однако «Catch 22», если хотите, иногда все еще проявляется в сторонних библиотеках Scala.
Когда у вас так много значений, обычно это признак того, что ваш дизайн все равно нуждается в переработке.
Формируйте прерывистые классы случаев, которые затем объединяются в более крупный. Это также делает код намного проще для понимания, анализа и поддержки. А также обойти эту проблему, с которой вы столкнулись.
Например, если бы я хотел хранить пользовательские данные, я мог бы сделать это....
case class User(name: Name, email: String)
case class Name(first: String, last: String)
С таким небольшим количеством вещей в этом, конечно, не было бы необходимости. Но если у вас есть 22 предмета, которые вы пытаетесь втиснуть в один класс, вам все равно захочется выполнять такую прерывистую классную работу.