Menu
CoddyTech

变更方法

本课属于 Coddy Swift 学习旅程的“面向对象编程”单元。第 9 课,共 57 课。

会更改属性的结构体方法必须标记为 mutating。如果没有这个关键字,方法就无法编译,因为值类型的方法会将 self 视为常量:

struct Counter {
    var count = 0

    mutating func increment() {
        count += 1
    }
}

var c = Counter()
c.increment()
c.increment()
print(c.count)

输出:

2

只能对 var 调用可变方法。对 let 常量调用不会通过编译,因为整个值是固定的:

var a = Counter()
a.increment()        // 没问题

let b = Counter()
// b.increment()     // 错误:b 是 let 常量

只读取属性的方法不会修改对象,常量也可以使用这些方法。好的设计会将更改集中在少数会修改对象的方法中:

struct Stack {
    var items: [Int] = []

    mutating func push(_ x: Int) { items.append(x) }
    mutating func pop() -> Int? { items.popLast() }
    func peek() -> Int? { items.last }
}

var s = Stack()
s.push(3)
s.push(8)
print(s.pop() ?? -1)
print(s.peek() ?? -1)

输出:

8
3

变异方法可以完全替换 self,这在重置值时很方便:

struct Score {
    var points = 0
    var bonus = 0

    mutating func reset() {
        self = Score()
    }
}

var s = Score(points: 10, bonus: 3)
s.reset()
print(s.points + s.bonus)

输出:

0
challenge icon

挑战

简单

完成 Wallet 结构体。add(_:) 和 spend(_:) 是 mutating 方法:spend 只会在余额充足时扣款,并返回是否扣款成功。report() 不会修改对象,并返回 balance 40。

提供的代码会读取 +n 和 -n 命令,并将它们应用到同一个 var 钱包上。遇到拒绝的支出时,代码会打印 denied,最后打印 report()。

你的代码应写在 Wallet.swift 中。main.swift 包含提供的输入/输出代码,不能编辑。

亲手试试

// 提供的输入/输出代码:保持原样
var input: [String] = []
while let line = readLine() { input.append(line) }
var wallet = Wallet()
for cmd in input {
    let amount = Int(cmd.dropFirst())!
    if cmd.hasPrefix("+") {
        wallet.add(amount)
    } else if !wallet.spend(amount) {
        print("denied")
    }
}
print(wallet.report())
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Swift 在线编辑器