Knu*_*daa 15 scala overloading type-erasure
我知道类型擦除使它们在运行时看起来相同,类型,所以:
class Bar {
def foo[A](xs: A*) { xs.foreach(println) }
def foo[A, B](xs: (A, B)*) { xs.foreach(x => println(x._1 + " - " + x._2)) }
}
Run Code Online (Sandbox Code Playgroud)
给出以下编译器错误:
<console>:7: error: double definition:
method foo:[A,B](xs: (A, B)*)Unit and
method foo:[A](xs: A*)Unit at line 6
have same type after erasure: (xs: Seq)Unit
def foo[A,B](xs: (A, B)*) { xs.foreach(x => println(x._1 + " - " + x._2)
) }
^
Run Code Online (Sandbox Code Playgroud)
但是有一种简单的方法可以写:
bar.foo(1, 2, 3)
bar.foo(1 -> 2, 3 -> 4)
Run Code Online (Sandbox Code Playgroud)
并让这些调用foo的不同重载版本,而不必明确命名它们:
bar.fooInts(1, 2, 3)
bar.fooPairs(1 -> 2, 3 -> 4)
Run Code Online (Sandbox Code Playgroud)
ret*_*nym 15
你可以在一个相当圆的方式.Foo是一个类型类,编译器有意地传递类型类的实例,与(推断的)类型参数兼容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)])
Run Code Online (Sandbox Code Playgroud)
在第二个电话,双方FooAny并FooTuple2可以通过,但是编译器选秀权FooTuple2,基于静态方法重载的规则.FooTuple2被认为更具体FooAny.如果认为两个候选人彼此具体,则会产生歧义错误.你也可以通过在超类中放置一个来优先选择其中一个,就像在中做的那样scala.LowPriorityImplicits.
UPDATE
重新关注DummyImplicit的想法,以及scala-user上的后续线程:
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"))
Run Code Online (Sandbox Code Playgroud)
这__在其未命名的类型参数中声明了一个类型参数化的特征,协变_.它的伴随对象__包含一个隐含的实例__[Any],我们稍后会需要它.第二次和第三次重载foo包括虚拟类型参数,同样未命名.这将被推断为Any.此类型参数具有一个或多个上下文边界,这些上下文边界被放入其他隐式参数中,例如:
def foo[A](a: Seq[Int])(implicit ev$1: __[A]) = 1
Run Code Online (Sandbox Code Playgroud)
多个参数列表在字节码中连接成单个参数列表,因此避免了双重定义问题.
请将此视为一个了解擦除,上下文边界和隐式搜索的机会,而不是作为在实际代码中应用的模式!
在我们只有2个重载的情况下,我们可以简化Landei的答案,并避免定义我们自己的隐式,通过使用scala.Predef.DummyImplicit它自动导入到每个范围.
class Bar {
def foo[A](xs: A*) { xs.foreach(println) }
def foo[A, B](xs: (A, B)*)(implicit s:DummyImplicit){
xs.foreach(x => println(x._1 + " - " + x._2))
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2716 次 |
| 最近记录: |