有没有办法让 for .. in
循环返回对集合条目的引用而不是副本?
假设我有一个 CGPoint
对象的数组 points
,我想遍历它们并将每个点传递给一个函数 adjustPoint
,它可以使用 inout
参数修改点。
现在执行以下操作不起作用,因为 for .. in
循环将点返回为不可变/可变(取决于我是否使用 var
)数组中实际点的副本:
for var point in points {
adjustPoint(point: &point) // This function only changes the copy
}
目前,我看到的唯一方法是遍历索引:
for i in 0..<points.count {
adjustPoint(point: &points[i])
}
这真的是唯一的方法吗?还是可以使用 for .. in
循环?
注意:我读过很久以前的这个问题(我相信是 Swift 1)所以我想也许他们同时改变了一些东西:turn for in loops local variables into mutable variables
最佳答案
所以你原来的基本答案 for
循环问题是:没有。 for...in
旨在为您提供值类型的副本。正如您在评论中所说,这是一种强制函数式编程风格。
要改变一个数组,你必须说 array[index]
以某种方式,现在您指的是原始值并且可以改变它。诀窍是找到一种可以防止常见错误的表达方式。我在下面提倡的四种技术是:
- 做一个强大的抽象
extension
所以你在整个代码中干 - 使用
indices
不是手动范围,也容易出错(...
与..<
) - 避免像
&
这样丑陋的 C 语言结构(见#1) - 考虑保留变异版本和非变异版本
这可能最符合 Swift 的精神,即古怪、冗长且比您想要的更烦人,但最终在适当的层到位的情况下非常具有表现力和功能:
import Foundation
import CoreGraphics
protocol Pointy {
var x: CGFloat { get set }
var y: CGFloat { get set }
func adjustBy(amount: CGFloat) -> CGPoint
mutating func adjustInPlace(amount: CGFloat) -> Void
}
extension CGPoint: Pointy {
func adjustBy(amount: CGFloat) -> CGPoint {
return CGPoint(x: self.x + amount, y: self.y + amount)
}
mutating func adjustInPlace(amount: CGFloat) -> Void {
x += amount
y += amount
}
}
extension Array where Element: Pointy {
func adjustBy(amount: CGFloat) -> Array<Pointy> {
return self.map { $0.adjustBy(amount: amount) }
}
mutating func adjustInPlace(amount: CGFloat) {
for index in self.indices {
// mysterious chunk of type calculus: need "as! Element" -- https://forums.developer.apple.com/thread/62164
self[index].adjustInPlace(amount: amount) // or self[index] = (self[index].adjustBy(amount: amount)) as! Element
}
}
}
// Hide the above in a Util.swift that noone ever sees.
// AND NOW the true power shows
var points = [ CGPoint(x: 3.0, y: 4.0) ]
points.adjustInPlace(amount: 7.5)
points.forEach { print($0) }
// outputs (10.5, 11.5)
let adjustedPoints = points.adjustBy(amount: 7.5) // Original unchanged
关于Swift for in - 获取条目作为引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39707845/