【问题标题】:Scala existentials - type mismatch, unable to infer T =:= TScala 存在 - 类型不匹配,无法推断 T =:= T
【发布时间】:2016-06-03 08:10:17
【问题描述】:

在 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 编译器中的错误 - 如果是,是否有解决它的最佳实践?

【问题讨论】:

    标签: scala generics type-inference existential-type


    【解决方案1】:

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

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

    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)
    

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

        我认为def contains(check:T):Boolean = value == checkcheck 上的类型限制了匹配。

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

        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
        

        【讨论】:

        • 这几乎等同于拥有def contains(check: Any)
        • 嗯,是的,我想您的解决方案更强大。
        猜你喜欢
        • 2014-12-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多