2015-01-05 24 views
7

Anlama içinde null ve tip ek açıklamaları ile uğraşırken garip davranışlar gibi görünen şeyleri anlamaya çalışıyorum. Örnek olarakScala istisnası, tip ek açıklama ile anlaşılırken

: içinde

def f(): String = null 

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

sonuç beklenen:

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

ancak, o zaman olsun b

def f(): String = null 

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

türüne tür ek açıklaması eklerseniz Bir çalışma zamanı istisnası:

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

Bu neden oluyor? Yine de ilk örnekte String türünde b örtük değil midir? İkinci örnekte açık tip ek açıklama değişiyor?

(Not, örnekler Scala 2.11.4 çalıştırıldı)

+0

Eğer repl içinde 'reify' kullanarak görebilirsiniz olarak ikinci örnek, bir maça derler:' ithalat scala.reflect.runtime.universe ._; {for {...}}. Sana neden olduğunu söyleyemem. AIUI 'null' eşleşmiyor çünkü eşleme türü (ya da değer),' b' 'String' bir derleme zamanı türüne sahip olsa bile; Bu, bir anlamda tip sistemde bir deliktir ve scala kodu genellikle boş değerlerden kaçınmalıdır. – lmm

+0

Ben kimsenin hayranı değilim, inan bana! Bunun üzerine tökezlediğim gerçek kodda bazı eski java kodlarıyla entegre etmek için 'try's kullanıyordum. Ancak, null burada benim için rastlantısal görünüyor: Ben tuhaf (korkutucu?) Buluyorum yönüyle (türkçe olmayan) bir çalışma zamanı istisna daha tür özgüllük sonuçları ekleyerek olmasıdır. –

+0

Bu, bir 'for' /' verim 'türlerini bir desen eşlemesine yerleştiren bir dilin tuhaflığıdır; ifadelerde "sıradan" tiplerle ortaya çıkacak bir sorun değil. Söyleyebileceğim tek şey bu talihsiz, ama muhtemelen bu aşamada değiştirilemez; Bu sebepten ötürü bir sol/sol tarafın herhangi bir türünü vermekten kaçınmaya eğilimliyim:/ – lmm

cevap

7

null şey bir örneği değildir:

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

Tip desen boş olmayan belirtir.

çeviri göstermek için bir hile göstereceğim yorum yapmak olan

:

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

Bu neyin yanlış gittiğini gösteriyor, ancak tartışmasız bir hata çünkü _by construction_ zaten doğru türe sahip olduğundan ('val b: String = f'), o son haritadaki desen eşlemesinin bir nedeni yoktur. (Aynı zamanda, kimlik fonksiyonunun optimize edilmediği bir hatadır, ama daha karmaşık bir durum hayal edebiliyoruz.) –

+0

@RexKerr evet, tartışmasız. Eski 'val b: String = f() 'sözdizimini kullanmışsa daha güçlü bir argüman, belki de modulo SI-900, burada jeneratörün üzerindeki tip patlaması filtre anlamına gelir. Ama sıradan maçı optimize edemezsin. Belki de "val i = 42: Int" yazmalıyız. Sonra 'val s: String = null: String' Tuple1'de sarılmış gibi başarısız olabilir. –

+0

Dil özellikleri, anlatmadaki tip ek açıklamasının şekersizleştirilmesinin desen eşlemesi olarak uygulanmasını ister mi? –