Где хранится моя переменная? (Быстрый)

Один из моих небольших экспериментов со Swift:

func store<T>(var x: T) -> (getter: (Void -> T), setter: (T -> Void)) {
    return ({ x }, { x = $0 })
}

x — это тип значения.

Мои вопросы:

  • Где именно хранится x (с точки зрения стека/кучи)?
  • Каковы подводные камни такого хранения x?
  • Это безопасно?
  • Когда x будет уничтожен (если когда-нибудь)?

person Vatsal Manot    schedule 13.08.2015    source источник


Ответы (1)


Параметры передаются функциям и методам по значению — это означает, что копия параметра создается и используется в теле функции.

Параметры, полученные функциями и методами, являются неизменяемыми, то есть их значение нельзя изменить. Однако модификатор var делает параметр изменяемым. Важно учитывать, что копия параметра является изменяемой: параметр, переданный в функцию, не имеет отношения к параметру, полученному телом функции, кроме исходной копии. Тем не менее, изменение параметра с помощью модификатора var делает его изменяемым, но его время жизни заканчивается с телом функции и не влияет на исходный параметр, переданный в функцию.

Есть еще один вариант, модификатор inout, который работает как var, но когда функция возвращает значение, оно копируется обратно в переданную переменную.

Стоит отметить, что до сих пор я неявно учитывал только типы значений. Если экземпляр ссылочного типа (класса или замыкания) передается функции в качестве параметра var, любое изменение, сделанное с помощью этого параметра, фактически выполняется для экземпляра, переданного в функцию (это наиболее существенное различие между значениями и ссылочными типами). ). Экземпляр, на который указывает переменная x, имеет то же время жизни, что и параметр, переданный в функцию.

Все это говорит о том, что в вашем случае это работает немного по-другому. Вы возвращаете замыкание (хорошо, их 2, но это не меняет вывод), и замыкание захватывает x, что приводит к тому, что x сохраняется до тех пор, пока переменная, которой назначено замыкание, находится в области видимости:

let x = 5
let (getter, setter) = store(x)

В приведенном выше коде, когда getter и setter будут освобождены, x (как переменная, определенная в функции store) также перестанет существовать.

Чтобы ответить на ваши вопросы:

  1. x — это переменная, созданная при вызове функции store. Поскольку вы явно указываете типы значений, то x должно быть выделено в стеке (в отличие от кучи, которая должна использоваться для ссылочных типов)
  2. ловушка заключается в том, что он освобождается, когда освобождаются 2 возвращаемых значения (которые являются ссылочными типами, являющимися ссылочными типами закрытия).
  3. это может быть полезно в некоторых нишевых случаях, но в целом я бы держался подальше от этого - обратите внимание, что это мое собственное мнение
  4. уже описано выше (когда функция возвращает значения, они освобождаются)
person Antonio    schedule 13.08.2015
comment
Блестяще сформулировано, я очень ценю время, которое вы потратили на это! Однако я не понимаю оправдания описанной вами ловушки. - person Vatsal Manot; 13.08.2015
comment
Это должно быть проще: если T является типом значения, переменная размещается в стеке, а замыкания (являющиеся ссылочными типами) — в куче. Таким образом, данные хранятся в стеке и поддерживаются двумя экземплярами, выделенными в куче. - person Antonio; 13.08.2015
comment
имейте в виду, что COW-реализация стандартного массива Swift, вероятно, хранит свои данные в куче, даже если сам массив является типом значения - person Max Desiatov; 13.08.2015
comment
@MaxDesiatov: Насколько мне известно (но я могу ошибаться), внутри массив использует ссылочный тип (то есть класс) для хранения данных - конечно, разработчик ничего не видит. Это означает, что данные хранятся в куче - person Antonio; 13.08.2015
comment
Насколько я знаю, inout не передается по ссылке: это копирование и обратное копирование. (по крайней мере, при использовании со значениями) - person oisdk; 13.08.2015
comment
Да, информация здесь и здесь - person oisdk; 13.08.2015
comment
@oisdk да, это правильно - спасибо, что указали на это. Я исправил в ответе. Я неявно предположил, что & автоматически переводится как ссылка на — слишком много лет потрачено на C++ :) - person Antonio; 13.08.2015