← Назад к вопросам
Коллекции — это структуры или классы в Swift?
1.3 Junior🔥 191 комментариев
#Язык Swift
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Коллекции (Collections) в Swift: структуры или классы
Ответ: СТРУКТУРЫ (Value Types)
Все встроенные коллекции в Swift — Array, Dictionary, Set — это структуры (value types), а не классы (reference types).
Array — Структура
struct Array<Element> {
// Реальная реализация намного сложнее
// Но по поведению это value type
}
var array1 = [1, 2, 3]
var array2 = array1 // Копирование значения
array2.append(4)
print(array1) // [1, 2, 3]
print(array2) // [1, 2, 3, 4]
// Независимые копии!
Dictionary — Структура
struct Dictionary<Key, Value> where Key: Hashable {
// Value type
}
var dict1: [String: Int] = ["a": 1, "b": 2]
var dict2 = dict1 // Копирование
dict2["c"] = 3
print(dict1) // ["a": 1, "b": 2]
print(dict2) // ["a": 1, "b": 2, "c": 3]
Set — Структура
struct Set<Element> where Element: Hashable {
// Value type
}
var set1: Set<Int> = [1, 2, 3]
var set2 = set1 // Копирование
set2.insert(4)
print(set1) // [1, 2, 3]
print(set2) // [1, 2, 3, 4]
Почему структуры?
1. Copy-on-Write (CoW) оптимизация
// Swift оптимизирует копирование
var arr1 = [1, 2, 3]
var arr2 = arr1 // На самом деле не копирует данные немедленно
// Только когда модифицируем:
arr2.append(4) // Вот здесь создается копия
// До модификации arr1 и arr2 делили один буфер в памяти
// Это очень эффективно!
2. Потокобезопасность
// Структура безопаснее в многопоточности
class ArrayWrapper {
var array = [1, 2, 3]
}
let wrapper = ArrayWrapper() // Reference type
var arr1 = wrapper.array // Copy
var arr2 = wrapper.array // Еще одна copy
// wrapper.array может быть изменен из другого потока
// Но arr1 и arr2 безопасны (это копии)
// Со структурой:
var array = [1, 2, 3]
var copy = array // Copy (безопасно)
3. Предсказуемость
// С классом нужно постоянно думать о ссылках
class MutableArray {
var items: [Int] = []
}
let arr1 = MutableArray()
let arr2 = arr1 // arr1 и arr2 указывают на ОДН объект
arr2.items.append(1)
print(arr1.items) // [1] (изменилось!)
// Со структурой все ясно
var arr1 = [Int]()
var arr2 = arr1 // Копия
arr2.append(1)
print(arr1) // [] (не изменилось)
Сравнение Value Type vs Reference Type
// VALUE TYPE (Array, Dictionary, Set, Struct)
var valueArray1 = [1, 2, 3]
var valueArray2 = valueArray1
valueArray2.append(4)
// valueArray1 остался [1, 2, 3]
// valueArray2 теперь [1, 2, 3, 4]
// REFERENCE TYPE (Class)
class ReferenceArray {
var items = [1, 2, 3]
}
let refArray1 = ReferenceArray()
let refArray2 = refArray1 // Указывает на ТОТ ЖЕ объект
refArray2.items.append(4)
// refArray1.items = [1, 2, 3, 4]
// refArray2.items = [1, 2, 3, 4]
// Это ОДИН объект в памяти
Практические последствия
1. Mutating функции в структурах
struct Stack {
private var elements: [Int] = []
// Нужен mutating, потому что это структура
mutating func push(_ value: Int) {
elements.append(value) // Изменяет self
}
}
var stack = Stack()
stack.push(1) // Работает
let immutableStack = Stack()
immutableStack.push(2) // Ошибка: let не может быть mutated
// С классом
class ClassStack {
private var elements: [Int] = []
// Не нужен mutating
func push(_ value: Int) {
elements.append(value) // Изменяет внутреннее состояние
}
}
let classStack = ClassStack()
classStack.push(1) // Работает! (потому что это reference type)
2. Производительность
// Структура дешево копируется благодаря CoW
let largeArray = Array(1...1000000)
let copy = largeArray // Практически бесплатно (до модификации)
// Класс всегда копирует reference
class LargeArrayWrapper {
var items = Array(1...1000000)
}
let obj1 = LargeArrayWrapper()
let obj2 = obj1 // Копирует только reference (8 байт)
// Но если изменим obj2.items - это создаст копию массива
3. Передача в функции
// Структура (копируется)
func processArray(_ arr: [Int]) {
var mutableArray = arr // Копия (CoW оптимизирует)
mutableArray.append(999)
}
var original = [1, 2, 3]
processArray(original)
print(original) // [1, 2, 3] (не изменилось)
// Класс (передается reference)
func processClass(_ obj: LargeArrayWrapper) {
obj.items.append(999) // Изменяет исходный объект
}
let obj = LargeArrayWrapper()
obj.items = [1, 2, 3]
processClass(obj)
print(obj.items) // [..., 999] (изменилось!)
Почему Apple выбрала структуры
// Правило: Value Semantics (семантика значений)
// Коллекции представляют ДАННЫЕ, не сущности
let numbers = [1, 2, 3] // Это данные
let copy = numbers // Логично, что это копия
let user = User(name: "John") // Это сущность
let another = user // Нужна ли копия?
// Возможно, мы хотим ссылку на одного пользователя
// Поэтому:
// - Коллекции → struct (value type)
// - Domain Models → class или struct (в зависимости от контекста)
Сравнение с другими языками
Пython: list = reference type (class)
JavaScript: Array = reference type (object)
Rust: Vec = owns data (value type, но no copy)
Swift: Array = value type (with CoW optimization)
Когда использовать какой тип
// Для коллекций — ВСЕГДА структуры, это встроено
let array = [1, 2, 3] // Array<Int> struct
let dict = ["key": "value"] // Dictionary struct
let set = Set([1, 2, 3]) // Set struct
// Для моделей данных — обычно структуры
struct Person {
let name: String
let age: Int
}
// Для объектов с поведением — часто классы
class DatabaseConnection {
func connect() {}
func query(_ sql: String) {}
}
Практический пример
// Задача: работать с коллекцией пользователей
struct User {
let id: Int
let name: String
}
var users = [User(id: 1, name: "John")]
var backup = users // Копия (значение)
users.append(User(id: 2, name: "Jane"))
print(users) // [John, Jane]
print(backup) // [John] — независимая копия
// Это безопасно и предсказуемо!
Выводы
- Array, Dictionary, Set — структуры (value types)
- Copy-on-Write оптимизирует копирование
- Потокобезопаснее чем reference types
- Семантика значений — коллекции это данные
- Mutating нужен для изменения структур
- Reference equality (===) не работает для коллекций (используй ==)