表达继承的不同符号
为什么有不同的符号来表达继承?在泛型中,我必须使用 <:- 运算符 - 在普通的类继承中,我必须使用 extends 关键字。
例如,我必须这样写:
class X[A <: B] extends Y
但为什么不写这样的东西:
class X[A <: B] <: Y
或者
class X[A extends B] extends Y // like Java
我对当前的表示法没有问题,但我想知道是否有理由以不同的方式表示泛型的类型层次结构。
why are there different notations to express inheritance? In generics I have to use the <:-operator - in a normal class-inheritance I have to use the extends keyword.
For example I have to write this:
class X[A <: B] extends Y
But why not writing something like this:
class X[A <: B] <: Y
or
class X[A extends B] extends Y // like Java
I have no problem with the current notation, but I want to know whether there is a reason to notate the type hierarchy of generics in a different way.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
好吧,没有什么可以阻止 Scala 这样做,但事实上,它们根本不表达相同的东西。而且,事实上,您可以在 Java 中看到这一点,您可以写
X super Y
,但不能写class X super Y
。关键字
extends
表达了类之间的关系,一种继承关系。另一方面,<:
和>:
表达了类型之间的关系,即边界之一。当我说X <: Y
时,X
和Y
都是有效的String
,例如, whileString extends String
是没有意义的。List[String] <: List[AnyRef]
也是这种情况,但同样,List[String] extends List[AnyRef]
是没有意义的。而且,为了说明这一点,Set[String] <: Set[AnyRef]
不是真的。在我刚刚给出的所有这些示例中,我们谈论的是相同的类,但不一定是相同的类型。当然,类型之间还存在其他关系,例如视图边界 (
<%
) 和上下文边界 (:
)。因此,仅仅因为
extends
隐含<:
,并不意味着<:
隐含extends
,仅此一点就足以避免使用相同的关键字。再加上类型之间的其他关系,您就几乎达成了交易。Well, there is nothing stopping Scala from doing so, but, as a matter of fact, they do not express the same thing at all. And, in fact, you can see that in Java, where you can write
X super Y
, but you can't sayclass X super Y
.The keyword
extends
express a relationship between classes, one of inheritance. On the other hand,<:
and>:
express a relationship between types, one of boundaries. When I sayX <: Y
, then it is valid for bothX
andY
to beString
, for example, whileString extends String
would be meaningless. It is also the case thatList[String] <: List[AnyRef]
, though, again,List[String] extends List[AnyRef]
is meaningless. And, just to make the point, it is not true thatSet[String] <: Set[AnyRef]
. In all these examples I just gave we are talking about the same class, but not, necessarily, about the same type.And, of course, there are other relationships between types, such as view bounds (
<%
) and context bounds (:
).So, just because
extends
implies<:
, it doesn't follow that<:
impliesextends
, which, alone, is reason enough to avoid using the same keyword. Add to that the other relationships between types, and you have pretty much a closed deal.当您将示例扩展(没有双关语)超出这一简单情况时,它会变得更加明显。
多重继承:
Mixins:
参数化:
多个(相关)类型参数:
上下文边界:视图
边界:
通用方法:
如您所见,类型参数中可以指定的关系比类型参数中指定的关系丰富得多声明类时可以使用简单的线性层次结构,特别是当您允许边界时。
还值得注意的是,类或方法的泛型类型参数经常会被推断,允许您编写:
而不是
因此,使用符号的方式非常不同。
更新
我刚刚想到了一个特定的例子,它演示了两种符号的同时使用,并展示了它们如何保持不同:
这要求类型参数
T
是混合Foo
和Bar
中的子类型。这同样适用于结构类型:
It becomes a bit more obvious when you extend (no pun intended) your example beyond that one simple case.
Multiple inheritance:
Mixins:
Parameterization:
Multiple (related) type params:
Context bounds:
View bounds:
Generic Methods:
As you can see, the relationships that may be specified in a type parameter are far richer than the simple linear hierarchy available when declaring a class, especially when you allow for bounds.
It's also worth noting that generic type parameters for classes or methods will very often be inferred, allowing you to write:
instead of
So the way in which the notations are used is very different.
update
One particular example has just spring to mind, demonstrating the use of both notations simultaneously and showing how they need to remain distinct:
This requires that the type-param
T
be a subtype something mixing in bothFoo
andBar
.The same applies with structural types: