web-dev-qa-db-ja.com

22フィールドのScalaケースクラス制限を回避するには?

Scalaのケースクラスには、コンストラクタで22フィールドの制限があります。この制限を超えたいのですが、ケースクラスで機能する継承または構成でそれを行う方法はありますか?

47
Phil

最近(2016年10月、OPの6年後)、ブログ投稿「 Scala and 22Richard Dallaway その限界を探る:

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を省略することでこれを行いました。
つまり、 Function22 および Tuple22 はまだ存在しています。

制限の回避(post Scala 2.11)

この制限を回避するための2つの一般的なトリックがあります。

  • 最初の方法は、入れ子になったタプルを使用することです。
    タプルに22個を超える要素を含めることはできないのは事実ですが、各要素自体をタプルにすることができます

  • もう1つの一般的なトリックは、22の制限がない異種リスト(HLists)を使用することです。

ケースクラスを使用する場合は、形状のない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])
}

Slicklessコードベースには 26列の完全な例 があります。

41
VonC

この issue は、Scala 2.11で修正される予定です。

30
Brian

ケースクラスのように機能する通常のクラスを作成します。

私は今でも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 class MyClass(street: String, city: String, state: String, Zip: Integer)

あなたはこれを行うことができます

case class MyClass(address: Address)

他のオプションもあります:

  • アイテムをタプルにグループ化する
  • 自分で作る Function23 trait(または何でも)
  • currying を使用します

更新:他の人が述べたように、これはScala 2.11-のリリース後の問題ではなくなりました。場合は、サードパーティのScalaライブラリにまだ表示されます。

19
Vidya