Vous pouvez, d'une manière assez ronde. Foo
est une classe de type, et le compilateur transmet implicitement une instance de la classe de type, compatible avec le paramètre de type (inféré) A
.
trait Foo[X] {
def apply(xs: Seq[X]): Unit
}
object Foo {
implicit def FooAny[A]: Foo[A] = new Foo[A] {
def apply(xs: Seq[A]) = println("apply(xs: Seq[A])")
}
implicit def FooTuple2[A, B]: Foo[(A, B)] = new Foo[(A, B)] {
def apply(xs: Seq[(A, B)]) = println("apply(xs: Seq[(A, B)])")
}
def apply[A](xs: A*)(implicit f: Foo[A]) = f(xs)
}
Foo(1, 2, 3) // apply(xs: Seq[A])
Foo(1 -> 2, 2 -> 3) // apply(xs: Seq[(A, B)])
Dans le deuxième appel, les deux FooAny
et FooTuple2
pourrait être passé, mais le compilateur ramasse FooTuple2
, sur la base des règles de surcharge de méthode statique. FooTuple2
est considéré plus spécifique que FooAny
. Si deux candidats sont considérés comme aussi spécifiques l'un de l'autre, une erreur d'ambiguïté est soulevée. Vous pouvez également préférer l'un à l'autre en en plaçant un dans une superclasse, comme cela est fait au scala.LowPriorityImplicits
.
MISE À JOUR
Riffing de l'idée DummyImplicit, et le fil de suivi sur scala-utilisateur:
trait __[+_]
object __ {
implicit object __ extends __[Any]
}
object overload {
def foo(a: Seq[Boolean]) = 0
def foo[_: __](a: Seq[Int]) = 1
def foo[_: __ : __](a: Seq[String]) = 2
}
import overload._
foo(Seq(true))
foo(Seq(1))
foo(Seq("s"))
Ce déclare un trait de type paramétrées __
, covariant dans son paramètre de type sans nom _
. Son objet compagnon __
contient une instance implicite de __[Any]
, dont nous aurons besoin plus tard. Les deuxième et troisième surcharges de foo
comprennent des paramètres de type fictif, encore une fois sans nom. Ceci sera déduit comme Any
. Ce paramètre de type a une ou plusieurs bornes de contexte, qui sont Dessucré en paramètres implicites supplémentaires, par exemple:
def foo[A](a: Seq[Int])(implicit ev$1: __[A]) = 1
Les multiples listes de paramètres sont concaténés en une seule liste de paramètres dans le bytecode, de sorte que le problème de la double définition est contournée .
Considérez ceci comme une opportunité d'apprendre l'effacement, les limites de contexte et la recherche implicite, plutôt que comme un modèle à appliquer en code réel!
La méthode la plus simple consiste à utiliser un ClassManifest lié au contexte pour chacun des paramètres de type: 'def foo [A : ClassManifest] (xs: A *) ... '. J'ai ajouté ceci comme une réponse avec plus de commentaires ci-dessous. –
En cas de surcharge, considérez: http://stackoverflow.com/questions/2510108/why-avoid-method-overloading –
Voir aussi: http://stackoverflow.com/questions/3307427/scala-double-definition-2-methods- avoir le même type d'effacement – retronym