Имеет ли Scala синтаксис обновления записи для создания модифицированных клонов неизменяемых структур данных?
В Mercury я могу использовать:
A = B^some_field := SomeValue
связать A с копией B, за исключением того, что some_field
является SomeValue
вместо того, что было в B. Я считаю, что эквивалент Haskell выглядит примерно так:
a = b { some_field = some_value }
Есть ли у Scala что-то подобное для "модификации" неизменяемых значений. Альтернативой, похоже, является конструктор, который непосредственно устанавливает каждое поле в экземпляре, что не всегда идеально (если есть инварианты, которые должен поддерживать конструктор). Плюс это было бы действительно неуклюже и намного более хрупким, если бы я должен явно передать любое другое значение в экземпляре, в котором я хочу иметь измененную копию.
Я ничего не мог найти по этому поводу в googling или в кратком обзоре справочного руководства по языку или "Scala по примеру" (который я прочитал от начала до конца, но не впитал все тем не менее, поэтому он может быть там).
Я вижу, что эта функция может иметь некоторые странные взаимодействия с защитой и подклассами в стиле Java, хотя...
Ответы
Ответ 1
Для этого вы можете использовать классы case, но вам этого не нужно. Классы классов не являются волшебными - модификатор case
просто экономит вам много ввода.
Метод копирования реализуется с использованием параметров named и default. Имена те же, что и поля, а значения по умолчанию - текущие значения полей. Вот пример:
class ClassWithCopy(val field1:String, val field2:Int) {
def copy(field1:String = this.field1, field2:Int = this.field2) = {
new ClassWithCopy(field1,field2);
}
}
Вы можете использовать его так же, как метод копирования для классов case. Именованные и стандартные параметры являются очень полезной функцией, а не только для методов копирования.
Ответ 2
Если вы определяете свой класс как 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)
Он даже работает с полиморфными классами case:
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
.
Ответ 3
Если объект, который вы планируете модифицировать, является классом case, тогда вы можете использовать метод автоматической генерации копии:
scala> val user = User(2, "Sen")
user: User = User(2,Sen)
scala> val corrected = user.copy(name = "Sean")
corrected: User = User(2,Sean)