структура vs клас швидкою мовою


192

З книги Apple "Однією з найважливіших відмінностей між структурами та класами є те, що структури завжди копіюються, коли вони передаються навколо у вашому коді, але класи передаються за посиланням".

Хтось може допомогти мені зрозуміти, що це означає? Мені здаються, що класи та структури однакові.


3
Дивіться різницю між структурою та класом у .NET: stackoverflow.com/a/13275/19100 , я здогадуюсь, що Swift використовує ту саму семантику.
Далле

23
@jonrsharpe може бути вам легким? чи можете ви дати мені відповідь, якщо ви знаєте це
Manish Agrawal

1
Значення порівняно з посиланням не є лише концепцією OOP. Це там у С, як і void my_func(int a)проти void my_func(int &a). Це дуже принципове питання програмування. Детальніше: stackoverflow.com/questions/373419 / ...
superarts.org

Відповіді:


473

Ось приклад із a 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більше сенсу, так що ви можете легко копіювати їх і обчислювати з ними або змінювати значення, не боячись побічних ефектів.


"Але для значень, які не складніші за просто число ..." Дякую за це Алекс
Майк Рападас

7
@MichaelRapadas Числа насправді є структурами у Свіфті .
Микола Рухе

Чи можете ви пояснити це, aStruct and bStruct are two structs with the same value!це бентежить мене, оскільки значення змінних всередині структури різні.
Julian Król

@ JulianKról А, лінії aStructі bStructмають однакові значення. Вони обидва мають одне nameполе, яке встановлено "Bob". Але це дві різні структури. Це доводиться в наступному рядку, коли ви можете змінити назву однієї з структур, а інша залишається незмінною.
Алекс Уейн

Щойно пропустив завдання. Зрозуміло, дякую. Можливо, це надто спекотно назовні :-)
Julian Król

60

І клас, і структура можуть:

  • Визначте властивості для зберігання значень
  • Визначте методи забезпечення функціональності
  • Будьте продовжені
  • Відповідність протоколам
  • Визначте іціалізатори
  • Визначте підписки, щоб забезпечити доступ до своїх змінних

Тільки клас може робити:

  • Спадщина
  • Тип лиття
  • Визначте дезініціалізатори
  • Дозволити підрахунок посилань для кількох посилань.

32

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

Класи - це еталонні типи. Це означає, що якщо ви призначите екземпляр класу змінній, він буде містити лише посилання на екземпляр, а не копію .


5
+1 для "Якщо ви призначите екземпляр класу іншій змінній, він міститиме лише посилання на екземпляр, який не копіюється."
Сайф

8

Наведені вище відповіді є правильними. Я сподіваюся, що моя відповідь допоможе тому, хто не розуміє вищезазначених відповідей.

Добре в Свіфті Є два типи об'єктів

  1. Структуру
  2. Клас

Основна відмінність між ними полягає

  • Структура - тип значення
  • Клас - еталонний тип

Наприклад, тут код, щоб добре зрозуміти.

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

Це була основна відмінність, але у нас є також і відмінності.

Клас

  1. Потрібно оголосити ініціалізатор (конструктор)
  2. Має деініціалізатори
  3. Може успадкувати від інших класів

Структуру

  1. У вас є безкоштовний ініціалізатор для вас, вам не потрібно декларувати initaliser, якщо ви зробите безкоштовний ініціалізатор, буде замінено вашим заявленим ініціалізатором
  2. Не майте дезініціалізатора
  3. Не вдається успадкувати іншу структуру

7

Це запитання здається дублюючим, але незалежно від цього, більшість випадків використання відповідатиме наступним чином:

  1. Однією з найважливіших відмінностей між структурами і класами є те, що структури є типовими типами і завжди копіюються, коли вони передаються навколо у вашому коді, а класи мають тип посилань і передаються посиланням.

  2. Крім того, класи мають спадщину, яка дозволяє одному класу успадковувати характеристики іншого.

  3. Властивості структури зберігаються в Stack, а екземпляри Class зберігаються в Heap, отже, іноді стек різко швидше, ніж клас.

  4. Struct автоматично отримує ініціалізатор за замовчуванням, тоді як у Class нам потрібно ініціалізувати.

  5. Структура є безпечною для ниток або однотонним в будь-який момент часу.

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

  1. Коли ви робите копію типу значення, вона копіює всі дані з того, що ви копіюєте, у нову змінну. Вони є 2 окремими речами і зміна однієї не впливає на іншу.
  2. Коли ви робите копію еталонного типу, нова змінна посилається на те саме місце пам'яті, що і те, що ви копіюєте. Це означає, що зміна одного змінить інше, оскільки вони обидва посилаються на одне місце пам’яті. Зразок коду нижче може бути сприйнятий як довідковий.

// 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

Привіт Діліпе, чи можете ви навести приклад для "Структура є безпечною для потоку або однократним в будь-який момент часу?". Заздалегідь спасибі.
Нарасимха Налламсетті

3

Якщо ви поглянете далі в посібнику з яблуками, ви побачите цей розділ: "Структури та перерахування - це типи цінності"

У цьому розділі ви побачите це:

“Нехай hd = роздільна здатність (ширина: 1920, висота: 1080) var cinema = hd Цей приклад оголошує константу, що називається hd, і встановлює її дозволу екземпляр ініціалізований із шириною та висотою відео у форматі Full HD (ширина 1920 пікселів на 1080 пікселів у висоту).

Потім він оголошує змінну, що називається кінотеатр, і встановлює її до поточного значення hd. Оскільки роздільна здатність є структурою, робиться копія існуючого примірника, і ця нова копія призначається кінотеатру. Навіть незважаючи на те, що hd та кінотеатри зараз однакові по ширині та висоті, вони є двома абсолютно різними екземплярами за кадром.

Далі властивість ширини кінотеатру вносять у ширину трохи ширшого стандарту 2К, який використовується для цифрової кінопроекції (2048 пікселів у ширину та 1080 пікселів у висоту):

Кіно. Width = 2048 Перевірка властивості ширини кінотеатру показує, що він дійсно змінився на 2048:

Println ("кінотеатр зараз (кіно. Ширина) пікселів у ширину") // друкує "кінотеатр зараз шириною 2048 пікселів. Однак властивість ширини оригінального екземпляра hd все ще має стару значення 1920 року:

println ("hd нерухомий (hd. ширина) пікселів у ширину") // друкується "hd досі 1920 пікселів"

Коли для кінотеатру було задано поточне значення hd, значення, збережені у hd, були скопійовані у новий екземпляр кінотеатру. Кінцевим результатом є два абсолютно окремих екземпляри, які щойно містять однакові числові значення. Оскільки це окремі екземпляри, встановлення ширини кінофільму на 2048 не впливає на ширину, що зберігається в hd. "

Уривок: Apple Inc. "Мова швидкого програмування". iBooks. https://itun.es/us/jEUH0.l

Це найбільша різниця між структурами та класами. Структури копіюються та класи посилаються.


1

Зазвичай (у більшості мов програмування) об'єкти - це блоки даних, які зберігаються в купі, і тоді посилання (як правило, вказівник) на ці блоки містить name який використовується для доступу до цих блоків даних. Цей механізм дозволяє обмінюватися об'єктами в купі, копіюючи значення своїх посилань (покажчиків). Це не стосується основних типів даних, таких як Integers, і це тому, що пам'ять, необхідна для створення посилання, майже така ж, як і об'єкт (в даному випадку ціле число). Таким чином, вони передаватимуться як значення, а не як еталон у випадку великих об'єктів.

Swift використовує структуру для підвищення продуктивності навіть із об'єктами String і Array.

Справді гарне читання тут


1

Для того, щоб зрозуміти різницю між структурами та класами, нам потрібно знати головну різницю між значеннями та типовими типами. Структури - це типи значень, і це означає, що кожна зміна на них просто модифікує це значення, Класи - це еталонні типи, і кожна зміна типу посилання змінює значення, виділене в цьому місці пам'яті або посилання. Наприклад:

Почнемо з класу, цей клас відповідає 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 пунктівClassInstanceB, воно також змінило значення 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 pointStructInstanceA цей випадок не змінюється, і це тому, що типи значень працюють по-різному, і кожна зміна в одному з їх екземплярів буде " незалежний »і не вплине на іншого.

Swift пропонує використовувати більше типів значень, і ви можете сказати, що їх бібліотеки базуються на структурах, щоб уникнути проблем, які викликають типи посилань, як ненавмисне зміна значення тощо. Структури - це спосіб продовжити Swift. Сподіваюся, це допомагає.


1

Ось приклад, який точно показує різницю між структурою та класом.

скріншот написаного коду на ігровому майданчику
скріншот написаного коду на ігровому майданчику

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

1
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"

1

Швидкі типи

Value type це тип, значення якого копіюється, коли воно присвоюється змінній або константі або коли воно передається функції

Reference types не копіюються, коли вони присвоєні змінній або константі або коли вони передані функції

Значення Тип :
Struct, Enum, Tuple
struct String, struct Array( Set, Dictionary)

  • При призначенні або передачі value type створюється нова копія даних. На насправді copy on write- COWмеханізм використовується з деякими оптимізаціями, наприклад , копія створюється при зміні об'єкта
  • Коли ви змінюєте екземпляр, він має лише локальний ефект.
  • Використовується пам'ять стека .

Тип посилання :
Class,Function

  • При призначенні або передати reference typeв нову посилання буде створено оригінальний екземпляр (адреса примірника копіюється).
  • Коли ви змінюєте екземпляр, він має глобальний ефект, оскільки цей примірник є спільним та доступним будь-яким посиланням, які вказують на нього.
  • Heap пам'ять використовується.

введіть тут опис зображення

Value typeрекомендується використовувати за замовчуванням . Найбільшою перевагою Value typeє те, що вони зазвичай єthread safe

Reference type Плюси:

  • вони можуть бути успадковані,
  • deinit() може бути використаний,
  • порівняти випадки за посиланням ===,
  • Objective-Cсумісність, оскільки вона Value Typeбула введена в Swift.

[Докладніше про змінність]
Вибір між структурами та
типами
класів Класи та структури


0

В Альредеї багато про це написано, я хотів би додати там аналогію. Сподіваюся, ви ніколи не матимете сумнівів після цього: Підсумок: класи передаються посиланням, тоді як структури передаються за значенням.

Припустимо, ви ділитесь документом Google doc зі своїм другом. Тепер, якщо він щось змінить у цьому, ви також побачите, що зміни у вашому документі google означають, що ваша копія також впливає. Це в основному " передано посиланням ".

Але припустимо, якщо у вашій машині збережено файл .XLS. Ви надаєте цей файл передайте своєму другові. Тепер, якщо він вносить якісь зміни у цей файл, ваш файл не буде змінено / виконано, оскільки у вас є своя копія. Це в основному " передане значення ". У вас є кілька простих програм, щоб перевірити цю аналогію на швидких ігрових майданчиках.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.