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 MutableCollection
può permettono di sostituire differente-lunghezze nella loro setter pedice, ad esempio Array
fa.
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? –
@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. –
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! –