Swift operator `subscript` []
It looks like there are 2 questions here.
1. How can I enable subscripting
on my own custom class?
To enable subscripting
on your class Container
you need to implement the subscript
computed property like this.
class Container {
private var list : [Any] = [] // I made this private
subscript(index:Int) -> Any {
get {
return list[index]
}
set(newElm) {
list.insert(newElm, atIndex: index)
}
}
}
Now you can use it this way.
var container = Container()
container[0] = "Star Trek"
container[1] = "Star Trek TNG"
container[2] = "Star Trek DS9"
container[3] = "Star Trek VOY"
container[1] // "Star Trek TNG"
2. Can I access one element of Container
that supports subscripting writing something like data[1][2]
?
If we use your example no, you cannot. Because data[1]
returns something of type Any
. And you cannot subscript Any
.
But if you add a cast it becomes possible
var container = Container()
container[0] = ["Enterprise", "Defiant", "Voyager"]
(container[0] as! [String])[2] // > "Voyager"
how to define a custom subscripting array operator which makes array elements spring into existence if necessary
This isn’t related to the subscript operator, but more a question of how to define a ??=
operator. Which you can do, but it might not work quite the way you expect.
Here’s a possible implementation:
// first define the ??= operator
infix operator ??= { }
// then some pretty standard logic for an assignment
// version of ??
func ??=<T>(inout lhs: T?, rhs: T) {
lhs = lhs ?? rhs
}
This compiles, and works as you might be expecting:
var i: Int? = 1
i ??= 2 // i unchanged
var j: Int? = nil
j ??= 2 // j is now Some(2)
It will also work in combination with subscripts:
var a: [Int?] = [1, nil]
a[1] ??= 2
a[1] // is now Some(2)
I say this might not work completely as expected because of the types. a ?? b
takes an optional a
, and if it’s nil
, returns a default of b
. However it returns a non-optional value. That’s kinda the point of ??
.
On the other hand, ??=
cannot do this. Because the left-hand side is already determined to be optional, and an assignment operator cannot change the type only the value. So while it will substitute the value inside the optional in the case of nil
, it won’t change the type to be non-optional.
PS the reason the ??=
function compiles at all is because non-optional values (i.e. what you will get back from lhs ?? rhs
) are implicitly upgraded to optional values if necessary, hence lhs ?? rhs
, of type T
, can be assigned to lhs
, which is of type T?
.
How do I implement custom operator [] in swift
apple docs
Subscripts enable you to query instances of a type by writing one or
more values in square brackets after the instance name. Their syntax
is similar to both instance method syntax and computed property
syntax. You write subscript definitions with the subscript keyword,
and specify one or more input parameters and a return type, in the
same way as instance methods.
Subscript is not an operator. Just a method marked with the subscript
keyword.
subscript (index:Int) -> T {
return impl[index + frontCur]
}
Read this:
class MyColl {
private var someColl : [String] = []
subscript(index: Int) -> String {
get {
return someColl[index]
}
set(value) {
someColl[index] = value
}
}
}
And read this:
Swift has a well-designed and expansive suite of built-in collection types. Beyond Array, Dictionary, and the brand new Set types, the standard library provides slices, lazy collections, repeated sequences, and more, all with a consistent interface and syntax for operations. A group of built-in collection protocols—SequenceType, CollectionType, and several others—act like the steps on a ladder. With each step up, a collection type gains more functionality within the language and the standard library.
What is additional advantage of subscript use over method
Subscripts have three advantages over functions that I can think of:
Familiarity. Many Swift programmers are familiar with using
[]
to access array elements in other languages like Python, C, C++, and Java.Terseness. If you want to access a collection element using a function, the function needs a name. Even a short name like
at
(which Smalltalk uses) requires more characters than[]
. Comparearray[i]
toarray.at(i)
.Flexibility. A subscript operator can allow both reading and writing. You can even use a subscript operator on the left side of a mutating binary operator, like this:
array[i] += 1
Without the subscript operator, you'd need to explicitly write two separate function calls, like this:
array.at(i, put: array.at(i) + 1)
Or maybe use a function that takes a mutation closure, like this:
array.at(i, update: { $0 + 1 })
Why I Cannot subscript a value of type '[String : [String]]' with an argument of type 'String.SubSequence' (aka 'Substring')?
You can simply use Dictionary's
init(grouping:by:)
initializer
like so,
var animalsDict = Dictionary(grouping: animals) { String($0.first!) }
var animalSectionTitles = animalsDict.keys.sorted()
Output:
print(animalsDict) //["G": ["Giraffe", "Greater Rhea"], "P": ["Panda", "Peacock", "Pig", "Platypus", "Polar Bear"], "E": ["Emu"], "H": ["Hippopotamus", "Horse"], "K": ["Koala"], "L": ["Lion", "Llama"], "R": ["Rhinoceros"], "D": ["Dog", "Donkey"], "B": ["Bear", "Black Swan", "Buffalo"], "M": ["Manatus", "Meerkat"], "W": ["Whale", "Whale Shark", "Wombat"], "S": ["Seagull"], "T": ["Tasmania Devil"], "C": ["Camel", "Cockatoo"]]
print(animalSectionTitles) //["B", "C", "D", "E", "G", "H", "K", "L", "M", "P", "R", "S", "T", "W"]
Differences between subscript and functions in Swift
if you mean subscripts for custom classes, then no. looks like they are just syntactic sugar for computed properties
class IHaveASubscript<T> {
private var array: Array<T>
init() {
array = []
}
subscript (index: Int) -> T {
get {
return array[index]
}
set(newValue) {
array[index] = newValue
}
}
func elementAtIndex(index: Int) -> T {
return array[index]
}
func setElementAtIndex(index: Int, element: T) {
array[index] = element
}
}
swift: Cannot use mutating member on immutable value: subscript is get-only
You need to extend MutableCollection
. A normal Collection
does not support setting through subscripts, the mutable counterpart does.
extension MutableCollection where Index == Int, Element == [MyData] {
//...
}
Swift error Cannot subscript a value of type [Uint8]
The error message is misleading. The problem is that you cannot
convert an UInt8
to Int
with
theDigest[theCount] as Int
You have to create a new Int
from the UInt8
with
Int(theDigest[theCount])
instead.
If you don't understand the cause for some error message it is often
helpful to split a complex expression into several simple ones.
In this case
let tmp1 = theDigest[theCount]
let tmp2 = tmp1 as Int // error: cannot convert value of type 'UInt8' to type 'Int' in coercion
let tmp3 = countLeadingZeroNybbles(tmp2)
gives a constructive error message for the second line.
Swift: Subscript with Ranges error
I haven't got the book you are using, but this line:
var table = MathTable(num: 5)
Should probably be this:
var table = MathTableWithRanges(num: 5)
Related Topics
Scenekit - Scntext Centering Incorrectly
Delete All Characters After a Certain Character from a String in Swift
How Is a Type-Erased Generic Wrapper Implemented
Target Parameter in Dispatchqueue
Swift Lazy Subscript Ignores Filter
Ycombinator Not Working in Swift
Why Do I Still Need to Unwrap Swift Dictionary Value
How to Get Unmanaged Object from Realm Query in Swift
How to Represent Magnitude for Mass in Swift
Peak Detection for Growing Time Series Using Swift
Dyld: Library Not Loaded: @Rpath/Libswiftcore.Dylib Problem with New Xcode (10.2)
How to Connect Localhost (With Invalid Certificate) Using Alamofire
App Crash on Sign in (Xcode 9.3) Exc_Bad_Access (Code=1, Address=0X1)
Swift 3, Xcode 8 Instantiate View Controller Is Not Working
Navigationview Doesn't Display Correctly When Using Tabview in Swiftui
Swift Didset Get Index of Array
How to Integrate Latest Sdwebimage API in My Swift Based Project