<:<运算符如何在Scala中运行?
在
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] 它是如何使用的一个例子是TraversableOnce的toMap方法: def toMap[T,U](implicit ev: A <:< (T,U)): immutable.Map[T,U] = 我不明白的是这是如何工作的.我明白A<:< B在句法上等同于类型<:< [A,B].但是我不知道当且仅当A<:B时,编译器才能找到该类型的隐式.我假设$conforms的定义中的asInstanceOf调用使某种方式成为可能,但是如何?此外,使用抽象类的单例实例而不仅仅是使用对象是否重要? 解决方法
假设我们有以下简单类型层次结构:
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<:<的基本类型. 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不是String,因此它不是Bar<:<的子类型字符串,所以它不是我们需要的.但$conforms是编译器可以获得的唯一位置<:<实例(除非我们定义了我们自己的,这将是危险的),所以它非常正确地拒绝编译这个废话. 要解决第二个问题:<:< [ - From,To]类是必需的,因为我们需要此类型类的类型参数才有用.单身Any<:<任何值都可以定义为一个对象 - 使用val和匿名类的决定可以说有点简单,但它是一个你不应该担心的实现细节. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |