Was ist ein Slice in Swift?

85

Was ist ein Slice in Swift und wie unterscheidet es sich von einem Array?

Aus der Dokumentation geht hervor, dass die Typensignatur des Index (Bereich):

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

Warum nicht Array<T>lieber einen anderen als einen zurückgeben Slice<T>?

Es sieht so aus, als könnte ich ein Slice mit einem Array verketten:

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

Dies ergibt jedoch den Fehler:

Es konnte keine Überladung für 'tiefgestellt' gefunden werden, die die angegebenen Argumente akzeptiert

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

Was ist eine Scheibe?

hjing
quelle

Antworten:

97

Das Slice zeigt in das Array. Es macht keinen Sinn, ein anderes Array zu erstellen, wenn das Array bereits vorhanden ist und das Slice nur den gewünschten Teil davon beschreiben kann.

Das Hinzufügen verursacht impliziten Zwang, also funktioniert es. Damit Ihre Aufgabe funktioniert, müssen Sie Folgendes erzwingen:

var list = ["hello", "world"]
var slice: Array<String> = Array(list[0..<list.count])
matt
quelle
Das macht Sinn. Wird dies irgendwo in der Dokumentation beschrieben?
Hjing
2
Es ist wirklich ein Implementierungsdetail. Sie haben geschickt das Randgehäuse untersucht, das die Funktionsweise der Black Box enthüllt ...!
Matt
2
Eigentlich ist Slice eine Kopie des Arrays. Nachdem Sie das ursprüngliche Array aktualisiert haben, ändert sich das Slice nicht mehr. Dies liegt an der Struktur der Natur. Und für den Hinweis, Sliceable Protokoll impliziert nicht die Verwendung von Slice-Typ
Marcin
4
Die schnelle Sprache hat sich geändert und ein Slice verwendet tatsächlich drei Auslassungspunkte und nicht zwei Entwickler.apple.com/library/ios/documentation/General/Reference/…
Daniel Galasko
7
Es würde die Korrespondenz nicht ruinieren, wenn Sie eine einfache Bearbeitung hinzufügen würden, die neue Leser darüber informiert, dass sich die Bereichsoperatoren geändert haben.
Daniel Galasko
22

Hinweis: Diese Antwort ist ab Swift Beta 3 glücklicherweise ungültig, da Arrays jetzt echte Werttypen sind.


@matt ist oben korrekt - die Slice<T>Punkte im Array. Dies scheint der Art und Weise zu widersprechen, wie Swift mit allen anderen Datentypen umgeht, mit denen wir arbeiten, da sich der Wert des Slice ändern kann, selbst wenn es als Konstante deklariert ist:

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

Das Schlimmste ist, dass sich das Slice wie ein Array verhält. Angesichts der Tatsache, dass wir in Swift eine Unveränderlichkeit erwarten, scheint es gefährlich, dass sich die tiefgestellten Werte des Slice ohne Vorwarnung ändern können:

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

Wenn sich das zugrunde liegende Array jedoch zu drastisch ändert, werden sie ausgehängt:

arr.removeAtIndex(0)                       // this detaches slice from arr
println(slice)                             // ["bonjour", "le monde"]
arr[0] = "hola"
println(slice)                             // ["bonjour", "le monde"]
Nate Cook
quelle
6
Tatsächlich funktioniert Scheiben nur wie Arrays, wie Sie sagen. Schnelle Arrays haben veränderbare Elemente, auch wenn sie als unveränderlich deklariert sind . Versuchen Sie es zum Beispiel let arr = ["hello", "world", "goodbye"]; arr[0] = "bonjour". Sie werden feststellen, dass es funktioniert. Bei unveränderlichen Arrays ist seltsamerweise nur die Größe unveränderlich, nicht der Inhalt. (Siehe "Veränderbarkeit von Sammlungen" in der Programmiersprache Swift )
Matt Gibson
1
"Veränderliche Elemente" - Dies ist nicht mehr wahr
Alex Brown
14

Zusammenfassung:

Die obigen Antworten waren bis zur Beta 3 wahr (und können sich in zukünftigen Versionen erneut ändern).

Slice verhält sich jetzt wie ein Array, ist jedoch, wie oben erwähnt, effektiv eine flache Kopie eines Arrays unter der Haube, bis eine Änderung vorgenommen wird. Slices (jetzt) ​​sehen eine Momentaufnahme der ursprünglichen Werte.

Beachten Sie auch, dass sich die Slice-Syntax geändert hat:

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

Beispiel:

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

Dies ermöglicht eine viel gleichmäßigere Verarbeitung, da die Verarbeitung von Listen im Python-Stil einfacher ist (IMHO) - Filtern einer Liste, um eine andere zu erstellen. Gemäß Matts Antwort vor Beta 3 mussten Sie ein temporäres Array erstellen, um ein Slice zuzuordnen. Der neue Code ist jetzt einfacher:

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

(obwohl um fair zu sein, ist foo immer noch ein Stück)

Referenz:

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

Wichtige Änderungen, gelöste Probleme, - Schnelle Sprache, Absatz 1

"Array in Swift wurde komplett neu gestaltet, um eine vollständige Semantik wie Dictionary und String ... m zu erhalten."

Chris Conover
quelle