Scala存在 - 类型不匹配,无法推断T =:= T.

时间:2016-06-03 08:10:17

标签: scala generics type-inference existential-type

在Scala中使用存在类型时,编译器似乎将存在主体的每个用法推断为不同的类型参数,即使它们实际上是相同的。

对于一个简单的人为例子 - 给出以下代码

class Box[T](value:T){
  def get:T = value
  def contains(check:T):Boolean = value == check
}

我可以做以下

val b1 = new Box(1)
b1.contains(b1.get)

然而,当使用存在类型时......

 val b2 : Box[_] = new Box(1)
 b2.contains(b2.get)

我收到以下错误(在scala 2.11.7中

[error] /private/tmp/exttest/test.scala:53: type mismatch;
[error]  found   : (some other)_$6(in value b2)
[error]  required: _$6(in value b2)
[error]   b2.contains(b2.get)

我的假设是编译器会理解在两种情况下都使用相同的类型参数_$6,但它似乎失去了跟踪并将它们视为单独的类型。

我是否从根本上误解了存在类型的某些内容,或者这是Scala编译器中的错误 - 如果是这样,是否有最好的做法可以解决它?

3 个答案:

答案 0 :(得分:6)

这可能更多是限制而不是错误。

通常,解决此问题的简单方法是将敏感代码移动到通用方法:

def containsSelf[T](box: Box[T]): Boolean =
  box.contains(box.get)

val b2 : Box[_] = new Box(1)
containsSelf(b2)

或者使用类型成员而不是泛型来设计您的类。这可能是更多的样板,但确实完全符合您的要求:

trait Box {
  type Element
  def get: Element
  def contains(check: Element): Boolean
}
object Box {
  type Aux[T] = Box { type Element = T }
  def apply[T](value: T): Box.Aux[T] =
    new Box {
      type Element = T
      def get = value
      def contains(check: T) = value == check
    }
}

val b2: Box = Box(1)
b2.contains(b2.get)

答案 1 :(得分:2)

另一个解决方案是使用类型变量模式为通配符命名,并帮助Scala找出它们是相同的:

val b2 : Box[_] = new Box(1)
b2 match {
  case b: Box[a] => b.contains(b.get)
}

答案 2 :(得分:0)

我认为checkdef contains(check:T):Boolean = value == check上绑定的类型会限制匹配。

当我应用这样的解决方法时,我得到以下内容:

scala> class Box[T](value:T){
     |  def get:T = value
     |  def contains(check:X forSome { type X}):Boolean = value == check
     | }
warning: there was one feature warning; re-run with -feature for details
defined class Box

scala> val b1 = new Box(1)
b1: Box[Int] = Box@745d86ec

scala> b1.contains(b1.get)
res0: Boolean = true

scala> val b2 : Box[_] = new Box(1)
b2: Box[_] = Box@5bd46b54

scala>  b2.contains(b2.get)
res1: Boolean = true