Быстрое программирование: структуры и классы

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

Что такое структуры?

Структуры представляют собой типы value. Они объявляются с использованием ключевого слова struct

struct ElectricCar {
    var batteryRange: Int
    var topSpeed: Int
}

Что такое классы?

Классы являются ссылочными типами. Они объявляются с использованием ключевого слова class

class ElectricCar {
    var batteryRange: Int
    var topSpeed: Int
}

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

В чем сходство структур и классов?

  • Оба могут иметь свойства для хранения значений.
  • У обоих могут быть методы для обеспечения функциональности.
  • Оба могут иметь инициализаторы для определения начального состояния.
  • Оба варианта открыты для расширения.
  • Оба могут соответствовать протоколу.
  • В обоих случаях для доступа к значениям может использоваться синтаксис нижнего индекса.

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

Чем класс отличается от структуры?

  • Классы поддерживают наследование.
  • Классы поддерживают проверку типов.
  • Классы поддерживают деинициализаторы, которые помогают нам освобождать выделенную память.
  • Классы допускают подсчет ссылок, что позволяет им иметь более одного экземпляра.

Что особенного в структуре?

  • Не требует инициализации. Однако при необходимости мы можем предоставить собственный инициализатор.
  • Не имеет наследования. Это делает их легкими и обеспечивает лучшую производительность.

Принципиальное различие между структурами и классами заключается в их типах. Как мы видели ранее, structs are value types, тогда как classes are reference type. Давайте посмотрим, что это значит

Что означают типы значений?

Типы значений при назначении или передаче функции создают новую копию значения и сохраняют ее в новом месте. Новый экземпляр создается и сохраняется в текущем стеке памяти. Изменение структуры не изменяет исходное значение.

Пример:

struct ElectricCar {
    var batteryRange: Int
    var topSpeed: Int
}

var longRange = ElectricCar(batteryRange: 314, topSpeed: 145)
var performance = longRange
performance.topSpeed = 164

print("LONG RANGE::: Top Speed: \(longRange.topSpeed) mph Battery Range: \(longRange.batteryRange) mi")
print("PERFORMANCE::: Top Speed: \(performance.topSpeed) mph Battery Range: \(performance.batteryRange) mi")

Выход:

LONG RANGE::: Top Speed: 145 mph Battery Range: 314 mi
PERFORMANCE::: Top Speed: 164 mph Battery Range: 314 mi

topSpeed переменной performance обновляется, но не перезаписывает переменную longRange. Это связано с тем, что когда longRange присваивается performance, Swift создает копию значения и сохраняет ее в новом месте. Следовательно, любое изменение performance не влияет на исходное значение longRange.

Что означают ссылочные типы?

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

Пример:

class ElectricCar {
    var batteryRange: Int
    var topSpeed: Int
    
    //Required initialisers.
    init(batteryRange: Int, topSpeed: Int) {
        self.batteryRange = batteryRange
        self.topSpeed = topSpeed
    }
}

let longRange = ElectricCar(batteryRange: 314, topSpeed: 145)
let performance = longRange
performance.topSpeed = 164

print("LONG RANGE::: Top Speed: \(longRange.topSpeed) mph Battery Range: \(longRange.batteryRange) mi")
print("PERFORMANCE::: Top Speed: \(performance.topSpeed) mph Battery Range: \(performance.batteryRange) mi")

Выход:

LONG RANGE::: Top Speed: 164 mph Battery Range: 314 mi
PERFORMANCE::: Top Speed: 164 mph Battery Range: 314 mi

topSpeed переменных performance и longRange указывают на один и тот же экземпляр Car. Поэтому, когда мы выполняем любую модификацию, она изменяет экземпляр. Поскольку существует только один экземпляр, модификация отражается, когда мы пытаемся получить доступ через другую ссылку.

Некоторые другие интересные особенности типа ссылки:

  • Это также увеличивает количество ссылок исходного значения. Следовательно, важно деинициализировать любые нежелательные ссылки.
  • Ссылочные типы longRange и performance объявлены как constant. Компилятор позволяет нам изменять их свойства, поскольку константы фактически не меняются. Это эталонный экземпляр, который изменяется.
  • Swift предоставляет нам операторы идентификации, которые позволяют сравнивать два типа экземпляров. Его представляет ===

Как мы выбираем между структурами и классами?

  • Apple рекомендует «Использовать структуры по умолчанию».
  • Используйте структуры для моделирования данных, если у вас есть удаленная база данных, в которой хранится конечное состояние.
  • Используйте структуры, если вы не хотите, чтобы изменения отражались глобально. Поскольку структуры являются типами значений, их область действия ограничена локально. Это скрывает наши изменения от других областей кода. Кроме того, это снижает риск случайного глобального изменения чего-либо и делает нас более уверенными в нашем коде.
  • Если вы создаете шаблон наследования с нуля, используйте для его создания структуры и протоколы. Протоколы достаточно мощны, чтобы позволить структурам адаптироваться к любому шаблону.

Сценарии, в которых нам нужно использовать класс, следующие:

  • Когда наш код взаимодействует с кодом Obj-C.
  • Когда наш код требует совместного использования экземпляров. Мы можем использовать класс, когда другая часть нашего кода использует общий экземпляр или отслеживать состояние.
  • Когда наш код требует полного контроля над состоянием, таким как файловые менеджеры, подключения к БД, сетевые контроллеры и т. д.

Использованная литература:

Спасибо за прочтение и делитесь отзывами.