So the basic answer for your original for
loop question is: no. The for...in
is designed to give you copies of value types. It's a forced-functional programming style as you said yourself in the comments.
To mutate an array you must say array[index]
in some fashion or another and now you're referring to the original value and can mutate it. The trick is finding an expressive way that prevents common errors. The four techniques I'm advocating below are:
- Make a powerful abstraction as an
extension
so you DRY throughout the code
- Use
indices
not a manual range which is also error prone (...
vs. ..<
)
- Avoid ugly throwbacks to C-language constructs like
&
(see #1)
- Consider keeping around the mutating version and the non-mutating version
This is probably most in keeping with the spirit of Swift, that is, quirky, verbose, and more nettlesome than you'd want, but ultimately very expressive and powerful with the proper layers in place:
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