Reputation: 1517
I'm trying to modify this extension in order to get mutability:
extension Collection where Element: Equatable {
/// Returns the element at the specified index iff it is within count, otherwise nil.
subscript (safe index: Index) -> Element? {
indices.contains(index) ? self[index] : nil
}
}
I want to achieve this working:
var array = ["Hello", "World"]
array[safe: 5] = "Other word" // This will not be setted because index is out of bounds, but error won't be throwed.
When I try to modify the subscript extension...
extension Collection where Element: Equatable {
/// Returns the element at the specified index iff it is within count, otherwise nil.
subscript (safe index: Index) -> Element? {
get {
indices.contains(index) ? self[index] : nil
}
mutating set {
if indices.contains(index) {
self[index] = newValue <<<-- ERROR
}
}
}
}
... I get this error: Missing argument label 'safe:' in subscript
Upvotes: 3
Views: 869
Reputation: 272760
Collection
's subscript
is get-only.
MutableCollection
is the protocol that Array
conforms to, that declares the settable subscript
that we all know and love. After all, your extension requires the collection to be mutable, and not all Collection
s are mutable, only MutableCollection
s are.
extension MutableCollection {
/// Returns the element at the specified index iff it is within count, otherwise nil.
subscript (safe index: Index) -> Element? {
get {
indices.contains(index) ? self[index] : nil
}
mutating set {
if indices.contains(index), let value = newValue {
self[index] = value
}
}
}
}
Note that I also added a check in the setter for the case when newValue == nil
(because the subscript has type Element?
, you can assign nil
to it!). In that case, the subscript won't do anything. The Element : Equatable
constraint is also not needed.
Technically, this can also be done on RangeReplaceableCollection
s, which is another one of those protocols that Array
conforms to. But subscripts are supposed to be O(1) time, and replaceSubrange
isn't necessarily so.
extension RangeReplaceableCollection {
/// Returns the element at the specified index iff it is within count, otherwise nil.
subscript (safe index: Index) -> Element? {
get {
indices.contains(index) ? self[index] : nil
}
mutating set {
if indices.contains(index), let value = newValue {
self.replaceSubrange(index...index), with: CollectionOfOne(value))
}
}
}
}
Upvotes: 6
Reputation: 54745
The problem is that Collection
has no mutable subscript setter. To get that, you need to extend MutableCollection
instead.
extension MutableCollection where Element: Equatable {
/// Returns the element at the specified index iff it is within count, otherwise nil.
subscript(safe index: Index) -> Element? {
get {
indices.contains(index) ? self[index] : nil
}
mutating set {
if indices.contains(index), let value = newValue {
self[index] = value
}
}
}
}
Upvotes: 1