0__*_*0__ 22 swing scala pattern-matching type-erasure
我正在实现一个Swing组件,我想要克服#### untypedness Reactor.所以我认为这会奏效:
trait Foo[A] extends scala.swing.Publisher {
final case class Bar(parent: Vector[A], children: A*) extends scala.swing.event.Event
}
trait Test {
val foo: Foo[Int]
foo.reactions += {
case foo.Bar(parent, children) => {
println(parent.sum - children)
}
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这给了我两个编译器警告:
The outer reference in this type test cannot be checked at run time.
final case class Bar(parent: Vector[A], children: A*) extends scala.swing.event.Event
^
The outer reference in this type test cannot be checked at run time.
case foo.Bar(parent, children) => {
^
Run Code Online (Sandbox Code Playgroud)
我应该忽略这些警告吗?我可以抑制它们吗?我应该改变设计吗?
Jam*_*pic 34
在Scala中,内部类是"路径依赖的".
我将以您的代码为例.如果你有两个Foo[Int]s,叫做foo和bar,那么foo.Bar就是一个不同的类型bar.Bar.请注意,这与Java的内部类的概念不同,其中foo.Bar和bar.Bar类型相同.
在任何情况下,JVM都不直接支持内部类,因此在Java和Scala中,类Bar编译为一个名为的JVM类Foo$Bar.内部类的实例几乎总是包含对其所有者的引用 - "外部引用".
现在,当你在路径依赖类型(如代码中的那个)上获得模式匹配时,Scala编译器将生成字节码,它执行两件事:它将检查类(因此它将检查它收到的对象)是一个实例Foo$Bar),它将检查外部引用(因此它将检查所接收对象的外部引用是否是foo).
但是,在您的代码中,编译器无法找到检查外部引用的方法,因为您已将内部类声明为final.
因此,如果您忽略该警告,那么您的模式将匹配所有实例Foo$Bar,即使它们不属于foo.你会比我更好,这是否会成为一个问题.
或者,您可以通过使您的内部类非最终来修复它.
Ps,我不完全确定为什么Scala编译器无法检查最终内部类的外部引用,但我发现如果内部类是final,那么outer$是私有的,而如果它是非final的,outer$则是public.在编译器的内部可能值得一试,找出原因.
事实证明这是一个已知的问题 - SI-4440.如果不使用Scala编译器,则删除最终内部类的外部引用(这是非常合法的,因为子类也不可能使用它们).这样做的一个积极结果是外部类可以被垃圾收集,而内部类仍在使用中,因此Scala开发人员不愿意重新引入外部引用,因为害怕引入内存泄漏.