结构类型不调用正确的实现?
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
方法已更改,因此它只接受 Char
s.
String
本身就有一个方法contains(elem: java.lang.CharSequence): Boolean
。 String
是 CharSequence
,因此当您在 String
上调用 contains("B")
时,将调用该方法并且 String
不会转换为 WrappedString
.
我的印象是 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
方法已更改,因此它只接受 Char
s.
String
本身就有一个方法contains(elem: java.lang.CharSequence): Boolean
。 String
是 CharSequence
,因此当您在 String
上调用 contains("B")
时,将调用该方法并且 String
不会转换为 WrappedString
.