斯威夫特的片子是什么?

Swift 中的切片是什么? 它与数组有什么不同?

根据文档,下标(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]

什么是切片?

38859 次浏览

The slice points into the array. No point making another array when the array already exists and the slice can just describe the desired part of it.

The addition causes implicit coercion, so it works. To make your assignment work, you would need to coerce:

var list = ["hello", "world"]
var slice: Array<String> = Array(list[0..<list.count])

Note: This answer is happily invalid as of Swift beta 3, since arrays are now true value types.


@matt is correct, above - the Slice<T> points into the array. That seems contrary to the way Swift handles all the other data types we're working with, since it means the value of the slice can change even if it's declared as a constant:

var arr = ["hello", "world", "goodbye"]    // ["hello", "world", "goodbye"]
let slice = arr[0..2]                      // ["hello", "world"]
arr[0] = "bonjour"
println(slice)                             // ["bonjour", "world"]

The worst part is that the slice acts just like an array. Given that in Swift we have an expectation of immutability it seems dangerous that the subscripted values of the slice can change without warning:

println(slice[1])                          // "world"
arr[1] = "le monde"
println(slice[1])                          // "le monde"

But if the underlying array changes too drastically, they get unhooked:

arr.removeAtIndex(0)                       // this detaches slice from arr
println(slice)                             // ["bonjour", "le monde"]
arr[0] = "hola"
println(slice)                             // ["bonjour", "le monde"]

Summary:

The answers above were true up until Beta 3 (and may change again in future releases)

Slice now acts just like an array, but as @matt said above, is effectively a shallow copy to an array under the hood, until a change is made. Slices (now) see a snapshot of the original values,

Also note that slice syntax has changed:

[from..upToButNotIncluding] -> [from..<upToButNotIncluding]

Example:

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"]

This allows much more uniform processing, as it is simpler (IMHO) to do python style list processing - filtering one list to make another. per Matt's answer prior to Beta 3, you had to create a temporary array in order to map a slice. The new code is now simpler:

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}]

(though to be fair, foo is still a slice)

Reference:

http://adcdownload.apple.com//Developer_Tools/xcode_6_beta_3_lpw27r/xcode_6_beta_3_release_notes__.pdf

Important Changes, Issues Resolved, - Swift Language, Paragraph 1

"Array in Swift has been completely redesigned to have full value semantics like Dictionary and String...m"