内存访问冲突

<aside> 🦊 访问两个值时,冲突会发生的场景:

  1. 至少有一个是写访问
  2. 访问的是同一个地址
  3. 访问在时间线上部分重叠

</aside>

in-out 参数访问冲突

长期写访问期间外部访问造成的冲突

<aside> 🛀 一个函数会对它所有的 in-out 参数保持长期写访问。这种保持长期的写访问带来的问题是,你不能再访问以 in-out 形式传入的原始变量,即使作用域原则和访问权限允许——任何访问原始变量的行为都会造成冲突。

</aside>

var stepSize = 1

func increment(_ number: inout Int) {
    number += stepSize
}

increment(&stepSize)
// 错误:stepSize 访问冲突

memory_increment_2x.png

解决外部访问造成的冲突

// 显式拷贝
var stepSize = 1

func increment(_ number: inout Int) {
    number += stepSize
}

var copyOfStepSize = stepSize
increment(&copyOfStepSize)

// 更新原来的值
stepSize = copyOfStepSize
// stepSize 现在的值是 2

长期写访问多个 in-out 参数传入相同变量造成的冲突

<aside> 🥑 长期写访问的存在还会造成另一种结果,往同一个函数的多个 in-out 参数里传入同一个变量也会产生冲突。

</aside>

func balance(_ x: inout Int, _ y: inout Int) {
    let sum = x + y
    x = sum / 2
    y = sum - x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore)  // 正常
balance(&playerOneScore, &playerOneScore)
// 错误:playerOneScore 访问冲突

<aside> 🐭 因为操作符也是函数,它们也会对 in-out 参数进行长期写访问。例如,假设 balance(_:_:) 是一个名为 <^> 的操作符函数,那么 playerOneScore <^> playerOneScore 也会造成像 balance(&playerOneScore, &playerOneScore) 一样的冲突。

</aside>

值类型可变方法中对 self 访问的冲突