开发者

Does Scala have record update syntax for making modified clones of immutable data structures?

开发者 https://www.devze.com 2023-03-19 09:34 出处:网络
In Mercury I can use: A = B^some_field := SomeValue to bind A to a copy of B, except that some_field is SomeValue instead of whatever it was in B. I believe the Haskell equivalent is something like

In Mercury I can use:

A = B^some_field := SomeValue

to bind A to a copy of B, except that some_field is SomeValue instead of whatever it was in B. I believe the Haskell equivalent is something like:

a = b { some_field = some_value }

Does Scala have something like this for "modifying" immutable values. The alternative seems to be to have a constructor that directly sets every field in the instance, which isn't always ideal (if there are invarients the constructor should be maintaining). Plus i开发者_开发百科t would be really clunky and much more fragile if I had to explicitly pass every other value in the instance I want to have a modified copy of.

I couldn't find anything about this by googling, or in a brief survey of the language reference manual or "Scala By Example" (which I have read start-to-finish, but haven't absorbed all of yet, so it may well be in there).

I can see that this feature could have some weird interactions with Java-style access protection and subclasses though...


If you define your class as a case class, a convenient copy method is generated, and calling it you can specify with named parameters new values for certain fields.

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)

It even works with polymorphic case classes:

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)

Note that s2 has a different type than s.


You can use case classes for this, but you don't have to. Case classes are nothing magical - the modifier case just saves you a lot of typing. The copy method is realized by the use of named and default parameters. The names are the same as the fields and the defaults are the current values of the fields. Here's an example:

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

You can use this just like the copy method on case classes. Named and default parameters are a very useful feature, and not only for copy methods.


If the object you're planning on modifying is a case class then you can use the autogenerated copy method:

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

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号