美文网首页
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