为什么这不起作用? 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中它们将是。)
答案 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]
当然,这意味着您必须检查您的类型是否正确而不是编译器!
对于编辑:对编译器
中的类型参数大小写有特殊支持但是对于类型成员没有这样的支持,我希望添加它是非常重要的。
答案 2 :(得分:0)
因为函数的返回类型不能依赖于参数,所以它必须是静态的。考虑一下:
case object HasStrings extends Outer {
override type Inner = Int
}
val list = Seq(HasInts, HasStrings).map { obj => id(obj) }
如果您要做的工作有效,则上述行有效。但是由此产生的list
可能是什么类型?
我认为,您正在寻找通用类型而不是类型成员。 (顺便说一句,这是不&#34;存在类型&#34;,这是一个完全不同的野兽)。