В чем ключевые различия между классом и структурой в Swift?

Ответ

Основные различия между классом (ссылочный тип) и структурой (значимый тип) в Swift:

Критерий Класс Структура
Тип Reference type (ссылочный) Value type (значимый)
Наследование Поддерживает (единичное) Не поддерживает
Инициализатор по умолчанию Нет (нужен свой) Memberwise init (автоматически)
Изменение свойств в методах По умолчанию разрешено Требует ключевого слова mutating
Управление памятью ARC (подсчет ссылок) Копирование при передаче (copy-on-write для оптимизации)
Тождество (===) Можно проверить Неприменимо

Практическое правило (Swift-стандарт):

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

Пример, иллюстрирующий разницу:

// Класс (ссылочный тип)
class RefClass { var data = 1 }
let a = RefClass()
let b = a // b ссылается на тот же объект, что и a
b.data = 2
print(a.data) // 2 (изменение через b видно в a)

// Структура (значимый тип)
struct ValStruct { var data = 1 }
var x = ValStruct()
var y = x // y получает независимую копию данных x
y.data = 2
print(x.data) // 1 (оригинал x не изменился)

Ответ 18+ 🔞

А, вот эта тема, блядь, классика жанра! Сидишь такой, пишешь себе код, всё пучком, а потом — бац! — и получаешь неожиданный пиздец, потому что перепутал класс со структурой. Давайте разберём, в чём тут собака зарыта, а то она, сука, может и укусить.

Короче, есть у нас два главных героя: Класс и Структура. И они, блядь, как небо и земля.

Класс — это ссылочный тип. Представь себе ящик с данными в памяти. Ты создал объект — получил ящик. А когда ты присваиваешь его другой переменной или передаёшь в функцию, ты не копируешь ящик, сука, ты просто даёшь ещё одну бумажку с адресом этого же ящика. Все, у кого есть адрес, лезут в один и тот же ящик и могут там всё перевернуть. Проверить, один ли это ящик, можно оператором === (тройное равно). И да, классы могут плодиться через наследование, как кролики.

Структура — это значимый тип. Тут всё по-честному. Создал — получил свою личную пачку данных. Скопировал в другую переменную — получил новую, независимую пачку. Изменяешь одну — другая нихуя не меняется. Никакого общего ящика. И наследование им, блядь, нахуй не сдалось. Зато за тебя компилятор может сгенерить инициализатор со всеми свойствами (memberwise init), что очень удобно.

Практический вывод, чтобы не облажаться:

  • Структуры — твои лучшие друзья по умолчанию. Модельки, настройки, простые данные — всё в структуры. Swift сам так делает (взгляни на Int, String, Array — все они структуры, блядь!).
  • Классы — для особых случаев. Когда тебе реально нужно, чтобы десять мест в коде смотрели на один объект и меняли его сообща. Или когда без наследования и полиморфизма совсем пипец.

Вот, смотри, наглядный пиздец в коде:

// Класс (ссылочный тип) — общий ящик на всех
class RefClass { var data = 1 }
let a = RefClass()
let b = a // b — это просто второй ключ от того же сейфа
b.data = 2 // Открыли сейф и положили туда двойку
print(a.data) // 2 (Опа-на! В сейфе a теперь тоже лежит двойка!)

// Структура (значимый тип) — у каждого свой конверт
struct ValStruct { var data = 1 }
var x = ValStruct()
var y = x // y получает СВОЮ копию содержимого конверта x
y.data = 2 // Меняем бумажку в конверте y
print(x.data) // 1 (А в оригинальном конверте x всё ещё единичка! Всё честно.)

Вот и вся магия, ёпта. Запомни эту разницу, а то будешь потом ловить баги, которые появляются из ниоткуда, и охуевать, как так вышло. Swift любит, когда ты понимаешь, что делаешь.