Scala 抽象类中的不可变副本更新
我希望我的类既不可变又可更新。这是我的样板:Scala 抽象类中的不可变副本更新,scala,Scala,我希望我的类既不可变又可更新。这是我的样板: case class A(a: Int, b: Int) { def withB(newB: Int) = copy(b=newB) } 它按预期工作。问题是,如果我希望客户机派生A,但不直接实例化它,该怎么办?这: abstract case class A(a: Int, b: Int) { def withB(newB: Int) = copy(b=newB) } 不起作用。(当然不是,如果不实例化,怎么可能复制自己?) 如果我希望
case class A(a: Int, b: Int) {
def withB(newB: Int) = copy(b=newB)
}
它按预期工作。问题是,如果我希望客户机派生A
,但不直接实例化它,该怎么办?这:
abstract case class A(a: Int, b: Int) {
def withB(newB: Int) = copy(b=newB)
}
不起作用。(当然不是,如果不实例化,怎么可能复制自己?)
如果我希望客户机派生A
,但不直接实例化它,该怎么办
您可以使用生成器模式来完成此操作。构建器将是一个(case)类,它拥有创建a
所需的一切,您可以将其传递到需要实例化a
的位置
比如说,
case class ABuilder(one: Int = 1, two: String = "") {
def withOne(v: Int) = copy ...
def withTwo(v: String) = copy ...
def build(): A = ...
}
您需要开始研究其他模式,以帮助您更新不可变对象。开始查看
镜头类型。它们是这样工作的:
trait Lens[A,B]{
self =>
def get(obj: A): B
def set(obj: A, value: B): A
def andThen(that: Lens[B, C]): Lens[A,C]{
def get(obj: A) = that get (self get obj)
def set(obj: A, value: C) = self set (obj, that set(self get obj, value))
}
}
这样,您就可以定义一个“get”和“set”,它既符合Scala中大多数事物的纯粹性(它们通过制作副本来工作),也符合Scala中大多数事物的可组合性。因此,在您的示例中,您不会在对象本身上使用two
方法定义,而是为其创建一个镜头
使用镜头:
case class Bar(c: Int)
case class Foo(a: Int, b: Bar)
object LensFooBar extends Lens[Foo, Bar]{
def get(foo: Foo) = foo.b
def set(foo: Foo, bar: Bar) = foo.copy(b = bar)
}
object LensBarC extends Lens[Bar, Int]{
def get(bar: Bar) = bar.c
def set(bar: Bar, value: Int) = bar.copy(c = value)
}
val myFirst = Foo(1, Bar(2))
val updated = LensFooBar.set(myFirst, Bar(3))
val lenser = LensFooBar andThen LensBarC
val updatedFurther = lenser set(myFirst, 3)
这两个镜头都在做同样的事情,但这不仅应该说明如何使用不可变的嵌套结构,还应该说明如何在类中为每个要更改的字段放置方法之外使用不可变的对象
您可以看到这一点,也可以阅读Scalaz如何实现Lens。makecopy
abstract,因此任何派生类都必须实现它?根据定义,不可变对象是不可更新的,不是吗?