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 : C
ist 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
}
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
Wie stelle ich die Implementierung von 'c: ClassTag' in den untergeordneten Klassen zur Verfügung? Wie sollte es aussehen? –
scheint es redundante Wiederholung in 'Objekt StringClass erweitert MyClass' - Typ A =' String' und val-Tag = reflect.classTag ['String']? Kann ich das vermeiden? –