【发布时间】:2016-02-16 15:37:33
【问题描述】:
我的印象是Structural Types 在后台使用反射(表明需要tell the compiler 来启用"-language:reflectiveCalls"),并且任何与该类型匹配的对象都将使用它自己的函数版本。例如,如果我在Seq 上调用.contains,那么它将使用Seq 版本,如果我在String 上调用它,那么它将使用从@987654330 获得的StringOps 中定义的版本@
那么在 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) 为自己返回 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
针对关于编译器错误的评论,这里是screencast of my terminal showing this working
【问题讨论】:
-
你确定你试过这样吗?在 Scala 2.11 中,我在实例化地图的行中得到类型不匹配。这是因为 String 和 Seq 都没有方法 contains(Any)。它们的包含方法具有不同的签名。因此,如果在 scala 2.10 中进行这种类型检查,这将是一个错误。
-
这在 scala 2.10.3 中运行,版本在 REPL 中注明
-
@dth 我为你添加了我的 REPL 的视频截屏
标签: scala reflection structural-typing