我想创建一个迭代数组(或集合或序列)的函数。然后我将用一个数组调用该函数,并调用该数组的反转版本(但效率很高:没有创建一个新数组来保持反向)。
如果我这样做:
func doIteration(points: [CGPoint]) {
for p in points {
doSomethingWithPoint(p)
}
// I also need random access to points
doSomethingElseWithPoint(points[points.count-2]) // ignore obvious index error
}
如果我有这个:
let points : [CGPoint] = whatever
我可以做得很好:
doIteration(points)
但是如果我这样做的话:
doIteration(points.reverse())
我得到'无法转换类型的值'ReverseRandomAccessCollection< [CGPoint]>预期参数类型[_]'
现在,我不想这样做:
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
即使它会起作用,因为那会(如果我错了就纠正我)创建一个新数组,从reverse()返回的ReverseRandomAccessCollection初始化它。
所以我想我想编写我的doIteration函数来获取某种序列类型,所以我可以直接传递reverse()的结果,但是ReverseRandomAccessCollection根本不符合任何东西。我想我错过了什么 - 这里接受的模式是什么?
答案 0 :(得分:2)
如果您将参数的类型更改为通用类型,则应获得所需的功能:
func doIteration
<C: CollectionType where C.Index: RandomAccessIndexType, C.Generator.Element == CGPoint>
(points: C) {
for p in points {
doSomethingWithPoint(p)
}
doSomethingElseWithPoint(points[points.endIndex - 2])
}
更重要的是,这个不会导致数组的副本。如果查看reverse()
方法生成的类型:
let points: [CGPoint] = []
let reversed = points.reverse() // ReverseRandomAccessCollection<Array<__C.CGPoint>>
doIteration(reversed)
你会看到它只是创建了一个引用原始数组的结构。 (虽然它确实有值类型语义)并且由于正确的通用约束,原始函数可以接受这个新集合。
答案 1 :(得分:0)
你可以这样做
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
或者
doIteration(points.reverse() as [CGPoint])
但我不认为足迹的观点存在任何真正的差异。
let reversedPoints : [CGPoint] = points.reverse()
doIteration(reversedPoints)
实际上,在这种情况下,会创建一个包含引用的新数组到原始数组中的CGPoint(s)
。这要归功于Swift用于管理结构的写时复制机制。
所以分配的内存如下:
points.count * sizeOf(指针)
另一方面,你可以写这样的东西
doIteration(points.reverse() as [CGPoint])
但你真的在挽救记忆吗?让我们来看看。
创建一个临时变量,该变量在函数doIteration
的范围内 可用,并且只需要points
中包含的每个元素的指针,所以我们再次:
points.count * sizeOf(指针)
所以我认为您可以安全地选择其中一种解决方案。
我们应该记住,Swift以非常聪明的方式管理结构。
写作时
var word = "Hello"
var anotherWord = word
在第一行Swift创建一个Struct并用值“Hello”填充它。
在第二行,Swift检测到没有真正的理由来创建原始String的副本,因此在anotherWord
内写入对原始值的引用。
只有在修改word
或anotherWord
时,Swift才会真正创建原始值的副本。