Swift中的切片是什么?


85

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]

什么是切片?

Answers:


97

切片指向数组。当数组已经存在并且切片只能描述其所需部分时,再也没有必要制作另一个数组。

加法会导致隐式强制,因此可以正常工作。为了使您的作业正常进行,需要强制执行以下操作:

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

那讲得通。在文档的任何地方都有描述吗?
hjing

2
确实,这是一个实现细节。您巧妙地探查了揭示黑匣子工作原理的表壳……!
马特2014年

2
切片实际上是数组的副本。更新原始阵列后,切片将不会更改。这是由于结构性质。而对于音符,可切片的协议并不意味着片类型的用法
马辛

4
雨燕的语言已经改变和切片实际使用三个省略号而不是两个developer.apple.com/library/ios/documentation/General/Reference/...
丹尼尔Galasko

7
如果您添加了一个简单的编辑通知新读者范围运算符已更改,这不会破坏对应关系吗?
Daniel Galasko 2015年

22

注意:由于数组现在是真实的值类型,因此从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中我们对不可变性有一个期望,因此可以在没有警告的情况下更改slice的下标值似乎很危险:

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

6
事实上,片工作只是像阵列,就像你说的。Swift数组具有可变元素,即使它们被声明为不可变的。例如,尝试let arr = ["hello", "world", "goodbye"]; arr[0] = "bonjour"。您会发现它有效。奇怪的是,对于不可变数组,只有大小是不可变的,而不是内容。(请参见Swift编程语言“集合的可变性” )
Matt Gibson 2014年

1
“易变的元素” -这不再是真实的
亚历克斯·布朗

14

概要:

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

这允许更统一的处理,因为更简单(IMHO)进行python样式列表处理-过滤一个列表以制作另一个列表。根据Beta 3之前Matt的回答,您必须创建一个临时数组才能映射切片。现在,新代码更加简单:

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仍然是一个片段)

参考:

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

重要更改,已解决的问题,-Swift语言,第1段

“ Swift中的数组已被完全重新设计,以具有字典和String ... m等全值语义。”

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.