快速语言中的结构与类

structure vs class in swift language

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

有人能让我明白这意味着什么吗,对我来说,类和结构似乎是一样的。


下面是一个使用class的例子。注意当名称更改时,两个变量引用的实例是如何更新的。Bob现在是Sue,在Bob被引用的地方。

1
2
3
4
5
6
7
8
9
10
11
12
13
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结构不会更改。

1
2
3
4
5
6
7
8
9
10
11
12
13
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更有意义,这样您就可以轻松地复制它们并使用它们进行计算,或者在不担心副作用的情况下修改这些值。


类和结构都可以做到:

  • 定义属性以存储值
  • 定义提供功能的方法
  • 被延长
  • 符合协议
  • 定义初始化器
  • 定义下标以提供对其变量的访问

只有类可以做到:

  • 遗传
  • 型铸造
  • 定义去初始化器
  • 允许对多个引用进行引用计数。


struct是值类型。这意味着,如果您将结构的实例复制到另一个变量,那么它只是复制到变量。

值类型示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    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

    这是主要的区别,但我们也有次要的区别。

    等级

  • 必须声明初始化器(构造函数)
  • 有脱镍剂
  • 可以从其他类继承
  • 结构

  • 它为您提供了可用的初始化器,如果您提供了可用的初始化器,则不必声明初始化器。初始化器将被声明的初始化器覆盖。
  • 没有去初始化器
  • 不能从其他结构继承

  • 这个问题似乎是重复的,但不管怎样,以下内容将回答大多数用例:

  • 结构和类之间最重要的区别之一结构是值类型,并且在它们在代码中传递,类是引用类型和通过引用传递。

  • 此外,类具有继承性,允许一个类继承另一个的特征。

  • 结构属性存储在堆栈上,类实例存储在堆栈上因此,有时堆栈比班级。

  • 结构自动获取默认初始值设定项,而在类中,我们必须初始化。

  • 结构在任何时候都是线程安全的或单例的。

  • 而且,为了总结结构和类之间的区别,有必要了解值类型和引用类型之间的区别。

  • 复制值类型时,它会从您要复制到新变量中的内容。它们是两个分开的事情和改变一个不会影响另一个。
  • 复制引用类型时,新变量引用与正在复制的内容的内存位置相同。这意味着改变一个会改变另一个,因为它们都指相同的内存位置。下面的示例代码可以作为参考。
  • //sampleplayground.playground

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
      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)

    输出:

    1
    2
    3
    4
    5
    Current Name:  John
    Modified Name John
    *************************
    myStructExistingValue:  Animation
    myStructNewValue:  Thriller


    如果您在苹果手册中看得更远,您将看到以下部分:"结构和枚举是值类型"

    在本节中,您将看到:

    "?let? ?hd? = ?Resolution?(?width?: ?1920?, ?height?: ?1080?) ?var?
    ?cinema? = ?hd This example declares a constant called hd and sets it
    to a Resolution instance initialized with the width and height of full
    HD video (1920 pixels wide by 1080 pixels high).

    It then declares a variable called cinema and sets it to the current
    value of hd. Because Resolution is a structure, a copy of the existing
    instance is made, and this new copy is assigned to cinema. Even though
    hd and cinema now have the same width and height, they are two
    completely different instances behind the scenes.

    Next, the width property of cinema is amended to be the width of the
    slightly-wider 2K standard used for digital cinema projection (2048
    pixels wide and 1080 pixels high):

    ?cinema?.?width? = ?2048 Checking the width property of cinema shows
    that it has indeed changed to be 2048:

    ?println?(?"cinema is now ?(?cinema?.?width?)? pixels wide"?) ?//
    prints"cinema is now 2048 pixels wide However, the width property of
    the original hd instance still has the old value of 1920:

    println?(?"hd is still ?(?hd?.?width?)? pixels wide"?) // prints"hd
    is still 1920 pixels wide"

    When cinema was given the current value of hd, the values stored in hd
    were copied into the new cinema instance. The end result is two
    completely separate instances, which just happened to contain the same
    numeric values. Because they are separate instances, setting the width
    of cinema to 2048 doesn’t affect the width stored in hd."

    Excerpt From: Apple Inc."The Swift Programming Language." iBooks.
    https://itun.es/us/jEUH0.l

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


    为了理解结构和类之间的区别,我们需要知道值类型和引用类型之间的主要区别。结构是值类型,这意味着它们上的每一个更改都将修改该值,类是引用类型,引用类型中的每一个更改都将修改在该内存或引用位置分配的值。例如:

    让我们从一个类开始,这个类符合等价,只是为了能够比较实例,我们创建了一个名为pointClassInstanceA的实例和其他名为pointClassInstanceB的实例,我们将类A分配给类B,现在断言说它们是相同的……

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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,因为它们共享相同的引用,并且更改了该引用的值。

    让我们做同样的事情,但是使用一个结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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的方法。希望它有帮助。


    下面是一个例子,它精确地显示了结构和类之间的区别。

    操场写代码截图screenshot of written code in playground

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    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

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

    Swift使用struct来提高性能,即使使用字符串和数组对象也是如此。

    一本非常好的书


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    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"

    Alreday有很多关于这个的文章,我想在这里添加一个类比。希望你以后永远不要怀疑:底线:类是通过引用传递的,而结构是通过值传递的。

    假设你和你的朋友分享了一份谷歌文档。现在,如果他改变了其中的任何东西,你也会看到你的谷歌文档上的改变,意味着你的拷贝也会受到影响。这基本上是"通过引用"。

    但是假设,如果您的机器中保存了.xls fie。你提供给你朋友的文件。如果他在那个文件中做了任何更改,你的文件不会因为你有自己的副本而被弄乱/影响。基本上就是"通过价值传递"。你已经有多个简单的程序在那里检查这个类比在快速操场。