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 那行 aStructbStruct 具有相同的值。它们都有一个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 是一种类型,其值在分配给变量或常量、传递给函数或从函数返回时被复制。 (还有asis 检查复制结构)

Reference types 在分配给变量或常量或传递给函数时不会被复制

值类型

Struct, Enum[About], Tuplestruct 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语言中的结构与类的主要内容,如果未能解决你的问题,请参考以下文章

结构体与类

➽08结构体与类

➽08结构体与类

apple Swift语言新手教程

Apple Swift编程语言新手教程

swift 雨燕 新手教程