一、与class的不同点

age给定默许值

/**结构体*/
struct FFHobbyGirls {
    var age = 10
    func hobbyGirls() {
        print("hobbyGirls")
    }
}
var t = FFHobbyGirls()

age不给定默许值

/**结构体*/
struct FFHobbyGirls {
    var age: Int
    func hobbyGirls() {
        print("hobbyGirls")
    }
}
var t = FFHobbyGirls(age: 10)

定论:
相对于class来说,struct会主动给定初始化方法,假如是class的情况下,会报错

二、假如我们的特点有默许的初始值,那么我们的系统就不会供给默许的初始化方法了

在SIL视点来分析一下原理:
翻开项目文件夹目录

cd /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice

把 mian.swift编译成main.sil并翻开(举荐运用vs code)

swiftc -emit-sil main.swift | xcrun swift-demangle >> ./main.sil && open main.sil
No application knows how to open /Users/zhou/Desktop/SwiftTwoPractice/SwiftTwoPractice/main.sil.

来看main.sil,供给了两个初始化方法

init(age: Int = 10)
init()

struct FFHobbyGirls {
  @_hasStorage @_hasInitialValue var age: Int { get set }
  func hobbyGirls()
  init(age: Int = 10)
  init()
}

假如我自己完成了init方法

struct FFHobbyGirls {
    var age = 10
    func hobbyGirls() {
        print("hobbyGirls")
    }
    init(age:Int) {
        self.age = age
    }
}

假如是这样的话,其时编译器就不会帮我生成init方法了,再次查看main.sil

struct FFHobbyGirls {
  @_hasStorage @_hasInitialValue var age: Int { get set }
  func hobbyGirls()
  init(age: Int)
}

这个时分这里面就只有我们自己生成的初始化方法了

三、结构体是值类型

先了解什么是值类型:

  • 地址存储的就是值
  • 传递的过程中相当于传递了一个副本

比如:

func test() {
    var age = 18
    var age2 = age //设置断点 ①
    age = 30 //设置断点 ②
    age2 = 45
    print("age=\(age),age2\(age2)")
}

var age = 18
意味着在栈区声明晰一个地址来存储age变量,然后将18这个字面量给到其时的地址空间

在栈区创建的内存空间是由系统办理的
经过lldb调试来查看age的地址,这个地址很明显是个栈上的地址空间(高地址)

(lldb) po withUnsafeMutablePointer(to: &age){print($0)}
0x00007ffeefbff410
0 elements

然后对这个内存进行格局化输出,在这个内存地址里面直接存储的我们的值18(0x0000000000000012 )

(lldb) x/8g 0x00007ffeefbff410
0x7ffeefbff410: 0x0000000000000012 0x0000000000000000
0x7ffeefbff420: 0x00007ffeefbff440 0x0000000100002a14
0x7ffeefbff430: 0x00007ffeefbff468 0x0000000100015025
0x7ffeefbff440: 0x00007ffeefbff458 0x00007fff20393621

当铺开设置的断点①,停留在断点②处的时分,将age赋值给了age2,同等于我直接把age里面的值18拿出来赋值给了age2,也就是说将18赋值给了age2

相同适用lldb调试看成果:

(lldb) po withUnsafeMutablePointer(to: &age2){print($0)}
0x00007ffeefbff408
0 elements
(lldb) po withUnsafeMutablePointer(to: &age){print($0)}
0x00007ffeefbff410
0 elements

可以看出,age与age2这两个地址只差了8字节巨细,栈空间地址分配的过程中是从高到低的,这也可以认证age是存储在栈上的
然后我在格局过输出age与age2的值:

(lldb) x/8g 0x00007ffeefbff408
0x7ffeefbff408: 0x0000000000000000 0x0000000000000012
0x7ffeefbff418: 0x0000000000000000 0x00007ffeefbff440
0x7ffeefbff428: 0x0000000100002a14 0x00007ffeefbff468
0x7ffeefbff438: 0x0000000100015025 0x00007ffeefbff458
(lldb) x/8g 0x00007ffeefbff410
0x7ffeefbff410: 0x0000000000000012 0x0000000000000000
0x7ffeefbff420: 0x00007ffeefbff440 0x0000000100002a14
0x7ffeefbff430: 0x00007ffeefbff468 0x0000000100015025
0x7ffeefbff440: 0x00007ffeefbff458 0x00007fff20393621
(lldb) 

这个值也是相同的,在修正的过程中,修正的是其时独立地址里面的内存的值,也就意味着,在这个过程中,可以说age变量是一个值类型
相同的,看struct的比如:

struct FFHobbyGirls {
    var age: Int = 18
    var age2: Int = 20
}
//结构体再赋值的过程中并不会同享状况
var t = FFHobbyGirls()
print("end")

经过lldb调试查看:

(lldb) po t
▿ FFHobbyGirls
  - age : 18
  - age2 : 20
(lldb) po withUnsafeMutablePointer(to: &t){print($0)}
0x00000001000081a0
0 elements
(lldb) x/8g 0x00000001000081a0
0x1000081a0: 0x0000000000000012 0x0000000000000014
0x1000081b0: 0x0000000000000000 0x0000000000000000
0x1000081c0: 0x0000000000000000 0x0000000000000000
0x1000081d0: 0x0000000000000000 0x0000000000000000

可以看出,这个结构体的地址0x00000001000081a0中,直接存储的就是0x0000000000000012、0x0000000000000014,所以认证了结构体是值类型

注意点:尽量避免在值类型中包括引证类型