Вы можете, в довольно круглом порядке. Foo
- это класс типа, а компилятор несчетно передает экземпляр класса типа, совместимый с параметром типа (inferred) 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)])
Во втором вызове оба FooAny
и FooTuple2
могут быть приняты, но компилятор выбирает FooTuple2
, основанный на правилах статического метода перегрузки. FooTuple2
более конкретно, чем FooAny
. Если два кандидата считаются такими же конкретными, как и друг друга, возникает ошибка двусмысленности. Вы также можете предпочесть один над другим, поместив его в суперкласс, как это делается в scala.LowPriorityImplicits
.
UPDATE
риффы от в DummyImplicit идею, а продолжительность нить на лестницу-пользователь:
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"))
Объявляет типа-параметризованных признак __
, коварианты в его безымянный параметр типа _
. Свой сопутствующий объект __
содержит неявный экземпляр __[Any]
, который нам понадобится позже. Вторая и третья перегрузки foo
включают параметры фиктивного типа, снова неназванные. Это будет выведено как Any
. Этот параметр типа имеет один или более контекстные границы, которые Обессахаренная в дополнительные неявные параметры, например:
def foo[A](a: Seq[Int])(implicit ev$1: __[A]) = 1
множественных списков параметров объединяются в один список параметров в байткоде, так что проблема двойного определения обойдена ,
Пожалуйста, рассматривайте это как возможность узнать о стирании, контексте и неявном поиске, а не как шаблон, который будет применяться в реальном коде!
Самый простой способ сделать это с помощью связанного с контекстом ClassManifest для каждого из параметров типа: 'def foo [A : ClassManifest] (xs: A *) ... '. Я добавил это как ответ с дополнительными комментариями ниже. –
При перегрузке учитывать: http://stackoverflow.com/questions/2510108/why-avoid-method-overloading –
См. Также: http://stackoverflow.com/questions/3307427/scala-double-definition-2-methods- стирать-то же типа – retronym