LEARN X · ЗА 16 МИН
Swift
Swift за 16 минут: переменные, опционалы, switch, коллекции, функции, структуры и классы, enum, протоколы, ошибки и дженерики на примерах.
Swift — современный, безопасный и быстрый язык от Apple для iOS, macOS и не только. Главная фишка — опционалы: компилятор не даёт случайно обратиться к nil. Ниже весь язык на одной странице: почти без прозы, всё в комментариях кода.
Вывод и комментарии
// Однострочный комментарий
/* Многострочный
комментарий */
/* Вложенные /* тоже работают */ в Swift */
print("Привет, мир!") // Привет, мир!
print("a", "b", "c") // a b c (разделитель — пробел)
print("без переноса", terminator: "") // без \n в конце
print("1", "2", separator: "-") // 1-2
Переменные и типы
Тип чаще выводится автоматически, но его можно указать явно.
let constant = 42 // константа (let) — менять нельзя
var variable = 10 // переменная (var) — можно менять
variable = 20 // ок
// Явное указание типа
let age: Int = 30
let pi: Double = 3.14
let isReady: Bool = true
let name: String = "Анна"
// Вывод типа компилятором
let n = 7 // Int
let d = 2.5 // Double
let flag = false // Bool
let text = "hi" // String
// Числовые литералы
let hex = 0xFF // 255
let binary = 0b1010 // 10
let million = 1_000_000 // подчёркивания для читаемости
// Преобразование типов — только явное
let i = 3
let x = 2.0
let sum = Double(i) + x // 5.0
Строки
let first = "Иван"
let last = "Петров"
// Интерполяция через \(...)
let full = "\(first) \(last)" // Иван Петров
let info = "Сумма: \(2 + 3)" // Сумма: 5
// Конкатенация
let greeting = "Привет, " + first // Привет, Иван
// Многострочная строка
let poem = """
Строка один
Строка два
"""
// Методы
let s = "Swift"
print(s.count) // 5 (длина)
print(s.uppercased()) // SWIFT
print(s.lowercased()) // swift
print(s.hasPrefix("Sw")) // true
print(s.hasSuffix("ft")) // true
print(s.contains("wi")) // true
print(s.isEmpty) // false
print(s.replacingOccurrences(of: "i", with: "I")) // SwIft
Опционалы
Ключевая фишка Swift. Опционал (Optional) — это значение, которое может быть nil. Тип с ? хранит либо значение, либо его отсутствие.
var maybeName: String? = "Олег" // опционал: String или nil
maybeName = nil // допустимо
// Принудительное извлечение (!) — упадёт, если nil. Опасно!
var surname: String? = "Сидоров"
print(surname!) // Сидоров (но если бы был nil — crash)
// Безопасно: if let (опциональная привязка)
if let name = maybeName {
print("Имя: \(name)")
} else {
print("Имени нет") // если maybeName == nil
}
// guard let — ранний выход из функции
func greet(_ who: String?) {
guard let who = who else {
print("Никого")
return
}
print("Привет, \(who)") // who здесь уже не опционал
}
greet("Маша") // Привет, Маша
greet(nil) // Никого
// Оператор ?? — значение по умолчанию (nil-coalescing)
let display = maybeName ?? "Гость"
print(display) // Гость (если maybeName == nil)
// Опциональная цепочка — ?. безопасно обращается к свойству
let len = maybeName?.count // Int? : длина или nil
print(len ?? 0) // 0, если nil
Операторы и условия
// Арифметика: + - * / % и сравнения == != < > <= >=
let a = 7, b = 3
print(a % b) // 1 (остаток)
// Логические: && (и), || (или), ! (не)
if a > 5 && b < 5 {
print("оба условия верны")
}
// Тернарный оператор
let max = a > b ? a : b // 7
// switch с сопоставлением с образцом (pattern matching)
let score = 85
switch score {
case 90...100:
print("Отлично")
case 70..<90: // 70..<90 — без верхней границы
print("Хорошо") // сюда
case 0..<70:
print("Подтянись")
default:
print("Некорректно")
}
// switch должен покрывать все случаи (отсюда default)
// break по умолчанию — проваливания нет
// switch по кортежу с привязкой значений
let point = (2, 0)
switch point {
case (0, 0):
print("начало координат")
case (let x, 0):
print("на оси X в \(x)") // на оси X в 2
case (_, let y) where y > 0:
print("верхняя полуплоскость")
default:
print("другое")
}
Циклы
// for-in по диапазону
for i in 1...3 { // 1...3 — включая 3
print(i) // 1, 2, 3
}
for i in 0..<3 { // 0..<3 — без 3
print(i) // 0, 1, 2
}
// Шаг через stride
for i in stride(from: 0, to: 10, by: 2) {
print(i) // 0 2 4 6 8
}
// for-in по массиву
for fruit in ["яблоко", "груша"] {
print(fruit)
}
// Игнорирование значения через _
for _ in 1...3 {
print("тук") // три раза
}
// while — проверка до тела
var k = 0
while k < 3 {
print(k) // 0 1 2
k += 1
}
// repeat-while — тело выполняется хотя бы раз
var m = 5
repeat {
print(m) // 5 (один раз)
m += 1
} while m < 3
Коллекции
// Массив (Array) — упорядоченный
var nums: [Int] = [1, 2, 3]
nums.append(4) // [1, 2, 3, 4]
nums.insert(0, at: 0) // [0, 1, 2, 3, 4]
nums.remove(at: 0) // [1, 2, 3, 4]
print(nums.count) // 4
print(nums.first ?? -1) // 1 (опционал!)
print(nums.contains(3)) // true
let doubled = nums.map { $0 * 2 } // [2, 4, 6, 8]
let evens = nums.filter { $0 % 2 == 0 } // [2, 4]
let total = nums.reduce(0, +) // 10
// Словарь (Dictionary) — пары ключ-значение
var ages: [String: Int] = ["Анна": 30, "Боб": 25]
ages["Вера"] = 40 // добавить
print(ages["Анна"] ?? 0) // 30 (доступ — опционал)
ages["Боб"] = nil // удалить
for (name, age) in ages {
print("\(name): \(age)")
}
// Множество (Set) — уникальные, без порядка
var tags: Set<String> = ["swift", "ios", "swift"]
print(tags.count) // 2 (дубль убран)
tags.insert("apple")
print(tags.contains("ios")) // true
Функции
// Базовая функция с типами параметров и возврата
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
print(add(2, 3)) // 5
// _ перед параметром убирает метку аргумента при вызове
// Метки аргументов (внешнее имя)
func greet(name: String, from city: String) -> String {
return "\(name) из \(city)" // city — внутреннее имя
}
print(greet(name: "Лена", from: "Казани")) // Лена из Казани
// Значения по умолчанию
func power(_ base: Int, _ exp: Int = 2) -> Int {
var r = 1
for _ in 0..<exp { r *= base }
return r
}
print(power(5)) // 25 (exp по умолчанию 2)
print(power(2, 3)) // 8
// Несколько возвращаемых значений через кортеж
func minMax(_ arr: [Int]) -> (min: Int, max: Int) {
return (arr.min()!, arr.max()!)
}
let r = minMax([3, 1, 9])
print(r.min, r.max) // 1 9
// Замыкания (closures) — функции-значения
let square = { (x: Int) -> Int in x * x }
print(square(4)) // 16
// Замыкание как аргумент; $0 — первый параметр
let sorted = [3, 1, 2].sorted { $0 < $1 } // [1, 2, 3]
print(sorted)
Структуры и классы
struct — тип-значение (копируется при присваивании), class — ссылочный тип (передаётся по ссылке). Это ключевое различие.
// Структура — value type
struct Point {
var x: Int
var y: Int
// Метод, меняющий свойства, помечается mutating
mutating func moveRight() { x += 1 }
func describe() -> String { "(\(x), \(y))" }
}
var p1 = Point(x: 0, y: 0) // авто-инициализатор
var p2 = p1 // КОПИЯ
p2.moveRight()
print(p1.describe()) // (0, 0) — оригинал не тронут
print(p2.describe()) // (1, 0)
// Класс — reference type
class Counter {
var value = 0 // свойство со значением по умолчанию
init(start: Int) { // явный инициализатор
value = start
}
func increment() { value += 1 }
}
let c1 = Counter(start: 10)
let c2 = c1 // ССЫЛКА на тот же объект
c2.increment()
print(c1.value) // 11 — изменился и c1!
// Наследование — только у классов
class Animal {
func sound() -> String { "..." }
}
class Dog: Animal {
override func sound() -> String { "Гав" }
}
print(Dog().sound()) // Гав
Перечисления
// Простой enum
enum Direction {
case north, south, east, west
}
let dir = Direction.north
switch dir {
case .north: print("север") // север
default: print("другое")
}
// Raw values — сырые значения
enum Planet: Int {
case mercury = 1, venus, earth // 1, 2, 3
}
print(Planet.earth.rawValue) // 3
print(Planet(rawValue: 1)!) // mercury (опционал!)
enum Status: String {
case active = "активен"
case banned = "заблокирован"
}
print(Status.active.rawValue) // активен
// Associated values — связанные значения
enum Result {
case success(code: Int)
case failure(message: String)
}
let res = Result.failure(message: "нет сети")
switch res {
case .success(let code):
print("ок \(code)")
case .failure(let message):
print("ошибка: \(message)") // ошибка: нет сети
}
Протоколы и расширения
protocol — набор требований (как интерфейс). extension добавляет функциональность существующему типу.
// Протокол — контракт
protocol Describable {
var title: String { get } // требуемое свойство
func describe() -> String // требуемый метод
}
// Тип соответствует протоколу
struct Book: Describable {
var title: String
func describe() -> String { "Книга: \(title)" }
}
print(Book(title: "Swift").describe()) // Книга: Swift
// Расширение добавляет методы существующему типу
extension Int {
func squared() -> Int { self * self }
var isEven: Bool { self % 2 == 0 }
}
print(5.squared()) // 25
print(4.isEven) // true
// Расширение протокола с реализацией по умолчанию
extension Describable {
func describe() -> String { "Объект: \(title)" }
}
struct Movie: Describable {
var title: String // describe() берётся из расширения
}
print(Movie(title: "Дюна").describe()) // Объект: Дюна
Обработка ошибок
// Свой тип ошибки — соответствует протоколу Error
enum DivError: Error {
case divisionByZero
}
// Функция, которая может бросить ошибку — throws
func divide(_ a: Int, by b: Int) throws -> Int {
if b == 0 {
throw DivError.divisionByZero // бросаем ошибку
}
return a / b
}
// do / try / catch — перехват ошибки
do {
let r = try divide(10, by: 2)
print(r) // 5
let bad = try divide(1, by: 0)
print(bad) // не выполнится
} catch DivError.divisionByZero {
print("Деление на ноль!") // сюда
} catch {
print("Другая ошибка: \(error)")
}
// try? — превращает ошибку в nil (получаем опционал)
let safe = try? divide(8, by: 0) // nil
print(safe ?? -1) // -1
// try! — уверены, что ошибки не будет (иначе crash)
let sure = try! divide(9, by: 3) // 3
print(sure)
Дженерики
Дженерики (generics) позволяют писать код, работающий с любым типом, сохраняя типобезопасность.
// Обобщённая функция: T — параметр-тип
func swapTwo<T>(_ a: inout T, _ b: inout T) {
let tmp = a
a = b
b = tmp
}
var x = 1, y = 2
swapTwo(&x, &y) // & передаёт по ссылке (inout)
print(x, y) // 2 1
// Обобщённый тип — стек для любого T
struct Stack<T> {
private var items: [T] = []
mutating func push(_ item: T) { items.append(item) }
mutating func pop() -> T? { items.popLast() }
var count: Int { items.count }
}
var s = Stack<Int>()
s.push(1)
s.push(2)
print(s.pop() ?? -1) // 2
print(s.count) // 1
// Ограничение типа: T должен соответствовать протоколу
func maxOf<T: Comparable>(_ a: T, _ b: T) -> T {
return a > b ? a : b
}
print(maxOf(3, 9)) // 9
print(maxOf("a", "b")) // b (строки тоже Comparable)