Swift for in - get条目作为参考

Kei*_*wan 3 for-loop pass-by-reference swift

有没有办法让for .. in循环返回集合条目的引用而不是副本

假设我有一个对象数组points,CGPoint我想循环它们并将每个点传递给一个adjustPoint可以使用inout参数修改点的函数.

现在执行以下操作不起作用,因为for .. in循环将点返回为不可变/可变(取决于我是否使用var)数组中实际点的副本:

for var point in points {
    adjustPoint(point: &point)  // This function only changes the copy
}
Run Code Online (Sandbox Code Playgroud)

目前,我认为这样做的唯一方法是遍历索引:

for i in 0..<points.count {
    adjustPoint(point: &points[i])
}
Run Code Online (Sandbox Code Playgroud)

这真的是唯一的方式,还是for .. in循环可能?

注意:我已经阅读了很久以前的这个问题(我相信Swift 1)所以我想也许他们在此期间改变了一些东西:将循环局部变量转换为可变变量

Bas*_*Zen 7

因此,原始for循环问题的基本答案是:不.本for...in是为了给你值类型的副本.正如你在评论中所说的那样,这是一种强制功能的编程风格.

要改变一个数组,你必须array[index]以某种方式说出来,现在你指的是原始值,并且可以改变它.诀窍是找到一种可以防止常见错误的表达方式.我在下面提倡的四种技术是:

  1. 做一个强大的抽象,extension让你在整个代码中干掉
  2. indices不要使用也容易出错的手动范围(...vs. ..<)
  3. 避免像C语言结构那样丑陋的回归&(参见#1)
  4. 考虑保持变异版本和非变异版本

这可能最符合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
Run Code Online (Sandbox Code Playgroud)