如何解决22个字段的Scala案例类限制?

Scala案例类在构造函数中有22个字段的限制。 我想超过这个限制,是否有办法做到与案例类一起工作的inheritance或组合?

最近(2016年10月,OP之后六年), Richard Dallaway的博客文章“ Scala and 22 ”探索了这个限制:

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

Case classes with > 22 parameters are now allowed. 

这可能会导致你认为在Scala中没有22个限制,但事实并非如此。 限制依赖于函数和元组

Scala 2.11中引入的修复( PR 2305 )除去了上述常见场景的限制:构build案例类,字段访问(包括复制)和模式匹配( baring边缘案例 )。

它通过忽略22个字段以上的case类的unapplytupled来做到这一点。
换句话说, Function22Tuple22的限制依然存在。

围绕极限(post Scala 2.11)

绕过这个限制有两个常用的技巧。

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

  • 另一个常见的技巧是使用异构列表(HList),这里没有限制。

如果你想要使用case类,那么最好使用无形的HList实现。 我们已经创build了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]) } 

在Slickless代码库中有26个完整的例子 。

这个问题将在Scala 2.11中得到解决。

构build一个类似于案例类的普通类。

我仍然使用scala 2.10.X,因为这是Spark所支持的最新版本,在Spark-SQL中,我大量使用了case类。

具有超过22个字段的case classes的解决方法:

 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) 

你也有其他的select:

  • 将项目分组为元组
  • 创build你自己的Function23特质(或其他)
  • 使用咖喱

更新:正如其他人已经注意到的,这已经不是Scala 2.11发布之后的问题 – 尽pipe我会毫不犹豫地使用术语“修复”。 不过,如果你愿意的话,“Catch 22”有时候还会出现在第三方的Scala库中。

当你有这么多的价值时,通常表明你的devise需要重新devise。

形成间歇性的案例类,然后聚合成较大的一个。 这也使代码更容易理解,推理和维护。 以及绕过这个问题,你有。

例如,如果我想存储用户数据,我可能会这样做….

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

有了这么less的东西,这当然就没有必要了。 但是,如果你有22件事想要塞进一个class级,那么无论如何你都会想做这种间歇性的class级工作。