警告 "Simultaneous accesses to parameter 'self' ..." 真的适用于此吗?
Does the warning "Simultaneous accesses to parameter 'self' ..." really apply here?
我写了一个 Array
的扩展,允许我弹出最后一个元素并立即将它添加到另一个数组:
extension Array {
mutating func popLast(to otherArray: inout [Element]) -> Element? {
guard self.count > 0 else { return nil }
return otherArray.appendAndReturn(self.popLast()!)
}
mutating func appendAndReturn(_ element: Element) -> Element {
self.append(element)
return element
}
}
playground 中的这个简单示例很有魅力:
var newNumbers = [1,2,3,4,5,6,7,8,9]
var usedNumbers: [Int] = []
newNumbers.popLast(to: &usedNumbers)
print(usedNumbers) // [9]
for _ in newNumbers {
newNumbers.popLast(to: &usedNumbers)
}
print(usedNumbers) // [9, 8, 7, 6, 5, 4, 3, 2, 1]
但是在结构内部使用扩展(警告后的代码)给了我这个警告:
Simultaneous accesses to parameter 'self', but modification requires
exclusive access; consider copying to a local variable
struct Test {
var newNumbers = [1,2,3,4,5,6,7,8,9]
var usedNumbers: [Int] = []
mutating func getNewNumber() -> Int? {
return newNumbers.popLast(to: &usedNumbers)
}
}
这只是一个警告,我的应用程序运行正常,符合预期的行为,但我很好奇这里是否真的存在危险。查看 SE-0176,我理解警告的目的,如果我要使用它从我追加它的同一个数组中弹出最后一个元素,因为写时复制可能会搞砸。所以我猜这与结构有关。但是在同一结构内的两个不同数组上使用它,我认为没有危险。 我是不是遗漏了什么,有没有办法编写可以避免潜在问题的扩展?
更新:
您的代码无需修改即可运行。
正如@Hamish 在下面的评论中指出的那样,这个 was a bug that is now fixed in the version of Swift which shipped with Xcode 9 beta 3. I also verified that it works at the IBM Swift Sandbox 使用 Linux x86_64 build Swift开发。 4.0(2017 年 7 月 13 日).
正如您在评论中发现的那样,问题是您需要独占访问该结构才能对其进行变异,但是您将对该结构的一部分的引用传递给了 inout 参数。这显然应该有效,因为您正在访问结构的不同部分,但是 due to a bug 这里的编译器太严格了。
警告建议复制到局部变量。由于您的 return 很复杂,我使用 defer
语句将 newNumbers
的副本 return 复制到 newNumbers
以避免必须存储调用结果在临时变量中:
struct Test {
var newNumbers = [1,2,3,4,5,6,7,8,9]
var usedNumbers: [Int] = []
mutating func getNewNumber() -> Int? {
var newNumbersCopy = newNumbers
defer { newNumbers = newNumbersCopy }
return newNumbersCopy.popLast(to: &usedNumbers)
}
}
您也可以选择通过复制 usedNumbers
:
来修复它
mutating func getNewNumber() -> Int? {
var usedNumbersCopy = usedNumbers
defer { usedNumbers = usedNumbersCopy }
return newNumbers.popLast(to: &usedNumbersCopy)
}
我写了一个 Array
的扩展,允许我弹出最后一个元素并立即将它添加到另一个数组:
extension Array {
mutating func popLast(to otherArray: inout [Element]) -> Element? {
guard self.count > 0 else { return nil }
return otherArray.appendAndReturn(self.popLast()!)
}
mutating func appendAndReturn(_ element: Element) -> Element {
self.append(element)
return element
}
}
playground 中的这个简单示例很有魅力:
var newNumbers = [1,2,3,4,5,6,7,8,9]
var usedNumbers: [Int] = []
newNumbers.popLast(to: &usedNumbers)
print(usedNumbers) // [9]
for _ in newNumbers {
newNumbers.popLast(to: &usedNumbers)
}
print(usedNumbers) // [9, 8, 7, 6, 5, 4, 3, 2, 1]
但是在结构内部使用扩展(警告后的代码)给了我这个警告:
Simultaneous accesses to parameter 'self', but modification requires exclusive access; consider copying to a local variable
struct Test {
var newNumbers = [1,2,3,4,5,6,7,8,9]
var usedNumbers: [Int] = []
mutating func getNewNumber() -> Int? {
return newNumbers.popLast(to: &usedNumbers)
}
}
这只是一个警告,我的应用程序运行正常,符合预期的行为,但我很好奇这里是否真的存在危险。查看 SE-0176,我理解警告的目的,如果我要使用它从我追加它的同一个数组中弹出最后一个元素,因为写时复制可能会搞砸。所以我猜这与结构有关。但是在同一结构内的两个不同数组上使用它,我认为没有危险。 我是不是遗漏了什么,有没有办法编写可以避免潜在问题的扩展?
更新:
您的代码无需修改即可运行。
正如@Hamish 在下面的评论中指出的那样,这个 was a bug that is now fixed in the version of Swift which shipped with Xcode 9 beta 3. I also verified that it works at the IBM Swift Sandbox 使用 Linux x86_64 build Swift开发。 4.0(2017 年 7 月 13 日).
正如您在评论中发现的那样,问题是您需要独占访问该结构才能对其进行变异,但是您将对该结构的一部分的引用传递给了 inout 参数。这显然应该有效,因为您正在访问结构的不同部分,但是 due to a bug 这里的编译器太严格了。
警告建议复制到局部变量。由于您的 return 很复杂,我使用 defer
语句将 newNumbers
的副本 return 复制到 newNumbers
以避免必须存储调用结果在临时变量中:
struct Test {
var newNumbers = [1,2,3,4,5,6,7,8,9]
var usedNumbers: [Int] = []
mutating func getNewNumber() -> Int? {
var newNumbersCopy = newNumbers
defer { newNumbers = newNumbersCopy }
return newNumbersCopy.popLast(to: &usedNumbers)
}
}
您也可以选择通过复制 usedNumbers
:
mutating func getNewNumber() -> Int? {
var usedNumbersCopy = usedNumbers
defer { usedNumbers = usedNumbersCopy }
return newNumbers.popLast(to: &usedNumbersCopy)
}