我磕磕绊绊,希望这是一个基本问题.可能是因为我是
Scala的新手,可能我仍然缺少一些重要的概念.
我试图以FP方式编程,并且不需要具有可变状态的数据类是不可变的,使用一些转换方法来创建新对象以在需要时更新它们.但是,当我有特征和一般继承时,我在维护这个方法的返回类型时遇到了困难.我希望尽可能地避免混乱的类型演员或类似的事情,因为这对我来说仍然是一种学习经历.
在这里看到这个例子,我有一个不可变的类扩展了一些特征. update方法旨在更改数据,调用实际类的某些方法(在trait中是抽象的)并返回更新到新数据的同一类的新实例.可以将其粗略地映射到模板模式.
trait MyTrait { val someDataVal : Integer; def update(newDataVal) : MyTrait = { //some logic takes place here,which is common abstractUpdate(newDataVal) } //some logic takes place,specific to the implementation class def abstractUpdate(newDataVal : Integer) : MyTrait } class MyClass(dataVal : Integer) extends MyTrait { override val someDataVal = dataVal def abstractUpdate(newDataVal : Integer) : MyClass = { //some class specific logic here ........ MyClass(newDataVal) } def someOtherFunction() : Integer = { //some logic here ..... } }
我显然不希望将update()复制并粘贴到MyClass中,我希望它保留在特征中,以便我可以通过扩展它的任何类来使用它.但是如果我试着调用它,我得到的是MyTrait类型的对象,所以我不能在它上面调用someOtherFunction().
什么是正确的Scala方法来实现这种OO重用并仍然让我的代码干净?
UPDATE
请注意我放置的地方//这里发生了一些逻辑,这意味着我可能在那里有一些代码,我希望将其集中在特征中,而不是复制和粘贴到扩展它的每个具体类中.这只是解释问题的骨架.谢谢你的时间.
UPDATE
代码示例基于wheaties提供的答案.问题在于退货.
trait MyTrait[T <: MyTrait[T]]{ def update(newValue: Int): T = { if (newValue == 0) return this; //this creates a type mismatch else concreteUpdate(newValue) } def concreteUpdate(value : Int) : T } class MyClass(value: Int) extends MyTrait[MyClass] { override def concreteUpdate(value : Int) = new MyClass(value) }
解决方法
之前我已经回答了类似的问题,@ GaborBakos的评论就是现货.如果您希望能够使用TraverseableLike的map方法执行类似的操作,那么您需要执行以下操作:
trait MyTrait[T <: MyTrait[T]]{ def update(newValue: Int): T }
这基本上是一个依赖于自身的类型定义!因此,更新的返回类型是T.然后:
class MyClass(value: Int) extends MyTrait[MyClass]{ def update(newValue: Int) = new MyClass(newValue) }
这应该工作,因为T是MyClass.
边注:
不要把val放在特质中.相反,让它成为一个def.这样,您就不会遇到想要扩展您的类的任何人的初始化排序问题.如果你不遵循这个建议,那么你可以遇到一个非常零的字段被视为空的情况.