В чем разница между let и var в Swift?
Ключевое различие: изменяемость
В Swift let и var отличаются главным образом тем, разрешают ли они изменять значение после первого присваивания. Это основа системы управления памятью и безопасности типов в языке.
let(константа) — значение нельзя изменить после инициализации. Один раз присвоили — и всё, дальше только чтение.var(переменная) — значение можно менять сколько угодно раз.
Пример с объяснением
let pi = 3.14159
pi = 3.0 // Ошибка: pi — константа
var counter = 0
counter += 1 // Работает: counter — переменная
А как же массивы и словари?
Тут есть важный нюанс. let запрещает замену самого значения, но не запрещает изменение содержимого, если тип является ссылочным (класс) или имеет мутирующие методы (структуры с методами, помеченными mutating).
Пример со словарём:
let capitals = ["Россия": "Москва", "Франция": "Париж"]
capitals["Германия"] = "Берлин" // Работает! Добавляем новую пару
capitals = ["Италия": "Рим"] // Ошибка! Нельзя заменить сам словарь
Почему так? Потому что capitals — это константа, указывающая на область памяти. Саму область памяти менять нельзя (нельзя заставить capitals указывать на другой словарь), но содержимое этой области (добавление/удаление элементов) — можно, если тип это поддерживает.
Когда что использовать?
- Всегда начинайте с
let. Если компилятор не ругается — оставляйтеlet. Это делает код безопаснее и понятнее. - Используйте
varтолько если значение действительно должно меняться. Например, счётчик циклов, аккумулятор суммы, состояние UI. - Для
IBOutletи подобных вещей, которые инициализируются позже, используйтеvar(илиletс отложенной инициализацией).
А что будет, если всегда писать var?
Код будет работать, но это плохая практика по нескольким причинам:
- Вы теряете информацию о намерениях:
letявно говорит "это значение не изменится",var— "будьте осторожны, оно может поменяться". - Компилятор не сможет оптимизировать код (константы легче оптимизировать).
- Вы рискуете случайно изменить значение, которое не должно меняться, и получить трудноуловимую ошибку.
Дополнительно: let в замыканиях
Если вы используете let внутри замыкания, вы захватываете значение, а не ссылку. Это важно для избежания циклических ссылок.
var x = 10
let closure = { [x] in print(x) } // Захватываем значение 10
x = 20
closure() // Выведет 10, а не 20
Итог: let — это константа, var — переменная. Используйте let везде, где возможно. Это сделает ваш код чище, безопаснее и производительнее.
Практический совет: "let by default"
В Swift сообществе есть золотое правило: всегда используйте let, пока компилятор не скажет иначе. Это не просто стиль, а способ избежать целого класса ошибок.
Представьте, что вы пишете функцию:
func calculateTotal(price: Double, tax: Double) -> Double {
let total = price + price * tax // total не должен меняться
// ... много кода ...
// если бы total был var, вы могли бы случайно его изменить
return total
}
Используя let, вы гарантируете, что total останется именно тем, что вы вычислили. Если позже кто-то (или вы сами) попытается его изменить, компилятор сразу выдаст ошибку.
Ещё один пример — работа с опционалами:
let user: String? = getUserName()
if let name = user { // name — константа, её нельзя изменить
print("Привет, \(name)")
}
Здесь if let создаёт временную константу name, и вы не сможете случайно её перезаписать внутри блока.
Запомните: var — это исключение, а не правило. Если вы пишете var, спросите себя: "Действительно ли это значение будет меняться?" Если нет — замените на let. Ваш будущий я и коллеги скажут спасибо.