swift语言中的结构与类
Posted
技术标签:
【中文标题】swift语言中的结构与类【英文标题】:structure vs class in swift language 【发布时间】:2014-08-04 17:41:36 【问题描述】:来自苹果书 “结构和类之间最重要的区别之一是结构在代码中传递时总是被复制,但类是通过引用传递的。”
谁能帮我理解这意味着什么?对我来说,类和结构似乎是一样的。
【问题讨论】:
查看 .NET 中结构和类的区别:***.com/a/13275/19100,我猜 Swift 使用相同的语义。 @jonrsharpe 对您来说可能很容易吗?如果你知道这个,你能给我答案吗 值与引用不是 OOP 唯一的概念。它在 C 语言中,例如void my_func(int a)
与 void my_func(int &a)
。这是编程的一个非常基本的问题。阅读更多:***.com/questions/373419/…
【参考方案1】:
这是一个带有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
时,aStruct
中的 Bob
结构体不会改变。
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
更有意义,这样您就可以轻松地复制它们并使用它们进行计算或修改值,而不必担心副作用。
【讨论】:
"但是对于那些 no 比简单的数字更复杂的值..." 感谢 Alex @MichaelRapadas 数字实际上 是 Swift 中的结构。 你能澄清一下aStruct and bStruct are two structs with the same value!
这让我很困惑,因为结构内的变量值是不同的。
@JulianKról A 那行 aStruct
和 bStruct
具有相同的值。它们都有一个name
字段,设置为"Bob"
。但它们是两种不同的结构。当您可以更改其中一个结构的名称而另一个保持不变时,这一点在下一行得到证明。
刚刚错过了作业。很清楚,谢谢。也许外面太热了:-)【参考方案2】:
类和结构都可以:
定义属性以存储值 定义提供功能的方法 被扩展 遵守协议 定义初始化程序 定义下标以提供对其变量的访问只有班级才能做到:
继承 类型转换 定义去初始化器 允许对多个引用进行引用计数。【讨论】:
【参考方案3】: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
类是引用类型。这意味着如果您将类的实例分配给变量,它将只保存对实例的引用,而不保存副本。
【讨论】:
+1 表示“如果将类的实例分配给另一个变量,它将只保存实例的引用而不是复制。”【参考方案4】:以上答案是正确的,希望我的回答对不理解以上答案的人有所帮助。
在 Swift 中有两种类型的对象
-
结构体
类
它们之间的主要区别是
结构是值类型 类是reference类型例如这里的代码就很好理解了。
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
这是主要区别,但我们也有次要区别。
类
-
必须声明初始化器(构造器)
具有取消初始化程序
可以从其他类继承
结构
-
它有免费的初始化器,你不必声明初始化器,如果你做免费的初始化器将被你声明的初始化器覆盖
没有取消初始化程序
不能从其他结构继承
【讨论】:
【参考方案5】:这个问题似乎是重复的,但无论如何,以下将回答大部分用例:
结构和类之间最重要的区别之一 是结构是值类型,并且总是在它们被复制时被复制 在您的代码中传递,并且类是引用类型和 通过引用传递。
此外,类具有继承,允许一个类继承 另一个人的特征。
Struct 属性存储在 Stack 中,Class 实例存储在 因此,在堆上,有时堆栈比 类。
Struct 自动获取默认初始化程序,而在 Class 中,我们 必须初始化。
结构在任何时候都是线程安全的或单例的。
还有, 总结一下结构体和类的区别,有必要了解一下值类型和引用类型的区别。
-
当您复制一个值类型时,它会从
您要复制到新变量中的内容。它们是 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,你能举个例子说明“结构在任何时候都是线程安全的或单例的。”?提前致谢。 结构在任何时候都不是线程安全的或单例的。【参考方案6】:Swift 类型
Value type
是一种类型,其值在分配给变量或常量、传递给函数或从函数返回时被复制。 (还有as
和is
检查复制结构)
Reference types
在分配给变量或常量或传递给函数时不会被复制
值类型:
Struct
, Enum
[About], Tuple
struct String
, struct Array
(Set
, Dictionary
)
(Objective-C int
...)
字符串和内置集合值类型包含对heap
的内部引用以管理其大小
value type
时,会创建一个新的数据副本。 copy on write
- COW
机制用于 一些 特定类(如 Collections(Array, Dictionary, Set))[About] 并进行了一些优化,例如在修改对象时创建副本.对于自定义类型,您应该自己支持 COW
当您修改一个实例时,它只具有本地效果。
通常使用堆栈内存[About]
参考类型:Class
, Function
(Objective-C 所有其他)
使用ARC
reference type
时,将创建对原始实例的新引用(复制实例的地址)。
当您修改一个实例时,它具有全局效果,因为该实例是共享的,并且可以被指向它的任何引用访问。
通常使用堆内存[About]
Value type
建议默认使用。 Value type
最大的优势就是通常都是thread safe
Reference type
优点:
deinit()
可以用,
通过引用===
比较实例,
Objective-C
互操作性,因为 Value Type
是在 Swift 中引入的。
[Stack vs Heap][let vs var, class vs struct][Class vs Structure]
Choosing Between Structures and ClassesTypesClasses And Structures
【讨论】:
【参考方案7】:如果您在苹果手册中进一步查看,您将看到以下部分: “结构和枚举是值类型”
在本节中,您将看到:
“让hd=分辨率(宽度:1920,高度:1080)var cinema = hd 这个例子声明了一个叫做 hd 的常量并设置它 到一个使用完整宽度和高度初始化的分辨率实例 高清视频(1920 像素宽 x 1080 像素高)。
然后它声明一个名为cinema的变量并将其设置为当前 高清的价值。因为 Resolution 是一个结构,是现有的一个副本 创建实例,并将这个新副本分配给电影院。虽然 hd 和cinema 现在具有相同的宽度和高度,它们是两个 幕后完全不同的实例。
接下来,将cinema的width属性修改为 用于数字电影放映的稍宽的 2K 标准(2048 像素宽和 1080 像素高):
cinema.width = 2048 检查电影放映的宽度属性 它确实已更改为 2048:
println("电影现在是(cinema.width)像素宽")// 打印“电影现在是 2048 像素宽但是,宽度属性 原始的 hd 实例仍然具有 1920 的旧值:
println("hd 仍然是(hd.width) 像素宽") // 打印“hd 仍然是 1920 像素宽”
当cinema被赋予当前的hd值时,hd中存储的值 被复制到新的影院实例中。最终结果是两个 完全独立的实例,恰好包含相同的实例 数值。因为它们是单独的实例,所以设置宽度 到 2048 年的电影不影响存储在 hd 中的宽度。”
摘自:Apple Inc. “Swift 编程语言”。电子书。 https://itun.es/us/jEUH0.l
这是结构体和类之间最大的区别。复制结构并引用类。
【讨论】:
【参考方案8】:通常(在大多数编程语言中),对象是存储在堆上的数据块,然后对这些块的引用(通常是指针)包含用于访问这些数据块的name
。这种机制允许通过复制对象的引用(指针)的值来共享堆中的对象。这不是整数等基本数据类型的情况,这是因为创建引用所需的内存几乎与对象相同(在这种情况下为整数值)。因此,在大对象的情况下,它们将作为值而不是作为引用传递。
Swift 使用 struct 来提高性能,即使是 String 和 Array 对象。
A really good reading here
【讨论】:
【参考方案9】:为了理解结构体和类之间的区别,我们需要知道值类型和引用类型之间的主要区别。结构是值类型,这意味着对它们的每次更改都只会修改该值,类是引用类型,并且引用类型的每次更改都会修改在该内存或引用位置分配的值。例如:
让我们从一个类开始,这个类符合 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 的方式。 希望对您有所帮助。
【讨论】:
【参考方案10】:这是一个例子,准确地展示了结构和类之间的区别。
操场上编写代码的屏幕截图
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
【讨论】:
【参考方案11】: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"
【讨论】:
【参考方案12】:已经有很多关于此的文章,我想在此处添加一个类比。希望您在此之后永远不会有任何疑问: 底线: 类通过引用传递,而结构体通过值传递。
假设您正在与您的朋友共享一个 google 文档表。现在,如果他更改了其中的任何内容,您还将在您的 google 文档上看到更改,这意味着您的副本也会受到影响。 这基本上是“通过引用传递”。
但是假设,如果您的机器中保存了一个 .XLS 文件。您将该文件提供给您的朋友。现在,如果他对该文件进行任何更改,您的文件将不会被弄乱/影响,因为您有自己的副本。 这基本上是“按值传递”。 您已经有多个简单的程序可以在 Swift Playground 中检查这个类比。
【讨论】:
以上是关于swift语言中的结构与类的主要内容,如果未能解决你的问题,请参考以下文章