所以我一直在用 Swift 的数组做一些实验。并使用以下代码发现了一些东西:
var shoppingList = ["Chocolate", "Bread", "Cheese", "Apple"]
println(shoppingList)
shoppingList[2..<2] = ["Butter", "Milk"] //Question #1 (Insert after 2nd element)
println(shoppingList)
shoppingList[0..<0] = ["Coffee"]
println(shoppingList)
shoppingList[7..<7] = ["Berry", "ie"] //Question #2 (Append at the end of array)
println(shoppingList)
给出以下输出:
[Chocolate, Bread, Cheese, Apple]
[Chocolate, Bread, Butter, Milk, Cheese, Apple]
[Coffee, Chocolate, Bread, Butter, Milk, Cheese, Apple]
[Coffee, Chocolate, Bread, Butter, Milk, Cheese, Apple, Berry, Pie]
问题#1:试验 subscript 语法,似乎使用 ..< 将 Insert 到给定位置的数组的一个项目(在我的示例中通过 [2..<2] 位于第二个元素之后。与调用数组的 insert(_:atIndex 方法相反,这对 性能 是否有任何差异?或者取决于场景, 可读性 将只是使用 insert() 的好处?
问题#2:根据此处的 Swift 文档:Collection Type - See Modifying/Accessing Arrays
NOTE
You can’t use subscript syntax to append a new item to the end of an
array.
然后我的问题是为什么我可以使用 [7..<7] 将 2 个元素“Berry”和“Pie”附加到数组的末尾?
在撰写本文时,我正在使用 Swift 1.2。
Best Answer-推荐答案 strong>
这看起来是一个很好的问题,所以我玩了一下。
看下标与7..<7 的例子, 半开范围运算符 ..< 正在创建 Range 看起来像这样的结构:
let range = 7..<7
print(range.startIndex) // 7
print(range.endIndex) // 7
这也许是显而易见的。但是结束索引超出数组边界的范围对数组下标有什么影响?下标函数声明如下所示:
subscript (subRange: Range<Int>) -> ArraySlice<Element>
如果我们打电话
let shoppingList = ["Coffee", "Chocolate", "Bread", "Butter", "Milk", "Cheese", "Apple"]
let item = shoppingList[6..<7]
// item: ArraySlice<Int> = "Apple"
我们取回了一片“Apple”,正如您所期望的 - 我们已经要求了一片 shoppingList 包含索引为 6 或更高且索引低于 7 的元素,因此我们返回一个包含索引 6 处的单个项目的切片。
还要注意这种行为:
let item = shoppingList[6...6]
print(range.startIndex) // 6
print(range.endIndex) // 7
endIndex 实际上是 7 ,但是查看上面的下标,您不会期望任何问题,也不会得到任何问题。看待这个问题的一种方式是说 endIndex 子范围的第一个数组元素的索引不是 要包含在数组切片中。我们可以假设下标实现对此进行了边界检查。
那么这个下标的 getter 的实现会是什么样的呢?让我们试试看:
extension Array {
func myRangeSubscript(subRange: Range<Int>) -> ArraySlice<Element> {
if count < subRange.endIndex { fatalError("Out of bounds!") }
var slice = ArraySlice<Element>()
for i in subRange {
slice.append(self[i])
}
return slice
}
}
传入时7..<7 , 因为 x 不存在整数哪里7 >= x < 7 ,for 循环不会输入一次。这说明了为什么shoppingList[7..<7] 有效,尽管乍一看似乎索引超出范围。
考虑下标赋值可能是什么样子只是一小步:
subscript(subRange: Range<Int>) -> ArraySlice<Element> {
get {
//...
}
set(newElements) {
// newElements: Array<Element> = []
self.removeRange(subRange)
var elementIndex = 0
for i in subRange {
self.insert(newElements[elementIndex++], atIndex: i)
}
}
}
尽管文档另有说明,但您显然可以“附加”到数组末尾的原因可能是语义上您实际上并没有附加 - 您正在用新的元素数组替换数组中的一系列元素。碰巧的是 n..<n 范围,你用你的新数组替换一个空的元素数组。从技术上讲,也许不是追加/插入,而是相当古怪的替换!因此,虽然文档在技术上可能是正确的,但实际上他们只是不考虑这种边缘情况。
简而言之,关于性能问题,我不能肯定地说下标是如何实际实现的。但很明显,使用此范围下标执行插入至少需要与使用 insert(_:atIndex 一样长的时间。或单个索引下标(无论如何它很可能调用 insert(_:atIndex ),因为在准备 ArraySlice 时可能会有一些开销。创建,或调用 removeRange(_ .
出于这个原因,以及它的可读性较差并且没有在语义上反射(reflect)您要执行的操作的事实,我将避免使用此范围下标来插入数组项。只要坚持 insert(_:atIndex 或相应的下标 - 这就是它们的用途!
关于ios - 在 Swift 中修改数组,(通过下标语法插入和附加),我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/31872443/
|