Узнайте, как создавать собственные типы данных с помощью структур в Swift. Практические примеры, свойства, методы и мутирующие функции для разработчиков.
В Swift мы привыкли работать со встроенными типами: String, Int, Bool, Array. Но что делать, если нужно описать, например, персонажа аниме или гильдию? Для этого существуют структуры. Структура — это пользовательский тип данных, который может содержать собственные переменные (свойства) и функции (методы). В этой статье вы научитесь создавать структуры, работать с их экземплярами и поймёте, когда их использовать.
Вот простой пример структуры, описывающей персонажа аниме:
struct AnimeCharacter {
let name: String
let show: String
let powerLevel: Int
func printSummary() {
print("\(name) из \(show) — уровень силы: \(powerLevel)")
}
}Обратите внимание: AnimeCharacter начинается с заглавной буквы — это соглашение для всех типов в Swift. name, show и powerLevel — это свойства, а printSummary() — метод.
Теперь создадим несколько персонажей:
let naruto = AnimeCharacter(name: "Naruto", show: "Naruto Shippuden", powerLevel: 9000)
let goku = AnimeCharacter(name: "Goku", show: "Dragon Ball Z", powerLevel: 9001)
print(naruto.name) // "Naruto"
print(goku.powerLevel) // 9001
naruto.printSummary() // "Naruto из Naruto Shippuden — уровень силы: 9000"
goku.printSummary() // "Goku из Dragon Ball Z — уровень силы: 9001"Хотя оба созданы из одной структуры, это разные экземпляры — изменение одного не влияет на другой. Когда вызывается printSummary() у naruto, он использует данные Наруто, а у goku — данные Гоку. Swift обрабатывает это автоматически.
Теперь, когда вы увидели структуру в деле, дадим названия её частям:
Последний пункт стоит рассмотреть подробнее.
Когда вы пишете AnimeCharacter(name: "Naruto", show: "Naruto Shippuden", powerLevel: 9000), это похоже на вызов функции. Swift автоматически создаёт внутри каждой структуры специальную функцию init(), используя все свойства как параметры. Эти строки идентичны:
let naruto = AnimeCharacter(name: "Naruto", show: "Naruto Shippuden", powerLevel: 9000)
let naruto = AnimeCharacter.init(name: "Naruto", show: "Naruto Shippuden", powerLevel: 9000)Обычно используется первый вариант, но теперь вы знаете, что происходит «под капотом».
Swift также умно работает со значениями по умолчанию. Если свойству задано значение по умолчанию, оно становится необязательным в инициализаторе:
struct Ninja {
let name: String
var chakraLevel = 100
}
let kakashi = Ninja(name: "Kakashi") // chakraLevel = 100 по умолчанию
let rock = Ninja(name: "Rock Lee", chakraLevel: 0) // у Rock Lee нет чакры 😄Допустим, мы хотим, чтобы ниндзя мог тренироваться и увеличивать уровень чакры:
struct Ninja {
let name: String
var chakraLevel: Int
func train() {
chakraLevel += 50 // ❌ Не сработает!
print("\(name) усердно тренировался!")
}
}Swift откажется компилировать этот код. Почему? Хотя chakraLevel — переменная, Swift не знает, является ли сам экземпляр структурой переменной (var) или константой (let). Если бы вы создали let ninja, изменение его свойств было бы недопустимо.
Решение — пометить метод, изменяющий свойства, ключевым словом mutating:
struct Ninja {
let name: String
var chakraLevel: Int
mutating func train() {
chakraLevel += 50
print("\(name) усердно тренировался! Уровень чакры теперь \(chakraLevel).")
}
}Теперь код работает, но только если экземпляр создан как var:
var naruto = Ninja(name: "Naruto", chakraLevel: 100)
naruto.train() // ✅ "Naruto усердно тренировался! Уровень чакры теперь 150."
let sasuke = Ninja(name: "Sasuke", chakraLevel: 100)
sasuke.train() // ❌ Ошибка — нельзя вызвать mutating метод у константыДва важных момента о mutating:
mutating, его нельзя вызвать у константы, даже если метод ничего не меняетmutatingВы можете спросить: если метод — это просто функция внутри структуры, зачем их использовать? Не проще ли обойтись обычными функциями?
Ключевое отличие: методы принадлежат типу — они живут внутри структуры (или класса, или перечисления). Обычные функции существуют сами по себе.
Это важно по двум причинам:
struct Guild {
let name: String
var memberCount: Int
func describe() {
// Можно напрямую обращаться к name и memberCount
print("\(name) насчитывает \(memberCount) участников.")
}
}Обычная функция вне структуры не смогла бы получить доступ к этим свойствам без явной передачи данных.Вы помните кортежи из статьи о функциях — они позволяют вернуть несколько значений за раз:
func getCharacterInfo() -> (name: String, powerLevel: Int) {
return ("Luffy", 8500)
}Кортеж и структура могут содержать похожие данные. Когда что использовать?
Кортеж — это анонимная структура. Он хорош для одноразовых ситуаций, например, возврата двух значений из функции. Но если одна и та же форма данных используется в нескольких функциях, лучше выбрать структуру:
// С кортежами — повторяемо и сложно обновлять:
func authenticate(_ user: (name: String, powerLevel: Int, guild: String)) { ... }
func showProfile(for user: (name: String, powerLevel: Int, guild: String)) { ... }
func signOut(_ user: (name: String, powerLevel: Int, guild: String)) { ... }
// Со структурой — чисто, переиспользуемо и легко обновлять:
struct Hero {
var name: String
var powerLevel: Int
var guild: String
}
func authenticate(_ hero: Hero) { ... }
func showProfile(for hero: Hero) { ... }
func signOut(_ hero: Hero) { ... }Если нужно добавить новое свойство, например var rank: String, вы добавляете его один раз в структуру, и все функции автоматически его получают. С кортежами пришлось бы обновлять каждую сигнатуру вручную.
Правило: используйте кортежи для быстрых одноразовых возвратов нескольких значений, а структуры — когда одна и та же форма данных встречается в нескольких местах.
| Термин | Значение |
|---|---|
| Структура | Пользовательский тип данных со своими свойствами и методами |
| Свойство | Переменная или константа, принадлежащая структуре |
| Метод | Функция, принадлежащая структуре |
| Экземпляр | Конкретная копия структуры |
| Инициализатор | Функция для создания экземпляра |
| mutating | Помечает метод, изменяющий свойства структуры |
Структуры — один из важнейших строительных блоков в Swift. В SwiftUI почти всё, что вы будете строить, будет структурой. Освоив их сейчас, вы сделаете дальнейшее обучение намного проще и естественнее. 🌸
Прямо сейчас откройте Xcode или Swift Playgrounds и создайте структуру для вашего любимого персонажа или объекта. Добавьте 3–5 свойств, напишите метод, который выводит информацию, и поэкспериментируйте с mutating. Чем больше практики — тем быстрее вы освоите Swift.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →