Scala是否具有用于创建不可变数据结构的修改克隆的记录更新语法?

时间:2011-07-12 09:33:49

标签: scala immutability

在水星中,我可以使用:

A = B^some_field := SomeValue

将A绑定到B的副本,除了some_fieldSomeValue而不是B中的任何内容。我相信Haskell的等价物是这样的:

a = b { some_field = some_value }

Scala是否有类似“修改”不可变值的东西。替代方案似乎是有一个构造函数直接设置实例中的每个字段,这并不总是理想的(如果构造函数应该保持不变)。如果我必须明确地传递我想要修改副本的实例中的每个其他值,它会非常笨重而且更加脆弱。

我通过谷歌搜索,或者在语言参考手册或“Scala By Example”(我已经阅读了从头到尾,但还没有完全吸收所有内容)的简短调查中找不到任何相关内容,所以它可能就在那里。)

我可以看到这个功能可能会与Java风格的访问保护和子类进行一些奇怪的交互...

3 个答案:

答案 0 :(得分:26)

如果您将类定义为case class,则会生成一个方便的copy方法,并且调用它可以为命名参数指定某些字段的新值。

scala> case class Sample(str: String, int: Int)
defined class Sample

scala> val s = Sample("text", 42)
s: Sample = Sample(text,42)

scala> val s2 = s.copy(str = "newText")
s2: Sample = Sample(newText,42)

它甚至适用于多态案例类:

scala> case class Sample[T](t: T, int: Int)
defined class Sample

scala> val s = Sample("text", 42)
s: Sample[java.lang.String] = Sample(text,42)

scala> val s2 = s.copy(t = List(1,2,3), 42)
s2: Sample[List[Int]] = Sample(List(1, 2, 3),42)

请注意,s2的类型与s不同。

答案 1 :(得分:11)

您可以为此使用案例类,但您不必这样做。案例类并不神奇 - 修饰符case只会为您节省大量的输入内容。 通过使用命名和默认参数来实现复制方法。名称与字段相同,默认值是字段的当前值。这是一个例子:

class ClassWithCopy(val field1:String, val field2:Int) {
    def copy(field1:String = this.field1, field2:Int = this.field2) = {
        new ClassWithCopy(field1,field2);
    }
}

您可以像使用案例类的复制方法一样使用它。命名和默认参数是一个非常有用的功能,不仅适用于复制方法。

答案 2 :(得分:4)

如果您计划修改的对象是案例类,那么您可以使用自动生成的复制方法:

scala> val user = User(2, "Sen")
user: User = User(2,Sen)

scala> val corrected = user.copy(name = "Sean")
corrected: User = User(2,Sean)