Структура против класса в быстром языке
Из книги Apple "Одно из самых важных различий между структурами и классами заключается в том, что структуры всегда копируются, когда они передаются в вашем коде, а классы передаются по ссылке".
Может ли кто-нибудь дать мне понять, что это значит, для меня класс и структура, кажется, то же самое.
14 ответов
Вот пример с class
, Обратите внимание, что при изменении имени экземпляр, на который ссылаются обе переменные, обновляется. Bob
сейчас Sue
везде, где Bob
когда-либо упоминался.
class SomeClass {
var name: String
init(name: String) {
self.name = name
}
}
var aClass = SomeClass(name: "Bob")
var bClass = aClass // aClass and bClass now reference the same instance!
bClass.name = "Sue"
println(aClass.name) // "Sue"
println(bClass.name) // "Sue"
А теперь с struct
мы видим, что значения копируются, и каждая переменная сохраняет свой собственный набор значений. Когда мы устанавливаем имя Sue
, Bob
структурировать в aStruct
не меняется
struct SomeStruct {
var name: String
init(name: String) {
self.name = name
}
}
var aStruct = SomeStruct(name: "Bob")
var bStruct = aStruct // aStruct and bStruct are two structs with the same value!
bStruct.name = "Sue"
println(aStruct.name) // "Bob"
println(bStruct.name) // "Sue"
Таким образом, для представления сложной структуры с состоянием, class
является удивительным. Но для значений, которые являются просто измерением или битами связанных данных, struct
имеет больше смысла, так что вы можете легко копировать их и вычислять с ними или изменять значения, не опасаясь побочных эффектов.
И класс, и структура могут делать:
- Определите свойства для хранения значений
- Определите методы для обеспечения функциональности
- Быть расширенным
- Соответствовать протоколам
- Определить инициализаторы
- Определите подписки, чтобы обеспечить доступ к их переменным
Только класс может сделать:
- наследование
- Тип литья
- Определите деинициализаторы
- Разрешить подсчет ссылок для нескольких ссылок.
struct
являются типами значений. Это означает, что если вы копируете экземпляр структуры в другую переменную, он просто копируется в переменную.
Пример для типа значения
struct Resolution {
var width = 2
var height = 3
}
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd //assigning struct instance to variable
println("Width of cinema instance is \(cinema.width)")//result is 1920
println("Width of hd instance is \(hd.width)")//result is 1920
cinema.width = 2048
println("Width of cinema instance is \(cinema.width)")//result is 2048
println("Width of hd instance is \(hd.width)")//result is 1920
Классы являются ссылочными типами. Это означает, что если вы назначите экземпляр класса переменной, он будет содержать только ссылку на экземпляр, а не копию.
Быстрые типы
Value type
- это тип, значение которого копируется, когда оно присваивается переменной или константе, или когда оно передается функции
Reference types
не копируются, когда они назначаются переменной или константе, или когда они передаются функции
Тип значения:
Struct
, Enum
, Tuple
struct String
, struct Array
(Set
, Dictionary
)
- Когда вы назначаете или сдаете
value type
создается новая копия данных. Собственноcopy on write
-COW
механизм используется с некоторыми оптимизациями, например, копия создается при изменении объекта - Когда вы изменяете экземпляр, он имеет только локальный эффект.
- Используется стековая память.
Тип ссылки:
Class
, Function
- Когда вы назначаете или сдаете
reference type
будет создана новая ссылка на исходный экземпляр (адрес экземпляра копируется). - Когда вы изменяете экземпляр, он имеет глобальный эффект, потому что экземпляр является общим и доступен по любой ссылке, которая указывает на него.
- Используется память кучи.
Value type
рекомендуется использовать по умолчанию. Самое большое преимуществоValue type
это то, что обычно они thread safe
Reference type
Плюсы:
- они могут передаваться по наследству,
deinit()
может быть использован,- сравнить экземпляры по ссылке
===
, Objective-C
совместимость, потому чтоValue Type
был представлен в Swift.
[let vs var, class vs struct]
Выбор между структурами и
типами
классов Классы и структуры
Основные различия между структурами и классами:
- Структуры не могут наследовать от других типов.
- Классы используют приведение типов для обработки класса как суперкласса или подкласса, а также для проверки принятия протокола. Структуры могут использовать только часть принятия протокола.
- Структуры не имеют деинициализаторов.
- Структуры не могут иметь несколько ссылок на один и тот же экземпляр
Вышеуказанные ответы верны. Я надеюсь, что мой ответ поможет тому, кто не понимает ответы выше.
Ну в Swift есть два типа объектов
- Struct
- Учебный класс
Основное различие между ними
- Структура является типом значения
- Класс является ссылочным типом
Например, здесь код, чтобы понять, хорошо.
struct SomeStruct {
var a : Int;
init(_ a : Int) {
self.a = a
}
}
class SomeClass {
var a: Int;
init(_ a: Int) {
self.a = a
}
}
var x = 11
var someStruct1 = SomeStruct(x)
var someClass1 = SomeClass(x)
var someStruct2 = someStruct1
var someClass2 = someClass1
someClass1.a = 12
someClass2.a // answer is 12 because it is referencing to class 1 property a
someStruct1.a = 14
someStruct2.a // answer is 11 because it is just copying it not referencing it
Это было основным отличием, но у нас также есть различия.
Учебный класс
- Должен объявить инициализатор (конструктор)
- Имеет деинициализаторы
- Может наследовать от других классов
Struct
- Он имеет бесплатный инициализатор для вас, вам не нужно объявлять инициализатор, если вы делаете бесплатный инициализатор, будет перезаписан вашим объявленным инициализатором
- Не иметь деинициализатор
- Не может наследовать от другой структуры
Этот вопрос кажется дублирующим, но, тем не менее, следующее ответило бы на большинство случаев использования:
Одним из наиболее важных различий между структурами и классами является то, что структуры являются типами значений и всегда копируются, когда они передаются в вашем коде, а классы являются ссылочным типом и передаются по ссылке.
Кроме того, у классов есть Наследование, которое позволяет одному классу наследовать характеристики другого.
Свойства структуры хранятся в стеке, а экземпляры классов хранятся в куче, следовательно, иногда стек значительно быстрее класса.
Struct автоматически получает инициализатор по умолчанию, тогда как в Class мы должны инициализировать.
Struct является потокобезопасным или одноэлементным в любой момент времени.
А также, чтобы подвести итог разницы между структурами и классами, необходимо понимать разницу между типом value и ссылочным типом.
- Когда вы создаете копию типа значения, он копирует все данные из объекта, который вы копируете, в новую переменную. Это две разные вещи, и изменение одного не влияет на другое.
- Когда вы делаете копию ссылочного типа, новая переменная ссылается на ту же область памяти, что и копируемая вещь. Это означает, что изменение одного изменит другое, поскольку они оба ссылаются на одну и ту же область памяти. Пример кода ниже может быть взят в качестве ссылки.
// sampleplayground.playground
class MyClass {
var myName: String
init(myName: String){
self.myName = myName;
}
}
var myClassExistingName = MyClass(myName: "DILIP")
var myClassNewName = myClassExistingName
myClassNewName.myName = "John"
print("Current Name: ",myClassExistingName.myName)
print("Modified Name", myClassNewName.myName)
print("*************************")
struct myStruct {
var programmeType: String
init(programmeType: String){
self.programmeType = programmeType
}
}
var myStructExistingValue = myStruct(programmeType: "Animation")
var myStructNewValue = myStructExistingValue
myStructNewValue.programmeType = "Thriller"
print("myStructExistingValue: ", myStructExistingValue.programmeType)
print("myStructNewValue: ", myStructNewValue.programmeType)
Выход:
Current Name: John
Modified Name John
*************************
myStructExistingValue: Animation
myStructNewValue: Thriller
Если вы посмотрите дальше в руководстве Apple, вы увидите этот раздел: "Структуры и перечисления являются типами значений"
В этом разделе вы увидите это:
"Let hd = Разрешение (ширина: 1920, высота: 1080) var cinema = hd В этом примере объявляется константа с именем hd и устанавливается ее разрешение. экземпляр инициализируется с шириной и высотой видео Full HD (1920 пикселей в ширину и 1080 пикселей в высоту).
Затем он объявляет переменную cinema и устанавливает текущее значение hd. Поскольку Resolution - это структура, создается копия существующего экземпляра, и эта новая копия назначается кинотеатру. Несмотря на то, что hd и cinema теперь имеют одинаковую ширину и высоту, они представляют собой два совершенно разных случая за кулисами.
Далее, свойство width в кинотеатре изменяется на ширину чуть более широкого стандарта 2K, используемого для проецирования цифрового кино (2048 пикселей в ширину и 1080 пикселей в высоту):
Cinema. Width = 2048 Проверка свойства width у cinema показывает, что оно действительно изменилось на 2048:
Println ("cinema is now (cinema. Width) пикселей") // печатает "cinema теперь 2048 пикселей в ширину. Однако свойство width исходного экземпляра hd по-прежнему имеет старый значение 1920 года:
println ("hd по-прежнему (hd. width) пикселей") // печатает "hd по-прежнему 1920 пикселей в ширину"
Когда кино было дано текущее значение hd, значения, сохраненные в hd, были скопированы в новый экземпляр кино. Конечный результат - два совершенно разных экземпляра, которые просто содержат одинаковые числовые значения. Поскольку они являются отдельными экземплярами, установка ширины кино на 2048 не влияет на ширину, сохраненную в hd ".
Выдержка из: Apple Inc. "Язык программирования Swift". IBooks. https://itun.es/us/jEUH0.l
Это самая большая разница между структурами и классами. Структуры копируются и ссылки на классы.
Обычно (в большинстве языков программирования) объекты представляют собой блоки данных, которые хранятся в куче, а затем ссылка (обычно указатель) на эти блоки содержит name
использует для доступа к этим блокам данных. Этот механизм позволяет совместно использовать объекты в куче путем копирования значения их ссылок (указателей). Это не относится к базовым типам данных, таким как целые числа, и это потому, что память, необходимая для создания ссылки, почти такая же, как объект (в данном случае целочисленное значение). Таким образом, они будут передаваться как значения, а не как ссылка в случае больших объектов.
Swift использует struct для повышения производительности даже с объектами String и Array.
1.structure is value type.
= > when we assign structure variable to other variable or pass as parameter to function, it creates separate/new copy => so that changes made on one variable does not reflect on another.[We can say like **call by value** concept]
Example :
struct DemoStruct
{
var value: String
init(inValue: String)
{
self.value = inValue
}
}
var aStruct = DemoStruct(inValue: "original")
var bStruct = aStruct // aStruct and bStruct are two structs with the same value! but references to diff location`enter code here`
bStruct.value = "modified"
print(aStruct.value) // "original"
print(bStruct.value) // "modified"
2.class is reference type.
= > when we assign structure variable to other variable or pass as parameter to function, it **does not** creates separate/new copy => so that changes made on one variable does not reflect on another.[We can say like **call by reference** concept]
Example:
class DemoClass
{
var value: String
init(inValue: String)
{
self.value = inValue
}
}
var aClass = DemoClass(inName: "original")
var bClass = aClass // aClass and bClass now reference the same instance!
bClass.value = "modified"
print(aClass.value) // "modified"
print(bClass.value) // "modified"
Вот пример, который показывает разницу между структурой и классом точно.
скриншот написанного кода на детской площадке
struct Radio1{
var name:String
// init(name:String) {
// self.name = name
// }
}
struct Car1{
var radio:Radio1?
var model:String
}
var i1 = Car1(radio: Radio1(name:"murphy"),model:"sedan")
var i2 = i1
//since car instance i1 is a struct and
//this car has every member as struct ,
//all values are copied into i2
i2.radio?.name //murphy
i2.radio = Radio1(name: "alpha")
i2.radio?.name //alpha
i1.radio?.name //murphy
//since Radio1 was struct ,
//values were copied and thus
// changing name of instance of Radio1 in i2
//did not bring change in i1
class Radio2{
var name:String
init(name:String) {
self.name = name
}
}
struct Car2{
var radio:Radio2?
var model:String
}
var i3 = Car2(radio: Radio2(name:"murphy"),model:"sedan")
//var radioInstance = Radio2(name: "murphy")
//var i3 = Car2(radio: radioInstance,model:"sedan")
var i4 = i3
//since i3 is instance of struct
//everything is copied to i4 including reference of instance of Radio2
//because Radio2 is a class
i4.radio?.name //murphy
i4.radio?.name="alpha"
i4.radio?.name //alpha
i3.radio?.name //alpha
//since Radio2 was class,
//reference was copied and
//thus changing name of instance
//of Radio2 in i4 did bring change in i3 too
//i4.radio?.name
//i4.radio = Radio2(name: "alpha")
//i4.radio?.name
//
//i3.radio?.name
Чтобы понять разницу между структурами и классами, нам нужно знать основное различие между типами значений и ссылками. Структуры являются типами значений, и это означает, что каждое изменение в них будет просто изменять это значение, классы являются ссылочными типами, а каждое изменение в ссылочном типе будет изменять значение, выделенное в этом месте памяти или ссылки. Например:
Давайте начнем с Class, этот класс соответствует Equatable, просто чтобы иметь возможность сравнивать экземпляры, мы создаем экземпляр с именем pointClassInstanceA
и другие называются pointClassInstanceB
мы назначаем класс A классу B, теперь утверждение говорит, что они одинаковы...
class PointClass: Equatable {
var x: Double
var y: Double
init(x: Double, y: Double) {
self.x = x
self.y = y
}
static func == (lhs: PointClass, rhs: PointClass) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
}
var pointClassInstanceA = PointClass(x: 0, y: 0)
var pointClassInstanceB = pointClassInstanceA
assert(pointClassInstanceA==pointClassInstanceB)
pointClassInstanceB.x = 10
print(pointClassInstanceA.x)
//this prints 10
Хорошо, что здесь произошло, почему, если мы просто изменили значение x для pointsClassInstanceB, оно также изменило значение x для pointClassInstanceA? хорошо, это показывает, как работают ссылочные типы, когда мы присваиваем экземпляр A в качестве значения экземпляра B, а затем мы изменяем X одного из них, он изменит оба X, потому что они имеют одну и ту же ссылку, и то, что изменилось, было значением этого ссылка.
Давайте сделаем то же самое, но со структурой
struct PointStruct: Equatable {
var x: Double
var y: Double
init(x: Double, y: Double) {
self.x = x
self.y = y
}
static func == (lhs: PointStruct, rhs: PointStruct) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
}
var pointStructInstanceA = PointStruct(x: 0, y: 0)
var pointStructInstanceB = pointStructInstanceA
assert(pointStructInstanceA==pointStructInstanceB)
pointStructInstanceB.x = 100
print(pointStructInstanceA.x)
//this will print 0
У нас в основном та же структура, что и у нашего класса, но теперь вы можете видеть, что когда вы печатаете значение x pointStructInstance A, этот случай не меняется, и это происходит потому, что типы значений работают по-разному, и каждое изменение в одном из их экземпляров будет " независимый "и не повлияет на других.
Swift предлагает использовать больше типов значений, и вы можете сказать, что их библиотеки основаны на структурах, чтобы избежать проблем, которые вызывают ссылочные типы, таких как непреднамеренное изменение значения и т. Д. Структуры - это путь к Swift. Надеюсь, поможет.
Поскольку многие уже указывали на различия в копировании структур и классов, все это можно понять, откуда они берутся в c, структура типа
struct A {
let a: Int
let c: Bool
}
в памяти, локальной для родительского объекта или структуры func, это будет что-то вроде
64bit for int
8 bytes for bool
теперь для
class A {
let a: Int
let c: Bool
}
вместо содержимого данных, хранящихся в локальной памяти, структуре или классе, это будет один указатель
64bit address of class A instance
Когда вы копируете два, легко понять, почему есть разница, скопируйте первый, вы скопируете 64-битный для int и 8-битный для логического значения, скопируйте второй, вы скопируете 64-битный адрес в экземпляр класса A, вы можете иметь несколько копий одного и того же адреса памяти, все указывающие на один и тот же экземпляр, но каждая копия структуры будет отдельной копией.
Теперь все может усложниться, потому что вы можете смешать два, которые у вас есть, что-то вроде
struct A {
let a: ClassA
let c: Bool
}
ваша память будет выглядеть примерно так
64bit address of class A instance
8 bytes for bool
Это проблема, потому что даже если у вас есть несколько копий структуры в вашей программе, все они имеют копию одного и того же объекта ClassA, это означает, что так же, как множественные ссылки на экземпляр ClassA, который вы передаете, должен иметь счетчик ссылок, сохраняющий то, как существует много ссылок на объект, чтобы знать, когда их удалить, ваша программа может иметь несколько ссылок на структуру A, которым необходимо вести подсчет ссылок на свои экземпляры ClassA, это может занять много времени, если в вашей структуре много классов, или структуры, которые он содержит, содержат множество классов, теперь, когда вы копируете свою структуру, компилятор должен генерировать код, который проходит через каждый отдельный экземпляр класса, на который ссылаются в вашей структуре и подструктурах, и увеличивает счетчик ссылок, чтобы отслеживать, сколько ссылки есть.Это может сделать классы намного быстрее для передачи, так как вам просто нужно скопировать его единственный адрес, и ему не нужно будет увеличивать счетчик ссылок любого из его дочерних элементов, потому что он хочет уменьшить счетчик ссылок любого дочернего элемента, который он содержит, до своего собственного счетчик ссылок достигает 0.
С некоторыми типами структур Apple дело обстоит еще сложнее, поскольку в них на самом деле есть типы объектов. Преимущество данных, на которые ссылаются, заключается в том, что их можно хранить в памяти, удлинять и сокращать по желанию, и они могут быть очень разнообразными. большой, в отличие от данных, хранящихся в локальном стеке, поэтому такие типы, как String, Array, Set, Dictionary, хотя они действуют как структура и даже будут создавать дубликаты своих внутренних данных, если вы попытаетесь изменить их, чтобы вы не меняли все вхождение, там данные по-прежнему должны считаться ссылками, и поэтому структура, содержащая множество этих типов, все еще может работать медленно, потому что внутренние данные для каждого из них должны быть сохранены.
Конечно, передача типов структур может снизить вероятность большого количества ошибок, но они также могут замедлить работу вашей программы в зависимости от типов, которые они содержат.
Сегодня об этом много написано, я бы хотел добавить аналогию. Надеюсь, что после этого у вас никогда не возникнет сомнений: Итог:классы передаются по ссылке, а структуры передаются по значению.
Предположим, вы поделились листом Google Doc со своим другом. Теперь, если он что-то изменит в этом, вы также увидите, что изменения в вашем документе Google, означает, что ваша копия также влияет. Это в основном "передано по ссылке".
Но предположим, что если у вас есть файл.XLS, сохраненный на вашем компьютере. Вы передаете этот файл своему другу. Теперь, если он вносит какие-либо изменения в этот файл, ваш файл не будет испорчен / поврежден, потому что у вас есть собственная копия. Это в основном "передано по значению". У вас есть несколько простых программ, чтобы проверить эту аналогию на быстрых игровых площадках.