Карта модифицирует массив объектов в Swift 2.2 (3.0)


person kernelpanic    schedule 28.03.2016    source источник


Ответы (3)


Если вы хотите сохранить этот синтаксис, просто используйте (изменяемую) временную переменную

gnomes = gnomes.map { (gnome: Gnome) -> Gnome in
  var mutableGnome = gnome
  mutableGnome.age = 140
  return mutableGnome
}
person vadian    schedule 28.03.2016

(Ниже следует случай, когда Gnome является ссылочным типом; классом, поскольку вы не показали нам, как вы определили Gnome. О случае, когда Gnome является типом значения (структурой), см. @vadian: ответ)


Удаление var не повлияет на использование .map для изменения изменяемых членов массива объектов типа reference. То есть вы можете просто использовать свой старый подход (однако, опуская var в сигнатуре закрытия .map).

class Gnome {
    var age = 42
}

var gnomes = [Gnome(), Gnome(), Gnome()]

gnomes = gnomes.map {
    $0.age = 150
    return $0
}

/* result */
gnomes.forEach { print($0.age) } // 3x 150

Однако, если вы просто хотите изменить исходный массив, а не присваивать результат .map новому массиву, .forEach может быть более подходящим выбором, чем .map.

gnomes.forEach { $0.age = 140 }

/* result */
gnomes.forEach { print($0.age) } // 3x 140
person dfrib    schedule 28.03.2016
comment
возвращает ошибку $0 is immutable. Это моя вина. Я должен был быть более точным :( Я использую структуры вместо классов, я уверен, что то, что делает их неизменяемыми по умолчанию - person kernelpanic; 28.03.2016
comment
@kernelpanic Поскольку вы не показали нам свой класс Gnome, мне пришлось включить один из моих собственных. Вы уверены, что свойство age вашего класса является изменяемым (как и ваш массив гномов)? Вышеупомянутое отлично работает для меня на Swift 2.2 и Xcode 7.3. - person dfrib; 28.03.2016
comment
@dfri Я подозреваю, что Gnome - это структура - person vadian; 28.03.2016
comment
Проголосовал за ссылку на .forEach(), это то, что я искал. - person jan.vogt; 08.06.2016
comment
@jan.vogt рад помочь. - person dfrib; 08.06.2016

Данный:

struct Gnome {
    var age: Int = 0
}

var gnomes = Array(count: 5, repeatedValue: Gnome())

... есть два достойных варианта. Первый, как выразился @vadian:

gnomes = gnomes.map{
    var gnome = $0
    gnome.age = 70
    return gnome
}

В то время как второй сохраняет контроль над «старением» private и упрощает сопоставление в точке вызова:

struct Gnome {
    private(set) var age: Int = 0

    func aged(age: Int) -> Gnome {
        var gnome = self
        gnome.age = age
        // any other ageing related changes
        return gnome
    }
}

gnomes = gnomes.map{ $0.aged(140) }

Конечно, ссылочные типы по-прежнему занимают свое место в программировании, и в данном случае это может быть лучше. Трение, с которым мы здесь сталкиваемся, предполагает, что мы пытаемся обращаться с этими структурами так, как если бы они были объектами. Если вам нужно именно такое поведение, вам следует рассмотреть возможность реализации Gnome как class.

person Milos    schedule 28.03.2016