1. Основы строк в Swift
Если числа — это то, чем программа думает, то строки — это то, чем программа разговаривает с человеком. Почти любая консольная задача в итоге сводится к тому, что вы должны вывести результат в правильном формате: словами, с пробелами, иногда со знаками : или =. И даже если задача чисто математическая, вы всё равно печатаете текст.
В Swift строковый тип называется String. Он хранит последовательность символов, то есть «текст». Важный момент: строка — это данные, такие же, как число. Её можно сохранить в переменную, передать дальше по коду, «собрать» из кусочков, а потом вывести.
Самая простая строка — это строковый литерал, то есть текст в кавычках:
let title = "LibraryCLI"
print(title) // LibraryCLI
Здесь title — константа типа String. Никакой магии: просто значение, которое хранит текст.
Литералы строк: "..." и что считается символом
Когда вы видите "Hello", мозг разработчика часто думает: «ну это же просто слово». Но для программы это набор символов. И программа не умеет угадывать «правильные пробелы» или «где поставить запятую», пока вы сами это не напишете. Пробел — это тоже символ. Точка — тоже символ. Даже два пробела подряд — это два символа (и иногда это может сломать проверку ответа в задачах).
В простых задачах уровня 2 нам достаточно запомнить несколько практических правил. Строка пишется в двойных кавычках, внутри можно хранить любые обычные символы, и если вы хотите вывести красивую фразу, вы должны явно добавить пробелы и знаки препинания туда, где они нужны.
Например, сравним «красиво» и «слеплено»:
let firstName = "Ivan"
let lastName = "Petrov"
let good = firstName + " " + lastName
print(good) // Ivan Petrov
let bad = firstName + lastName
print(bad) // IvanPetrov
Обратите внимание: " " — это строка из одного пробела. Да, пробел — настолько важен, что у него есть собственная строка.
Конкатенация через +: склеиваем строки как LEGO
Слово «конкатенация» звучит так, будто это заклинание из мира компиляторов, но по факту это «склеивание строк». В Swift строки можно складывать оператором +. Результатом будет новая строка.
Тут удобно думать про строки как про LEGO‑кирпичики: у вас есть кусочки текста, и вы собираете из них одну фразу. Но, как и в LEGO, если вы забыли деталь (например пробел), конструкция получается странной.
Пример: делаем аккуратное сообщение о количестве книг. Пока без ввода — просто как тренировка форматирования.
let libraryName = "City Library"
let booksCount = 12
let message = "Library: " + libraryName + ", books: " + "\(booksCount)"
print(message) // Library: City Library, books: 12
Стоп. А что это за "\(booksCount)"? Это уже интерполяция, чуть ниже мы разберём её. Пока заметим важное: оператор + умеет склеивать строку со строкой, но не «строку с числом».
Почему "x=" + 10 не компилируется
Очень типичная ситуация новичка: вы хотите вывести «x=10», пишете "x=" + 10, и Swift говорит: «нет». Причина простая и даже полезная: + — это не «универсальный скотч», а оператор, который должен понимать, что именно он складывает.
Строка — это String. Число — это Int. И компилятор не хочет угадывать, как именно вы хотите превратить число в текст. Поэтому выражение вида str + 1 для Swift выглядит подозрительно, и компилятор выдаёт ошибку, потому что типы не совпадают. Такая ситуация даже приводится как пример того, как компилятор ищет проблему в выражении str + 1 и почему человеку сразу понятно, что не так, а компилятору нужно вывести это через систему ограничений типов.
Практически это означает одно: нельзя складывать String и Int напрямую. Нужно либо явно превратить число в строку (позже мы научимся делать это через ввод и преобразования), либо использовать интерполяцию строк.
Чтобы не ломать компиляцию, «плохую» строку можно оставить как комментарий — чтобы помнить, что так делать нельзя:
let x = 10
let prefix = "x="
// let text = prefix + x // так нельзя: String + Int
let okText = prefix + "\(x)"
print(okText) // x=10
Сейчас это выглядит как «костыль». Но это на самом деле подсказка к следующему разделу: интерполяция — наш основной инструмент для таких задач.
Интерполяция "\(...)": самый дружелюбный способ вставлять значения
Интерполяция строк в Swift — это когда вы внутри строки пишете \(что-то) и Swift аккуратно вставляет туда значение, превращая его в текст. Для новичка это обычно самое приятное: меньше ручного склеивания, меньше забытых пробелов, и код читается как нормальная фраза.
Выглядит это так:
let bookTitle = "Dune"
let pages = 412
let text = "Book: \(bookTitle), pages: \(pages)"
print(text) // Book: Dune, pages: 412
Обратите внимание на ощущение «это читается как предложение». Именно это качество делает интерполяцию предпочтительным способом форматирования в большинстве задач.
Ещё важный плюс: в интерполяцию можно вставлять не только Int, но и вообще любые значения, которые нормально печатаются. А печататься они у нас уже умеют, потому что print(...) — наш базовый инструмент.
Интерполяция выражений: \(a + b) и «мини‑формулы» в тексте
Когда вы впервые видите "\(a + b)", может показаться, что Swift начинает «выполнять код внутри строки». Так и есть: внутри \(…) можно писать выражение, и оно будет вычислено, а результат подставится в строку.
Это суперполезно для задач, где нужно вывести не только число, но и пояснение: «3 + 4 = 7». С конкатенацией это делается длинно и легко ошибиться. С интерполяцией — аккуратно.
let a = 3
let b = 4
let line = "\(a) + \(b) = \(a + b)"
print(line) // 3 + 4 = 7
Заметьте, как хорошо видно структуру результата. Такой код легко проверить глазами, а это в программировании почти суперспособность.
И да: это тот самый момент, когда можно легально «вставить математику в текст» и почувствовать себя немного волешбником, но без перебора.
Небольшой рефакторинг: читаемость важнее «одной строки»
На первых порах очень хочется написать всё «в одну строку», потому что кажется, что так «профессиональнее». На практике профессионально — это когда через неделю вы сами понимаете свой код без археологической экспедиции.
Поэтому полезное правило: если строка собирается из нескольких частей, особенно если там есть числа и выражения, не бойтесь делать промежуточные let. Это не «лишний код», это забота о тех, кто будет читать этот код.
Сравним. Вариант «слишком плотно»:
let currentPage = 37
let totalPages = 120
print("Progress: \(currentPage)/\(totalPages) (\(currentPage * 100 / totalPages)%)")
Вариант красивее:
let currentPage = 37
let totalPages = 120
let percent = currentPage * 100 / totalPages // Int-деление, дробь отбрасывается
let text = "Progress: \(currentPage)/\(totalPages) (\(percent)%)"
print(text) // Progress: 37/120 (30%)
Во втором варианте проще понять, где что считается, и проще исправить, если вы вдруг изменили формулу. И да, обратите внимание на «целочисленность»: percent получился Int, потому что мы работаем с Int.
2. Мини‑приложение: печатаем статус «мини‑библиотеки»
Чтобы примеры не были набором разрозненных строк, давайте продолжим развивать маленькое консольное приложение‑заготовку. Пусть это будет «мини‑библиотека» (очень ранний предок нашего будущего CLI‑проекта): программа пока не читает ввод и не хранит данные, она просто красиво печатает статус — название библиотеки, текущую книгу и прогресс чтения.
Наша цель здесь не «сделать полезное приложение», а натренировать навык: превращать числа и данные в аккуратный текстовый вывод, не теряя пробелы и смысл.
Начнём с основы: зададим данные и выведем аккуратную шапку.
let appName = "MiniLibrary"
let version = 1
let header = "\(appName) v\(version)"
print(header) // MiniLibrary v1
Обратите внимание: v\(version) — это типичный паттерн, и он читается отлично.
Теперь добавим «данные о книге» и соберём одну красивую строку отчёта. Нам понадобятся и String, и Int.
let bookTitle = "Clean Code"
let currentPage = 57
let totalPages = 464
let progress = "\(currentPage)/\(totalPages)"
print("Now reading: \(bookTitle) — \(progress)") // Now reading: Clean Code — 57/464
Символ — (длинное тире) — это тоже просто символ строки. Swift не возражает, если вы печатаете нормальный человеческий текст.
Добавим процент, используя арифметику Int из прошлой лекции:
let currentPage = 57
let totalPages = 464
let percent = currentPage * 100 / totalPages
let line = "Progress: \(percent)%"
print(line) // Progress: 12%
И теперь соберём «итоговый отчёт» в более читаемом стиле: отдельные кусочки в let, потом финальная строка.
let libraryName = "City Library"
let bookTitle = "Clean Code"
let currentPage = 57
let totalPages = 464
let percent = currentPage * 100 / totalPages
let report = "Library: \(libraryName). Book: \(bookTitle). \(percent)% read."
print(report) // Library: City Library. Book: Clean Code. 12% read.
Пока выглядит скромно, но это именно тот навык, который потом спасает на реальных задачах: вы делаете вывод предсказуемым, понятным и «как в условии».
Схема: как мы собираем текст
Иногда полезно увидеть процесс как мини‑конвейер:
flowchart LR
A["Данные (Int/String)"] --> B["Формулы (Int)"]
B --> C["Интерполяция в String"]
C --> D["print(...)"]
В этой лекции мы в основном тренируем узел C: превращение данных в текст.
3. Типичные ошибки при работе со строками
Ошибка №1: забытые пробелы при конкатенации.
Когда вы склеиваете строки через +, легко получить "IvanPetrov" вместо "Ivan Petrov". Проблема не в Swift, а в том, что пробел — такой же символ, как буква. Хороший способ лечения — чаще использовать интерполяцию, а если всё же склеиваете, явно добавлять " " там, где по смыслу должен быть пробел.
Ошибка №2: попытка сложить строку и число оператором +.
Выражение вида "x=" + 10 не компилируется, потому что + не умеет автоматически приводить Int к String. С точки зрения системы типов это действительно разные миры, и пример str + 1 — классическая ситуация, где компилятор честно говорит «тип не тот». Лучшее решение на этом этапе — интерполяция: "x="\(10).
Ошибка №3: превращение вывода в «лапшу» из + + +.
Иногда новичок начинает собирать строку так: "a=" + "\(a)" + ", b=" + "\(b)" + ... — и через минуту уже никто не понимает, сколько там кавычек и где потерялась запятая. Интерполяция заметно чище: "a="\(a), b=\(b). Если строка всё равно получается длинной, разбивайте её на промежуточные let.
Ошибка №4: ожидание, что программа «догадается» о пунктуации.
Частая мелочь: забыли двоеточие, точку, запятую или пробел в конце, и ответ не засчитывается. Для человека это «ну понятно же», а для проверяющей системы это совсем другой текст. Относитесь к строкам как к точному контракту: что вывели — то и считается.
Ошибка №5: слишком раннее усложнение и попытка «умничать про строки».
Swift действительно относится к строкам серьёзно, потому что текст бывает сложнее, чем кажется (юникод, составные символы и так далее), и в документах подчёркивается, что строка в Swift ориентирована на человеческое восприятие символов. Но на нашем уровне это не повод паниковать: сегодня достаточно уверенно владеть кавычками, + и "\(...)", а всё остальное придёт позже, когда будет реальная потребность.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ