Kurze Antwort:
Wenn Sie eine Variable des MutableCollection
Art haben, dann müssen Sie den Index Setter nennen nur mit einer Reihe und eine neue Scheibe mit der gleichen Länge. Einige Typen MutableCollection
(wie Array
) erlauben eine unterschiedliche Länge Ersatzelemente einfügen oder löschen konforme, aber im allgemeinen eine veränderbare Sammlung braucht das nicht zulassen.
Insbesondere die Standardimplementierung des MutableCollection
Index Setter bricht mit einer Laufzeitausnahme, wenn der Bereich und die neue Scheibe nicht die gleiche Länge haben.
Lange Antwort:
Zunächst ist zu beachten, dass Sie zu
public subscript(bounds: Range<Index>) -> MutableSlice<Self>
in Ihrer eigenen Sammlung nicht zu implementieren, da es eine Standardimplementierung in eine Protokollerweiterung hat. Wie man in der source code dieses Verfahrens sehen kann, ruft das Subskript setter eine
internal func _writeBackMutableSlice()
Funktion, die here implementiert ist. , dass die gemeinsame Anzahl von Elementen aus der Scheibe zum Zielbereich ersten Kopien funktionieren, überprüft und dann, dass der Index-Bereich und die neue Scheibe die gleiche Länge haben:
_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")
So können Sie nicht die Länge einer Änderung MutableCollection
über den (Standard) Index Setter, und zu versuchen, so zu tun, wird das Programm abgebrochen.
Als Beispiel nehmen wir Gebrauch MutableCollection
eine „minimal“ Typ entspricht, definieren:
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
}
}
}
Dann Ersetzen eines Teils der Sammlung mit einer Scheibe von der gleichen Länge Werke:
var mc = MyCollection([0, 1, 2, 3, 4, 5])
mc[1 ... 2] = mc[3 ... 4]
print(mc) // [0, 3, 4, 3, 4, 5]
Aber für verschiedene Längen bricht es mit einer Laufzeitausnahme ab:
mc[1 ... 2] = mc[3 ... 3]
// fatal error: Cannot replace a slice of a MutableCollection with a slice of a smaller size
Hinweis
, dass konkrete Typen MutableCollection
kann konformen ermöglicht unterschiedliche Längen Ersatz in ihrem Index Setter, wie zum Beispiel Array
tut.
Also, wenn ich 'tiefgestellt (Bounds:)' selbst implementieren soll (zum Beispiel, wenn ich etwas anderes als 'MutableSlice' will), sollte ich nur 'assert' verwenden, um sicherzustellen, dass die Anzahl der Elemente übereinstimmt? –
@TimVermeulen: Ich bin mir nicht 100% sicher, aber ich denke du darfst eine andere Anzahl von Elementen akzeptieren. Zum Beispiel entspricht "Array" auch "MutableCollection", hat jedoch einen eigenen Setter, der das Einfügen oder Löschen von Elementen ermöglicht. - Jede Funktion, die einen Parameter 'MutableCollection' annimmt, muss davon ausgehen, dass nur Ersetzungen gleicher Länge möglich sind. –
Interessant. Ich denke, es ist nur verwirrend, weil Swifts Typsystem nicht erzwingen kann, dass die gegebene Teilsequenz die richtige Anzahl von Elementen haben muss (und weil die Dokumentation es auch nicht sehr gut erklärt). Danke vielmals! –