Trait 继承和 self 类型注释之间的区别
在 Scala 中,我已经看到了构造
trait T extends S
并
trait T { this: S =>
用于实现类似的事情(即必须在创建实例之前定义 S
中的抽象方法)。他们之间有什么区别?为什么你会使用其中一种而不是另一种?
In Scala, I've seen the constructs
trait T extends S
and
trait T { this: S =>
used to achieve similar things (namely that the abstract methods in S
must be defined before an instance may be created). What's the difference between them? Why would you use one over the other?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
自类型注释允许您表达循环依赖关系。例如:
这对于简单继承来说是不可能的。
Self type annotations allow you to express cyclic dependencies. For instance:
This is not possible with simple inheritance.
我会使用自我类型进行依赖管理:这个特征需要混合另一个特征。并且我会使用继承来完善另一个特征或接口。
举个例子:
现在,如果 FooRemoting 和 FooPersistence 都继承自 FooService,并且 FooService 有成员和方法,那么 Services 会是什么样子?
而对于继承,我们会有类似的东西:
I'd use self-types for dependency-management: This trait requires another trait to be mixed in. And I'd use inheritance to refine another trait or interface.
Just as an example:
Now, if FooRemoting and FooPersistence both would have inherited from FooService, and FooService has members and methods, how would Services look like?
Whereas for inheritance, we'd have something like:
自从提出问题以来,我遇到了这些帖子:
Spiros Tzavellas 讨论了使用特征作为公共接口,使用自我类型作为必须由实现类混合的帮助器。
例如:
Scala 之旅 讨论使用带有抽象类型成员的自类型注释 - 大概是无法
扩展
抽象类型成员(?)Since asking the question I came across these posts:
Spiros Tzavellas talks about using a trait as the public interface and the self type as a helper that must be mixed in by the implementation class.
For example:
A Tour of Scala discusses using self type annotations with abstract type members - presumably it's not possible to
extend
an abstract type member(?)我知道这个问题很旧,但我想添加一些说明和示例。
特质遗传和自我类型之间存在三个主要区别。
语义
继承是对象范式中耦合度最高的关系之一,如果 A 扩展 B,则意味着 A 是 B。
假设我们有以下代码,
我们说狗是 一只动物。我们可以将消息
bark
和stop
发送给goodboy
,因为它是一只狗,它理解这两种方法。现在假设我们有一个新特征,
这次安全不是动物,这很好,因为如果我们确认安全是动物,那么在语义上就会不正确,它们是不同的概念,可以一起使用。
现在我们可以创建一种新的狗,
guardDog
是一只狗,一种动物和安全。它理解停止
、吠叫
和监视
,因为它是一只有安全感的狗。但是如果我们创造一只这样的新狗会发生什么呢?
guardDog2
只是一只 Dog,因此我们无法调用lookout
方法。 (好吧,这是一只具有安全性的狗,但我们只看到一只狗)循环依赖
自类型允许我们在类型之间创建循环依赖。
以下代码无法编译。
这种代码在依赖注入(蛋糕模式)中很常见。
多功能性
最后但并非最不重要的一点是,谁使用我们的特征可以决定它们的使用顺序,因此由于特征线性化,尽管使用的特征相同,但最终结果可能会有所不同。
对于正常的继承,我们不能这样做,特征和类之间的关系是固定的。
希望这会有用。
I know this question is old but I would like to add some clarification and examples.
There are three main differences between trait inheritance and self types.
Semantics
Inheritance is one of the relationships with the most coupling of the object paradigm, if A extends B, that means that A is a B.
Let's say we have the following code,
We are saying that a Dog is an Animal. We can send the messages
bark
andstop
togoodboy
because is a Dog, it understand both methods.Now suppose we have a new trait,
This time Security is NOT an Animal, and that is fine because would be semantically incorrect if we affirm that a Security is an Animal, they are different concepts, that can be used together.
So now we can create a new kind of dog,
guardDog
is a Dog, an Animal and Security. It understandstop
,bark
andlookout
because is a Dog with Security.But what happens if we create a new dog like this?
guardDog2
is just a Dog, so we can't calllookout
method. (okok, it's a Dog with Security, but we just see a Dog)Cyclic Dependencies
Self Types allow us to create cyclic dependencies between types.
The following code doesn't compile.
This kind of code is very common in dependency injection (cake pattern).
Versatility
Last but not least, who uses our traits can decide the order in which they are used, so thanks to Trait Linearization the final result can be different although the traits used are the same.
With normal inheritance we can't do that, the relations between traits and classes are fixed.
Hope this can be useful.
答案是“循环”。但不仅如此。
自类型注释为我解决了继承的基本问题:你继承的东西不能使用你的东西。
有了自我型,一切都变得容易了。
我的模式如下,可以被认为是一个退化的蛋糕:
您可以以多种行为分解您的类,这些行为可以从程序集中的任何位置调用,同时保持干净的类型。
不需要经常(并且错误地)将蛋糕图案与痛苦的间接联系起来。
过去十年中,一半(如果不是全部)复杂的 Java DI 框架都致力于做到这一点,当然不需要打字。
仍在该领域使用 JAVA 的人们显然正在浪费时间:“SCALA ouakbar”。
The answer is "circularity". But not only.
Self type annotation solves for me the fundamental problem of inheritance: what you inherit from cannot use what you are.
With the self type, everything becomes easy.
My pattern is the following and can be considered as a degenerated cake:
You can explode your class in multiple behaviours which can be called from anywhere in the assembly, while staying cleanly typed.
No need for the painful indirection too often (and wrongly) identified with the cake pattern.
Half (if not the totality) of the convoluted Java DI frameworks of the last ten years have been devoted to do this, of course without the typing.
People still using JAVA in this domain are clearly loosing their time: "SCALA ouakbar".
虽然它没有回答你的问题,但我试图理解自我类型注释,基本上迷失在答案中,并且不知何故最终循环了你的问题的变体,该问题侧重于使用自我类型注释来声明依赖关系。
因此,我在这里发布了一个用例的描述,其中很好地说明了自类型注释,即类似于“this”作为子类型的类型安全情况:
http://programming-scala.labs.oreilly.com/ch13.html#SelfTypeAnnotationsAndAbstractTypeMembers
希望这对最终的人有帮助偶然回答这个问题(并且像我一样,在开始探索之前没有时间阅读 scala 书:-))
Although it doesn't answer your question, I was trying to understand the self-type annotations and basically got lost in answers, and somehow ended up cycling through variations of your question, which focuses on usage of self-type annotations for stating dependencies.
So here I post a description of an use case where self-type annotations are well illustrated, namely something like a type-safe case of 'this' as a subtype:
http://programming-scala.labs.oreilly.com/ch13.html#SelfTypeAnnotationsAndAbstractTypeMembers
hoping that it would be helpful to those who end up on this question by chance (and, like me, didn't have time to read a scala book before starting to explore :-) )