ときどき、あるオブジェクトの型が、複数の他の型のサブタイプであると表現する必要が生じます。 Scalaでは、これは複合型を用いて表現できます。複合型とはオブジェクトの型同士を重ねることです。
2つのトレイトCloneableとResetableがあるとしましょう。
trait Cloneable extends java.lang.Cloneable {
override def clone(): Cloneable = {
super.clone().asInstanceOf[Cloneable]
}
}
trait Resetable {
def reset: Unit
}
今、関数cloneAndResetを書きたいとします。それはオブジェクトを受け取り、それをクローンして、元のオブジェクトをリセットします。
def cloneAndReset(obj: ?): Cloneable = {
val cloned = obj.clone()
obj.reset
cloned
}
パラメータobjの型は何かという疑問が生じます。もしCloneableであれば、オブジェクトをcloneすることができますが、resetすることはできません。もしResetableであれば、resetすることができますが、cloneの操作はできません。そのような状態で型キャストを回避するためにobjの型をCloneableとResetableの両方であると指定することができます。Scalaではこの複合型はCloneable with Resetableのように書くことができます。
こちらが書き変えた関数です。
def cloneAndReset(obj: Cloneable with Resetable): Cloneable = {
//...
}
複合型は複数のオブジェクトの型からなり、一つだけの細別型(refinement)を持てます。細別型は既存オブジェクトのメンバーのシグネチャを絞り込むのに使えます。
一般的な形はA with B with C ... { refinement }です。
細別の使い方の例はミックスインを用いたクラス合成のページにあります。