Swift 结构体

作者: LiYaoPeng | 来源:发表于2018-03-26 16:50 被阅读0次

    对 Swift 学习 的一些总结
    学习文献:
    Chris Eidhof. “Swift 进阶”

    类与结构体的主要不同点

    • 语义:

    类:引用类型(引用语义),需要自己管理其引用计数、引用值得变化
    结构体: 值类型(值语义),在设计结构体时,我们可以要求编译器保证不可变性。

    • 内存管理方式:

    类:类的实例只能通过引用来间接地访问。类能有很多个持有者。
    结构体:可以被直接持有及访问,不会被引用,但是会被复制。也就是说,结构体的持有者是唯一的。

    • 共享代码:

    类: 通过继承来共享代码
    结构体 (以及枚举):不能被继承。想要在不同的结构体或者枚举之间共享代码,我们需要使用不同的技术,比如像是组合、泛型以及协议扩展等。

    值类型

    值永远不会改变,它们具有不可变的特性。这 (在绝大多数情况下) 是一件好事,因为使用不变的数据可以让代码更容易被理解。不可变性也让代码天然地具有线程安全的特性,因为不能改变的东西是可以在线程之间安全地共享的。

    值语义

    1. 结构体不能通过引用来进行比较,只能通过它们的属性来比较两个结构体。虽然可以用 var 来在结构体中声明可变的变量属性,但是这个可变性只体现在变量本身上,而不是指里面的值。改变一个结构体变量的属性,在概念上来说,和为整个变量赋值一个全新的结构体是等价的。我们总是使用一个新的结构体,并设置被改变的属性值,然后用它替代原来的结构体。
    2. 结构体只有一个持有者。比如,当我们将结构体变量传递给一个函数时,函数将接收到结构体的复制,它也只能改变它自己的这份复制。这叫做值语义 (value semantics) (又作复制语义)

    引用语义

    类对象会拥有很多持有者,这被叫做引用语义 (reference semantics)。

    结构体

    结构体为值类型

    值类型意味着一个值变量被复制时,这个值本身也会被复制,而不只限于对这个值的引用的复制。在几乎所有的编程语言中,标量类型都是值类型。这意味着当一个值被赋给新的变量时,并不是传递引用,而是进行值的复制。

    let a = 12
    let b = a 
    a += 1 
    print (a) // 13
    print (b) // 12
    b的值没有根据a的值进行改变
    

    结构体的赋值 特点

    1. 定义结构体 PY_Point 它里面有一个 let x = 12, 以及var y, 可以比较 y是否大于x
       struct PY_Point {
            let x = 12
            var y = 0
            func isReaterThanX() -> Bool {
                return y > x
            }
        }
    
    1. 赋值: 下面打印结果表示 两个结构体已经不是同一个结构体了。发生了复制现象。
           var point = PY_Point(y: 13)
            var pointTemp = point
        
            withUnsafePointer(to: &point) { pointAddress in
                print("point 地址: \(pointAddress)")
            }
            withUnsafePointer(to: &pointTemp) {pointTempAddress in
                print("pointTemp 地址: \(pointTempAddress)")
            }
            /**
             point 地址: 0x00007ffeec4d7a00
             pointTemp 地址: 0x00007ffeec4d7a10
             */
    
    1. 结构体(值类型)内部赋值:

    可以看到,多次调用了didSet 方法,但是pointTemp的地址没有改变
    “理解值类型的关键就是理解为什么这里会被调用。对结构体进行改变,在语义上来说,与重新为它进行赋值是相同的。当我们改变了结构体中某个深层次的属性时,其实还是意味着我们改变了结构体,所以 didSet 依然会被触发。
    虽然语义上来说,我们将整个结构体替换为了新的结构体,但是编译器依然会原地进行变更。由于这个结构体没有其他所有者,实际上我们没有必要进行复制。不过如果有多个持有者的话,重新赋值意味着发生复制。对于写时复制的结构体,工作方式会略有不同

       var pointTemp: PY_Point? = PY_Point(y: 13) {
            didSet {
                print("pointTemp didSet 调用了")
            }
        }
     func valuation() {
        withUnsafePointer(to: &pointTemp) {pointTempAddress in
                print("pointTemp 地址: \(pointTempAddress)")
            }
            pointTemp?.y = -1
            withUnsafePointer(to: &pointTemp) {pointTempAddress in
                print("pointTemp 地址: \(pointTempAddress)")
            }
        }
    //调用valuation()打印结果为 
    /**
    pointTemp 地址: 0x00007ffee9379a00
    pointTemp didSet 调用了
    pointTemp didSet 调用了
    pointTemp 地址: 0x00007ffee9379a00
    pointTemp didSet 调用了
    */
    

    结构体内建方法

    1. 结构体可以添加方法 ,比如比较x,y大小的方法
    struct PY_Point {
            let x = 12
            var y = 0
            func isReaterThanX() -> Bool {
                return y > x
            }
        }
    
    1. 结构体方法中修改自身的属性值

    编译器自动补充了关键词 mutating
    对不可变x属性,提示了Left side of mutating operator isn't mutable: 'x' is a 'let' constant (x为let 修饰,值不能被修改)

    extension PY_Point {
        mutating func y_offset1() {
            y += 1
        }
    
        mutating func x_offset1() {
    ///报错 Left side of mutating operator isn't mutable: 'x' is a 'let' constant
            x += 1
        }
    }
    

    mutating / inout关键词

    • inout: 函数中,我们可以将参数标记为 inout 来使其可变。就和一个普通的参数一样,值被复制并作为参数被传到函数内。不过,我们可以改变这个复制 (就好像它是被 var 定义的一样)。然后当函数返回时,原来的值将被覆盖掉。
    postfix func ++ (left: inout CGFloat) {
        left += 1
    }
     var a:CGFloat = 1
            a++ 
            print(a)
    // 打印结果为 2.0
    
    • mutating: 函数体内部你可以随时使用 self。如果我们想要改变 self,或是改变 self 自身或者嵌套的 (比如 self.y) 任何属性,我们就需要将方法标记为 mutating.mutating 将隐式的 self 参数变为可变的,并且改变了这个变量的值。
    • mutating 其实和inout做了同样的事情,它将隐式的 self 参数变为可变的,并且改变了这个变量的值

    写时复制

    在 Swift 标准库中, Array、Dictionary、 Set 这样的集合类型是通过一种叫做写时复制 (copy-on-write) 的技术实现的。
    请参考 Swift 写时复制

    相关文章

      网友评论

        本文标题:Swift 结构体

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