为什么不扩展其他类的类必须从特征扩展? (不起作用)

时间:2011-11-09 20:10:54

标签: scala traits

我从Scala开始,我发现这有点奇怪。在java中,我可以这样做:

interface Foo{}

public class Bar implements Foo{}

我正在尝试使用Scala做类似的事情,但它不起作用:

trait Foo;
class Bar with Foo; // This doesn't work!

我必须使用“extends”关键字:

class Bar extends Foo; // This works OK!

现在,它很好,但这不是我想要的。

我注意到另一件奇怪的事情是,鉴于Scala中的每个类都来自AnyRef(请参阅scala-lang.org的这张图片:http://www.scala-lang.org/sites/default/files/images/classhierarchy.png),我可以这样做:

class Bar extends AnyRef with Foo; // This works too!

那么,我错过了什么?没有扩展它就没有意义使用特征吗?

谢谢!

3 个答案:

答案 0 :(得分:21)

首先请注意,扩展/实现差异对编译器没有任何意义,因为它不知道。我并不是说它很糟糕,只是语言本来可以做到的。在C#中,您编写class A : B, C, D而不是class A extends B implements C, Dclass A implements B, C, D。所以你可以认为Scala的extends就像冒号一样,with就像逗号一样。

然而,在过去,曾经是class Bar with Foo。当Scala在2006年回归2.0时,它发生了变化。请参阅the change history

我想我记得(不确定)原因只是class Bar with Foo读得不好。

在Scala中,A with BAB类型的交集。如果对象属于A with B类型和A类型,则属于B类型。因此,可以阅读class A extends B with C class A扩展类型B with Cclass A with B没有这样的事情。

答案 1 :(得分:8)

如果你来自Java,它起初听起来很奇怪(对我来说也是一样),但实际上现在我发现它比Java更常规的语法,我需要明确说明我是否想要{{1 }}或implement其他类/接口。但我认为这是个人品味的问题。

您是说extend还是extends实际上并不重要。它们都表示两种事物之间的相同关系:(与委托和组合形成对比,代表具有关系)。例如,您可以在此处找到有关它的更多信息:

http://www.javacamp.org/moreclasses/oop/oop5.html

尝试将implementsextendsimplements替换为with,然后变得更加清晰。

在Scala中,您还有is a关系的其他变体。例如自我类型

is a

你要说的是,trait Bar { self: Foo => // ... } 没有直接扩展/实现Bar,但是想要扩展Foo的所有其他类也应该扩展Bar

自我类型可以允许有趣的事情。例如,两个相互依赖的类/特征:

Foo

答案 2 :(得分:3)

Programming in Scala (2nd ed)讨论了第12章中的特征。它注意到extends

  

您可以使用extends关键字来混合特征;在那种情况下你   隐式继承了trait的超类。例如,在代码清单12.2中,类   Frog子类AnyRefPhilosophical的超类)并混入   Philosophical

(这里,Philosophical是一个特质。)

所以,你的推理完全正确。

关于AnyRef的主题,您应该阅读Scala class hierarchytop types。 (AnyRef不是顶级类型,但它非常接近。)