Как создать неизменяемый массив в 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.