Можно ли захватывать value-типы (структуры, перечисления) в capture list замыкания в Swift?

Ответ

Да, capture list в Swift работает с value-типами (структуры, перечисления, кортежи) так же, как и с reference-типами (классы).

Ключевое поведение: При захвате value-типа в списке захвата создается неизменяемая копия значения на момент создания замыкания.

Пример:

var number = 10

// Захватываем текущее значение `number` (10)
let closure = { [number] in
    print("Захваченное значение: (number)") // Всегда выведет 10
}

number = 20 // Изменение исходной переменной
closure() // Вывод: "Захваченное значение: 10"

Зачем это нужно?

  • Фиксация состояния: Чтобы замыкание работало со значением, актуальным на момент его определения, а не на момент вызова.
  • Предотвращение неявных зависимостей: Особенно полезно при захвате изменяемых (var) value-типов, чтобы избежать неожиданного поведения, если исходная переменная изменится позже.
  • Для reference-типов capture list используется для управления подсчетом ссылок (создания weak или unowned ссылок). Для value-типов он управляет копированием значения.

Ответ 18+ 🔞

Ну, слушай, смотри, как это работает, а то многие думают, что capture list — это только для классов, чтобы weak/unowned делать. А вот нихуя!

Для этих твоих структур, перечислений и прочей value-хуйни capture list работает по-другому, но логика там железная. Суть в чём: когда ты value-тип в квадратные скобочки засовываешь, замыкание хватает моментальную копию значения. Ту самую, которая была в секунду создания замыкания. И всё, приехали. Дальше хоть исходную переменную в пизду разнеси — замыканию похуй, у него своя, отдельная, законсервированная копия.

Смотри, как это выглядит, чтоб не быть мудаком, который потом три часа дебажит:

var number = 10

// Вот тут, в этот самый момент, замыкание схватило значение 10 и засунуло себе в карман.
let closure = { [number] in
    print("Захваченное значение: (number)") // И будет тут вечно сидеть эта десятка, как ядрёна вошь!
}

number = 20 // А тут мы исходную переменную переписали. Волнение ебать!
closure() // А вызов-то что покажет? Правильно, старую добрую десятку. "Захваченное значение: 10"

А нахуя это вообще надо, спросишь? Да затем же, нахуй!

  • Зафиксировать состояние, блядь. Чтобы твоё замыкание не бегало за изменяющейся переменной, как собака за хвостом, а работало с тем, что было актуально, когда его создали. Как фотография, ёпта.
  • Отрезать неявные зависимости. Особенно кайфово, когда у тебя var какая-нибудь летучая. Захватил копию — и спи спокойно, никто тебе снаружи логику не сломает.
  • Для reference-типов capture list — это про управление памятью (weak, unowned). Для value-типов — это про управление данными, про то, какую именно копию значения ты хочешь использовать. Вот и вся разница, чих-пых тебя в сраку.