Может ли структура (struct) в Swift содержать свойство другого типа структуры?

Ответ

Да, может. Это стандартная практика для композиции типов.

Пример:

struct Point {
    var x: Double
    var y: Double
}

struct Rectangle {
    var origin: Point // Вложенная структура
    var size: Point
}

Важные нюансы:

  1. Семантика копирования (Value Semantics): При копировании экземпляра Rectangle копируются и все его вложенные структуры (origin и size).
  2. Запрет прямой рекурсии: Структура не может содержать свойство своего же типа, так как это создало бы бесконечный размер.
    struct Node { // Ошибка компиляции: Value type 'Node' cannot have a stored property that recursively contains it
        var next: Node?
    }
  3. Косвенная рекурсия: Для рекурсивных структур используйте indirect с перечислениями (enum).
    indirect enum LinkedListNode {
        case value(Int, next: LinkedListNode?)
    }

Ответ 18+ 🔞

Ага, слушай, вот тут такая тема интересная вырисовывается. Можно ли в одну структуру запихнуть другую? Да запросто, блядь! Это ж как матрёшка, только для кода. Стандартная практика, хуле.

Смотри, вот тебе живой пример, чтоб мозги не закипели:

struct Point {
    var x: Double
    var y: Double
}

struct Rectangle {
    var origin: Point // Смотри-ка, вложил одну структуру в другую, как в карман
    var size: Point
}

Ну и что тут такого, скажешь? А вот, блядь, подводные камни есть, как в озере, где Муму утопили.

Во-первых, семантика копирования, ёпта. Это не просто слова умные. Это значит, что когда ты копируешь свой Rectangle, то вместе с ним нахуй копируются и все его внутренности — и origin, и size. Не ссылкой, а целиком, новенькие. Как будто ксерокс сделал. Это важно понимать, а то потом будешь удивляться, пиздец, почему одно изменилось, а другое нет.

Во-вторых, прямую рекурсию, сука, нельзя. Это как пытаться засунуть себя самого себе в карман. Компилятор тебе такого не позволит, сразу наорет.

struct Node { // Ошибка компиляции: Value type 'Node' cannot have a stored property that recursively contains it
    var next: Node? // Ну ты чего, блядь, совсем? Это ж бесконечность получится!
}

Представь, компилятор сидит и думает: "Так, Node... О, в нём есть next, который тоже Node... А в том next опять next... Ёбушки-воробушки, да я тут до второго пришествия считать буду!". И всё, пиздец, ошибка.

Но! Если очень хочется рекурсивную хуйню, то выход есть — косвенная рекурсия через indirect в перечислениях. Это как договориться с компилятором на берегу.

indirect enum LinkedListNode {
    case value(Int, next: LinkedListNode?) // Вот так уже можно, он под капотом ссылку спрячет
}

Вот так-то, друг. Вкладывай структуры, не бойся, главное — в себя самого не пытайся.