在水星中,我可以使用:
A = B^some_field := SomeValue
将A绑定到B的副本,除了some_field
是SomeValue
而不是B中的任何内容。我相信Haskell的等价物是这样的:
a = b { some_field = some_value }
Scala是否有类似“修改”不可变值的东西。替代方案似乎是有一个构造函数直接设置实例中的每个字段,这并不总是理想的(如果构造函数应该保持不变)。如果我必须明确地传递我想要修改副本的实例中的每个其他值,它会非常笨重而且更加脆弱。
我通过谷歌搜索,或者在语言参考手册或“Scala By Example”(我已经阅读了从头到尾,但还没有完全吸收所有内容)的简短调查中找不到任何相关内容,所以它可能就在那里。)
我可以看到这个功能可能会与Java风格的访问保护和子类进行一些奇怪的交互...
答案 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)