Cos'è uno slice in Swift?


85

Che cos'è una slice in Swift e in che cosa differisce da un array?

Dalla documentazione, il tipo di firma del pedice (Range) è:

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

Perché non restituire un altro Array<T>piuttosto che un Slice<T>?

Sembra che io possa concatenare una fetta con un array:

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

Ma questo produce l'errore:

non è stato possibile trovare un sovraccarico per "indice" che accetta gli argomenti forniti

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

Cos'è una fetta?

Risposte:


97

La sezione punta nella matrice. Non ha senso creare un altro array quando l'array esiste già e la slice può semplicemente descrivere la parte desiderata di esso.

L'aggiunta causa una coercizione implicita, quindi funziona. Per far funzionare il tuo incarico, dovresti forzare:

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

Ha senso. È descritto da qualche parte nella documentazione?
hjing

2
È un dettaglio di implementazione, davvero. Hai sapientemente sondato il bordo cassa che rivela il funzionamento della scatola nera ...!
matt

2
in realtà Slice è una copia di array. Dopo aver aggiornato l'array originale, la slice non cambierà. Ciò è dovuto alla natura strutturale. E per la nota, il protocollo Sliceable non implica l'utilizzo del tipo Slice
Marcin

4
La lingua rapida è cambiata e una slice utilizza effettivamente tre puntini di sospensione e non due developer.apple.com/library/ios/documentation/General/Reference/…
Daniel Galasko

7
Non rovinerebbe la corrispondenza se aggiungessi una semplice modifica per informare i nuovi lettori che gli operatori di gamma sono cambiati?
Daniel Galasko

22

Nota: questa risposta è felicemente non valida a partire da Swift beta 3, poiché gli array ora sono veri tipi di valore.


@matt è corretto, sopra - i Slice<T>punti nell'array. Ciò sembra contrario al modo in cui Swift gestisce tutti gli altri tipi di dati con cui stiamo lavorando, poiché significa che il valore della fetta può cambiare anche se è dichiarato come costante:

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

La parte peggiore è che la fetta si comporta proprio come un array. Dato che in Swift abbiamo un'aspettativa di immutabilità, sembra pericoloso che i valori in sottoscrizione dello slice possano cambiare senza preavviso:

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

Ma se l'array sottostante cambia troppo drasticamente, vengono sganciati:

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

6
In effetti, le sezioni funzionano proprio come gli array, come dici tu. Gli array Swift hanno elementi mutabili, anche se sono dichiarati immutabili . Ad esempio, prova let arr = ["hello", "world", "goodbye"]; arr[0] = "bonjour". Scoprirai che funziona. Con gli array immutabili, stranamente, è solo la dimensione che è immutabile, non il contenuto. (Vedi "Mutability of Collections" in The Swift Programming Language )
Matt Gibson

1
"Elementi mutevoli" - Questo non è più vero
Alex Brown

14

Sommario:

Le risposte precedenti erano vere fino alla Beta 3 (e potrebbero cambiare di nuovo nelle versioni future)

Slice ora agisce proprio come un array, ma come ha detto @matt sopra, è effettivamente una copia superficiale di un array sotto il cofano, fino a quando non viene apportata una modifica. Le sezioni (ora) vedono un'istantanea dei valori originali,

Si noti inoltre che la sintassi delle sezioni è cambiata:

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

Esempio:

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

Ciò consente un'elaborazione molto più uniforme, poiché è più semplice (IMHO) eseguire l'elaborazione di elenchi in stile Python, filtrando un elenco per crearne un altro. secondo la risposta di Matt prima della Beta 3, dovevi creare un array temporaneo per mappare uno slice. Il nuovo codice è ora più semplice:

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

(anche se per essere onesti, foo è ancora una fetta)

Riferimento:

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

Modifiche importanti, problemi risolti, - Swift Language, paragrafo 1

"Array in Swift è stato completamente ridisegnato per avere una semantica a valore pieno come Dictionary e String ... m"

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.