2015-03-04 14 views
5

Ho la seguente riga di codice:Scala Set [_] vs Set [Qualsiasi]

case set: Set[Any] => setFormat[Any].write(set) 

Tuttavia, il compilatore genera un avviso:

non-variable type argument Any in type pattern scala.collection.Set[Any] is unchecked since it is eliminated by erasure [warn]

Mi sembra giusto.

Così posso cambiare la mia linea a questo:

case set: Set[_] => setFormat[Any].write(set) 

Ora ho un errore:

[error] found : scala.collection.Set[_]

[error] required: scala.collection.Set[Any]

Q1. Qual è la differenza tra questi due?

Poi posso cambiare il mio codice al seguente:

case set: Set[_] => setFormat[Any].write(set.map(s => s)) 

Ora è felice senza errori o avvisi.

Q2. Perché funziona?

+0

potresti fornire i tipi/firme di setFormat e scrivere? –

+0

solo curioso, rimuove l'esplicito '[Any]' e la mappa, come suggerito nella mia risposta sotto "Note", funziona nel tuo caso? –

risposta

12

Q1: A Set[Any] è un Set il cui tipo di elementi è Qualsiasi. A Set[_] è un Set il cui tipo di elementi è sconosciuto. Forse è un Set[Int], forse un Set[String], forse un Set[Any]. Contrariamente alla maggior parte delle collezioni (immutabili), Set non è covariante (la dichiarazione è trait Set[A], non trait Set[+A]). Quindi un Set[String] non è un Set[Any] e, più in generale, non è possibile garantire che un set di cui non si conosce il tipo (ad esempio Set[_]) sia un Set[Any].

Q2: Funziona perché qualunque sia la (sconosciuto) di tipo A degli elementi del set, la funzione identità s => s può essere considerato una funzione A => Qualsiasi. (Varianza è Function1[-T1, +R] Poi, il risultante set.map(s => s) può essere digitato come Set[Any], come richiesto

Nota:.. Difficile essere sicuri, senza la definizione di SetFormat e scrivere, ma non si ha realmente bisogno di essere esplicito con il [Any] tipo di argomento in setFormat[Any]? uno può passare esistenziale a una funzione generica, cioè

val x: X[_] = .... 
def f[A](xa: X[A]) = ... 
f(x) // allowed 

ma essendo esplicito al sito di invito (f[Any](x)) non sarà consentito, come noi non sappiamo se X è un X[Any].

Nota: circa Set non essendo covariante: Questo è un peccato, poiché ci si sente molto che anche un insieme di Gatti è un insieme di Animali. Ecco una ragione per questo (potrebbero essercene altri).

Set ha un metodo def contains(a: A): Boolean e questa firma impedisce la covarianza. Altre raccolte hanno uno def contains[A1 >: A](a: A): Boolean, che consente la covarianza, ma che è effettivamente equivalente a def contains(a: Any): Boolean.

Funziona, perché l'implementazione è basata sul metodo equals, disponibile ovunque (fornito con la JVM) e che accetta un argomento di tipo Any. È abbastanza probabile che chiamare con un valore di un tipo non correlato al contenuto della lista sia un errore e che una firma più vincolata sia migliore, ma è un piccolo prezzo da pagare per la covarianza.

Ma questa firma rilassata per contains vincola l'implementazione in base a equals (e possibilmente anche hashCode). Non funzionerebbe per un'implementazione basata su Ordering, che non accetterebbe un argomento non tipizzato. Proibire tali (molto comuni) implementazioni dell'insieme può essere considerato un prezzo troppo alto per la covarianza.

+1

vedere anche http://stackoverflow.com/q/676615/86485 ("Perché il set immutabile di Scala non covariante nel suo tipo?") –