Scalaに<:<
は、型の制約を目撃するクラスがあります。差出人Predef.scala
:
sealed abstract class <:<[-From, +To] extends (From => To) with Serializable
private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
implicit def $conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
それがどのように使用されるかの例は、次のtoMap
方法にありTraversableOnce
ます:
def toMap[T, U](implicit ev: A <:< (T, U)): immutable.Map[T, U] =
私が理解していないのは、これがどのように機能するかです。A <:< B
構文的にはタイプと同等であることを理解してい<:<[A, B]
ます。しかし、がの場合に限り、コンパイラがその型の暗黙を見つける方法がわかりませんA <: B
。私はと仮定asInstanceOf
の定義における通話が$conforms
何らかの形でこれを可能にしているが、どのように?また、object
?を使用するだけでなく、抽象クラスのシングルトンインスタンスを使用することも重要です。
次の単純な型階層があるとします。
trait Foo
trait Bar extends Foo
私たちはBar
拡張する証拠を求めることができますFoo
:
val ev = implicitly[Bar <:< Foo]
を使用してコンソールでこれを実行すると-Xprint:typer
、次のように表示されます。
private[this] val ev: <:<[Bar,Foo] =
scala.this.Predef.implicitly[<:<[Bar,Foo]](scala.this.Predef.$conforms[Bar]);
そのため、コンパイラーは$conforms[Bar]
、要求した暗黙の値として選択しました。もちろん、この値には型Bar <:< Bar
があり<:<
ますが、2番目の型パラメーターが共変であるため、これはのサブタイプでありBar <:< Foo
、法案に適合します。
(Scalaコンパイラーが探しているタイプのサブタイプを見つける方法を知っているという事実には、ここにいくつかの魔法が関わっていますが、それはかなり一般的なメカニズムであり、その動作はそれほど驚くことではありません。)
ここで、以下をBar
拡張する証拠を要求するとしますString
。
val ev = implicitly[Bar <:< String]
オンにすると-Xlog-implicits
、次のように表示されます。
<console>:9: $conforms is not a valid implicit value for <:<[Bar,String] because:
hasMatchingSymbol reported error: type mismatch;
found : <:<[Bar,Bar]
required: <:<[Bar,String]
val ev = implicitly[Bar <:< String]
^
<console>:9: error: Cannot prove that Bar <:< String.
val ev = implicitly[Bar <:< String]
^
コンパイラーはBar <:< Bar
再試行しますが、Bar
はではないためString
、これはのサブタイプではないBar <:< String
ため、必要なものではありません。しかし$conforms
、コンパイラが<:<
インスタンスを取得できる唯一の場所であるため(独自に定義していない限り、危険です)、このナンセンスなコンパイルを適切に拒否します。
2番目の質問に対処するに<:<[-From, +To]
は、この型クラスの型パラメーターが役立つため、クラスが必要です。シングルトンAny <:< Any
値は、オブジェクトとして定義することもできます。val
匿名クラスを使用するかどうかの決定は、ほぼ間違いなく少し簡単ですが、これは実装の詳細であり、心配する必要はありません。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加