如何绕过22个字段的Scala案例类限制?

Phi*_*hil 47 scala case-class

Scala案例类在构造函数中限制为22个字段.我想超过这个限制,有没有办法用继承或组合使用案例类?

Von*_*onC 42

最近(2016年10月,也就是OP之后的六年),Richard Dallaway的博客文章" Scala and 22 " 探讨了这个限制:

早在2014年,当Scala 2.11发布时,一个重要的限制就被删除了:

Case classes with > 22 parameters are now allowed. 
Run Code Online (Sandbox Code Playgroud)

这可能会让您认为Scala没有22个限制,但事实并非如此.在函数和元组中存在限制.

Scala 2.11中引入的修复(PR 2305)消除了上述常见场景的限制:构造案例类,字段访问(包括复制)和模式匹配(条形边缘情况).

它通过省略这样做unapply,并tupled为case类以上的22场.
换句话说,限制Function22并且Tuple22仍然存在.

解决限制(后Scala 2.11)

绕过这个限制有两个常见的技巧.

  • 第一种是使用嵌套元组.
    虽然元组不能包含超过22个元素,但每个元素本身都可以是一个元组

  • 另一个常见的技巧是使用异构列表(HLists),其中没有22个限制.

如果您想使用案例类,最好使用无形HList实现.我们创建了Slickless库以使其更容易.特别是最近的mappedWith方法在无形HLists和案例类之间进行转换.它看起来像这样:

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])
}
Run Code Online (Sandbox Code Playgroud)

在Slickless代码库中有一个包含26列完整示例.


Bri*_*ian 30

这个问题将在Scala 2.11中修复.

  • 问题是固定的. (6认同)

Bog*_*gio 23

构建一个像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
    }
}
Run Code Online (Sandbox Code Playgroud)


Vid*_*dya 19

有趣的是你的构造函数是加载的,但你可以将相关的值打包到自己的case类中.

所以,虽然你可能有

case class MyClass(street: String, city: String, state: String, zip: Integer)
Run Code Online (Sandbox Code Playgroud)

你可以这样做

case class MyClass(address: Address)
Run Code Online (Sandbox Code Playgroud)

您还有其他选择:

  • 将项目分组为元组
  • 创建自己的Function23特征(或其他)
  • 使用currying

更新:正如其他人所说,在Scala 2.11发布后,这已不再是一个问题 - 尽管我会毫不犹豫地使用术语"修复".但是,如果您愿意,"Catch 22"有时仍会显示在第三方Scala库中.