如何绕过Scala大小写类22个字段的限制



Scala case类在构造函数中的字段限制为22个。我想超过这个限制,有没有一种方法可以通过继承或组合来实现这一点?

最近(2016年10月,OP六年后),Richard Dallaway的博客文章"Scala和22"探讨了这一限制:

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

Case classes with > 22 parameters are now allowed. 

也就是说,案例类字段的数量仍然存在限制,请参阅https://stackoverflow.com/a/55498135/1586965

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

Scala 2.11中引入的修复程序(PR 2305)消除了对上述常见场景的限制:构建用例类、字段访问(包括复制)和模式匹配(暴露边缘用例)。

对于22个字段以上的事例类,它省略了unapplytupled
换句话说,对Function22Tuple22的限制仍然存在。

绕过极限(Scala 2.11之后)

绕过这个极限有两个常见的技巧。

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

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

如果您想使用case类,那么最好使用shapeless 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列的完整示例。

这个问题将在Scala 2.11中得到修复。

构建一个类似case类的普通类。

我仍然使用scala2.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)

你还有其他选择:

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

更新:正如其他人所指出的,在Scala2.11-发布后,这不再是一个问题——尽管我会犹豫是否使用"修复"这个词。然而,如果你愿意的话,"Catch22"有时仍然会出现在第三方Scala库中。

如果与您的用例匹配,请尝试这样做。

val schema: StructType = StructType(
    Array(
      StructField(name = "name", StringType),
      StructField(name = "size", StringType)
    )
 )

https://stackoverflow.com/a/64281066/6666008

当你有这么多值时,通常表明你的设计无论如何都需要重新设计。

形成间歇性案例类,然后将其聚合为较大的案例类。这也使代码更易于理解、推理和维护。除了绕过你所面临的这个问题。

例如,如果我想存储用户数据,我可以这样做。。。。

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

由于东西太少,这当然没有必要。但是,如果你想在一节课上塞进22件事,你无论如何都会想做这种间歇性的案例课作业。

最新更新