Spec-Zone.ru › Swift

Типы значений и ссылочные типы в Swift

Типы в Swift группируются в две категории: типы значений и ссылочные типы. Они ведут себя по-разному, и понимание этого различия является важной частью понимания Swift.

Если вы новичок в программировании или переходите на Swift из другого языка, эти понятия могут быть новыми для вас.

Прежде чем перейти к коду, рассмотрим две разновидности одного и того же сценария, которые иллюстрируют основные различия в поведении типов значений и ссылочных типов.

Представьте, что вы работаете над документом, например, отчетом или электронной таблицей, и хотите, чтобы друг взглянул на него. Есть два распространенных способа поделиться этим документом с другом:

  1. Вы можете отправить другу копию документа по электронной почте.

  2. Если документ находится в Google Docs или Pages для iCloud, вы можете отправить другу ссылку на документ по электронной почте.

В обоих случаях ваш друг может прочитать и изменить ваш документ, но есть существенные различия.

Когда вы отправляете другу копию, у друга есть полностью отдельный экземпляр документа. Он может редактировать документ сколько угодно, но это не повлияет на вашу копию.

Когда вы отправляете другу ссылку, вы не отправляете сам документ. Вы отправляете ему URL, указывающий на документ в облаке. Поскольку у вас обоих есть ссылка на один и тот же документ, любые изменения, которые вы или ваш друг внесёте, будут видны обоим.

Различие в поведении при отправке копии документа или ссылки на общий документ очень похоже на различие в поведении между типами значений и ссылочными типами.

Типы значений

В Swift структуры, перечисления и кортежи — это типы значений. Они ведут себя подобно отправке вашему другу копии документа.

Присваивание значения константе или переменной, или передача значения в функцию или метод всегда создает копию значения.

В коде ниже объявляется struct типа Document с одним свойством text.

Создается экземпляр Document и присваивается myDoc.

Когда myDoc присваивается переменной friendDoc, исходный экземпляр копируется в новый экземпляр.

Поскольку это независимый экземпляр, изменение text friendDoc не влияет на text myDoc.

struct Document {
  var text: String
}

var myDoc = Document(text: "Great new article")
var friendDoc = myDoc

friendDoc.text = "Blah blah blah"

print(friendDoc.text) // prints "Blah blah blah"
print(myDoc.text) // prints "Great new article"

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

Аналогично, с типом значения вам никогда не придётся беспокоиться о том, что какая-то другая часть вашей программы изменит значение.

Ссылочные типы

В Swift классы, акторы и замыкания — это ссылочные типы. Они ведут себя подобно отправке другу ссылки на общий документ.

Присваивание ссылочного типа константе или переменной, или передача его в функцию или метод всегда является ссылкой на общий экземпляр, который присваивается или передается.

Код ниже идентичен приведенному выше примеру с одним небольшим, но важным изменением. Вместо объявления struct тип Document теперь объявлен как class.

Это небольшое изменение в коде, но с существенным изменением в поведении.

Как и раньше, создается экземпляр Document и присваивается myDoc.

Но теперь, когда myDoc присваивается переменной friendDoc, это ссылка на экземпляр, который присваивается.

Поскольку это ссылка на тот же экземпляр, изменение text friendDoc обновляет этот общий экземпляр, включая значение myDoc.

class Document {
  var text: String
}

var myDoc = Document(text: "Great new article")
var friendDoc = myDoc

friendDoc.text = "Blah blah blah"

print(friendDoc.text) // prints "Blah blah blah"
print(myDoc.text) // prints "Blah blah blah"

Когда вы отправляете другу ссылку на общий документ, ваш друг может вносить изменения в документ, не сообщая вам об этом. Вы можете полагаться на то, что ваш документ останется неизменным.

Аналогично, с типом ссылки любая часть вашей программы, имеющая ссылку, может внести изменения. Иногда неожиданные изменения могут привести к ошибкам.

Локальное рассуждение

В приведенном выше небольшом примере кода вы можете прочитать код строка за строкой и увидеть, как одна и та же ссылка присваивается двум различным переменным, и как изменение свойства с использованием одной переменной обновляет экземпляр, на который ссылаются обе переменные.

Возможность просмотреть код в одном месте и понять, что происходит, называется локальным рассуждением.

Теперь представьте себе более крупную программу, в которой разные части программы имеют ссылку на одну и ту же вещь. Ваш код может установить значение в определённом месте и полагаться на это значение, но затем где-то в другом месте, не связанная часть вашей программы может изменить значение незаметно для вас.

Формальное название данных, которые могут быть изменены из нескольких мест, — это общая изменчивая информация. Общая, потому что к ней можно получить доступ из многих мест в коде, изменчивая, потому что она может меняться, и информация как синоним данных, как в «текущее состояние вещей».

В этом случае вы не можете полностью понять, что происходит в одной части кода, не понимая, что может происходить во многих других частях вашего кода. Вы теряете способность к локальному рассуждению, что затрудняет понимание и отладку кода.

Одно из преимуществ использования типов значений заключается в том, что вы можете быть уверены, что ни одно другое место в вашей программе не может повлиять на значение. Вы можете рассуждать о коде перед собой, не зная, что происходит где-то ещё.

Это упрощает понимание кода и предотвращает ошибки из-за случайных или непредвиденных изменений в общей изменчивой информации.

Выбор типов значений или ссылочных типов

Вернёмся к примеру с документом. Было бы очень полезно, чтобы вы и ваш друг могли видеть и редактировать один и тот же документ.

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

В общем случае предпочтительнее использовать структуры вместо классов. Если вам не нужно поведение ссылочного типа, нет необходимости брать на себя дополнительную сложность и возможные проблемы.

Статья Выбор между структурами и классами описывает компромиссы более подробно.

Создание типов значений

Распространённым шаблоном проектирования в коде является композиция, которая объединяет более мелкие элементы для создания более крупных.

В Swift вы можете легко объединить типы значений, чтобы создать более сложные типы значений.

Таким образом, вы можете определить структуру, содержащую некоторые основные типы, такие как String, Int, Bool, возможно, значение перечисления. Поскольку всё в структуре является типом значения, структура ведёт себя как тип значения.

У вас может быть тип, который представляет собой более сложную структуру, содержащую экземпляр первой структуры и некоторые другие значения. Опять же, поскольку она составлена из типов значений, эта структура является типом значения.

Коллекции являются типами значений

Но в Swift создание типов значений не ограничивается структурами и перечислениями.

Хотя во многих языках коллекции, такие как массивы и словари, являются ссылочными типами, в Swift стандартные коллекции Array, Dictionary и String являются типами значений.

Это означает, что структура может содержать массив структур, возможно, словарь пар ключ-значение, множество перечислений. До тех пор, пока всё составлено из типов значений, экземпляр даже сложного типа рассматривается как значение.

Заключение

Понимание того, что такое типы значений и ссылочные типы, и различия в их поведении — важная часть обучения Swift и способности рассуждать о своём коде. Выбор между ними часто сводится к выбору между объявлением типа как struct или class. Вы можете узнать больше о структурах и классах в главе «Структуры и классы» книги «Язык программирования Swift».

Авторы

James Dempsey Джеймс Демпси
Джеймс Демпси — разработчик iOS и macOS, технический преподаватель и член рабочей группы сайта Swift.

Авторы Джеймс Демпси Джеймс Демпси — разработчик iOS и macOS, технический преподаватель и член рабочей группы сайта Swift.

Джеймс Демпси

The Swift Programming Language, Copyright © 2014-2025 Apple Inc.
Swift and the Swift logo are trademarks of Apple Inc.

Documentation for Swift 6.0.3


https://www.swift.org/documentation/articles/value-and-reference-types.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API