模式匹配&存在类型

时间:2016-04-25 08:26:58

标签: scala

为什么这不起作用? Scala应该在case HasInts的情况下理解outer.type <: HasInts.type。什么是变通方法(不删除类型成员)?

sealed trait Outer {
  type Inner
}

case object HasInts extends Outer {
  override type Inner = Int
}

def id(outer: Outer): outer.Inner =
  outer match {
    case HasInts => 0
  }

编辑:

另一方面,如果我们将类型成员从存在更改为通用,它将编译。

sealed trait Outer[Inner]

case object HasInts extends Outer[Int]

def id[I](outer: Outer[I]): I =
  outer match {
    case HasInts => 0
  }

为什么它会在第一种情况下起作用而不是第二种情况?它们可以说是完全相同的(事实上,在Dotty中它们将是。)

3 个答案:

答案 0 :(得分:2)

依赖类型。当您返回outer.Inner时,编译器没有特定的方法来确定Int是什么。错误很好:

scala> def id(outer: Outer): outer.Inner =
     |   outer match {
     |     case x@ HasInts => 0 : HasInts.Inner
     |   }
<console>:15: error: type mismatch;
 found   : HasInts.Inner
    (which expands to)  Int
 required: outer.Inner
           case x@ HasInts => 0 : HasInts.Inner
                                ^

编译器特别知道它是Int。但方法定义表明它返回outer.Inner。静态地使用依赖类型,除了outer.Inner之外没有其他信息,它基本上没有传达任何信息。例如,通过以下更改,它将起作用:

sealed trait Outer {
  type Inner >: Int
}

或者你可以:

sealed trait Outer {
  type Inner 
  def f: Inner
}

case object HasInts extends Outer {
  override type Inner = Int  
  def f:Inner = 23
}

def id(outer: Outer): outer.Inner = outer.f

我不确定是否必须转向依赖类型,因为稍微难以使它们正确(一旦dotty进入,它们甚至可能在将来被移除versions)。如果可以的话,我宁愿使用Outer[T]

答案 1 :(得分:1)

Scala根本不使用outer匹配HasInts来改进outer类型的事实。就像一个更简单的案例:

val x: Object = ...
x match {
  case _: String => x.length
}

无法编译,而是必须编写case s: String => s.length

因此,仍然需要显示0 outer.Inner的类型为outer: Outer,当然它不能。

对于解决方法,除了Jatin提到的那些,还有蛮力

(outer match {
   case HasInts => 0
 }).asInstanceOf[outer.Inner]

当然,这意味着您必须检查您的类型是否正确而不是编译器!

对于编辑:对编译器

中的类型参数大小写有特殊支持
  

In the method case, what you have here is a GADT: Patterns determine the type parameters of an corresponding methods in the scope of a pattern case.

但是对于类型成员没有这样的支持,我希望添加它是非常重要的。

答案 2 :(得分:0)

因为函数的返回类型不能依赖于参数,所以它必须是静态的。考虑一下:

case object HasStrings extends Outer {
  override type Inner = Int
}

val list = Seq(HasInts, HasStrings).map { obj => id(obj) }

如果您要做的工作有效,则上述行有效。但是由此产生的list可能是什么类型?

我认为,您正在寻找通用类型而不是类型成员。 (顺便说一句,这是&#34;存在类型&#34;,这是一个完全不同的野兽)。

相关问题