2016-09-26 70 views
-1

有没有一种方法,使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循环?

注:我读过这个问题,这是前一段时间(1斯威夫特我相信),所以我想,也许他们已经在此期间改变的东西:turn for in loops local variables into mutable variables

+0

也许你可以尝试将它们包装在一个班级中。 – dasdom

+2

为什么不使用地图?您将创建副本,但是'points = points.map {adjustPoint(point:$ 0)}'将会执行此操作。 – jjatie

+0

是的,我想功能方法是下一个最好的选择,并保持干净的东西,但我仍然不喜欢这样的事实,即斯威夫特使它很烦人,正确地使用引用,相反,你有所有这些“一次性 - 使用一次性“可变副本躺在无处不在。这可能只是个人偏好,但... – Keiwan

回答

3

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

变异数组你一定要说以某种方式或其他array[index],现在你指的是价值可以变异它。诀窍是找到一种可以防止常见错误的表达方式。这四个技巧,我下面提倡是:

  1. 做一个强大的抽象作为extension所以你干整个代码
  2. 使用indices不是手动量程这也容易出错(.....<
  3. 避免难看的返祖到C语言的结构,如&(见#1)
  4. 考虑周围的变异版本和非变异版本保持

这可能是最符合雨燕的精神,也就是离奇的,啰嗦了,更恼人的比你想要的,但最终极具表现力和强大的使用适当的图层到位:

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