Perché mappa/filtro ... non funziona con una matrice di nulla?
-
27-10-2019 - |
Domanda
Non è niente un sottotipo di tutti i tipi?
scala> val array = new Array(5)
array: Array[Nothing] = Array(null, null, null, null, null)
scala> array.map(_ => 42)
<console>:9: error: value map is not a member of Array[Nothing]
array.map(_ => 42)
^
scala> array.filter(_ != 42)
<console>:9: error: value filter is not a member of Array[Nothing]
array.filter(_ != 42)
^
È strano che questo non funzioni.
Questo è specificato, una funzione o un bug?
Soluzione
Quando vedi un comportamento strano che non coinvolge nulla, è perché l'algoritmo di inferenza di tipo pensa di non aver inserito nulla da solo, poiché viene introdotto durante l'inferenza del tipo: se non si sa che nulla di una variabile di tipo, allora è delimitato da qualsiasi e nulla. È stato a lungo nel mio elenco di cose da fare per vedere se posso introdurre un nuovo tipo di fondo solo interno a tale scopo, quindi nulla a livello di utente e nulla a livello di inferenza non è mescolato, ma è un compito piuttosto ambizioso. Tuttavia, ora potrei essere abbastanza hardcore per provarlo.
Altri suggerimenti
Sospetto che Scala non dovrebbe lasciarti fare quel tipo Array[Nothing]
istanza. Per definizione non ci sono casi di nulla in giro, eppure il tuo array sembra essere pieno di Nothing
s null, ma null non è un valore valido per Nothing
. Questo ad esempio fallisce con l'errore type mismatch; found : Null(null) required: Nothing
val n: Nothing = null
Quindi mi aspetterei di imbatterti nei guai ogni volta che puoi davvero ingannare il sistema per credere che tu stia finalmente ottenendo un molto ricercato ad esempio Nothing
…
Ecco un altro caso strano. Esegui questo:
object Main {
class Parametrized[T] { var value: T = _ }
def main(args: Array[String]) {
val p = new Parametrized // typed as Parametrized[Nothing]
val n = p.value // n is now actually an instance of Nothing... isn't it?
println(p.value) // prints null, but null is not an instance of Nothing
println(n) // throws NullPointerException...
}
}
Si noti che il tipo di array Scala è invariante. Così Nothing
Essere un sottotipo di tutto potrebbe non essere rilevante.
Anche map
e filter
non sono definiti Array
. Conversioni implicite in Predef
vengono utilizzati per fornire tali metodi per gli array.
Quindi il compilatore non è in grado di trovare una conversione implicita Array[Nothing]
a qualcosa che ha il map
o filter
definito. Usando la repl, posso effettivamente vedere che dovrebbe essere disponibile una tale conversione implicita:
scala> val conv = implicitly[Array[Nothing] <%< collection.mutable.ArrayOps[Nothing]]
conv: <%<[Array[Nothing],scala.collection.mutable.ArrayOps[Nothing]] = <function1>
scala> conv(new Array[Nothing](5)).filter(_ => true)
res8: Array[Nothing] = Array(null, null, null, null, null)
Quindi la domanda diventa perché il compilatore non considera il genericArrayOps
conversione.