快速语言的结构与类


192

苹果公司的书“结构和类之间最重要的区别之一是,结构在代码中传递时总是被复制,而类是通过引用传递的。”

谁能帮助我了解这意味着什么?在我看来,类和结构似乎是相同的。


3
请参阅.NET中的struct和class之间的区别:stackoverflow.com/a/13275/19100,我猜想Swift使用相同的语义。
dalle 2014年

23
@jonrsharpe对您来说可能很容易?您能给我答案吗,如果您知道这一点
Manish Agrawal 2014年

1
价值与参考不是唯一的面向对象的概念。在C中,就像void my_func(int a)vs 一样void my_func(int &a)。这是编程的一个非常基本的问题。阅读更多:stackoverflow.com/questions/373419/…–
superarts.org

Answers:


473

这是带有的示例class。请注意,更改名称后,两个变量引用的实例如何更新。Bob现在SueBob曾经被引用过的任何地方。

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"

现在,有了a,struct我们看到值被复制并且每个变量都保留自己的一组值。当我们将名称设置为时,in 中SueBob结构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则更有意义,因此您可以轻松地将它们复制并进行计算或修改值而不必担心副作用。


“至于价值观是没有不仅仅是一些更复杂的......”感谢这个亚历克斯
麦克Rapadas

7
@MichaelRapadas数字实际上 Swift 中的结构。
Nikolai Ruhe 2014年

您能否澄清一下,aStruct and bStruct are two structs with the same value!这使我感到困惑,因为结构内部的变量值不同。
朱利安·科洛(JulianKról),2015年

@JulianKról该行aStructbStruct具有相同的值。它们都有一个name设置为的字段"Bob"。但是它们是两种不同的结构。当您可以更改其中一个结构的名称,而另一个保持不变时,将在下一行证明这一点。
亚历克斯·韦恩

刚错过任务。很明显,谢谢。也许外面太热了:-)
朱利安·克罗(JulianKról)2015年

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

类是引用类型。这意味着,如果将类的实例分配给变量,则它将仅保留对该实例的引用而不包含copy


5
+1表示“如果将类的实例分配给另一个变量,它将仅保留该实例的引用而不是副本。”
赛义夫(Saif)2015年

8

以上答案是正确的,我希望我的答案能对不理解以上答案的人有所帮助。

在Swift中,有两种类型的对象

  1. 结构

它们之间的主要区别是

  • 结构是类型
  • 类是参考类型

例如,这里的代码很好理解。

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. 它为您提供免费的初始化程序,如果您执行免费的初始化程序,则不必声明初始化程序,否则声明的初始化程序将覆盖该初始化程序
  2. 没有反初始化器
  3. 无法从其他结构继承

7

这个问题似乎是重复的,但是无论如何,以下将回答大多数用例:

  1. 结构和类之间最重要的区别之一是,结构是值类型,并且在代码中传递它们时总是被复制,而类是引用类型并且通过引用传递。

  2. 另外,类具有继承性,该继承性允许一个类继承另一个类的特征。

  3. Struct属性存储在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

您好,Dilip,您能否举一个“结构在任何时间都是线程安全或单例的?”的示例。提前致谢。
Narasimha Nallamsetty

3

如果您在Apple手册中看得更远,则会看到以下部分:“结构和枚举是值类型”

在本节中,您将看到:

“ let hd =分辨率(宽度:1920,高度:1080)varcinema = hd此示例声明一个名为hd的常量并将其设置为Resolution实例使用全高清视频的宽度和高度(1920像素宽x 1080像素高)初始化。

然后,它声明一个名为Cinema的变量,并将其设置为hd的当前值。因为Resolution是一种结构,所以将复制现有实例,并将该新副本分配给电影院。尽管高清和电影现在具有相同的宽度和高度,但它们是幕后的两个完全不同的实例。

接下来,将电影院的width属性修改为用于数字电影院投影的稍宽的2K标准的宽度(宽2048像素,高1080像素):

cinema.width = 2048检查电影的width属性表明它确实已更改为2048:

println(“ cinema现在是(cinema.width。)像素宽”)///打印“ cinema现在是2048像素宽但是,原始hd实例的width属性仍旧1920年的价值:

println((“ hd仍为((hd..width。))像素宽”))//打印“ hd仍为1920像素宽”

当为电影提供hd的当前值时,存储在hd中的值将被复制到新的电影实例中。最终结果是两个完全独立的实例,它们恰好包含相同的数值。由于它们是单独的实例,因此将电影院的宽度设置为2048不会影响以hd存储的宽度。”

摘录自:苹果公司“ The Swift Programming Language”。iBooks。 https://itun.es/us/jEUH0.l

这是结构和类之间的最大区别。复制结构并引用类。


1

通常(在大多数编程语言中)对象是存储在堆上的数据块,然后对这些块的引用(通常是指针)包含name用于访问这些数据块的。这种机制允许通过复制对象的引用(指针)的值来共享堆中的对象。这不是诸如Integers之类的基本数据类型的情况,这是因为创建引用所需的内存与对象几乎相同(在这种情况下为整数值)。因此,在大对象的情况下,它们将作为值传递而不是作为参考。

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

好的,这里发生了什么,为什么如果我们只是更改pointsClassInstanceB的x值,它也更改了pointClassInstanceA的x值?好吧,这说明了引用类型是如何工作的,当我们将实例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

我们的结构与我们的类基本相同,但是现在您可以看到,当打印pointStructInstanceA的x值时,这种情况并没有改变,这是因为值类型的工作方式不同,并且它们实例之一上的每次更改都是“独立”,不会影响对方。

Swift建议使用更多的值类型,您可以告诉他们它们的库基于结构,以避免引用类型带来的问题,例如无意中修改值等。结构是继续使用Swift的方法。希望能帮助到你。


1

这是一个示例,精确显示了struct和class之间的区别。

在操场上编写代码的屏幕截图
在操场上编写代码的屏幕截图

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 将它们分配给变量或常量,或将它们传递给函数时,不会复制它们

值类型
StructEnumTuple
struct Stringstruct ArraySetDictionary

  • 当您分配或传递 value type新的数据副本时。实际上copy on write- COW机制用于某些优化,例如,在修改对象时创建副本
  • 当你修改一个实例它只有局部的效果。
  • 使用堆栈存储器

参考类型
ClassFunction

  • 当您分配或传递对原始实例reference type新引用时,将创建(实例的地址已复制)。
  • 当你修改一个实例它具有全球性影响,因为实例上共享和任何参考该访问点。
  • 使用堆内存

在此处输入图片说明

Value type建议默认使用。最大的优点Value type是通常thread safe

Reference type 优点:

  • 它们可以被继承,
  • deinit() 可以使用
  • 通过引用比较实例===
  • Objective-C互操作性,因为它Value Type是在Swift中引入的。

[关于可变性的更多信息]
在结构和类
类型之间进行选择类型
和结构


0

如今,有关此的文章很多,我想在此添加一个类比。希望您以后再也不会对此产生疑问:底线: 类是通过引用传递的,而结构是通过值传递的。

假设您正在与朋友共享一个Google文档表。现在,如果他更改了其中的任何内容,您还将看到Google文档上的更改,这意味着您的副本也受到了影响。这基本上是“ 通过引用传递 ”。

但是,假设您的计算机中保存有.XLS文件。您将文件提供给您的朋友。现在,如果他在该文件中进行任何更改,由于您拥有自己的副本,因此您的文件不会被弄乱/影响。这基本上是“ 按价值传递 ”。您已经有多个简单的程序可以在快速的操场上检查这种类比。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.