これらは一般化された型制約と呼ばれます。これにより、型パラメーター化されたクラスまたは特性内から、型パラメーターの1つをさらに制約できます。次に例を示します。
case class Foo[A](a:A) { // 'A' can be substituted with any type
// getStringLength can only be used if this is a Foo[String]
def getStringLength(implicit evidence: A =:= String) = a.length
}
暗黙の引数evidenceはコンパイラーによって提供され、iff AはStringです。あなたはと考えることができます証拠AであるString--the引数自体は唯一それが存在することを知って、重要ではありません。[編集:ええと、技術的には、からAへの暗黙的な変換を表すため、実際には重要です。これStringにより、呼び出しa.lengthを許可し、コンパイラーに怒鳴られることはありません]
これで次のように使用できます:
scala> Foo("blah").getStringLength
res6: Int = 4
しかし、私がFooそれ以外のものを含むものでそれを使用しようとした場合String:
scala> Foo(123).getStringLength
<console>:9: error: could not find implicit value for parameter evidence: =:=[Int,String]
あなたはそのエラーを「Int == Stringであるという証拠を見つけることができませんでした」と読むことができます... さらなる制限getStringLengthを課しているのタイプに、一般に必要AなものよりもをFooます。つまり、あなただけ呼び出すことができますgetStringLengthにFoo[String]。この制約はコンパイル時に適用されます。これはすばらしいことです。
<:<そして、<%<同様に作業が、わずかなバリエーションを持ちます:
A =:= B Aは正確にBでなければならないことを意味します
A <:< BAはBのサブタイプでなければならないことを意味します(単純な型制約に<:)
A <%< BAが表示可能でなければならないことを意味します Bとして。おそらく暗黙的な変換(単純型制約に類似<%)
@retronymによるこのスニペットは、この種のことがどのようにして達成され、一般化された型制約がどのようにしてこれをより簡単にするのかについての良い説明です。
補遺
あなたのフォローアップの質問に答えるために、確かに、私が与えた例はかなり工夫されており、明らかに役に立たない。しかしList.sumInts、整数のリストを合計するメソッドのようなものを定義するためにそれを使用することを想像してください。このメソッドが古いListで呼び出されるのを許可する必要はありませんList[Int]。ただし、Listタイプコンストラクターをそれほど制約することはできません。あなたはまだ文字列、foos、bars、whatnotsのリストを持ちたいと思っています。したがって、一般化された型制約をに配置sumIntsすることで、そのメソッドだけがでのみ使用できる追加の制約を持つことを保証できますList[Int]。基本的に、特定の種類のリスト用に特別なケースのコードを書いています。