Как использовать необязательные переменные с изменяемыми коллекциями?

#swift

#swift

Вопрос:

Кажется, я не могу заставить коллекции быть изменяемыми, когда они назначаются необязательным переменным. В приведенном ниже примере кода необязательный работает так, как ожидалось. Переменная будет сохранять изменяемое состояние в коллекции. Нет локальных переменных, я могу использовать переменное поле напрямую. Однако я не уверен, как использовать переменные с неизменяемыми коллекциями, должен ли я предположить, что «let» вместо «var» сработает?

Тем не менее, глядя на необязательный класс, требуется локальный var, чтобы придать коллекции изменяемое состояние (даже если XCode предлагает append(), когда я не использую локальный var). Действительно ли я должен писать код для обновления коллекции путем добавления локальных переменных? Есть ли более краткий способ без использования локального var? Мне любопытно узнать, является ли назначение коллекции простым псевдонимом или оно выполняет копию, либо мелкую, либо глубокую?

    class NonOptional {
        var exclamation: String[] // using var should set that collection as mutable...

        init() {
            self.exclamation = []
        }

        func write() {
            self.exclamation.append("exclamation")
        }

        func delete() {
            if self.exclamation.count > 0 {
                self.exclamation.removeAtIndex(0)
            }
        }
    }

    class Optional {
        var question: String[]? // using var should set that collection as mutable...

        init() {
            self.question = []
        }

        func write() {
            var local = self.question! // copy or pass by ref?
            local.append("question")    // why can't I just do self.foo!.append("foo") ?
        }

        func delete() {
            if self.question!.count > 0 {
                var local = self.question!
                local.removeAtIndex(0)
            }
        }
    }
  

Комментарии:

1. если вы не вызовете mutating метод в local или в question , они будут указывать на один и тот же экземпляр. после вызова любого mutating метода для любого они будут указывать на разные экземпляры. создание нового экземпляра займет O(n) время. подробнее об этом можно прочитать здесь: developer.apple.com/library/prerelease/ios/documentation/swift /…

Ответ №1:

Этот вопрос был задан, когда Swift 1 все еще находился в бета-версии, и с тех пор многое изменилось (хотя я не совсем уверен, что эта конкретная функция не существовала в Swift 1).

Для потомков изменение необязательного массива не является проблемой в Swift 3. Вот как вы это сделаете:

 var strings: [String]? = ["a", "b"]
strings?[0] = "A"
// strings is now Optional(["A", "b"])
strings?.append("c")
// strings is now Optional(["A", "b", "c"])
strings?.remove(at: 1)
// strings is now Optional(["A", "c"])
  

Ответ №2:

 var question: String[]? // using var should set that collection as mutable...
  

Это неправильно. var Там говорится, что необязательная ссылка является «изменяемой», то есть она может быть nil или установлена в фактический массив. Затем Swift по умолчанию делает массив неизменяемым.

Многие из этих мелких деталей, касающихся массивов и изменчивости, на данный момент немного меняются, я ожидаю, что будут исправления, изменения и четкое определение того, что должно произойти в ближайшие недели.

Комментарии:

1. Приятно слышать. Я знаю, что это не самое подходящее место для высказывания мнений, поэтому позвольте мне вместо этого внести предложение, даже если меня за это обвинят: я видел, как я часто сталкивался с подобными проблемами с Swift. Возможно, язык слишком старается быть обратно совместимым, не уверен. Для сохранения ключевого слова, такого как mut / mutating, этот синтаксис нелегко записать или даже прочитать. Я бы предпочел что-то вроде в Rust или OCaml, когда вы можете явно указать, являются ли переменные изменчивыми или нет. Сегодня неизменяемые массивы фактически изменяются за вычетом изменения размера, поэтому я думаю, что новое ключевое слово может исправить ситуацию как в ясности, так и в правильности

2. Проблема, из-за которой вы можете изменять неизменяемые массивы до тех пор, пока вы не измените их размер, по-видимому, будет исправлена по крайней мере в будущей версии. Таким образом, мы получим истинные неизменяемые массивы.

3. В то же время, что вы рекомендуете мне делать? Придерживайтесь NSMutable массивов с синтаксисом, подобным мосту, или используйте описанный выше трюк с переменным значением, по существу переопределяя массив как изменяемый для области действия функции? Просто пытаюсь выяснить, как лучше всего справиться с тем, что кажется большим недостатком в языковом дизайне. Я немного смущен, увидев, что это будет исправлено только позже. В конце концов, кажется, что управление памятью должно быть более прочно привязано к языковым схемам

4. Я не знаю вашей конкретной ситуации, но я бы использовал пустой массив по умолчанию, чтобы у меня не было необязательного типа. Тогда у меня просто есть хороший изменяемый массив, который по умолчанию является пустым массивом. В противном случае я бы использовал ваш трюк сверху. Кстати, вы можете напрямую инициализировать свойство на месте var myArray = String[]()