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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20258417/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:54:01  来源:igfitidea点击:

How to get around the Scala case class limit of 22 fields?

scalacase-class

提问by Phil

Scala case classes have a limit of 22 fields in the constructor. I want to exceed this limit, is there a way to do it with inheritance or composition that works with case classes?

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

采纳答案by VonC

More recently (Oct 2016, six years after the OP), the blog post "Scala and 22" from Richard Dallawayexplores that limit:

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

Back in 2014, when Scala 2.11 was released, an important limitation was removed:

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

Case classes with > 22 parameters are now allowed. 

That said, there still exists a limit on the number of case class fields, please see https://stackoverflow.com/a/55498135/1586965

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

This may lead you to think there are no 22 limitsin Scala, but that's not the case. The limit lives on in functions and tuples.

The fix (PR 2305) introduced in Scala 2.11 removed the limitation for the above common scenarios: constructing case classes, field access (including copying), and pattern matching (baring edge cases).

It did this by omitting unapplyand tupledfor case classes above 22 fields.
In other words, the limit to Function22and Tuple22still exists.

Working around the Limit (post Scala 2.11)

There are two common tricks for getting around this limit.

  • The first is to use nested tuples.
    Although it's true a tuple can't contain more than 22 elements, each element itself could be a tuple

  • The other common trick is to use heterogeneous lists (HLists), where there's no 22 limit.

If you want to make use of case classes, you may be better off using the shapeless HList implementation. We've created the Slickless libraryto make that easier. In particular the recent mappedWithmethodconverts between shapeless HListsand case classes. It looks like this:

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

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

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

解决限制(Scala 2.11 之后)

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

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

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

如果您想使用 case 类,最好使用 shapeless 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])
}

There's a full example with 26 columnsin the Slickless code base.

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

回答by Brian

This issueis going to be fixed in Scala 2.11.

问题将在 Scala 2.11 中修复。

回答by Boggio

Build a normal class that acts like a case class.

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

I still use scala 2.10.X since that is what is the latest supported by Spark, and in Spark-SQL I make heavy use of case classes.

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

The workaround for case classeswith more than 22 fields:

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

回答by Vidya

It's interesting your constructor is that loaded, but you could package related values into a case class of their own.

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

So while you might have

所以虽然你可能有

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

you can do this

你可以这样做

case class MyClass(address: Address)

You have other options too:

您还有其他选择:

  • Group items into tuples
  • Create your own Function23trait (or whatever)
  • Use currying
  • 将项目分组为元组
  • 创建自己的Function23特征(或其他)
  • 使用柯里化

UPDATE: As others have noted, this is no longer an issue after the release of Scala 2.11--though I would hesitate to use the term "fix." However, the "Catch 22," if you will, sometimes still shows up in third-party Scala libraries.

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

回答by Dante Romero

When you have that many values, it's usually a sign that your design needs to be reworked anyways.

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

Form intermittent case classes that then aggregate into the larger one. This also makes the code much easier to understand, reason about, and maintain. As well as bypassing this issue you are having.

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

For example, if I wanted to store user data I might do this....

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

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

With so few things, this of course wouldn't be necessary. But if you have 22 things you are trying to cram into one class, you'll want to do this sort of intermittent case class-work anyways.

这么少的东西,这当然没有必要。但是如果你想把 22 件事塞进一个班级,无论如何你都会想要做这种间歇性的案例课堂工作。