2013-12-14 5 views
9

Das funktioniert gutKeine ClassTag für MyClass.this.T für einen abstrakten Typ

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

aber dies nicht aufgrund des Fehlers No ClassTag available for MyClass.this.T

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

auch wenn Sie wie folgt vor:

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

Wie verwende ich eine abstrakte type und den Fehler loswerden?

Antwort

8
class M[A <: B: C] 

für

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

Daher ist kurz, wenn Sie A auf eine abstrakte Art Element bewegen, würden Sie so etwas wie

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

und benötigen jemand Implementierung M schreiben müssen zur Verfügung zu stellen solch ein Wertc. Wenn Sie M nicht abstrakte wollen, müssen Sie einen Konstruktor Wert Parameter des Typs erfordern C[A], was wiederum bedeutet, dass Typ A muss Konstruktortyp Parameter sein ...


bearbeiten die Kommentare zu beantworten: Die Notation A : Cist definiert als als Erweiterung auf einen impliziten Wertparameter vom Typ C[A]. Dort wird C als kontextgebunden bezeichnet, und es kann so verstanden werden, dass nach einer Typklasse C[_] für den Typ A gefragt wird. Wenn Sie M implementieren, müssen Sie den Modifikator implicit nicht wiederholen. Warum ist es da? Lassen Sie mich Ihnen ein Beispiel geben einen bekannten Typ-Klasse 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 
    } 
} 

Wenn Sie implicit entfernt, würden Sie die Anrufe xs.min und xs.max, die eine implizite Ordering erfordern ändern.

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) 

Hier Bar zeigt, wie Sie den impliziten Wertparameter bereitzustellen. Das wäre das gleiche für 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] 
} 

Wenn Ihr Kind Klasse ist generic wieder, müssen Sie für die Bereitstellung einer Klasse-Tag auf die Verantwortung zu übergeben:

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

Interessant. Ich habe ein bisschen herumgespielt und zwei Fragen kamen auf: 1) Warum ist die Methode 'c' in' M' * implizit *:? Ist eine nicht implizite Methode, die den beiden vorherigen Versionen entspricht, parametrisierte Typen? 2) Im speziellen Fall eines 'ClassTag' wird kein Konstruktorwert benötigt (ich habe ihn durch 'override val c = classTag [...]' in der Klasse ersetzt). Ist das nicht generell möglich? – Beryllium

+0

Wie stelle ich die Implementierung von 'c: ClassTag' in den untergeordneten Klassen zur Verfügung? Wie sollte es aussehen? –

+0

scheint es redundante Wiederholung in 'Objekt StringClass erweitert MyClass' - Typ A =' String' und val-Tag = reflect.classTag ['String']? Kann ich das vermeiden? –

Verwandte Themen