Имеется ли в Scala синтаксис обновления записей для создания модифицированных клонов неизменяемых структур данных? - PullRequest
15 голосов
/ 12 июля 2011

В Меркурии я могу использовать:

A = B^some_field := SomeValue

, чтобы связать A с копией B, за исключением того, что some_field равно SomeValue вместо того, что было в B. Я считаю, что эквивалент Haskellчто-то вроде:

a = b { some_field = some_value }

Есть ли у Scala что-то вроде этого для "изменения" неизменяемых значений.Похоже, альтернативой будет иметь конструктор, который напрямую устанавливает каждое поле в экземпляре, что не всегда идеально (если есть инварианты, которые должен поддерживать конструктор).Кроме того, было бы очень неуклюже и гораздо более хрупко, если бы мне пришлось явно передавать каждое другое значение в экземпляре, для которого я хочу иметь измененную копию.

Я не мог ничего найти по этому поводу, прибегая к помощи иликраткий обзор справочника по языку или «Scala By Example» (который я прочитал от начала до конца, но еще не освоил все, так что он вполне может быть там).

Iвидно, что эта функция может иметь некоторые странные взаимодействия с защитой доступа и подклассами в стиле Java ...

Ответы [ 3 ]

26 голосов
/ 12 июля 2011

Если вы определяете свой класс как 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.

11 голосов
/ 12 июля 2011

Для этого вы можете использовать классы падежей, но это не обязательно.Классы падежей не являются чем-то волшебным - модификатор case просто экономит много времени на печатании.Метод копирования реализован с использованием именованных и стандартных параметров.Имена совпадают с полями, а значения по умолчанию являются текущими значениями полей.Вот пример:

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

Вы можете использовать это так же, как метод copy для case-классов.Именованные параметры и параметры по умолчанию являются очень полезной функцией, и не только для методов копирования.

4 голосов
/ 12 июля 2011

Если объект, который вы планируете изменить, является классом дел, то вы можете использовать метод автоматически сгенерированного копирования:

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

scala> val corrected = user.copy(name = "Sean")
corrected: User = User(2,Sean)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...