2016-06-25 14 views
6

Da Apple's MutableCollection API reference:MutableCollection vs RangeReplaceableCollection

Il protocollo MutableCollection consente di modificare i valori degli elementi di una collezione, ma non la lunghezza della collezione stessa. Per le operazioni che richiedono l'aggiunta o la rimozione di elementi, consultare invece il protocollo RangeReplaceableCollection.

Tuttavia, MutableCollection richiede i seguenti pedice:

subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get set } 

Questo non consentono la modifica della lunghezza della collezione? Ad esempio, non potremmo chiamare il setter di questo pedice con un intervallo vuoto e una sottosequenza non vuota?

risposta

5

Risposta breve:

Se si dispone di una variabile del tipo MutableCollection allora è necessario chiamare il setter pedice solo con una gamma e una nuova fetta della stessa lunghezza. Alcuni tipi conformi a MutableCollection (come Array) consentono una sostituzione di lunghezza diversa per inserire o eliminare elementi, ma in generale, una raccolta mutabile non è necessario consentirlo.

In particolare, l'implementazione predefinita del MutableCollection pedice setter interrompe con un'eccezione runtime se l'intervallo e il nuova fetta non hanno la stessa lunghezza.

Più rispondere:

prima nota che non c'è bisogno di implementare

public subscript(bounds: Range<Index>) -> MutableSlice<Self> 

nella propria collezione, perché dispone di un'implementazione di default in un protocollo di estensione. Come si può vedere nella source code di tale metodo, il setter pedice chiama una funzione

internal func _writeBackMutableSlice() 

che viene realizzato here. che funzionano prime copie del numero comune di elementi dal fetta alla gamma di destinazione, quindi verifica che la gamma indice e il nuovo fetta hanno la stessa lunghezza:

_precondition(
    selfElementIndex == selfElementsEndIndex, 
    "Cannot replace a slice of a MutableCollection with a slice of a smaller size") 
_precondition(
    newElementIndex == newElementsEndIndex, 
    "Cannot replace a slice of a MutableCollection with a slice of a larger size") 

quindi non è possibile modificare la lunghezza di un MutableCollection via il settatore di pedice (predefinito), e il tentativo di farlo annullerà il programma.

Come esempio, fare utilizzare definiscono una "minima" tipo conforme alle MutableCollection:

struct MyCollection : MutableCollection, CustomStringConvertible { 

    var storage: [Int] = [] 

    init(_ elements: [Int]) { 
     self.storage = elements 
    } 

    var description: String { 
     return storage.description 
    } 

    var startIndex : Int { return 0 } 
    var endIndex : Int { return storage.count } 

    func index(after i: Int) -> Int { return i + 1 } 

    subscript(position : Int) -> Int { 
     get { 
      return storage[position] 
     } 
     set(newElement) { 
      storage[position] = newElement 
     } 
    } 
} 

Poi sostituzione di una parte della collezione con una fetta della stessa lunghezza opere:

var mc = MyCollection([0, 1, 2, 3, 4, 5]) 
mc[1 ... 2] = mc[3 ... 4] 
print(mc) // [0, 3, 4, 3, 4, 5] 

Ma per diverse lunghezze, si interrompe con un'eccezione di runtime:

mc[1 ... 2] = mc[3 ... 3] 
// fatal error: Cannot replace a slice of a MutableCollection with a slice of a smaller size 

noti che tipi concreti conforme al MutableCollectionpuò permettono di sostituire differente-lunghezze nella loro setter pedice, ad esempio Array fa.

+0

Quindi, se devo implementare 'subscript (bounds:)' me stesso (ad esempio se voglio qualcosa di diverso da 'MutableSlice '), dovrei semplicemente usare 'assert' per assicurarmi che il numero di elementi corrisponda? –

+0

@TimVermeulen: Non sono sicuro al 100%, ma penso che sia consentito accettare un diverso numero di elementi. Ad esempio, 'Array' è anche conforme a' MutableCollection', ma ha il proprio setter che consente l'inserimento o la cancellazione di elementi. - Ma ogni funzione che assume un parametro 'MutableCollection' deve presupporre che solo le sostituzioni della stessa lunghezza siano possibili. –

+0

Interessante. Immagino sia confuso solo perché il sistema di tipo di Swift non può imporre che la sottosequenza data abbia il giusto numero di elementi (e perché la documentazione non la spiega molto bene, neanche). Molte grazie! –