美文网首页
Swift5.1学习随笔之结构体struct

Swift5.1学习随笔之结构体struct

作者: SAW_ | 来源:发表于2020-04-14 11:15 被阅读0次

结构体

Swift标准库中,绝大多数的公开类型都是结构体,而枚举和类只占很小一部分
比如BoolIntDoubleStringArrayDictionary等常见的类型都是接头体

我们可以自定义结构体,举个例子🌰:

struct Date {
    var year: Int
    var month: Int
    var day: Int
}
//创建一个结构体变量,带有三个成员值
var date = Date(year: 2020, month: 4, day: 14)

所有的结构体都有一个编译器自动生成的初始化器(initializer,初始化方法、构造器、构造方法)
比如调用var date = Date(year: 2020, month: 4, day: 14),可以传入所有成员值,用来初始化所有成员(存储属性,Stroed Property)

结构体的初始化器

编译器会根据情况,可能会为结构体生成多个初始化器,宗旨是:保证所有成员都要初始值

struct Point {
    var x: Int
    var y: Int
}
var p1 = Point(x: 10, y: 10) //正确
var p2 = Point(x: 10) //报错:Missing argument for parameter 'y' in call
var p3 = Point(y: 10) //报错:Missing argument for parameter 'x' in call
var p4 = Point() //报错:Missing arguments for parameters 'x', 'y' in call
struct Point {
    var x: Int = 0
    var y: Int
}
var p1 = Point(x: 10, y: 10) //正确
var p2 = Point(x: 10) //报错:Missing argument for parameter 'y' in call
var p3 = Point(y: 10) //正确,因为x有初始值为0
var p4 = Point() //报错:Missing arguments for parameters 'x', 'y' in call
struct Point {
    var x: Int
    var y: Int = 0
}
var p1 = Point(x: 10, y: 10) //正确
var p2 = Point(x: 10) //正确,因为y有初始值0
var p3 = Point(y: 10) //报错:Missing argument for parameter 'x' in call
var p4 = Point() //报错:Missing arguments for parameters 'x', 'y' in call
struct Point {
    var x: Int = 10
    var y: Int = 10
}
var p1 = Point(x: 10, y: 10) //正确
var p2 = Point(x: 10) //正确,因为y有初始值0
var p3 = Point(y: 10) //正确,因为x有初始值0
var p4 = Point() //正确,因为x、y都有初始值0

下面这种写法可以通过吗?

struct Point {
    var x: Int?
    var y: Int?
}
var p1 = Point(x: 10, y: 10)
var p2 = Point(x: 10)
var p3 = Point(y: 10)
var p4 = Point()

解析:可以通过编译,因为可选项有初始值为nil,满足条件。

自定义初始化器

一旦在定义结构体的时候自定义了初始化器,编译器级不会自动帮它生产初始化器

虽然x、y都有初始化值0,但是用户自定义了初始化器,所有只有第一个初始化例子正确

struct Point {
    var x: Int = 0
    var y: Int = 0
    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}
var p1 = Point(x: 10, y: 10) //正确,满足需要两个参数
var p2 = Point(x: 10) //报错:Missing argument for parameter 'y' in call
var p3 = Point(y: 10) //报错:Missing argument for parameter 'y' in call
var p4 = Point() //Missing arguments for parameters 'x', 'y' in call

窥探初始化器的本质

struct Point {
    var x: Int = 0
    var y: Int = 0
}
var p = Point()
//上下两段结构体代码是等效的
struct Point {
    var x: Int
    var y: Int
    init() {
        x = 0
        y = 0
    }
}
var p = Point()

我们可以通过汇编来查看编译器实现跟自己实现是否有差别
先看第1段代码的汇编实现:




再看第2段代码的汇编实现:



你会发现它们两最终的汇编代码一模一样,连内存地址都一致,包括xy的赋值步骤,所以说明了自己实现的初始化器跟编译器自动生成的是样的,两个方法是等效的。

结构体的内存结构

struct Point {
    var x: Int = 0
    var y: Int = 0
}
var p = Point()

上面代码结构体变量p内存需要占用多少字节?
通过MemoryLayout来看看:

print(MemoryLayout<Point>.size) //16
print(MemoryLayout<Point>.stride) //16
print(MemoryLayout<Point>.alignment) //8

Point结构体变量需要16个字节,其中8字节个用来给x,8个字节用来给y,结构体内部成员的内存地址是挨在一起的。
通过一个第三方内存工具Mems来看看p内部16个字节内容的排列:

struct Point1 {
    var x: Int = 10
    var y: Int = 20
}
var p1 = Point1()
print(Mems.memStr(ofVal: &p1))
//通过第三方内存工具,可以看出内部16个字节的排列
//0x000000000000000a 0x0000000000000014

再看一个例子🌰:

struct Point2 {
    var x: Int = 0
    var y: Int = 0
    var origin: Bool = false //Bool占用1个字节
}
var p2 = Point2()
print(MemoryLayout<Point2>.size) //17
print(MemoryLayout<Point2>.stride) //24
print(MemoryLayout<Point2>.alignment) //8

Bool占用1个字节,所以Point2只需要17个字节就能存储三个成员,但是由于内存对齐是8倍数,所有最终需要占用24个字节

struct Point2_2 {
    var x: Int = 10
    var y: Int = 20
    var b: Bool = true
}
var p2_2 = Point2_2()
print(Mems.memStr(ofVal: &p2_2))
//通过第三方内存工具,可以看出内部24个字节的排列
//0x000000000000000a 0x0000000000000014 0x0000000000000001

相关文章

网友评论

      本文标题:Swift5.1学习随笔之结构体struct

      本文链接:https://www.haomeiwen.com/subject/hgqzmhtx.html