Scala 编译错误:未找到:类型 _$1

Nic*_*man 5 scala pattern-matching existential-type scalac scala-compiler

我正在研究 Scala 中的存在类型2.12.x。为此,我正在测试以下代码:

trait Parent
class ChildA extends Parent
class ChildB extends Parent

def whatIsInside(opt: Option[_ <: Parent]): String = {
  opt match {
    case _: Option[_ <: ChildA] => "ChildA"
    case _: Option[_ <: ChildB] => "ChildB"
    case _                      => throw new IllegalArgumentException("unknown type")
  }
}


whatIsInside(Some(new ChildA))
Run Code Online (Sandbox Code Playgroud)

由于类型擦除,我不希望这在运行时起作用,但是这甚至无法编译。我收到以下错误:

[error] ExistentialTypes.scala:12:24: not found: type _$2
[error]         case _: Option[_ <: ChildA] => "ChildA"
[error]                        ^
[error] ExistentialTypes.scala:13:24: not found: type _$3
[error]         case _: Option[_ <: ChildB] => "ChildB"
[error]                        ^
Run Code Online (Sandbox Code Playgroud)

有人可以解释这些错误吗?

And*_*kin 4

(不是完整的答案,而是一些注释和链接;也许它可以作为其他人的起点)

\n

在 2.12.13 中,如果出现在协变位置,编译器似乎能够证明F[_ <: X]F[X]是相同的类型:X

\n
println(implicitly[Option[_ <: ChildA] =:= Option[ChildA]])\n
Run Code Online (Sandbox Code Playgroud)\n

编译(有警告,但它编译):

\n
trait Parent\nclass ChildA extends Parent\nclass ChildB extends Parent\n\ndef whatIsInside(opt: Option[_ <: Parent]): String = {\n  opt match {\n    case _: Option[ChildA] => "ChildA"\n    case _: Option[ChildB] => "ChildB"\n    case None            => "None"\n    case _ => throw new Error("meh")\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这不会编译:

\n
trait Parent\nclass ChildA extends Parent\nclass ChildB extends Parent\n\ndef whatIsInside(opt: Option[_ <: Parent]): String = {\n  opt match {\n    case _: Option[_ <: ChildA] => "ChildA"\n    case _: Option[_ <: ChildB] => "ChildB"\n    case None            => "None"\n    case _ => throw new Error("meh")\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

_$2所以,看起来它一定与合成类型变量的边界推断有关。

\n

另外,这编译:

\n
def testConforms[A >: Nothing <: ChildA](ca: Option[A]): Option[_ <: Parent] = ca\n
Run Code Online (Sandbox Code Playgroud)\n

所以,除非我误解了规范

\n
\n

如果存在\xcf\x83对类型变量的替换a_i,\xe2\x80\xa6,a_n,使得\xcf\x83T符合,则可以确定对类型变量的pt最弱子类型约束,从而意味着符合 [预期类型] 。C1a1,\xe2\x80\xa6,anC0 \xe2\x88\xa7 C1Tpt

\n
\n

, thept将是Option[_ <: Parent], thena1,...,an将是单个合成类型_$2,并且约束_$2 >: Nothing <: ChildA应使该类型Option[_$2]符合Option[_ <: Parent]. 所以,看起来它应该有效,但事实并非如此。

\n
\n

奖金

\n

如果您只是想让它工作,那么只需跳过所有这些通配符,它​​们是不需要的:

\n
trait Parent\nclass ChildA extends Parent\nclass ChildB extends Parent\n\ndef whatIsInside(opt: Option[Parent]): String = {\n  opt match {\n    case Some(_: ChildA) => "ChildA"\n    case Some(_: ChildB) => "ChildB"\n    case None            => "None"\n    case _ => throw new Error("meh")\n  }\n}\n\n\nwhatIsInside(Some(new ChildA))\nwhatIsInside(Some(new ChildB))\nwhatIsInside(None)\n
Run Code Online (Sandbox Code Playgroud)\n

  • @MarioGalic我不认为这是“句法”的东西。示例中的“F”不会引入任何类型变量绑定器,而“Option[_ &lt;: ChildA]”确实为“_”引入了合成类型变量“_$2”,但随后无法推断出任何类型变量绑定器。合理的类型界限。我认为类型变量的界限推断有些问题。 (2认同)