Перейти к содержимому

Лекция 2. : Переменные, константы и базовые типы данных

1. Введение

На прошлой лекции мы познакомились с языком Swift, установили toolchain на Linux и написали первую программу. Сегодня разберём фундамент любой программы — переменные, константы и систему типов. Именно здесь начинаются ключевые отличия Swift от Python: строгая статическая типизация, разделение на изменяемые и неизменяемые привязки и отсутствие неявных преобразований.

Все примеры можно запускать в REPL (swift) или компиляцией файла (swiftc main.swift -o main && ./main).


2. var и let — изменяемость и неизменяемость

  • var — переменная, значение можно изменять.
  • let — константа, значение задаётся один раз.
var currentTemperature = 23.5
currentTemperature = 25.0 // ✅ допустимо
let maxTemperature = 45.0
// maxTemperature = 50.0 // ❌ ошибка компиляции

Сравнение с Python

# Python — нет встроенного механизма констант
MAX_TEMPERATURE = 45.0 # соглашение, не ограничение
MAX_TEMPERATURE = 50.0 # Python не запрещает

В Swift неизменяемость letгарантия компилятора, а не соглашение. Рекомендуется по умолчанию использовать let и переходить на var только при необходимости. Компилятор даже выдаёт предупреждение, если var ни разу не изменяется.


3. Базовые типы данных

3.1. Целые числа — Int

На 64-битных платформах (включая современный Linux) Int — 64-битное значение со знаком.

let population: Int = 7_900_000_000 // подчёркивания для читаемости
let negativeValue = -42 // тип выведен как Int

Также доступны Int8, Int16, Int32, Int64 и беззнаковые UInt8UInt64.

3.2. Числа с плавающей точкой — Double и Float

  • Double — 64 бит, ~15 значащих цифр. Рекомендуется по умолчанию.
  • Float — 32 бита, ~6 значащих цифр.
let pi: Double = 3.141592653589793
let gravity = 9.81 // дробный литерал → Double по умолчанию

3.3. Логический тип — Bool

let isLinux: Bool = true
let isComplete = false

В отличие от Python, Swift не допускает if 1: или if "hello"::

let number = 1
// if number { ... } // ❌ Int не является Bool
if number != 0 { print("Не ноль") } // ✅

3.4. Строки — String и символы — Character

let greeting: String = "Привет, Swift!"
let letter: Character = "A" // тип указан явно
let emoji: Character = "🐧"
// let c = "A" // без аннотации это String, не Character

4. Вывод типов и явная аннотация

Swift определяет тип по присвоенному значению (type inference):

let age = 25 // Int
let height = 1.78 // Double
let name = "Алексей" // String

Явная аннотация нужна, когда требуется конкретный тип или переменная объявляется без значения:

let temperature: Float = 36.6 // без аннотации был бы Double
var result: String // значение присвоится позже
result = "Готово"

Сравнение с Python

# Python — тип динамический, может меняться
x = 42 # int
x = "строка" # теперь str — Python не возражает
// Swift — тип фиксируется при объявлении
var x = 42
// x = "строка" // ❌ нельзя присвоить String переменной типа Int

5. Строгая типизация и Type Safety

Swift — строго типизированный язык: каждое значение имеет конкретный тип, проверяемый при компиляции. Нельзя смешивать типы без явного преобразования.

let a: Int = 10
let b: Double = 3.5
// let c = a + b // ❌ нельзя сложить Int и Double
let c = Double(a) + b // ✅ явное преобразование → 13.5
# Python — неявное приведение
a = 10
b = 3.5
c = a + b # ✅ int автоматически → float → 13.5

Строгая типизация предотвращает класс ошибок, которые в Python обнаруживаются только при запуске.


6. Преобразование типов

Преобразование всегда явное — через инициализатор целевого типа.

// Числовые
let intVal: Int = 42
let doubleVal = Double(intVal) // 42.0
let truncated = Int(3.14) // 3 — дробная часть отбрасывается
// Строки ↔ числа
let year = String(2025) // "2025"
let input = "314"
if let parsed = Int(input) {
print("Число: \(parsed)") // Число: 314
}
// Int("hello") вернёт nil, а не выбросит ошибку

В Python int("hello") выбрасывает ValueError. Swift возвращает nil — более безопасный подход без try/except. Подробнее об Optionals — на лекции 6.


7. Строковая интерполяция

Значения встраиваются в строку через \(выражение):

let language = "Swift"
let version = 6
print("Мы изучаем \(language) версии \(version)")
let a = 7, b = 3
print("\(a) + \(b) = \(a + b)") // 7 + 3 = 10

Сравнение с Python

# Python — f-строки
language = "Swift"
version = 6
print(f"Мы изучаем {language} версии {version}")
АспектSwiftPython
Синтаксис\(выражение){выражение} в f""
ФорматированиеString(format:){:.2f}
Проверка типовПри компиляцииПри выполнении

8. Многострочные строки

Swift поддерживает многострочные строки через тройные кавычки """:

let poem = """
Мой дядя самых честных правил,
Когда не в шутку занемог,
Он уважать себя заставил
И лучше выдумать не мог.
"""
print(poem)

Отступ определяется позицией закрывающих """ — общий отступ автоматически удаляется.

В Python тройные кавычки не управляют отступами — для этого нужен textwrap.dedent().


9. Работа со строками

9.1. Конкатенация и основные операции

let fullName = "Иван" + " " + "Петров"
var greeting = "Привет"
greeting += ", мир!" // "Привет, мир!"

9.2. Длина и символы

let text = "Привет"
print(text.count) // 6 — количество видимых символов (графемных кластеров)
let emoji = "👨‍👩‍👧‍👦"
print(emoji.count) // 1 — один видимый символ
print(emoji.utf8.count) // 25 байт в UTF-8

В Python len("👨‍👩‍👧‍👦") вернёт 7 (считает code points). Swift точнее отражает то, что видит пользователь.

9.3. Индексация

Строки в Swift не индексируются целыми числами — символы Unicode имеют переменную длину. Используется String.Index:

let word = "Swift"
let first = word[word.startIndex] // "S"
let last = word[word.index(before: word.endIndex)] // "t"
let third = word[word.index(word.startIndex, offsetBy: 2)] // "i"

9.4. Перебор и полезные методы

for char in "Swift" {
print(char) // S, w, i, f, t
}
let text = " Hello, Swift! "
print(text.uppercased()) // " HELLO, SWIFT! "
print(text.lowercased()) // " hello, swift! "
print(text.contains("Swift")) // true
print(text.hasPrefix(" He")) // true
let csv = "один,два,три"
let parts = csv.split(separator: ",") // ["один", "два", "три"]

Для trimmingCharacters(in:) на Linux необходим import Foundation:

import Foundation
let trimmed = text.trimmingCharacters(in: .whitespaces) // "Hello, Swift!"

10. Кортежи (Tuples)

Кортежи объединяют несколько значений разных типов в одно составное значение.

let coordinates = (55.7558, 37.6173) // (Double, Double)
let city = (name: "Москва", population: 12_600_000) // именованные элементы

Доступ к элементам

print(coordinates.0) // 55.7558 — по индексу
print(city.name) // "Москва" — по имени

Декомпозиция

let (latitude, longitude) = coordinates
print("Широта: \(latitude), долгота: \(longitude)")
let (cityName, _) = city // _ — игнорируем ненужное

Кортежи как возвращаемые значения

func divide(_ a: Int, by b: Int) -> (quotient: Int, remainder: Int) {
return (a / b, a % b)
}
let result = divide(17, by: 5)
print("Частное: \(result.quotient), остаток: \(result.remainder)")

Сравнение с Python

# Python
def divide(a, b):
return a // b, a % b
quotient, remainder = divide(17, 5)

Концепция та же, но в Swift кортежи типизированные и элементы могут иметь имена.


11. Type Aliases (typealias)

typealias создаёт альтернативное имя для существующего типа — повышает читаемость без создания нового типа.

typealias Celsius = Double
typealias Coordinate = (latitude: Double, longitude: Double)
let bodyTemp: Celsius = 36.6
let moscow: Coordinate = (latitude: 55.7558, longitude: 37.6173)

Сравнение с Python

# Python (typing) — рекомендация, не проверяется интерпретатором
from typing import TypeAlias
Celsius: TypeAlias = float

В Swift typealias полностью интегрирован в систему типов компилятора.


12. Сводная таблица: Swift vs Python

КонцепцияSwiftPython
Целые числаInt, Int8Int64int (произвольная точность)
Дробные числаDouble, Floatfloat
СтрокиStringstr
СимволCharacterstr длины 1
Логический типBool (строго)bool (truthy/falsy)
Константаlet (гарантия компилятора)Соглашение UPPER_CASE
Вывод типовСтатический, при компиляцииДинамический, при выполнении
Неявное преобразованиеЗапрещеноДопускается
Интерполяция строк\(expr)f"{expr}"
КортежиТипизированные, с именамиБез типизации
Псевдонимы типовtypealiasTypeAlias из typing

13. Практические задания

Задание 1. Переменные и константы

Объявите значения, выбрав let или var:

  • Имя пользователя (не меняется)
  • Текущий счёт в игре (меняется)
  • Число Пи (не меняется)
  • Текущая дата в формате строки (меняется)

Скомпилируйте через swiftc и убедитесь, что программа работает.

Задание 2. Преобразование типов

Объявите a: Int = 17 и b: Double = 3.0. Вычислите результат деления a на b (тип Double) и выведите через строковую интерполяцию.

Задание 3. Работа со строками

Создайте строку с полным именем. Выведите: количество символов, первый и последний символ, строку в верхнем регистре, результат проверки contains("ван").

Задание 4. Кортежи

Напишите функцию minMax(array:), возвращающую кортеж (min: Int, max: Int):

func minMax(array: [Int]) -> (min: Int, max: Int) {
// ваш код
}
let result = minMax(array: [3, 1, 7, -2, 5])
print("Мин: \(result.min), макс: \(result.max)")
// Ожидаемо: Мин: -2, макс: 7

Задание 5. Type Alias

Создайте typealias Student = (name: String, age: Int, grade: Double). Напишите функцию, принимающую [Student] и возвращающую средний балл.


14. Вопросы для самопроверки

  1. Чем let отличается от var? Почему let рекомендуется по умолчанию?
  2. Какой тип выведет компилятор для 3.14? А для 42?
  3. Почему let x: Int = 5; let y: Double = 2.5; let z = x + y не компилируется?
  4. Чем \(expr) в Swift отличается от f"{expr}" в Python с точки зрения безопасности?
  5. Почему Swift не позволяет text[0] для доступа к символу строки?
  6. Чем String.count отличается от len() на строках с эмодзи?
  7. Что вернёт Int("hello") и почему это безопаснее, чем int("hello") в Python?
  8. Приведите пример, когда строгая типизация Swift предотвращает ошибку, которая в Python обнаружилась бы только при выполнении.

15. Резюме

  • let и var — неизменяемость гарантируется компилятором, а не соглашениями.
  • Базовые типы (Int, Double, Float, String, Bool, Character) — полноценные структуры с методами.
  • Вывод типов позволяет не указывать тип явно, но тип фиксируется при компиляции.
  • Строгая типизация исключает неявные преобразования — ошибки обнаруживаются до запуска.
  • Строковая интерполяция через \(...) — удобный и типобезопасный аналог f-строк.
  • Кортежи — лёгкий способ группировки значений без создания отдельного типа.
  • typealias — осмысленные имена для существующих типов, повышающие читаемость.

На следующей лекции: операторы, управление потоком выполнения, switch с pattern matching и оператор guard.