如何解决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类的
unapply
和tupled
来做到这一点。
换句话说,Function22
和Tuple22
的限制依然存在。围绕极限(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级工作。