结构类型不调用正确的实现?

Structural Type doesn't call correct implementation?

我的印象是 Structural Types use reflection under the hood (indicated by the need to tell the compiler to enable "-language:reflectiveCalls") and that whatever object matches the type will be using it's own version of the function. For example, if I call .contains on a Seq than it will use the Seq version, if I call it on a String then it will use the version defined in StringOps 它来自 SeqLike

所以在 scala 2.10.3 中,为什么会发生这种情况:

Welcome to Scala version 2.10.3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_79).
Type in expressions to have them evaluated.
Type :help for more information.

scala> type Containable = { def contains(elem:Any):Boolean }
defined type alias Containable

scala> val myMap: Map[String, Containable] = Map("A" -> "B", "C" -> Seq("A","B"))
myMap: Map[String,Containable] = Map(A -> B, C -> List(A, B))

scala> myMap("A").contains("B")
res0: Boolean = false

scala> myMap("C").contains("B")
res1: Boolean = true

scala> "B".contains("B")
res3: Boolean = true

如您所见,String.contains(String) returns 本身是正确的,但如果它在被解释为 Containable 类型时被调用则不是,即使它与 StringOps class 中定义的方法相匹配。

我觉得这与 == 的实施有关,因为 .contains 文档说:

true if this sequence has an element that is equal (as determined by ==) to elem, false otherwise.

通过 isInstanceOf

检查类型的结果使这种感觉更加复杂
scala> val aVal = myMap("A")
aVal: Containable = B

scala> aVal.isInstanceOf[String]
res5: Boolean = false

scala> aVal.isInstanceOf[Seq[_]]
res6: Boolean = true

为了回应有关编译器错误的评论,这里是 screencast of my terminal showing this working

当您将 String 插入 Map 时,它们会转换为 WrappedString,因为 String 没有带有您签名的方法在 Containable.

中定义
scala> implicitly[String => Containable]
res10: String => Containable = <function1>

scala> res10("s")
res11: Containable = s

scala> res11.getClass
res12: Class[_ <: AnyRef] = class scala.collection.immutable.WrappedString

在 Scala 2.10.x WrappedString 中有一个方法 contains(elem: Any): Boolean。它检查 elem 是否是调用 contains 的集合的元素。 WrappedString 表示 Char 的集合,因此如果给它一个 String,该方法永远不会 return 为真。 在 scala 2.11.x 中,contains 方法已更改,因此它只接受 Chars.

String本身就有一个方法contains(elem: java.lang.CharSequence): BooleanStringCharSequence,因此当您在 String 上调用 contains("B") 时,将调用该方法并且 String 不会转换为 WrappedString.