2016-02-16 3 views
0

У меня создалось впечатление, что Structural Types использует отражение под капотом (указывается необходимостью tell the compiler для включения "-language:reflectiveCalls"), и что любой объект, соответствующий типу, будет использовать собственную версию функции. Например, если я называю .contains на Seq, чем он будет использовать версию 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 .Contains (String) возвращает истину для себя, но если это называется в то же время интерпретируются с как Containable типа, несмотря на то, что совпадает с определенным методом в класс StringOps.

У меня есть ощущение, это связанно с реализацией == после .contains документации говорит:

верно, если эта последовательность имеет элемент, который равен (как определено ==) для Эля, иначе лжи ,

это чувство усугубляется результатами проверки типа с помощью 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 я получаю missmatch типа в строке, где вы создаете экземпляр карты. Это связано с тем, что ни String, ни Seq, содержащие метод, не содержат (Any). Их методы содержат разные подписи. Так что если это typechecks в scala 2.10, это будет ошибкой. – dth

+0

Это работает в scala 2.10.3, версия отмечена в REPL – EdgeCaseBerg

+0

@dth Я добавил видеоролик моего REPL для вас – EdgeCaseBerg

ответ

3

При вставке 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. A WrappedString представляет коллекцию Char s, поэтому метод никогда не вернет true, если вы дадите ему String. В scala 2.11.x этот метод contains был изменен, поэтому он принимает только Char s.

String сам по себе имеет способ contains(elem: java.lang.CharSequence): Boolean. A String является CharSequence, поэтому, когда вы вызываете contains("B") на String, этот метод будет вызываться, а String не будет преобразован в WrappedString.

+0

О, ничего себе. Знаете ли вы, _why_ он превращается в WrappedString? – EdgeCaseBerg

+0

Я только что заметил, это изменение глубже. WrappedString реализует SeqLike, и подпись метода contains SeqLike изменилась в Scala 2.11. – dth

+0

Причина, почему она преобразуется, заключается в том, что String не имеет метода содержит (Any), но содержит только (CharSequence). Поскольку вы явно указывали тип Containable, компилятор должен был преобразовать его. – dth

Смежные вопросы