Swift中结构体中的属性可以直接被修改吗?

521 阅读2分钟

在 Swift 中,结构体(struct)是值类型,这意味着当你创建一个结构体的实例时,该实例会被复制。默认情况下,值类型的实例是不可变的,即你不能在方法内部直接修改结构体的属性。然而,Swift 提供了 mutating 关键字来允许在方法内部修改结构体的属性。下面详细解释为什么需要 mutating 关键字以及它是如何工作的。

为什么需要 mutating 关键字

  1. 值类型的不可变性

    • 结构体是值类型,意味着它们在赋值或传递时会被复制。因此,当你通过常量(let)声明一个结构体实例时,该实例是不可变的,你不能修改其属性。
    • 即使通过变量(var)声明的结构体实例,方法内部默认也是不可变的,除非你使用 mutating 关键字。
  2. 方法内的自我修改

    • 在方法内部,self 是一个不可变的常量,这意味着你不能直接修改 self 或其属性。
    • mutating 关键字告诉编译器,这个方法会修改 self 或其属性,从而允许在方法内部进行修改。

mutating 关键字的工作原理

  1. 方法签名

    • 当你在一个结构体中定义一个方法时,如果该方法需要修改结构体的属性,你需要在方法前加上 mutating 关键字。
  2. 内部行为

    • mutating 方法内部,self 变成一个可变的变量,允许你修改其属性。
    • 如果方法返回一个新的结构体实例,self 会被替换为新的实例。

示例

没有 mutating 关键字的情况

struct User {
    var name: String
    var age: Int

    func changeName(newName: String) {
        name = newName // 编译错误:Cannot assign to property: 'self' is immutable
    }
}

var user = User(name: "Alice", age: 30)
user.changeName(newName: "Bob")

使用 mutating 关键字

struct User {
    var name: String
    var age: Int

    mutating func changeName(newName: String) {
        name = newName // 允许修改
    }

    mutating func changeAge(newAge: Int) {
        age = newAge // 允许修改
    }
}

var user = User(name: "Alice", age: 30)
user.changeName(newName: "Bob")
user.changeAge(newAge: 35)

print(user.name) // 输出: Bob
print(user.age)  // 输出: 35

常量实例和 mutating 方法

即使结构体实例是通过常量(let)声明的,也不能调用 mutating 方法,因为常量实例是不可变的。

let user = User(name: "Alice", age: 30)
// user.changeName(newName: "Bob") // 编译错误:Cannot use mutating member on immutable value: 'user' is a 'let' constant

总结

  • 值类型的不可变性:结构体是值类型,默认情况下是不可变的。
  • mutating 关键字:允许在方法内部修改结构体的属性,通过在方法前加上 mutating 关键字来实现。
  • mutating 关键字提高了代码的可读性和可维护性,确保在常量实例上调用方法时不会意外地修改结构体的状态。