Scala existentials - 类型不匹配,无法推断 T =:= T
Scala existentials - type mismatch, unable to infer T =:= T
在 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)_(in value b2)
[error] required: _(in value b2)
[error] b2.contains(b2.get)
我的假设是编译器会理解在这两种情况下都使用相同类型的参数 _
,但是它似乎失去了追踪并将它们视为单独的类型。
我是否从根本上误解了有关存在类型的某些东西,或者这是 Scala 编译器中的错误 - 如果是,是否有解决它的最佳实践?
这可能更多的是限制而不是错误。
通常解决此问题的简单方法是将敏感代码移至通用方法:
def containsSelf[T](box: Box[T]): Boolean =
box.contains(box.get)
val b2 : Box[_] = new Box(1)
containsSelf(b2)
或者使用类型成员而不是泛型来设计您的 class。这可能有点样板,但完全符合您的要求:
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)
我认为 def contains(check:T):Boolean = value == check
中 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
另一种解决方案是使用类型变量模式为通配符命名并帮助 Scala 确定它们是相同的:
val b2 : Box[_] = new Box(1)
b2 match {
case b: Box[a] => b.contains(b.get)
}
在 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)_(in value b2)
[error] required: _(in value b2)
[error] b2.contains(b2.get)
我的假设是编译器会理解在这两种情况下都使用相同类型的参数 _
,但是它似乎失去了追踪并将它们视为单独的类型。
我是否从根本上误解了有关存在类型的某些东西,或者这是 Scala 编译器中的错误 - 如果是,是否有解决它的最佳实践?
这可能更多的是限制而不是错误。
通常解决此问题的简单方法是将敏感代码移至通用方法:
def containsSelf[T](box: Box[T]): Boolean =
box.contains(box.get)
val b2 : Box[_] = new Box(1)
containsSelf(b2)
或者使用类型成员而不是泛型来设计您的 class。这可能有点样板,但完全符合您的要求:
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)
我认为 def contains(check:T):Boolean = value == check
中 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
另一种解决方案是使用类型变量模式为通配符命名并帮助 Scala 确定它们是相同的:
val b2 : Box[_] = new Box(1)
b2 match {
case b: Box[a] => b.contains(b.get)
}