微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何证明两种类型在Scala中没有子类型关系?

(注意:这个动机需要漫长而艰苦的解释;你可以在这Accord issue上找到全面的讨论.它可能不是解决这个问题的正确方法,但我认为这个问题本身很有趣.)

我正在寻找一种实现二元运算符的方式,使得行为取决于右侧操作数的类型:如果与左侧操作数相同,则表现出一种行为,否则不同的行为.举个例子:

implicit class Extend[T](lhs: T) {
  def testAgainst(rhs: T) = println("same type")
  def testAgainst[U](rhs: U) = println("different type")
}

一个重载比第二个更具体,所以你会期望调用如5 testAgainst 10来触发第一个重载,而5 testAgainst“abcd”将调用第二个重载.虽然这在理论上是有道理的,但是由于擦除的签名对于两个重载都是相同的,所以不会进行编译.

我设法解决这个问题,需要在第一个重载中添加一个类型参数,但这正是我想避免的.一个不同的解决方案是修改通用重载,以要求编译器的证据表明类型之间没有子类型关系(与…相反,不幸的是Scala库不提供).

虽然在Scala中编码子类型关系通常很容易,但我发现没有办法编码缺少这种关系.有没有办法要求,因为第二次重载在编译时成为一个候选人,所以T< U或T>:> U是真的吗

解决方法

如果要强制这两种类型在编译时严格不同,那么 this is the question就可以了.使用定义=!=的一个答案,我们可以想象出多种方法,如下所示:

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")
}

我们也可以使用TypeTag在一个方法中进行类型测试.

import scala.reflect.runtime.universe._

implicit class Extend[T: TypeTag](lhs: T) {
  def testAgainst[U: TypeTag](rhs: U): Boolean = typeOf[T] =:= typeOf[U]
}

你当然可以修改它来分支行为.

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐