Scala:如何编写将类型化为接收者的实现类型的对象返回的方法
我知道 Scala 中不推荐使用案例类继承,但为了简单起见,我在以下示例中使用了它:
scala> case class Foo(val f: String) { def foo(g: String): Foo = { this.copy(f=g) }}
defined class Foo
scala> case class Bar(override val f: String) extends Foo(f)
warning: there were 1 deprecation warnings; re-run with -deprecation for details
defined class Bar
scala> Bar("F")
res0: Bar = Foo(F)
scala> res0.foo("G")
res1: Foo = Foo(G)
到目前为止,一切都很好。不过,我真正想要的是能够在 Foo 中编写一个方法 foo()
,当在 Bar 类型的对象上调用时,该方法返回 Bar 类型的对象,而不必在 Foo 中重新实现该方法类酒吧。有没有办法在 Scala 中做到这一点?
I'm aware that case class inheritance is deprecated in Scala, but for the sake of simplicity, I've used it in the following example:
scala> case class Foo(val f: String) { def foo(g: String): Foo = { this.copy(f=g) }}
defined class Foo
scala> case class Bar(override val f: String) extends Foo(f)
warning: there were 1 deprecation warnings; re-run with -deprecation for details
defined class Bar
scala> Bar("F")
res0: Bar = Foo(F)
scala> res0.foo("G")
res1: Foo = Foo(G)
So far, so good. What I really want, though, is to be able to write a method foo()
in Foo that returns an object of type Bar when called on an object of type Bar, without having to reimplement the method in class Bar. Is there a way to do this in Scala?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
构建器方法
是的,可以做到。一个很好的例子就是馆藏图书馆。
请参阅 Scala 集合的架构 了解如何实现事情已经完成了。
编辑:
它使用两种方法来重用实现。第一个是使用通用特征和构建器,另一个是使用类型类。
这样做的全部意义在于,您可以在共同特征上做一些有趣的事情,例如在
FooLike
中实现共同的map
。很难通过琐碎的代码看到好处。类型类方法
使用类型类的好处是,您可以向
Foo
和Bar
添加功能,即使您无法更改它们(例如String
代码>)。builder approach
Yes, it can be done. A good example of that is the collections library.
See The Architecture of Scala Collections to see how it was done.
Edit:
It uses two approaches to reuse implementations. The first is by using common traits and builders, and the other is using type classes.
The whole point of doing this, is so you can do something interesting at the common trait, like implementing common
map
inFooLike
. It's hard to see the benefits with trivial code.type class approach
The benefit of using a type class is that you can add features to
Foo
andBar
even when you can't change them (likeString
).copy 方法是由编译器实现的,它似乎不属于常见特征。最简单的方法是定义一个特征:
另一个选择是使用类型类来提供适当的构建器。但它不会保存键入的字符数。
The copy method is implemented by the compiler and it does not seem to belong a common trait. The easiest way to do it is to define a trait:
Another option is to use type classes to provide an appropriate builder. But it wont save the number of typed characters.
注意:这不会创建新对象,而是重新使用
this
对象。对于一般用途,请参阅 范式的回答。由于某种原因,它不能与
case 类
的copy
方法一起使用。 (但不可否认,由于case class
继承无论如何都不应该进行,所以不会出现问题。)。但对于任何其他方法,您可以使用this.type
来完成。如果您需要方法参数和方法主体中的自类型差异(而不是仅返回类型差异),则需要更进一步并定义
这将允许您将适当的方法主体添加到
特征
。 (请参阅:2D 和 3D 向量的正确类层次结构)Note: This does not create a new object but re-uses the
this
object. For general use, see paradigmatic’s answer.For some reason, it does not work together with the
case class
’scopy
method. (But admittedly, sincecase class
inheritance should not be done anyway, the problem does not occur.). But for any other method, you do it withthis.type
.If you need the self-type variance in method arguments and method bodys (as opposed to return-type-only variance), you will need to go one step further and define
This will allow you to add proper method bodies to the
trait
. (See: proper class hierarchy for 2D and 3D vectors)此解决方案不需要单独的特征。
This solution doesn't require a separate trait.