我从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!
那么,我错过了什么?没有扩展它就没有意义使用特征吗?
谢谢!
答案 0 :(得分:21)
首先请注意,扩展/实现差异对编译器没有任何意义,因为它不知道。我并不是说它很糟糕,只是语言本来可以做到的。在C#中,您编写class A : B, C, D
而不是class A extends B implements C, D
和class 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 B
是A
和B
类型的交集。如果对象属于A with B
类型和A
类型,则属于B
类型。因此,可以阅读class A extends B with C
class A
扩展类型B with C
。 class A with B
没有这样的事情。
答案 1 :(得分:8)
如果你来自Java,它起初听起来很奇怪(对我来说也是一样),但实际上现在我发现它比Java更常规的语法,我需要明确说明我是否想要{{1 }}或implement
其他类/接口。但我认为这是个人品味的问题。
您是说extend
还是extends
实际上并不重要。它们都表示两种事物之间的相同关系:是(与委托和组合形成对比,代表具有关系)。例如,您可以在此处找到有关它的更多信息:
http://www.javacamp.org/moreclasses/oop/oop5.html
尝试将implements
,extends
,implements
替换为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
子类AnyRef
(Philosophical
的超类)并混入Philosophical
。
(这里,Philosophical
是一个特质。)
所以,你的推理完全正确。
关于AnyRef
的主题,您应该阅读Scala class hierarchy和top types。 (AnyRef
不是顶级类型,但它非常接近。)