Swift 中的切片是啥?

Posted

技术标签:

【中文标题】Swift 中的切片是啥?【英文标题】:What is a slice in Swift?Swift 中的切片是什么? 【发布时间】:2014-07-27 05:14:40 【问题描述】:

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

从文档来看,subscript(Range) 的类型签名是:

subscript(Range<Int>) -> Slice<T>

为什么不返回另一个Array&lt;T&gt; 而不是Slice&lt;T&gt;

看起来我可以将切片与数组连接起来:

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

但这会产生错误:

找不到接受提供的“下标”的重载 论据

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

什么是切片?

【问题讨论】:

【参考方案1】:

切片指向数组。当数组已经存在并且切片可以描述它的所需部分时,没有必要再创建一个数组。

加法会导致隐式强制,所以它起作用了。为了让你的任务发挥作用,需要强制:

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

【讨论】:

这是有道理的。这在文档中的任何地方都有描述吗? 这是一个实现细节,真的。你巧妙地探究了揭示黑匣子工作原理的边缘案例......! 实际上 Slice 是数组的副本。更新原始数组后,切片不会改变。这是因为结构性质。需要注意的是,Sliceable 协议并不意味着使用 Slice 类型 swift 语言发生了变化,一个切片实际上使用了三个省略号而不是两个developer.apple.com/library/ios/documentation/General/Reference/… 如果您添加一个简单的编辑通知新读者范围运算符已更改,这不会破坏通信吗?【参考方案2】:

注意:这个答案在 Swift beta 3 中是无效的,因为数组现在是真值类型。


@matt 是正确的,上面 - Slice&lt;T&gt; 指向数组。这似乎与 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"]

【讨论】:

事实上,正如您所说,切片只是像数组一样工作。 Swift 数组具有可变元素,即使它们被声明为不可变。例如,尝试let arr = ["hello", "world", "goodbye"]; arr[0] = "bonjour"。你会发现它有效。奇怪的是,对于不可变数组,只有 size 是不可变的,而不是内容。 (参见Swift 编程语言中的“集合的可变性”) “可变元素” - 这不再是真的【参考方案3】:

总结:

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

参考:

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

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

" Swift 中的数组已经完全重新设计,具有完整的值语义,如 Dictionary 和 字符串...m"

【讨论】:

以上是关于Swift 中的切片是啥?的主要内容,如果未能解决你的问题,请参考以下文章

golang 切片后面3个点是啥意思

窥探Swift之数组安全索引与数组切片

在 Go 中创建 2D 切片的简洁方法是啥?

如何在 Swift 中对字符串进行切片? [复制]

Swift 4:不推荐使用 substring(with:)':请使用字符串切片下标 [重复]

在 golang 中使用私有地图、切片的最佳实践是啥?