不可变类中的方法继承
我磕磕绊绊地盼望一些基本问题。 可能是因为我是斯卡拉新手,可能我仍然错过了一些重要的概念。
我试图用FP方式编程,并且不需要具有可变状态的数据类是不可变的,有些转换方法会根据需要创建新对象来更新它们。 然而,当我有特征和一般继承的时候,我一直在努力维护这种方法的返回类型。 我希望尽可能避免混乱的类型或类似的事情,因为这对我来说仍然是一种学习体验。
在这里看到这个例子,我有一个不可改变的类扩展了一些特征。 update
方法的目的是改变数据,调用实际类的一些方法(在特征中是抽象的),并返回一个更新到新数据的同一类的新实例。 人们可以将其大致映射到模板模式。
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()
。
什么是正确的斯卡拉方法来实现这种OO重用,仍然有我的代码清洁?
UPDATE
请注意我放置的地方//some logic takes place here
,这意味着我可能在那里有一些代码,我希望将其集中在特性中,而不是复制并粘贴到扩展它的每个具体类中。 这只是一个框架来说明问题。 谢谢你的时间。
UPDATE
基于小麦提供的答案的代码示例。 问题在于这个return this
。
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
}
这基本上是一种依赖于它自己的类型定义! 因此, update
的返回类型是T
然后:
class MyClass(value: Int) extends MyTrait[MyClass]{
def update(newValue: Int) = new MyClass(newValue)
}
这应该工作,因为T
是MyClass
。
边注:
不要把val
放在特质中。 相反,使它成为一个def
。 这样,您就不会遇到想要扩展您的课程的任何人的初始化排序问题。 如果你不遵循这个建议,那么你可能遇到非null
字段被视为null
。
上一篇: Method inheritance in immutable classes
下一篇: Trait or Class that requires an implicit in order to exist?