任何人都可以在下面的代码中解释子类型(<:) 吗?为什么可以这样使用?当我们使用它?谢谢。
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
}
}
最佳答案
我知道那个密码! :)
因此,让我们确保您了解 <:
意思是,以防万一。 A <: B
表示 A
必须是 B
的子类型,或者,换句话说,A
的每个实例将是 B
的一个实例以及(但反之亦然)。
例如,我们知道每个 java 类都是 <: Object
(例如 String <: Object
)。
接下来,为什么type ValueChanged <: Event
.这通常出现在蛋糕图案中,但我将跳过对此的解释(类(class)确实提到了蛋糕图案,并提供了链接 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 服务器中实现它。但是,我认为类(class)利用了它,您可以编写实现它的类,而不是作为显示这些组件的东西,而是作为测试类,验证与这些组件的交互是否正确完成。
也就是说,您可以拥有
SwingImpl
扩展 SwingApi
并在您的桌面上显示这些内容,以及 SwingTest
这也扩展了 SwingApi
,但只是让人们验证正在做什么。
关于scala - Scala 中的子类型 : what is "type X <: Y"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20508529/