Почему стоит выбирать Struct Over Class?

428

Играя с Swift, исходя из фона Java, почему вы хотите выбрать Struct вместо класса? Похоже, что это одно и то же, а предложение Struct менее функционально. Зачем выбирать?

  • 11
    Структуры всегда копируются, когда они передаются в вашем коде, и не используют подсчет ссылок. источник: developer.apple.com/library/prerelease/ios/documentation/swift/…
  • 2
    Я бы сказал, что структуры более приспособлены для хранения данных, а не логики. Чтобы говорить в терминах Java, представьте себе структуры как «Объекты значения».
Показать ещё 3 комментария
Теги:
class
struct
design-principles

17 ответов

504
Лучший ответ

Согласно очень популярному протоколу WWDC 2015 Protocol Oriented Programming in Swift (видео, расшифровка), Swift предоставляет ряд функций, которые во многих случаях делают структуры лучше, чем классы.

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

С помощью Structs гораздо меньше нужно беспокоиться о утечке памяти или нескольких потоках, участвующих в доступе/изменении одного экземпляра переменной. (Для более технических соображений исключение - это захват структуры внутри замыкания, потому что тогда она фактически захватывает ссылку на экземпляр, если вы явно не отметили ее, чтобы ее копировать).

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

В разговоре излагаются эти сценарии, где классы предпочтительнее:

  • Копирование или сравнение экземпляров не имеет смысла (например, Window)
  • Время жизни экземпляра привязано к внешним эффектам (например, TemporaryFile)
  • Экземпляры - это только "стоки" - каналы только для записи во внешнее состояние (например, CGContext)

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

С другой стороны, документация Swift Programming Language несколько противоречива:

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

В качестве общего руководства рассмотрите вопрос о создании структуры при применении одного или нескольких из этих условий:

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

Примеры хороших кандидатов для структур включают:

  • Размер геометрической формы, возможно, инкапсулирует свойство ширины и свойство высоты, оба типа Double.
  • Способ ссылаться на диапазоны внутри серии, возможно, инкапсулируя свойство start и свойство length, как типа Int.
  • Точка в трехмерной системе координат, возможно, инкапсулирующая свойства x, y и z, каждый из которых является двойным.

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

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

  • 10
    @ElgsQianChen весь смысл этой записи в том, что структура должна быть выбрана по умолчанию, а класс должен использоваться только при необходимости. Структуры намного безопаснее и без ошибок, особенно в многопоточной среде. Да, вы всегда можете использовать класс вместо структуры, но структуры предпочтительнее.
  • 15
    @drewag Кажется, это полная противоположность тому, что говорится. Было сказано, что по умолчанию In practice, this means that most custom data constructs should be classes, not structures. Можете ли вы объяснить мне, как, прочитав это, вы получите, что большинство наборов данных должны быть структурами, а не классами? Они дали определенный набор правил, когда что-то должно быть структурой, и в значительной степени сказали: «Во всех других сценариях класс лучше».
Показать ещё 17 комментариев
148

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

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

Рассмотрим следующий пример, демонстрирующий две стратегии обертывания типа данных Int с помощью struct и class. Я использую 10 повторяющихся значений, чтобы лучше отражать реальный мир, где у вас есть несколько полей.

class Int10Class {
    let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
    init(_ val: Int) {
        self.value1 = val
        self.value2 = val
        self.value3 = val
        self.value4 = val
        self.value5 = val
        self.value6 = val
        self.value7 = val
        self.value8 = val
        self.value9 = val
        self.value10 = val
    }
}

struct Int10Struct {
    let value1, value2, value3, value4, value5, value6, value7, value8, value9, value10: Int
    init(_ val: Int) {
        self.value1 = val
        self.value2 = val
        self.value3 = val
        self.value4 = val
        self.value5 = val
        self.value6 = val
        self.value7 = val
        self.value8 = val
        self.value9 = val
        self.value10 = val
    }
}

func + (x: Int10Class, y: Int10Class) -> Int10Class {
    return IntClass(x.value + y.value)
}

func + (x: Int10Struct, y: Int10Struct) -> Int10Struct {
    return IntStruct(x.value + y.value)
}

Производительность измеряется с использованием

// Measure Int10Class
measure("class (10 fields)") {
    var x = Int10Class(0)
    for _ in 1...10000000 {
        x = x + Int10Class(1)
    }
}

// Measure Int10Struct
measure("struct (10 fields)") {
    var y = Int10Struct(0)
    for _ in 1...10000000 {
        y = y + Int10Struct(1)
    }
}

func measure(name: String, @noescape block: () -> ()) {
    let t0 = CACurrentMediaTime()

    block()

    let dt = CACurrentMediaTime() - t0
    print("\(name) -> \(dt)")
}

Код можно найти на странице https://github.com/knguyen2708/StructVsClassPerformance

ОБНОВЛЕНИЕ (27 марта 2018 года):

Начиная с версии Swift 4.0, Xcode 9.2, запускающей сборку выпусков на iPhone 6S, iOS 11.2.6, настройка Swift-компилятора - -O -whole-module-Optimization:

  • class версии занял 2,06 секунды
  • struct version заняла 4.17e-08 секунд (в 50 000 000 раз быстрее)

(У меня больше нет среднего числа пробегов, так как отклонения очень малы, менее 5%)

Примечание. Разница намного менее драматична без оптимизации всего модуля. Я был бы рад, если кто-то может указать, что делает флаг.


ОБНОВЛЕНИЕ (7 мая 2016 года):

Начиная с версии Swift 2.2.1, Xcode 7.3, запускающей сборку выпусков на iPhone 6S, iOS 9.3.1, усредненную за 5 прогонов, параметр Swift Compiler является -O -whole-module-Optimization:

  • class версии принял 2.159942142s
  • версия struct заняла 5,83E-08 (37 000 000 раз быстрее)

Обратите внимание: как кто-то сказал, что в реальных сценариях в структуре будет больше 1 поля, я добавил тесты для structs/classes с 10 полями вместо 1. Удивительно, но результаты не сильно отличаются.


ОРИГИНАЛЬНЫЕ РЕЗУЛЬТАТЫ (1 июня 2014 года):

(Ran on struct/class с 1 полем, а не 10)

Начиная с версии Swift 1.2, Xcode 6.3.2, запускает выпуск на iPhone 5S, iOS 8.3, усредненный за 5 прогонов

  • версия class заняла 9.788332333s
  • struct version заняла 0.010532942s (в 900 раз быстрее)

СТАРЫЕ РЕЗУЛЬТАТЫ (с неизвестного времени)

(Ran on struct/class с 1 полем, а не 10)

С выпуском сборки на моем MacBook Pro:

  • Версия class заняла 1.10082 сек.
  • Версия struct взяла 0.02324 сек (в 50 раз быстрее)
  • 25
    Верно, но кажется, что копирование множества структур вокруг будет медленнее, чем копирование ссылки на один объект. Другими словами, быстрее скопировать один указатель, чем скопировать произвольно большой блок памяти.
  • 2
    В большинстве случаев вы не просто копируете ссылку, но счетчик ссылок объекта должен также увеличиваться / уменьшаться, и это может повлиять на производительность.
Показать ещё 12 комментариев
60

Сходства между структурами и классами.

Я создал для этого простой пример. https://github.com/objc-swift/swift-classes-vs-structures

И отличия

1. Наследование.

Структуры

не могут наследовать быстро. Если вы хотите

class Vehicle{
}

class Car : Vehicle{
}

Перейти для класса.

2. Pass By

Структуры Swift проходят по значениям и экземплярам класса передаются по ссылке.

Контекстные различия

Константа константы и переменные

Пример (используется в WWDC 2014)

struct Point{

   var x = 0.0;
   var y = 0.0;

} 

Определяет структуру с именем Point.

var point = Point(x:0.0,y:2.0)

Теперь, если я попытаюсь изменить x. Его действительное выражение.

point.x = 5

Но если я определил точку как постоянную.

let point = Point(x:0.0,y:2.0)
point.x = 5 //This will give compile time error.

В этом случае целая точка неизменна.

Если я использовал класс Point вместо этого, это допустимое выражение. Поскольку в неизменной константе класса есть ссылка на сам класс, а не на его переменные экземпляра (если только эти переменные не определены как константы)

  • 0
    Вы можете наследовать структуры в Swift gist.github.com/AliSoftware/9e4946c8b6038572d678
  • 12
    Вышеупомянутая суть о том, как мы можем добиться наследования ароматов для struct. Вы увидите синтаксис, как. A: B. Это структура с именем A, реализующая протокол под названием B. В документации Apple четко сказано, что структура не поддерживает чистое наследование и не поддерживает.
Показать ещё 1 комментарий
28

Вот еще несколько причин для рассмотрения:

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

    struct MorphProperty {
       var type : MorphPropertyValueType
       var key : String
       var value : AnyObject
    
       enum MorphPropertyValueType {
           case String, Int, Double
       }
     }
    
     var m = MorphProperty(type: .Int, key: "what", value: "blah")
    

Чтобы получить это в классе, вам нужно будет добавить инициализатор и поддерживать intializer...

  1. Базовые типы коллекций, такие как Array, являются структурами. Чем больше вы используете их в своем коде, тем больше вы привыкнете к передаче по значению, а не по ссылке. Например:

    func removeLast(var array:[String]) {
       array.removeLast()
       println(array) // [one, two]
    }
    
    var someArray = ["one", "two", "three"]
    removeLast(someArray)
    println(someArray) // [one, two, three]
    
  2. По-видимому, неизменность по сравнению с изменчивостью - огромная тема, но многие умные люди думают о неизменности - структуры в этом случае - предпочтительнее. Mutable vs неизменяемые объекты

  • 4
    Это правда, что вы получаете автоматические инициализаторы. Вы также получаете пустой инициализатор, когда все свойства являются необязательными. Но если у вас есть структура в Framework, вам нужно написать сам инициализатор, если вы хотите, чтобы он был доступен за пределами internal области видимости.
  • 0
    @Abizern не знал этого, спасибо!
Показать ещё 5 комментариев
18

Некоторые преимущества:

  • автоматически потокобезопасно из-за невозможности совместного использования.
  • использует меньше памяти из-за отсутствия isa и refcount (и на самом деле обычно выделяется стек)
  • методы всегда статически отправляются, поэтому могут быть встроены (хотя @final может делать это для классов)
  • проще рассуждать (нет необходимости "защищать", как это типично для NSArray, NSString и т.д.) по той же причине, что и безопасность потоков
  • 0
    Не уверен, что это выходит за рамки этого ответа, но можете ли вы объяснить (или, я полагаю, ссылку) точку «методы всегда статически отправляются»?
  • 2
    Конечно. Я также могу прикрепить оговорку к нему. Цель динамической диспетчеризации - выбрать реализацию, если вы не знаете заранее, какую из них использовать. В Swift это может происходить либо из-за наследования (может быть переопределено в подклассе), либо из-за универсальной функции (вы не знаете, какой будет универсальный параметр). Структуры не могут быть унаследованы, а целая модульная оптимизация + универсальная специализация в основном устраняют неизвестные универсальные шаблоны, поэтому методы можно просто вызывать напрямую, а не искать, что вызывать. Неспециализированные дженерики все еще выполняют динамическую диспетчеризацию для структур, хотя
Показать ещё 3 комментария
14

Предполагая, что мы знаем, что Struct - тип значения, а Class - ссылочный тип.

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

Основано на сообщении mikeash:

... Сначала рассмотрим некоторые крайние, очевидные примеры. Целые элементы, очевидно, можно копировать. Они должны быть типами ценности. Сетевые сокеты не могут быть надежно скопированы. Они должны быть ссылочными типами. Точки, как в x, y парах, могут быть скопированы. Они должны быть типами ценности. Контроллер, который представляет диск, не может быть надежно скопирован. Это должно быть ссылочным типом.

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

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

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

Коллекции - интересный случай. К ним относятся такие вещи, как массивы и словари, а также строки. Скопируются ли они? Очевидно. Является ли копирование чего-то, что вы хотите легко и часто? Это менее понятно.

Большинство языков говорят "нет" этому и делают свои ссылочные типы своих коллекций. Это верно в Objective-C и Java, Python и JavaScript и почти на всех других языках, о которых я могу думать. (Одним из основных исключений является C++ с типами коллекций STL, но C++ является бредовым сумасшедшим языкового мира, который делает все странно.)

Свифт сказал "да", что означает, что такие типы, как Array, Dictionary и String, являются структурами, а не классами. Они копируются при назначении и передают их в качестве параметров. Это вполне разумный выбор, пока копия дешевая, которую Swift очень сложно выполнить....

Кроме того, не используйте класс, когда вам нужно переопределить каждый экземпляр функции, т.е. Не иметь каких-либо общих функций.

Поэтому вместо нескольких подклассов класса. Используйте несколько структур, которые соответствуют протоколу.

  • 0
    Именно такое объяснение я искал. Ницца пиши :)
11

Структура намного быстрее, чем класс. Кроме того, если вам нужно наследование, вы должны использовать класс. Наиболее важным моментом является то, что Class является ссылочным типом, тогда как Structure - это тип значения. например,

class Flight {
    var id:Int?
    var description:String?
    var destination:String?
    var airlines:String?
    init(){
        id = 100
        description = "first ever flight of Virgin Airlines"
        destination = "london"
        airlines = "Virgin Airlines"
    } 
}

struct Flight2 {
    var id:Int
    var description:String
    var destination:String
    var airlines:String  
}

теперь давайте создадим экземпляр обоих.

var flightA = Flight()

var flightB = Flight2.init(id: 100, description:"first ever flight of Virgin Airlines", destination:"london" , airlines:"Virgin Airlines" )

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

func modifyFlight(flight:Flight) -> Void {
    flight.id = 200
    flight.description = "second flight of Virgin Airlines"
    flight.destination = "new york"
    flight.airlines = "Virgin Airlines"
}

также,

func modifyFlight2(flight2: Flight2) -> Void {
    var passedFlight = flight2
    passedFlight.id = 200
    passedFlight.description = "second flight from virgin airlines" 
}

так,

modifyFlight(flight: flightA)
modifyFlight2(flight2: flightB)

теперь, если мы напечатаем идентификатор полета и описание, мы получим

id = 200
description = "second flight of Virgin Airlines"

Здесь мы видим, что идентификатор и описание FlightA изменены, поскольку параметр, переданный методу изменения, фактически указывает на адрес памяти объекта flightA (тип ссылки).

теперь, если мы напечатаем идентификатор и описание экземпляра FLightB, мы получим,

id = 100
description = "first ever flight of Virgin Airlines"

Здесь мы видим, что экземпляр FlightB не изменяется, потому что в методе modifyFlight2 фактический экземпляр Flight2 проходит, а не ссылается (тип значения).

  • 1
    Вы никогда не создавали экземпляр FLightB
  • 0
    нет полетаB класса ....
Показать ещё 2 комментария
4

Отвечая на вопрос с точки зрения типов значений против ссылочных типов, из это сообщение в блоге Apple, это выглядит очень просто:

Используйте тип значения [например. struct, enum], когда:

  • Сравнение данных экземпляра с символом == имеет смысл
  • Вы хотите, чтобы копии имели независимое состояние
  • Данные будут использоваться в коде через несколько потоков

Используйте ссылочный тип [например. класс], когда:

  • Сравнение идентификатора экземпляра с === имеет смысл
  • Вы хотите создать совместное, изменяемое состояние

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

3

С классами вы получаете наследование и передаются по ссылке, структуры не имеют наследования и передаются по значению.

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

  • 0
    Не могли бы вы предоставить ссылки из того, что вы упомянули? Потому что на WWDC есть довольно много, чтобы выбрать из, я хотел бы смотреть тот, кто говорит на эту конкретную тему
  • 0
    Для меня это хорошее начало здесь: github.com/raywenderlich/…
Показать ещё 1 комментарий
2

В Swift был введен новый шаблон программирования, известный как программно-ориентированное программирование.

Шаблон создания:

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

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


Неверная копия дублирует только ссылку, которая указывает на эти объекты, тогда как глубокая копия дублирует ссылки на объекты.


Реализация глубокой копии для каждого ссылочного типа стала утомительной задачей. Если классы включают дополнительный ссылочный тип, мы должны реализовать шаблон прототипа для каждого из свойств ссылок. И тогда мы должны фактически скопировать весь граф объекта, реализуя протокол NSCopying.

class Contact{
  var firstName:String
  var lastName:String
  var workAddress:Address // Reference type
}

class Address{
   var street:String
   ...
} 

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

2

Я бы не сказал, что структуры предлагают меньше функциональности.

Конечно, я неизменен, за исключением мутирующей функции, но об этом.

Наследование работает отлично, пока вы придерживаетесь старой доброй идеи о том, что каждый класс должен быть абстрактным или окончательным.

Реализовать абстрактные классы как протоколы и конечные классы как структуры.

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

Вот почему свойства/поля в следующем примере все изменяемы, что я бы не делал в Java или С# или быстрых классах.

Пример структуры наследования с небольшим количеством грязного и простого использования внизу в функции с именем "пример":

protocol EventVisitor
{
    func visit(event: TimeEvent)
    func visit(event: StatusEvent)
}

protocol Event
{
    var ts: Int64 { get set }

    func accept(visitor: EventVisitor)
}

struct TimeEvent : Event
{
    var ts: Int64
    var time: Int64

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }
}

protocol StatusEventVisitor
{
    func visit(event: StatusLostStatusEvent)
    func visit(event: StatusChangedStatusEvent)
}

protocol StatusEvent : Event
{
    var deviceId: Int64 { get set }

    func accept(visitor: StatusEventVisitor)
}

struct StatusLostStatusEvent : StatusEvent
{
    var ts: Int64
    var deviceId: Int64
    var reason: String

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }

    func accept(visitor: StatusEventVisitor)
    {
        visitor.visit(self)
    }
}

struct StatusChangedStatusEvent : StatusEvent
{
    var ts: Int64
    var deviceId: Int64
    var newStatus: UInt32
    var oldStatus: UInt32

    func accept(visitor: EventVisitor)
    {
        visitor.visit(self)
    }

    func accept(visitor: StatusEventVisitor)
    {
        visitor.visit(self)
    }
}

func readEvent(fd: Int) -> Event
{
    return TimeEvent(ts: 123, time: 56789)
}

func example()
{
    class Visitor : EventVisitor
    {
        var status: UInt32 = 3;

        func visit(event: TimeEvent)
        {
            print("A time event: \(event)")
        }

        func visit(event: StatusEvent)
        {
            print("A status event: \(event)")

            if let change = event as? StatusChangedStatusEvent
            {
                status = change.newStatus
            }
        }
    }

    let visitor = Visitor()

    readEvent(1).accept(visitor)

    print("status: \(visitor.status)")
}
1

Structs являются value type а Classes являются reference type

  • Типы значений быстрее, чем ссылочные типы
  • Экземпляры типа значения безопасны в многопоточной среде, поскольку несколько потоков могут изменять экземпляр, не беспокоясь о состоянии гонки или взаимоблокировках.
  • Тип значения не имеет ссылок в отличие от ссылочного типа; поэтому нет утечек памяти.

Используйте тип value когда:

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

Используйте тип reference когда:

  • Вы хотите создать общее, изменяемое состояние.

Дополнительную информацию можно также найти в документации Apple

https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html


Дополнительная информация

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

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

В качестве напоминания вот список Swift

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

  • Struct
  • Enum
  • Кортеж
  • Примитивы (Int, Double, Bool и т.д.)
  • Коллекции (Массив, Строка, Словарь, Набор)

Типы ссылок:

  • Учебный класс
  • Все, что приходит от NSObject
  • функция
  • закрытие
1

Для многих API Cocoa требуются подклассы NSObject, которые заставляют вас использовать класс. Но кроме этого, вы можете использовать следующие случаи из блога Apples Swift, чтобы решить, следует ли использовать тип значения struct/enum или тип ссылки класса.

https://developer.apple.com/swift/blog/?id=10

0

Поскольку struct - это типы значений, и вы можете легко создать память, которая хранится в stack.Struct может быть легко доступна, и после того, как объем работы будет легко освобожден из памяти стека через поп из верхней части стека. С другой стороны, класс является ссылочным типом, который хранится в куче, а изменения, сделанные в одном объекте класса, будут влиять на другой объект, поскольку они тесно связаны и ссылочный тип. Все члены структуры являются общедоступными, тогда как все члены класса являются частными,

Недостатками структуры является то, что она не может быть унаследована.

0

Один из вопросов, не привлекший внимание в этих ответах, заключается в том, что переменная, содержащая класс vs struct, может быть let сохраняя возможность изменения свойств объекта, в то время как вы не можете сделать это со структурой.

Это полезно, если вы не хотите, чтобы переменная всегда указывала на другой объект, но все равно нужно изменить объект, то есть в случае наличия множества переменных экземпляра, которые вы хотите обновить один за другим. Если это структура, вы должны разрешить обнуление переменной для другого объекта с помощью var для этого, так как постоянный тип значения в Swift корректно разрешает нулевую мутацию, тогда как ссылочные типы (классы) не ведут себя таким образом,

0

По большей части структуры очень похожи на классы: вы можете поместить в них свойства и методы, у них есть инициализаторы, и они, как правило, ведут себя объектно-подобным образом, как и класс. Однако есть две основные вещи, которые отличает их от классов:

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

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

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

-1
  • Структура и класс - это пользовательские типы данных

  • По умолчанию структура является общедоступной, а класс - частной

  • Класс реализует принцип инкапсуляции

  • Объекты класса создаются в памяти кучи

  • Класс используется для повторного использования, тогда как структура используется для группировки данных в одной структуре

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

  • Элементы данных класса могут быть инициализированы непосредственно конструктором с меньшим значением и назначены параметризованным конструктором

  • 1
    Худший ответ когда-либо!
  • 1
    Абсолютно неверно

Ещё вопросы

Сообщество Overcoder
Наверх
Меню