(注意:这需要一个漫长而艰难的解释;你可以找到关于这个Accord问题的完整讨论.它甚至可能不是解决问题的正确方法,但我相信这个问题本身很有趣.)
我正在寻找一种实现二元运算符的方法,使得行为取决于右侧操作数的类型:如果它与左侧操作数相同则为一种行为,否则为不同的行为.举个例子:
implicit class Extend[T](lhs: T) {
def testAgainst(rhs: T) = println("same type")
def testAgainst[U](rhs: U) = println("different type")
}
Run Code Online (Sandbox Code Playgroud)
第一个重载比第二个重载更具体,所以你会期望一个调用,比如5 testAgainst 10触发第一个重载,而5 testAgainst "abcd"调用第二个重载.虽然这在理论上是有意义的,但这不会编译,因为擦除的签名对于两个重载都是相同的.
我设法以一种需要在第一次重载中添加类型参数的方式来解决这个问题,但这正是我想要避免的.另一种解决方案是修改泛型重载,以要求编译器证明类型之间没有子类型关系(=:=不幸的是,Scala库没有提供).
虽然在Scala中编码子类型关系通常很容易,但我发现没有办法对其缺失进行编码.有没有什么办法要求,对于第二个重载是在编译时的候选人,无论T <:< U或者T >:> U是真的吗?
如果您想强制两种类型在编译时严格不同,那么这就是您的问题。使用定义 的答案之一=!=,我们可以想象多种如下所示的方法:
implicit class Extend[T](lhs: T) {
def testAgainst(rhs: T) = println("same type")
def testAgainst[U](rhs: U)(implicit ev: T =!= U) = println("different type")
}
Run Code Online (Sandbox Code Playgroud)
我们还可以很容易地使用一种方法进行类型测试TypeTag。
import scala.reflect.runtime.universe._
implicit class Extend[T: TypeTag](lhs: T) {
def testAgainst[U: TypeTag](rhs: U): Boolean = typeOf[T] =:= typeOf[U]
}
Run Code Online (Sandbox Code Playgroud)
当然,您可以修改它来分支行为。
scala> 1 testAgainst 2
res98: Boolean = true
scala> 1 testAgainst "a"
res99: Boolean = false
scala> List(1, 2, 3) testAgainst List(true, false)
res100: Boolean = false
scala> List(1, 2) testAgainst List.empty[Int]
res102: Boolean = true
Run Code Online (Sandbox Code Playgroud)