表达继承的不同符号

发布于 2024-10-04 04:51:13 字数 352 浏览 2 评论 0原文

为什么有不同的符号来表达继承?在泛型中,我必须使用 <:- 运算符 - 在普通的类继承中,我必须使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

智商已欠费 2024-10-11 04:51:13

好吧,没有什么可以阻止 Scala 这样做,但事实上,它们根本不表达相同的东西。而且,事实上,您可以在 Java 中看到这一点,您可以写 X super Y,但不能写 class X super Y

关键字extends表达了之间的关系,一种继承关系。另一方面,<:>:表达了类型之间的关系,即边界之一。当我说 X <: Y 时,XY 都是有效的 String,例如, while String 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 say class 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 say X <: Y, then it is valid for both X and Y to be String, for example, while String extends String would be meaningless. It is also the case that List[String] <: List[AnyRef], though, again, List[String] extends List[AnyRef] is meaningless. And, just to make the point, it is not true that Set[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 <: implies extends, 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.

怂人 2024-10-11 04:51:13

当您将示例扩展(没有双关语)超出这一简单情况时,它会变得更加明显。

多重继承:

class C[A] extends X with Y with Z

Mixins:

val x = new X with Y

参数化:

class X[A <: B] extends Y[A]

多个(相关)类型参数:

class X[A >: B, B](x: A, xs: Seq[B])

上下文边界:视图

class X[A : Manifest]

边界:

class X[A <% Ordered[A]]

通用方法

class Foo[B] {
  def bar[A <: B](x: A) = ...
}

如您所见,类型参数中可以指定的关系比类型参数中指定的关系丰富得多声明类时可以使用简单的线性层次结构,特别是当您允许边界时。

还值得注意的是,类或方法的泛型类型参数经常会被推断,允许您编写:

val myList = List(1, 2, 3)

而不是

val myList = List[Int](1, 2, 3)

因此,使用符号的方式非常不同。

更新

我刚刚想到了一个特定的例子,它演示了两种符号的同时使用,并展示了它们如何保持不同:

def someMethod[T <: Foo with Bar](x: T) = ...

这要求类型参数 T 是混合 FooBar 中的子类型。

这同样适用于结构类型:

type Closable = { def close: Unit } //alias for a structural type
def someMethod[T <: Closable](x: T) = ...

It becomes a bit more obvious when you extend (no pun intended) your example beyond that one simple case.

Multiple inheritance:

class C[A] extends X with Y with Z

Mixins:

val x = new X with Y

Parameterization:

class X[A <: B] extends Y[A]

Multiple (related) type params:

class X[A >: B, B](x: A, xs: Seq[B])

Context bounds:

class X[A : Manifest]

View bounds:

class X[A <% Ordered[A]]

Generic Methods:

class Foo[B] {
  def bar[A <: B](x: A) = ...
}

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:

val myList = List(1, 2, 3)

instead of

val myList = List[Int](1, 2, 3)

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:

def someMethod[T <: Foo with Bar](x: T) = ...

This requires that the type-param T be a subtype something mixing in both Foo and Bar.

The same applies with structural types:

type Closable = { def close: Unit } //alias for a structural type
def someMethod[T <: Closable](x: T) = ...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文