0

我的印象是结构类型在底层使用反射(需要告诉编译器启用"-language:reflectiveCalls"),并且任何与类型匹配的对象都将使用它自己的函数版本。例如,如果我调用.containsaSeq它将使用Seq版本,如果我调用它 aString那么它将使用它从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

正如你所看到的,a String.contains( String) 为自己返回 true,但如果它在被解释为Containable类型时被调用,则不会返回 true,即使它与 StringOps 类中定义的方法匹配。

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

如果此序列有一个元素等于(由 == 确定)elem,则为 true,否则为 false。

通过检查类型的结果使这种感觉更加复杂isInstanceOf

scala> val aVal = myMap("A")
aVal: Containable = B

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

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

为了回应关于编译器错误的评论,这是我的终端的截屏视频,显示了这个工作

4

1 回答 1

3

当您将Strings插入 s 时Map,它们会转换为 a 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.xWrappedString中有一个方法contains(elem: Any): Boolean。它检查是否是调用elem集合的元素。containsAWrappedString表示 s 的集合Char,因此如果您给它一个 s,该方法将永远不会返回 true String。在 scala 2.11.x 中,该contains方法已更改,因此它只接受Chars。

String本身就有方法contains(elem: java.lang.CharSequence): Boolean。AString是 aCharSequence因此,当您调用contains("B")a时String,将调用该方法并且String不会转换为 a WrappedString

于 2016-02-16T16:02:33.240 回答