структура против класса в быстром языке

192

Из книги Apple «Одно из самых важных различий между структурами и классами заключается в том, что структуры всегда копируются, когда они передаются в вашем коде, а классы передаются по ссылке».

Может ли кто-нибудь помочь мне понять, что это значит? Мне кажется, что классы и структуры одинаковы.

Маниш Агравал
источник
3
Смотрите различие между структурой и классом в .NET: stackoverflow.com/a/13275/19100 , я предполагаю, что Swift использует ту же семантику.
Далле
23
@jonrsharpe может быть легко для вас? Можете ли вы дать мне ответ, если вы знаете это
Маниш Агравал
1
Значение против ссылки не является концепцией только ООП. Это там, в Си, как void my_func(int a)против void my_func(int &a). Это очень фундаментальный вопрос программирования. Читайте больше: stackoverflow.com/questions/373419/…
superarts.org

Ответы:

473

Вот пример с 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"

Таким образом, для представления сложной сущности с состоянием, a classэто здорово. Но для значений, которые являются просто измерением или битами связанных данных, structболее разумно, чтобы вы могли легко копировать их и вычислять с ними или изменять значения, не опасаясь побочных эффектов.

Алекс Уэйн
источник
«Но для значений, которые не сложнее, чем просто число ...» Спасибо за это Алекс
Майк Рападас
7
@MichaelRapadas Числа на самом деле являются структурами в Swift.
Николай Рюэ
Не могли бы вы уточнить это, aStruct and bStruct are two structs with the same value!меня смущает, так как значения переменных внутри структуры разные.
Джулиан Крол
@ JulianKról Эта строка aStructи bStructимеет одинаковые значения. Они оба имеют одно nameполе, которое установлено "Bob". Но это две разные структуры. Это подтверждается следующей строкой, когда вы можете изменить имя одной из структур, а другая остается без изменений.
Алекс Уэйн
Просто пропустил задание. Это понятно, спасибо. Может быть, это слишком жарко на улице :-)
Джулиан Крол
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

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

Ну в Swift Есть два типа объектов

  1. Struct
  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. Может наследовать от других классов

Struct

  1. Он имеет бесплатный инициализатор для вас, вам не нужно объявлять инициализатор, если вы делаете бесплатный инициализатор, будет перезаписан вашим заявленным инициализатором
  2. Не иметь деинициализатор
  3. Не может наследовать от другой структуры
Дара
источник
7

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

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

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

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

  4. Struct автоматически получает инициализатор по умолчанию, тогда как в Class мы должны инициализировать.

  5. Struct является потокобезопасным или одиночным в любой момент времени.

А также, чтобы подвести итог различий между структурами и классами, необходимо понимать разницу между типами value и reference.

  1. Когда вы делаете копию типа значения, он копирует все данные из того, что вы копируете, в новую переменную. Это две разные вещи, и изменение одной не влияет на другую.
  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
ДИЛИП КОСУРИ
источник
Привет Дилип, Можете ли вы привести пример для "Struct является потокобезопасным или синглтон в любой момент времени." ?. Заранее спасибо.
Нарасимха Налламсетти
3

Если вы посмотрите дальше в руководстве 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». интерактивные книги. https://itun.es/us/jEUH0.l

Это самая большая разница между структурами и классами. Структуры копируются и ссылки на классы.

Стюарт Касаротто
источник
1

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

Swift использует struct для улучшения производительности даже с объектами 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 для 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 для 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механизм используется с некоторыми оптимизациями, например , копия создается при изменении объекта
  • Когда вы изменяете экземпляр, он имеет только локальный эффект.
  • Stack памяти используется.

Тип ссылки :
Class,Function

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

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

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

Reference type Плюсы:

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

[let vs var, class vs struct]
Выбор между структурами и
типами
классов Классы и структуры

yoAlex5
источник
0

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

Предположим, вы поделились листом Google Doc со своим другом. Теперь, если он что-то изменит в этом, вы также увидите, что изменения в вашем документе Google, означает, что ваша копия также влияет. Это в основном " передано по ссылке ".

Но предположим, что если у вас есть файл .XLS, сохраненный на вашем компьютере. Вы передаете этот файл своему другу. Теперь, если он вносит какие-либо изменения в этот файл, ваш файл не будет испорчен / поврежден, потому что у вас есть собственная копия. Это в основном " передано по значению ". У вас есть несколько простых программ, чтобы проверить эту аналогию на быстрых игровых площадках.

ASP
источник