Как создать неизменяемый массив в Swift?
Как создать неизменяемый массив в Swift?
Поверхностное чтение документов предложит вам просто сделать
let myArray = [1,2,3]
Но, к сожалению, это на самом деле производит изменчивый массив фиксированного размера. Эта изменчивость создает обычные головоломки с непредвиденным псевдонимом и функциями, изменяющими их аргументы:
let outterArray = [myArray, myArray]
outterArray[0][0] = 2000
outterArray //=> [[2000,2,3],[2000,2,3]] surprise!
func notReallyPure(arr:Int[]) -> () { arr[0] = 3000 }
notReallyPure(myArray)
myArray // => [3000,2,3]
Не намного лучше, чем C.
Если я хочу неизменность, лучше всего поместить его в NSArray
так:
let immutableArray = NSArray(myArray: [1,2,3])
Это кажется орехом. Что мне здесь не хватает?
ОБНОВЛЕНИЕ (2015-07-26):
Этот вопрос относится к самым ранним дням Свифта. С тех пор Swift был обновлен, поэтому неизменяемые массивы на самом деле неизменяемы, как показывают ниже.
Ответы
Ответ 1
Это изменилось с Xcode 6 beta 3. В то время как массивы, как вы описали, были полупеременными, поскольку их элементы изменяемы, но их длина фиксирована, теперь неизменяемые массивы используют одну и ту же семантику значений как словари:
Из примечаний к выпуску Xcode 6 beta 3:
• Массив в Swift был полностью переработан, чтобы иметь полную семантику значений, такую как Dictionary и String, всегда имевшиеся в Swift. Это устраняет различные проблемы с изменением - теперь массив "let" полностью неизменен, а массив "var" полностью изменен - правильно составлен с помощью словаря и строки и решает другие более глубокие проблемы. Ценностная семантика может быть удивительной, если вы привыкли к массивам NSArray или C: теперь копия массива производит полную и независимую копию всех элементов с использованием эффективной ленивой реализации копии. Это серьезное изменение для Array, и все еще есть некоторые проблемы с производительностью, которые необходимо решить. пожалуйста! см. язык быстрого программирования для получения дополнительной информации. (17192555)
Исходная информация о массивах в книге Swift была обновлена 7 июля 2014 года, чтобы отразить изменения бета-версии. (Если вы используете iBooks на Mac, как и я, вам может потребоваться удалить и повторно загрузить его, чтобы получить обновление 7 июля - я не мог автоматически обновить эту вещь.)
Ответ 2
Кажется, будет ошибкой и скоро будет исправлено.
Процитировано Apple dev forum:
Вопрос:
Несоответствие с let для Array и Dictionary
Окончательный ответ:
Это считается ошибкой, а не функцией, и будет зафиксировано в позже Бета.
-Крис
Ответ 3
Для этого нет большого ответа, и это причудливо.
Однако вы можете предотвратить случайную мутацию массивов, когда они текут через вашу программу, вызывая yourArray.unshare()
. Это приводит к копированию массива при назначении новой переменной.
Ответ 4
Теперь это возможно.
От Apple Developer
Если вы назначаете массив или словарь константе, этот массив или словарь неизменен, а его размер и содержимое не могут быть изменены.
Итак, теперь
let myArray = [1,2,3]
создает полностью неизменяемый массив. Ура!
Ответ 5
ИМХО простейшее обходное решение просто обернуть его в закрытие следующим образом:
let mutableElements = [0,1,2,3]
let reallyImmutable = {[0,1,2,3]}
println(mutableElements)
for i in 0..mutableElements.count { mutableElements[i] *= -1 }
println(mutableElements) // [0, -1, -2, -3]
println(reallyImmutable())
for i in 0..reallyImmutable().count { reallyImmutable()[i] *= -1 }
println(reallyImmutable()) // [0, 1, 2, 3]
println(reallyImmutable()[2]) // 2
let anotherImmutable = { reallyImmutable().map{ $0 * $0 } }
println(anotherImmutable()) // [0, 1, 4, 9]
Вы платите дополнительно {} за объявление и() за каждый доступ, но это также заставляет ваш код говорить сам за себя.
Dan Mutable Programmer
P.S. Написал класс оболочки ImmutableArray.