Ответ
Место хранения Value Type (структуры, перечисления, кортежи) определяется его контекстом, а не самим типом.
Правила размещения:
- В стеке: Локальные переменные и параметры функций, не захваченные замыканием.
- В куче (Heap): Когда value type является:
- Свойством ссылочного типа (
class). - Захвачен замыканием, которое само хранится в куче.
- Упакован (например, при использовании с протоколами
AnyилиAnyObject).
- Свойством ссылочного типа (
Пример:
struct Point { var x, y: Int }
func stackExample() {
var p = Point(x: 1, y: 2) // Хранится в стеке.
}
class Container {
var point = Point(x: 3, y: 4) // Хранится в куче, как часть экземпляра Container.
}
func heapExample() {
var localPoint = Point(x: 5, y: 6)
let closure = { print(localPoint.x) } // `localPoint` захватывается и может быть перемещен в кучу.
}
Ключевой вывод: Swift оптимизирует производительность, храня value types в стеке где это возможно, но прозрачно перемещает их в кучу при необходимости.
Ответ 18+ 🔞
А, слушай, вот эта вся хуйня про стек и кучу — она многих вводит в ступор, а на деле всё проще, чем кажется. Смотри, у нас есть value types: структуры, перечисления, кортежи. Так вот, где они живут — в стеке или в куче — зависит не от того, что они за хуйня, а от того, где они используются. Вот в чём, блядь, весь фокус.
Где что лежит, если по-простому:
- В стеке (быстро, чисто, по делу): Это когда у тебя локальная переменная в функции или параметр, который замыкание не схавало. Создал — поработал — выкинул. Красота.
- В куче (ну тут уже посложнее): Value type отправляется в эту помойку, когда:
- Он — свойство какого-нибудь класса. Ну, типа, класс — он всегда в куче, а значит и всё, что в нём сидит, туда же.
- Его захватило замыкание, которое само-то живёт в куче. Захватило — и всё, прощай, стек, теперь ты заложник кучи.
- Его насильно упаковали (boxing), например, когда ты пытаешься запихнуть структуру в
Anyили ещё какую-нибудь универсальную хуйню.
Смотри, как это выглядит в коде, ёпта:
struct Point { var x, y: Int }
func stackExample() {
var p = Point(x: 1, y: 2) // Всё, пизда, тут он в стеке. Быстро и чётко.
}
class Container {
var point = Point(x: 3, y: 4) // А вот эта точка — она уже в куче, потому что сидит внутри класса, этого пидораса ссылочного.
}
func heapExample() {
var localPoint = Point(x: 5, y: 6)
let closure = { print(localPoint.x) } // Внимание, блядь! `localPoint` захвачен! Теперь он, скорее всего, поедет в кучу вместе с замыканием.
}
Итог, который надо запомнить, чтобы не ебать мозг: Свифт — он не мудак, он старается держать value types в стеке, где это возможно, потому что там быстро. Но если обстоятельства, блядь, вынуждают (типа, класс или замыкание), то он без лишнего шума переносит эту хуйню в кучу. Ты этого даже не заметишь, но производительность может просесть. Вот такая, блядь, магия.