22フィールドのScalaケースクラス制限を回避するには?
Scalaのケースクラスには、コンストラクタで22フィールドの制限があります。この制限を超えたいのですが、ケースクラスで機能する継承または構成でそれを行う方法はありますか?
最近(2016年10月、OPの6年後)、ブログ投稿「 Scala and 22 」 Richard 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フィールドを超えるケースクラスの
unapply
とtupled
を省略することでこれを行いました。
つまり、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列の完全な例 があります。
この issue は、Scala 2.11で修正される予定です。
ケースクラスのように機能する通常のクラスを作成します。
私は今でも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ライブラリにまだ表示されます。