【问题标题】:How to get around the Scala case class limit of 22 fields?如何绕过 22 个字段的 Scala 案例类限制?
【发布时间】:2013-12-28 18:18:43
【问题描述】:

Scala 案例类在构造函数中限制为 22 个字段。我想超过这个限制,有没有办法通过与案例类一起使用的继承或组合来做到这一点?

【问题讨论】:

  • 是的,你的权利。在某些情况下,我使用隐式案例类,它使用的字段比实际类少。

标签: scala case-class


【解决方案1】:

有趣的是,您的构造函数已加载,但您可以将相关值打包到它们自己的案例类中。

所以虽然你可能有

case class MyClass(street: String, city: String, state: String, zip: Integer)

你可以这样做

case class MyClass(address: Address)

你也有其他选择:

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

更新:正如其他人所指出的,在 Scala 2.11 发布后,这不再是一个问题——尽管我会犹豫使用“修复”这个词。但是,如果您愿意的话,“Catch 22”有时仍会出现在第三方 Scala 库中。

【讨论】:

    【解决方案2】:

    这个issue 将在 Scala 2.11 中修复。

    【讨论】:

    • scala 2.11 是救生员!
    【解决方案3】:

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

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

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

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

    有了这么少的东西,这当然没有必要。但是,如果你有 22 样东西要塞进一堂课,那么无论如何你都会想做这种断断续续的案例课堂作业。

    【讨论】:

    • 有一个 json 需要解析,它有超过 22 个字段。使用像 json4s 这样的对象映射器,它需要一个包含所有字段的类。
    • 这个答案是我想到的第一个想法,它或多或少是正确的
    【解决方案4】:

    构建一个像案例类一样的普通类。

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

    超过 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
        }
    }
    

    【讨论】:

    • Extending Product 为您提供了很好的迭代部分,但您没有获得复制方法。复制方法在案例类中,但不是 Product trait,因为它是由 Scala 编译器生成的(现在可以为案例类中的每个字段强类型化)。
    • 您在 Spark 中注册了哪些序列化程序?我从 twitter.chill.avro.AvroSerializer.SpecificRecordBinarySerializer 开始,但在这种情况下,我的班级必须实现 SpecificRecordBase,这让我再次面临 22 个字段的限制。
    【解决方案5】:

    最近(2016 年 10 月,OP 后六年),Richard Dallaway 的博文“Scala and 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) 消除了对上述常见场景的限制:构造案例类、字段访问(包括复制)和模式匹配 (baring edge cases)。

    它通过省略 unapplytupled 来实现超过 22 个字段的案例类。
    也就是说,Function22Tuple22 的限制仍然存在。

    解决极限(Scala 2.11 后)

    有两个常见的技巧可以绕过这个限制。

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

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

    如果你想使用案例类,你最好使用无形的 HList 实现。我们创建了Slickless library 来简化此操作。特别是 the recent mappedWith method 在无形 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 代码库中有一个 full example with 26 columns

    【讨论】:

      猜你喜欢
      • 2017-03-21
      • 1970-01-01
      • 1970-01-01
      • 2014-06-27
      • 1970-01-01
      • 2015-03-25
      • 1970-01-01
      相关资源
      最近更新 更多