1. 程式人生 > >Scala Product、case類和元組

Scala Product、case類和元組

Product、case類和元組

case 關鍵字不僅可以推斷出val,同時自動增加一些方法,那麼增加了那些方法呢?

你定義的case 類會混入scala.Product 特徵,它提供了幾個關於例項欄位的通用方法。例如,對於Person 的例項:

package cn.com.tengen.test.obj
case class Person(name: String,age: Option[Int] = None)

object Person extends App{
  val p = Person("Lucky",Option(18))
  println(p.productArity) //元素的個數            輸出:2
  println(p.productElement(0))//第1個元素         輸出:Lucky
  println(p.productElement(1))//第二個元素        輸出:Some(18)
  p.productIterator foreach println//便利         輸出:Lucky  Some(18)
}

Product 原始碼:

package scala
trait Product extends scala.Any with scala.Equals {
  def productElement(n : scala.Int) : scala.Any
  def productArity : scala.Int
  def productIterator : scala.Iterator[scala.Any] = { /* compiled code */ }
  def productPrefix : java.lang.String = { /* compiled code */ }
}

儘管以通用方法訪問欄位非常有用,但由於對各個欄位使用的是Any 型別,而不是其具體型別,這種機制的作用受到了侷限。

對於不同的欄位數量, 也有Product 的子型別最大值為22。這些型別為特定的欄位添加了一些方法,可以保持該欄位的正確型別資訊。例如:

 Product2原始碼:

package scala
trait Product2[@scala.specialized +T1, @scala.specialized +T2] extends scala.Any with scala.Product {
  override def productArity : scala.Int = { /* compiled code */ }
  @scala.throws[scala.IndexOutOfBoundsException](classOf[scala.IndexOutOfBoundsException])
  override def productElement(n : scala.Int) : scala.Any = { /* compiled code */ }
  def _1 : T1
  def _2 : T2
}
object Product2 extends scala.AnyRef {
  def unapply[T1, T2](x : scala.Product2[T1, T2]) : scala.Option[scala.Product2[T1, T2]] = { /* compiled code */ }
}

這些方法返回了欄位的真正型別。這裡的型別引數是協變的,因為ProductN 特徵只用於不可變的型別。用類似_1 的方法訪問這些欄位需要使用對應的型別引數T1,T1 處在協變的位置(即返回值型別)。

這些方法與用來訪問元組元素的方法是相同的。事實上,所有的TupleN 型別都繼承了對應的ProductN 特徵,並提供了_1 到_N 方法的具體實現,N 最大可為22:


object Test {
  def main(args: Array[String]): Unit = {
    val t1 = ("Lucky", 26)
    println(t1)//輸出: (Lucky,26)
    println(t1._1)//輸出: Lucky
    println(t1._2)//輸出: 26
  }
}

為什麼個數的上限是22 ?這個數字的選擇有些隨意,但你可以合理地認為元組中有22 個元素無論如何都已經足夠多了。

這對於人類來說確實如此,但不幸的是,存在一個常見的情景需要超出這個數量限制:儲存大的資料“記錄”中的欄位(或列)。對於SQL 或NoSQL 資料集,包含超過22 個元素的情況並非罕見。元組很有用,至少對於小資料的確如此,因為元組可以保持欄位(列)的順序和型別。所以,22 個元素的限制是一個問題。

事實證明,在Scala 2.10 中,case 類也受到不超過22 個欄位的限制。但這個實現上的限制在2.11 版本中取消了,所以資料應用可以為超過22 個元素的資料記錄使用case 類。