Scala ひと巡り : 下限 型境界 (Lower Type Bounds)

上限型境界 [18]は、型を他の型のサブ型へ制限し、他方、下限型境界は、型が他の型のスーパー型であると宣言します。項 T >: A は、型パラメータ T あるいは抽象型 T が、型 A のスーパー型を参照することを表します。

次はそれが役に立つ例です:

case class ListNode[T](h: T, t: ListNode[T]) { def head: T = h def tail: ListNode[T] = t def prepend(elem: T): ListNode[T] = ListNode(elem, this) }

上記のプログラムは prepend (先頭に追加)操作を使って連結リストを実装します。残念ながら、この型は、クラス ListNode の型パラメータ中にあって、非変です; すなわち、型 ListNode[String]は 型 List[Object]のサブ型ではありません。変位指定アノテーション [17]の助けを借りて、このようなサブ型のセマンティクスを表現できます:

case class ListNode[+T](h: T, t: ListNode[T]) { ... }

残念ながら、共変の変位指定は型変数を共変の位置で使う場合のみ可能なので、このプログラムはコンパイルできません。型変数 T はメソッド prepend のパラメータ型として現われるので、この規則は破られています。しかし、下限型境界の助けを借りれば、T が共変の位置のみに現れる prepend メソッドを実装できます。

次は対応するコードです:

case class ListNode[+T](h: T, t: ListNode[T]) { def head: T = h def tail: ListNode[T] = t def prepend[U >: T](elem: U): ListNode[U] = ListNode(elem, this) }

新しい prepend メソッドは、少しばかり制約の少ない型を持つことに注意してください。これにより、たとえば、既に存在するリストの先頭にスーパー型のオブジェクトを追加できます。得られるリストは、このスーパー型のリストです。

次は、そのことを示すコードです:

object LowerBoundTest extends Application { val empty: ListNode[Null] = ListNode(null, null) val strList: ListNode[String] = empty.prepend("hello") .prepend("world") val anyList: ListNode[Any] = strList.prepend(12345) }