Swift 结构体

163 阅读3分钟

简介

结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,可以定义属性(存储属性,可以是常量、变量)和添加方法。

结构体是值类型

在 Swift 标准库中,绝大多数的公开类型都是结构体,比如Bool、Int、Double、 String、Array、Dictionary 等常见类型都是结构体。

语法

定义

通过关键字 struct 来定义结构体:

struct nameStruct { 
   def 1
   def 2
   ...
   
   method 1
   method 2
   ...
}

示例:Time 结构体,定义了三个存储属性和一个方法

struct Time {
    var hour: Int
    var minute: Int
    var second: Int
    
    func showTime() {
        print("\(hour):\(minute):\(second)")
    }
}

使用

所有的结构体都有一个编译器自动生成的初始化器(initializer,初始化方法、构造器、构造方法) ,编译器会根据情况,可能会为结构体生成多个初始化器,宗旨是:保证所有成员都有初始值

当定义结构体时,如果其中的属性没有初始化,则在初始化结构体时,没初始化过的属性为必传参数。

例如上面的 Time 结构体,定义中没有初始化 hour、minute、second,则在调用结构体初始化器的时候,三个参数均为必传参数,否则异常:

当将 minute、second 定义时初始化赋值,则在调用结构体初始化器时,hour 必传,minute、second 可选,因此 time0、time1、time2 是正确的,time3 异常

上面调用的是结构体自动生成的初始化构造器,同样我们也可以自定义初始化器。
当然,一旦我们自定义了初始化器,,编译器就不会再帮它自动生成其它的初始化器。

同样的原则:自定义的初始化器,也要能确保所有成员都有初始值,否则异常。 如:

自定义初始化器,保证 hour 能被初始化:

struct Time {
    var hour: Int
    var minute: Int = 0
    var second: Int = 0
    
    init(h: Int, m: Int, s: Int) {
        self.hour = h
        self.minute = m
        self.second = s
    }
    
    func showTime() {
        print("\(hour):\(minute):\(second)")
    }
}

var time3 = Time(h: 23, m: 59, s: 59);

初始化器的本质

struct Time {
    var hour: Int = 23
    var minute: Int = 59
    var second: Int = 59
}

var time = Time()

等价于:

struct Time {
    var hour: Int
    var minute: Int
    var second: Int
    init() {
        hour = 23
        minute = 59
        second = 59
    }
}

var time = Time()

分别 debug 调试,上面两种情况的汇编代码是一模一样的

结构体内存布局

结构体实际使用内存为结构体各成员字节长度之和,当然实际分配的内存还需根据内存对齐参数值得到。

struct Time {
    var hour: Int = 23
    var minute: Int = 59
    var second: Int = 59
    
}

print("实际使用: ",MemoryLayout<Time>.size)
print("实际分配: ",MemoryLayout<Time>.stride)
print("对齐值: ",MemoryLayout<Time>.alignment)

控制台打印信息:

实际使用:  24
实际分配:  24
对齐值:  8

结构体类型为值类型:

struct Time {
    var hour: Int = 23
    var minute: Int = 59
    var second: Int = 59
    
}

var time1 = Time()
print("赋值前time1-\(time1.hour):\(time1.minute):\(time1.second)")
var time2 = time1
time2.minute = 23
time2.second = 23
print("赋值并变更后time1-\(time1.hour):\(time1.minute):\(time1.second)")
print("赋值并变更后time2-\(time2.hour):\(time2.minute):\(time2.second)")

输出信息:

赋值前time1-23:59:59
赋值并变更后time1-23:59:59
赋值并变更后time2-23:23:23

可以看到当将 time1 直接赋值给 time2 后,修改 time2,并不会对 time1 产生影响。