Sto cercando di capire quello che sembra strano comportamento quando si tratta di null e digitare annotazioni all'interno di una comprensione.scala eccezione in per-comprensione con annotazione tipo
Per fare un esempio:
def f(): String = null
for {
a <- Option("hello")
b = f()
} yield (a, b)
risultati nella attesi:
//> res0: Option[(String, String)] = Some((hello,null))
tuttavia, se posso aggiungere un tipo di annotazione al tipo di b
def f(): String = null
for {
a <- Option("hello")
b: String = f()
} yield (a, b)
allora ottengo un'eccezione di runtime:
//> scala.MatchError: (hello,null) (of class scala.Tuple2)
Perché ciò accade? Ilnon è implicito nel tipo String
nel primo esempio? Che cosa cambia l'annotazione del tipo esplicito nel secondo esempio?
(Nota, esempi sono stati eseguiti in Scala 2.11.4)
Il secondo esempio viene compilato in un match, come si può vedere usando 'reify' nel repl:' import scala.reflect.runtime.universe ._; reificare {per {...}} '. Non posso dirti perché, però. AIUI 'null' non corrisponde perché la corrispondenza funziona sul tipo (o valore) di runtime, anche se' b' ha un tipo in fase di compilazione 'String'; questo è in un certo senso un buco nel sistema dei tipi, e il codice scala dovrebbe generalmente evitare di usare valori nulli. – lmm
Non sono un fan dei null, credimi! Nel codice effettivo in cui mi sono imbattuto in questo stavo usando 'Try's per l'integrazione con qualche codice java legacy. Tuttavia, qui mi sembra ininfluente: l'aspetto che trovo bizzarro (pauroso?) È che l'aggiunta di più specificità di tipo risulta in un'eccezione di runtime (non intuitiva). –
È una stranezza del linguaggio che mettere i tipi in un 'for' /' yield' produce una corrispondenza di pattern; non è un problema che si verificherebbe con tipi "ordinari" sulle espressioni. Tutto quello che posso dire è che è sfortunato, ma probabilmente non può essere cambiato in questa fase; Tendo ad evitare di dare mai un tipo sul lato sinistro di un for/yield per questo motivo:/ – lmm