任何人都可以在下面的代码中解释子类型(<:) 为什么可以这样使用?当我们使用它?谢谢.
trait SwingApi { type ValueChanged <: Event val ValueChanged: { def unapply(x: Event): Option[TextField] } type ButtonClicked <: Event val ButtonClicked: { def unapply(x: Event): Option[Button] } type TextField <: { def text: String def subscribe(r: Reaction): Unit def unsubscribe(r: Reaction): Unit } type Button <: { def subscribe(r: Reaction): Unit def unsubscribe(r: Reaction): Unit } }
Daniel C. So.. 11
我知道那个代码!:)
因此<:
,为了以防万一,请确保您了解其含义.A <: B
意味着A
必须是一个子类型B
,或者换句话说,每个实例都A
将是一个实例B
(但反之亦然).
例如,我们知道每个java类都是<: Object
(例如String <: Object
).
接下来,为什么type ValueChanged <: Event
.这通常在蛋糕模式中找到,但我会跳过对此的解释(课程确实提到了蛋糕模式,并提供了链接iirc).
这意味着对于任何扩展SwingApi
的类型,类型ValueChanged
必须是子类型Event
.这使得可以Event
在任何使用该类型声明的方法上调用方法ValueChanged
,而无需事先知道究竟是什么类型.
这类似于下一次使用:
type TextField <: { def text: String def subscribe(r: Reaction): Unit def unsubscribe(r: Reaction): Unit }
我们在这里声明TextField
应该有那些方法,所以当我们得到类型的东西TextField
(比如ValueChanged
提取器返回)时,我们可以在它上面调用这些方法.我们可以写这样的代码:
trait MyStuff extends SwingApi { def subscribeTo(event: ValueChanged) = event match { case ValueChanged(textField) => textField.subscribe(myReaction) } def myReaction: Reaction }
在这一点上,既没有SwingApi
,也不MyStuff
知道类型会怎样被用于ValueChanged
或TextField
和,然而,他们可以在正常代码中使用它们.
关于type
声明经常被忽略的一个有趣的事实是它们可以被类覆盖.也就是说,我可以这样写:
class SwingImpl extends SwingApi { class TextField { def text: String = ??? def subscribe(r: Reaction): Unit = ??? def unsubscribe(r: Reaction): Unit = ??? } // etc }
最后,您可能想知道这是什么用途.我举一个例子.当然,您希望生产代码在屏幕上显示图形元素等等,或许,您可以编写一个单独的类,在Web服务器中实现它.但是,我认为课程利用它,您可以编写实现它的类,而不是显示这些组件的类,而是作为测试类,验证与这些组件的交互是否正确完成.
也就是说,您可以SwingImpl
扩展SwingApi
并在桌面上显示内容,并且SwingTest
还可以扩展SwingApi
,但只需让人们验证正在执行的操作.