2015-01-05 24 views
7

Próbuję zrozumieć, co wydaje się dziwne zachowanie, gdy mamy do czynienia z wartościami null i adnotacje typu wewnątrz pojęcia for-understand.Wyjątek scala w zrozumieniu z adnotacją typu

Jako przykład:

def f(): String = null 

for { 
    a <- Option("hello") 
    b = f() 
} yield (a, b) 

skutkuje oczekiwana:

//> res0: Option[(String, String)] = Some((hello,null)) 

jednak, jeśli dodać typ adnotacji do rodzaju b

def f(): String = null 

for { 
    a <- Option("hello") 
    b: String = f() 
} yield (a, b) 

potem dostać wyjątek środowiska wykonawczego:

//> scala.MatchError: (hello,null) (of class scala.Tuple2) 

Dlaczego tak się dzieje? Czy w pierwszym przykładzie nie jest to typ ? Co zmienia adnotacja typu jawnego w drugim przykładzie?

(Uwaga, przykłady przeprowadzono w Scala 2.11.4)

+0

Drugi przykład kompiluje do meczu, jak widać z użyciem 'reify' w repl:' import scala.reflect.runtime.universe ._; reify {for {...}} '. Nie mogę ci powiedzieć, dlaczego. AIUI 'null' nie pasuje, ponieważ dopasowanie działa na typie (lub wartości) środowiska wykonawczego, nawet jeśli' b' ma typ "String" w czasie kompilacji; jest to w pewnym sensie dziura w systemie typów, a kod scala powinien zasadniczo unikać używania wartości null. – lmm

+0

Nie jestem fanem zerowej wartości, wierz mi! W rzeczywistym kodzie, w którym natknąłem się na to, używałem 'Try's do integracji z jakimś starszym kodem java. Jednak null wydaje mi się tu incydentalny: aspekt, który uważam za dziwaczny (przerażający?) Polega na tym, że dodanie większej liczby specyficzności typów powoduje (nieintuicyjny) wyjątek środowiska wykonawczego. –

+0

To dziwaczność języka, że ​​umieszczanie typów w 'for' /' yield' powoduje dopasowanie wzorca; nie ma problemu, który wystąpiłby w przypadku wyrażeń "zwykłych". Wszystko, co mogę powiedzieć, to niefortunne, ale prawdopodobnie nie można tego zmienić na tym etapie; Z tego powodu staram się unikać podawania typu po lewej stronie// z tego powodu:/ – lmm

Odpowiedz

7

null nie jest instancją wszystkiego:

scala> (null: String) match { case _: String => } 
scala.MatchError: null 
    ... 33 elided 

scala> val s: String = null 
s: String = null 

scala> s.isInstanceOf[String] 
res1: Boolean = false 

http://www.scala-lang.org/files/archive/spec/2.11/08-pattern-matching.html#type-patterns

Rodzaj wzór określa niezerowe.

Jeden trick za pokazanie tłumaczenie jest komentarz Pokaż:

scala> for { 
    | a <- Option("hello") 
    | b: String = f() 
    | } yield (a, b) // show 
object $read extends scala.AnyRef { 
    def <init>() = { 
    super.<init>; 
    () 
    }; 
    object $iw extends scala.AnyRef { 
    def <init>() = { 
     super.<init>; 
    () 
    }; 
    import $line4.$read.$iw.$iw.f; 
    object $iw extends scala.AnyRef { 
     def <init>() = { 
     super.<init>; 
     () 
     }; 
     val res1 = Option("hello").map(((a) => { 
     val b: String = f; 
     scala.Tuple2(a, b) 
     })).map(((x$1) => x$1: @scala.unchecked match { 
     case scala.Tuple2((a @ _), (b @ (_: String))) => scala.Tuple2(a, b) 
     })) 
    } 
    } 
} 
scala.MatchError: (hello,null) (of class scala.Tuple2) 
    at $anonfun$2.apply(<console>:10) 
    at $anonfun$2.apply(<console>:10) 
    at scala.Option.map(Option.scala:145) 
    ... 39 elided 
+0

To pokazuje, co jest nie tak, ale jest to prawdopodobnie błąd, ponieważ nie ma powodu, aby dopasowywać wzorce na tej ostatniej mapie, ponieważ _two construction_ ma już poprawny typ (w 'val b: String = f'). (Jest to również prawdopodobnie błąd, którego funkcja identyfikacji nie jest zoptymalizowana, ale możemy sobie wyobrazić bardziej złożony przypadek.) –

+0

@RexKerr tak, prawdopodobnie. Jest silniejszy arg, jeśli użyje starej składni 'val b: String = f()', może modulo SI-900 gdzie typ pat na generatorze oznacza filtr. Ale nie zoptymalizowałbyś zwykłego pojedynku. Może powinniśmy zacząć pisać 'val i = 42: Int'. Następnie 'val s: String = null: String' może zawieść tak, jakby był zawinięty w' Tuple1'. –

+0

Czy specyfikacja językowa nakazuje, aby odsłanianie adnotacji typu w zrozumieniu było zaimplementowane jako dopasowanie wzorca? –