Subscripts
Subscripts let you query and set members of a collection, list, or sequence
with concise square-bracket syntax — someArray[2] or
someDictionary["key"]. Classes, structures, and enumerations can
all define their own subscripts, giving your custom types the same natural
access syntax as the built-in collections.
Subscript syntax
Define a subscript with the subscript keyword. It looks like a
cross between an instance method and a computed property: you specify one or
more input parameters and a return type, then provide a getter and an
optional setter.
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimes = TimesTable(multiplier: 3)
print("6 × 3 is \(threeTimes[6])") // → 6 × 3 is 18
A read-only subscript that computes a value from its index.
Like a read-only computed property, a subscript with only a getter can drop
the get keyword and the explicit return for a
single expression.
Subscript usage
"Subscript" is just the technical name for the bracket access you've used all along on arrays and dictionaries. Their behavior is defined by subscripts in the standard library.
var numbers = [10, 20, 30]
print(numbers[0]) // → 10 (getter)
numbers[1] = 25 // setter
print(numbers) // → [10, 25, 30]
Subscript options
Subscripts can take any number of input parameters of any type, and can
return any type. They can use variadic parameters and provide default
parameter values, but they can't use inout parameters. A type
can also provide multiple subscripts (subscript overloading),
and Swift picks the right one based on the argument types.
Here's a read/write subscript that takes two parameters to index into a matrix stored as a flat array.
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
subscript(row: Int, column: Int) -> Double {
get {
grid[(row * columns) + column]
}
set {
grid[(row * columns) + column] = newValue
}
}
}
var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 1.5 // uses the setter
matrix[1, 0] = 3.2
print(matrix[0, 1]) // → 1.5 (uses the getter)
Tip: the setter implicitly receives the new value as
newValue, exactly like a computed property's setter. You can
give it your own name with set(newRow) if you prefer.
Subscripts on dictionaries
The Dictionary type's subscript takes a key and returns an
optional value, because the key might not be present. Assigning
nil through the subscript removes the key.
var ages = ["Anna": 28, "Brian": 35]
print(ages["Anna"]) // → Optional(28)
print(ages["Zoe"]) // → nil (key not present)
ages["Cara"] = 19 // add a new entry
ages["Brian"] = nil // remove an entry
print(ages) // → ["Anna": 28, "Cara": 19]
Note: this is why reading a dictionary value gives you an
optional — the subscript itself returns Value?. Use optional
binding or ?? to handle the missing-key case safely.
Type subscripts
Subscripts can belong to the type itself rather than an instance. Declare a
type subscript with static before
subscript (or class on a class to allow subclass
overrides). You then call it on the type with bracket syntax.
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter
static subscript(n: Int) -> Planet {
return Planet(rawValue: n)!
}
}
let third = Planet[3]
print(third) // → earth
A static subscript maps a number to a planet through the type itself.
Recap
Subscripts give your types the clean bracket-access syntax of the built-in
collections. You can make them read-only or read/write, accept multiple
parameters, overload them, and even attach them to a type with
static subscript. That wraps up the Functions & Types
cluster — next you'll move on to inheritance and the object-oriented side of
Swift.