什么是 Swift 中的切片,它与数组有何不同?
从文档中, subscript(Range) 的类型签名是:
subscript(Range<Int>) -> Slice<T>
为什么不返回另一个 Array<T>
而不是 Slice<T>
?
看起来我可以将切片与数组连接起来:
var list = ["hello", "world"]
var slice: Array<String> = [] + list[0..list.count]
但这会产生错误:
找不到接受提供的参数的“下标”的重载
var list = ["hello", "world"]
var slice: Array<String> = list[0..list.count]
什么是切片?
切片指向数组。当数组已经存在并且切片可以描述它的所需部分时,没有必要再创建一个数组。
添加会导致隐式强制,因此它可以工作。为了使您的任务有效,您需要强制:
var list = ["hello", "world"]
var slice: Array<String> = Array(list[0..<list.count])
注意:这个答案在 Swift beta 3 中是无效的,因为数组现在是真值类型。
@matt 是正确的,上面 - Slice<T>
指向数组。这似乎与 Swift 处理我们正在使用的所有其他数据类型的方式相反,因为这意味着切片的值可以改变,即使它被声明为常量:
var arr = ["hello", "world", "goodbye"] // ["hello", "world", "goodbye"]
let slice = arr[0..2] // ["hello", "world"]
arr[0] = "bonjour"
println(slice) // ["bonjour", "world"]
最糟糕的是,切片就像一个数组。鉴于在 Swift 中我们期望不变性,切片的下标值可以在没有警告的情况下更改似乎很危险:
println(slice[1]) // "world"
arr[1] = "le monde"
println(slice[1]) // "le monde"
但如果底层数组变化太大,它们就会脱钩:
arr.removeAtIndex(0) // this detaches slice from arr
println(slice) // ["bonjour", "le monde"]
arr[0] = "hola"
println(slice) // ["bonjour", "le monde"]
let arr = ["hello", "world", "goodbye"]; arr[0] = "bonjour"
。你会发现它有效。奇怪的是,对于不可变数组,只有 size 是不可变的,而不是内容。 (参见The Swift Programming Language中的“集合的可变性”)
概括:
上面的答案在 Beta 3 之前都是正确的(并且可能在未来的版本中再次更改)
Slice 现在的行为就像一个数组,但正如上面@matt 所说,实际上是对底层数组的浅拷贝,直到进行更改。切片(现在)看到原始值的快照,
另请注意,切片语法已更改:
[from..upToButNotIncluding] -> [from..<upToButNotIncluding]
例子:
var arr = ["hello", "world", "goodbye"] // ["hello", "world", "goodbye"]
var arrCopy = arr
let slice = arr[0..<2] // ["hello", "world"]
arr[0] = "bonjour"
arr // ["bonjour", "world", "goodbye"]
arrCopy // ["hello", "world", "goodbye"]
slice // ["hello", "world"]
这允许更统一的处理,因为执行 python 样式列表处理更简单(恕我直言) - 过滤一个列表以制作另一个列表。根据马特在 Beta 3 之前的回答,您必须创建一个临时数组才能映射切片。新代码现在更简单了:
class NameNumber {
var name:String = ""
var number:Int = 0
init (name:String, number:Int) {
self.name = name
self.number = number
}
}
var number = 1
let names = ["Alan", "Bob", "Cory", "David"]
let foo = names[0..<2].map { n in NameNumber(name:n, number:number++) }
foo // [{name "Alan" number 1}, {name "Bob" number 2}]
(虽然公平地说, foo 仍然是一片)
参考:
重要更改,已解决的问题,- Swift 语言,第 1 段
“Swift 中的数组已经完全重新设计,具有完整的值语义,如 Dictionary 和 String...m”