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
}
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
Come si fornisce l'implementazione di 'c: ClassTag' nelle classi figlie? Come dovrebbe essere? –
sembra che ci sia ripetizione ridondante in 'oggetto StringClass estende MyClass' - tipo A =' String' e val tag = reflect.classTag ['String']? Posso evitare questo? –