2012-04-05 11 views
6

Data una definizione di classe con il parametro tipo associato Animal[A <: String], sembra che il compilatore Scala non deduca B <: String da Animal[B]. L'inferenza è permessa? Come aiutare il compilatore a fare l'inferenza?Come definire le classi dei casi con membri con parametri di tipo non associato?

Di seguito è riportato un esempio concreto con classi di casi in cui la mancanza di questa inferenza è un problema.

Si consideri il seguente gerarchia di classe caso:

sealed trait Person[+T <: Person[T]] 
case class Student() extends Person[Student] 
case class Professor() extends Person[Professor] 

Ho bisogno di definire una classe case University cui posso istanziare con una variabile di tipo Person[_], per esempio val p: Person[_] = Student(). Ho pensato che questo avrebbe funzionato con la seguente definizione:

case class University(p: Person[_]) 

Ma questo viene a mancare la compilazione con l'errore:

type arguments [Any] do not conform to trait Person's type parameter bounds [+T <: Person[T]] 

Se mi legano il parametro type della classe caso University compila (compila anche con parametri non limitati se lascio cadere la parola case, ma questo non è un'opzione nel mio caso):

case class BoundUniversity[P <: Person[P]](p: Person[P]) 

ma questa versione parametrizzata non può essere istanziata con una variabile illimitata di tipo Person[_]:

val p: Person[_] = Student() 
BoundUniversity(p) 

fallisce compilazione con:

inferred type arguments [_$1] do not conform to method apply's type parameter bounds [P <: Person[P]] 

Lo stesso errore si verifica per un metodo con un argomento legato come:

def general[P <: Person[P]](p: P) = println(p) 

quindi questo è non specifico per i costruttori di classi.

Due domande:

  1. Il tipo Person è definita con limiti parametri Person[+T <: Person[T]], in modo che ciascuna istanza di questo tipo è assicurato da rispettare i limiti: val p: Person[P] implica che P <: Person[P]; O mi sta sfuggendo qualcosa? Quindi, come posso chiarirlo al compilatore in modo che non si lamenti?

  2. Come/Posso definire una classe case con membri con parametro tipo non associato come case class University(p: Person[_])?

+0

Il 'T' deve essere covariante? – leedm777

+0

@dave nel mio caso particolare 'T' deve essere covariante, ma penso che questo non cambi il problema: vedi l'esempio introduttivo. –

+0

Si potrebbe ottenere da qualche parte usando [tipi astratti] (http://docs.scala-lang.org/tutorials/tour/abstract-types.html), ma poi diventano [praticamente invarianti] (http: // stackoverflow. com/a/5359015/115478). – leedm777

risposta

2

Un tipo X[_] non è quasi mai quello che desideri. Quando si utilizza _ su un tipo, si sta sostanzialmente dicendo che non ti interessa quale sia quel parametro, perché non avrai mai bisogno di usarlo.

In ogni caso, questo compila. Potrebbe benissimo morderti lungo la strada, i tipi esistenziali sono le cose complicate che sono, ma ...

case class University(p: Person[t] forSome { type t <: Person[t] }) 
+0

Bel tipo esistenziale, grazie! Questo compila, ma non può essere istanziato con 'val p: Person [_] = Student(); Università (p) '. Il tipo "Persona [_]" che ho citato proviene da una lista: 'Elenco [Persona [_]] (Studente(), Professore())'. Nota che 'List (Student(), Professor())' non viene compilato. Sento che c'è uno schema qui ma non riesco a metterlo il dito sopra ... –

+0

In realtà questo non mostra errori nel mio Eclipse ma non compila con 'scalac'. Digitare mismtach, trovato 'Person [(some other) _1 (in method equals)] dove type (some other) _1 (nel metodo equals) <: schemdesc.hierarchy.eval.Person [_0]', richiesto 'Person [_ < : schemdesc.hierarchy.eval.Person [_0]] ' –

+0

@jullybobble La riga sopra compila - l'ho testata. Se hai un problema di compilazione, stai facendo qualcosa di diverso. E non puoi usare 'Persona [_]' - non funzionerà. È necessario utilizzare il tipo esistenziale sopra se vuoi che funzioni. –

Problemi correlati