2016-02-16 43 views
0

我的印象是,Structural Types使用反射罩下方(表示需要tell the compiler啓用"-language:reflectiveCalls"),並且任何匹配類型的對象都將使用它自己的函數版本。例如,如果我叫.containsSeq比它將使用Seq版本,如果我把它叫做一個String那麼它將使用StringOps它從SeqLike結構類型不調用正確的實現?

變得如此斯卡拉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。載有(String)返回自身真實的,但如果它被稱爲同時interpretted作爲Containable類型,即使該定義的方法匹配StringOps類。

我有感覺這與自.contains文件==實施做說:

如果是真的該序列具有相等的元素(如==確定),以ELEM,否則爲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

+0

你確定你已經嘗試過嗎?在Scala 2.11中,我在你實例化地圖的行中遇到類型錯配。這是由於既沒有String也沒有Seq擁有一個包含(Any)的方法。他們包含的方法有不同的簽名。所以如果這個類型在scala 2.10中會出現這個bug。 – dth

+0

這運行在斯卡拉2.10.3,該版本是在REPL – EdgeCaseBerg

+0

@dth中註明的我已經爲您添加了我的REPL的視頻截屏 – EdgeCaseBerg

回答

3

當您將String s轉換您的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的集合中的一個元素。 A WrappedString表示Char s的集合,因此如果您給它一個String,該方法將永不返回true。 在scala 2.11.x中,contains方法已被更改,因此它只接受Char s。

String本身有一個方法contains(elem: java.lang.CharSequence): Boolean。 A StringCharSequence,因此當您撥打contains("B")時,String將調用該方法,並且String不會轉換爲WrappedString

+0

哦哇。你知道_why_它被轉換成WrappedString嗎? – EdgeCaseBerg

+0

我剛剛注意到,這個變化更深。 WrappedString實現了SeqLike,SeqLike的contains方法的簽名在Scala 2.11中發生了變化。 – dth

+0

原因,爲什麼它被轉換,是,該字符串沒有一個方法包含(任何),但只包含(CharSequence)。正如你明確指定的那樣,編譯器必須對其進行轉換。 – dth