Swift for in - 获取条目作为参考
Swift for in - get entries as reference
有没有办法让 for .. in
循环 return references 到集合的条目而不是 copies?
假设我有一个包含 CGPoint
个对象的数组 points
,我想遍历它们并将每个点传递给一个函数 adjustPoint
,该函数可以使用 inout
参数。
现在执行以下操作不起作用,因为 for .. in
循环 return 点是不可变/可变的(取决于我是否使用 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]
,现在您指的是 original 值和 can 变异它。诀窍是找到一种可以防止常见错误的表达方式。我在下面提倡的四种技术是:
- 做一个强大的抽象作为
extension
这样你就可以在整个代码中 DRY
- 使用
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 { [=10=].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([=10=]) }
// outputs (10.5, 11.5)
let adjustedPoints = points.adjustBy(amount: 7.5) // Original unchanged
有没有办法让 for .. in
循环 return references 到集合的条目而不是 copies?
假设我有一个包含 CGPoint
个对象的数组 points
,我想遍历它们并将每个点传递给一个函数 adjustPoint
,该函数可以使用 inout
参数。
现在执行以下操作不起作用,因为 for .. in
循环 return 点是不可变/可变的(取决于我是否使用 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]
,现在您指的是 original 值和 can 变异它。诀窍是找到一种可以防止常见错误的表达方式。我在下面提倡的四种技术是:
- 做一个强大的抽象作为
extension
这样你就可以在整个代码中 DRY - 使用
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 { [=10=].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([=10=]) }
// outputs (10.5, 11.5)
let adjustedPoints = points.adjustBy(amount: 7.5) // Original unchanged