Swiftのスライスとは何ですか?


85

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]

スライスとは何ですか?

回答:


97

スライスは配列を指します。配列がすでに存在し、スライスがその目的の部分を記述できる場合、別の配列を作成しても意味がありません。

追加は暗黙の強制を引き起こすので、それは機能します。割り当てを機能させるには、次のことを強制する必要があります

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

それは理にかなっている。これはドキュメントのどこかに記載されていますか?
hjing 2014

2
本当に、それは実装の詳細です。あなたはブラックボックスの働きを明らかにするエッジケースを巧みに調べました...!
マット2014

2
実際、スライスは配列のコピーです。元の配列を更新した後、スライスは変更されません。これは構造体の性質によるものです。また、スライス可能なプロトコルは、スライスタイプの使用を意味するものではありません
Marcin

4
迅速な言語が変更され、スライスは、実際には3つの省略記号を使用しない2いdeveloper.apple.com/library/ios/documentation/General/Reference/...
ダニエルGalasko

7
範囲演算子が変更されたことを新しい読者に通知する簡単な編集を追加した場合、対応を損なうことはありませんか?
ダニエルガラスコ2015年

22

注:配列が真の値型になっているため、この回答はSwiftベータ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"]

6
実際、あなたが言うように、スライスは配列と同じように機能します。Swift配列には、不変として宣言されている場合でも、可変要素があります。たとえば、を試してくださいlet arr = ["hello", "world", "goodbye"]; arr[0] = "bonjour"。あなたはそれがうまくいくことがわかるでしょう。不変の配列では、奇妙なことに、不変なのはサイズだけであり、コンテンツではありません。(Swiftプログラミング言語の「コレクションの可変性」を参照)
Matt Gibson

1
「可変要素」-これはもはや真実ではありません
Alex Brown

14

概要:

上記の答えはベータ3まで真実でした(そして将来のリリースで再び変更される可能性があります)

スライスは配列のように機能するようになりましたが、@ 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スタイルのリスト処理(あるリストをフィルタリングして別のリストを作成する)を実行する方が簡単(IMHO)であるため、はるかに均一な処理が可能になります。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の配列は完全に再設計され、DictionaryやString ... mのような完全な値のセマンティクスを持つようになりました。」

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.