2013-12-14 22 views
9

Questo metodo funziona beneNessun ClassTag disponibili per MyClass.this.T per un tipo astratto

class MyClass[T<: Actor: ClassTag] extends Actor { 
    //.... 
} 

ma questo non a causa dell'errore No ClassTag available for MyClass.this.T

class MyClass extends Actor { 
    type T<: Actor 
    //... 
} 

anche quando effettuare le seguenti operazioni:

class MyClass extends Actor { 
    type T<: Actor: ClassTag //this doesn't even compile 
    //... 
} 

Come utilizzare un abstract type e eliminare l'errore?

risposta

8
class M[A <: B: C] 

è l'abbreviazione di

class M[A <: B](implicit c: C[A]) 

Pertanto, se si sposta A a un membro tipo astratto, si dovrà scrivere qualcosa come

abstract class M { 
    type A <: B 
    implicit protected def c: C[A] 
} 

e richiedono chiunque attuazione M di fornire tale valore c. Se si desidera M non astratta, è necessario richiedere un parametro di valore costruttore di tipo C[A], che a sua volta significa che tipo A deve essere parametro di tipo costruttore ...


Modifica di rispondere alle osservazioni: The notazione A : Cè definito come espandente a un parametro del valore implicito di tipo C[A]. Lì C è chiamato contesto limitato e può essere compreso come richiesta di una classe di tipo C[_] per il tipo A. Se l'utente implementaM, non è necessario ripetere il modificatore implicit. Perché è lì? Lasciate che vi faccia un esempio usando un noto Classe Tipo Ordering:

abstract class Foo { 
    type A 
    implicit protected def ord: Ordering[A] 

    protected def seq: Seq[A] 

    def range: (A, A) = { 
    val xs = seq 
    xs.min -> xs.max 
    } 
} 

Se è stato rimosso implicit, sarebbe necessario modificare le chiamate a xs.min e xs.max che richiedono un implicito Ordering.

object Bar extends Foo { 
    type A = Int 
    val seq = List(8, 34, 5, 21, 3, 13) 
    val ord = Ordering.Int // don't need to repeat `implicit` 
} 

Bar.range // (3, 34) 

Qui, Bar mostra come si fornisce il parametro di valore implicito. Questo sarebbe lo stesso per ClassTag:

trait MyClass { 
    type A 
    implicit def tag: reflect.ClassTag[A] 
} 

object StringClass extends MyClass { 
    type A = String 
    // type String is statically known, thus compiler gives us this: 
    val tag = reflect.classTag[String] 
} 

Se la classe bambino è generica di nuovo, è necessario passare la responsabilità di fornire un tag classe:

class GenericClass[A1](implicit val tag: reflect.ClassTag[A1]) { 
    type A = A1 
} 
+0

Interessante. Ho giocato un po 'con esso, e sono sorte due domande: 1) Perché il metodo 'c' in' M' * implicito *:? Non è un metodo non implicito equivalente alle precedenti due versioni che utilizzano tipi parametrizzati? 2) Nel caso speciale di un 'ClassTag' non è richiesto un valore di costruzione (l'ho sostituito con' override val c = classTag [...] 'nella classe). Questo non è generalmente possibile? – Beryllium

+0

Come si fornisce l'implementazione di 'c: ClassTag' nelle classi figlie? Come dovrebbe essere? –

+0

sembra che ci sia ripetizione ridondante in 'oggetto StringClass estende MyClass' - tipo A =' String' e val tag = reflect.classTag ['String']? Posso evitare questo? –