«Явный» тип в Java - это класс, который является неэквивалентным и имеет дело с «сырыми» объектами, а не с типичными типами типовых параметров.
Например, до того, как были доступны дженерики Java , вы должны использовать класс коллекции следующим образом:
LinkedList list = new LinkedList();
list.add(new MyObject());
MyObject myObject = (MyObject)list.get(0);
Когда вы добавляете свой объект в список, ему все равно, какой тип объекта он есть, и когда вы его получите из списка, вам нужно явно указать его на тот тип, который вы ожидаете.
Используя generics, вы удаляете «неизвестный» коэффициент, потому что вы должны явно указать, какой тип объектов может идти в списке:
LinkedList<MyObject> list = new LinkedList<MyObject>();
list.add(new MyObject());
MyObject myObject = list.get(0);
Обратите внимание, что с помощью дженериков вам не нужно бросать объект, исходящий из вызова get, сбор предварительно задан для работы с MyObject. Этот факт является основным движущим фактором для генериков. Он меняет источник ошибок времени выполнения во что-то, что можно проверить во время компиляции.
Совсем недавно (октябрь 2016 года, через шесть лет после OP) сообщение в блоге « Scala и 22 » из Ричарда Даллауэя исследует этот предел:
< blockquote>Еще в 2014 году, когда была выпущена Scala 2.11, было устранено важное ограничение:
Case classes with > 22 parameters are now allowed.
Это может заставить вас подумать, что нет 22 ограничений в Скала, но это не так. Ограничение сохраняется в функциях и кортежах.
Исправление ( PR 2305 ), введенное в Scala 2.11, устранило ограничение для вышеуказанных общих сценариев: построение классов case, доступа к полю (включая копирование) и сопоставление с образцом ( базирующие крайние случаи ).
Это делалось, опуская
unapply
иtupled
для классов case выше 22 полей. Другими словами, пределFunction22
иTuple22
все еще существует.Работа над пределом (post 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]) }
В базе данных Slickless имеется полный пример с 26 столбцами .
Когда у вас есть много значений, это обычно признак того, что ваш дизайн нуждается в повторной обработке.
Формируйте прерывистые классы case, которые затем объединяются в более крупные. Это также упрощает понимание кода, обоснование и поддержку кода. Как и в обход этой проблемы у вас есть.
Например, если бы я хотел хранить пользовательские данные, я мог бы это сделать ....
case class User(name: Name, email: String)
case class Name(first: String, last: String)
С таким количеством вещей, это, конечно, не было бы необходимо. Но если у вас есть 22 вещи, которые вы пытаетесь втиснуть в один класс, вы все равно захотите сделать такой класс прерывистого случая.
Создайте нормальный класс, который действует как класс 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
(или что-то еще) UPDATE: Как уже отмечали другие, это уже не проблема после выпуска Scala 2.11 - хотя я бы не решайтесь использовать термин «исправить». Тем не менее, «Catch 22», если хотите, иногда появляется в сторонних библиотеках Scala.