如何证明两种类型在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

相关文章

共收录Twitter的14款开源软件,第1页Twitter的Emoji表情 Tw...
Java和Scala中关于==的区别Java:==比较两个变量本身的值,即...
本篇内容主要讲解“Scala怎么使用”,感兴趣的朋友不妨来看看...
这篇文章主要介绍“Scala是一种什么语言”,在日常操作中,相...
这篇文章主要介绍“Scala Trait怎么使用”,在日常操作中,相...
这篇文章主要介绍“Scala类型检查与模式匹配怎么使用”,在日...