Generics - The Swift Programming Language (Swift 5.7)
Generics - The Swift Programming Language (Swift 5.7)
, 10:04
Generics
Generic code enables you to write flexible, reusable functions and types that can
work with any type, subject to requirements that you define. You can write code that
avoids duplication and expresses its intent in a clear, abstracted manner.
Generics are one of the most powerful features of Swift, and much of the Swift
standard library is built with generic code. In fact, you’ve been using generics
throughout the Language Guide, even if you didn’t realize it. For example, Swift’s
Array and Dictionary types are both generic collections. You can create an array
that holds Int values, or an array that holds String values, or indeed an array for
any other type that can be created in Swift. Similarly, you can create a dictionary to
store values of any specified type, and there are no limitations on what that type can
be.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 1 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
This function makes use of in-out parameters to swap the values of a and b, as
described in In-Out Parameters.
The swapTwoInts(_:_:) function swaps the original value of b into a, and the
original value of a into b. You can call this function to swap the values in two Int
variables:
1 var someInt = 3
2 var anotherInt = 107
3 swapTwoInts(&someInt, &anotherInt)
4 print("someInt is now \(someInt), and anotherInt is now \
(anotherInt)")
5 // Prints "someInt is now 107, and anotherInt is now 3"
The swapTwoInts(_:_:) function is useful, but it can only be used with Int values.
If you want to swap two String values, or two Double values, you have to write more
functions, such as the swapTwoStrings(_:_:) and swapTwoDoubles(_:_:)
functions shown below:
It’s more useful, and considerably more flexible, to write a single function that
swaps two values of any type. Generic code enables you to write such a function. (A
generic version of these functions is defined below.)
NOTE
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 2 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
In all three functions, the types of a and b must be the same. If a and b aren’t of the
same type, it isn’t possible to swap their values. Swift is a type-safe language, and
doesn’t allow (for example) a variable of type String and a variable of type Double to
swap values with each other. Attempting to do so results in a compile-time error.
Generic Functions
Generic functions can work with any type. Here’s a generic version of the
swapTwoInts(_:_:) function from above, called swapTwoValues(_:_:):
The generic version of the function uses a placeholder type name (called T, in this
case) instead of an actual type name (such as Int, String, or Double). The
placeholder type name doesn’t say anything about what T must be, but it does say
that both a and b must be of the same type T, whatever T represents. The actual
type to use in place of T is determined each time the swapTwoValues(_:_:) function
is called.
The other difference between a generic function and a nongeneric function is that
the generic function’s name (swapTwoValues(_:_:)) is followed by the placeholder
type name (T) inside angle brackets (<T>). The brackets tell Swift that T is a
placeholder type name within the swapTwoValues(_:_:) function definition.
Because T is a placeholder, Swift doesn’t look for an actual type called T.
ON THIS PAGE
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 3 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
1 var someInt = 3
2 var anotherInt = 107
3 swapTwoValues(&someInt, &anotherInt)
4 // someInt is now 107, and anotherInt is now 3
5
6 var someString = "hello"
7 var anotherString = "world"
8 swapTwoValues(&someString, &anotherString)
9 // someString is now "world", and anotherString is now
"hello"
NOTE
Type Parameters
In the swapTwoValues(_:_:) example above, the placeholder type T is an example
of a type parameter. Type parameters specify and name a placeholder type, and are
written immediately after the function’s name, between a pair of matching angle
brackets (such as <T>).
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 4 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
Once you specify a type parameter, you can use it to define the type of a function’s
parameters (such as the a and b parameters of the swapTwoValues(_:_:) function),
or as the function’s return type, or as a type annotation within the body of the
function. In each case, the type parameter is replaced with an actual type whenever
the function is called. (In the swapTwoValues(_:_:) example above, T was replaced
with Int the first time the function was called, and was replaced with String the
second time it was called.)
You can provide more than one type parameter by writing multiple type parameter
names within the angle brackets, separated by commas.
NOTE
Always give type parameters upper camel case names (such as T and
MyTypeParameter) to indicate that they’re a placeholder for a type, not a value.
Generic Types
In addition to generic functions, Swift enables you to define your own generic types.
These are custom classes, structures, and enumerations that can work with any
type, in a similar way to Array and Dictionary.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 5 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
This section shows you how to write a generic collection type called Stack. A stack
is an ordered set of values, similar to an array, but with a more restricted set of
operations than Swift’s Array type. An array allows new items to be inserted and
removed at any location in the array. A stack, however, allows new items to be
appended only to the end of the collection (known as pushing a new value on to the
stack). Similarly, a stack allows items to be removed only from the end of the
collection (known as popping a value off the stack).
NOTE
The illustration below shows the push and pop behavior for a stack:
3. The stack now holds four values, with the most recent one at the top.
5. After popping a value, the stack once again holds three values.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 6 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
Here’s how to write a nongeneric version of a stack, in this case for a stack of Int
values:
1 struct IntStack {
2 var items: [Int] = []
3 mutating func push(_ item: Int) {
4 items.append(item)
5 }
6 mutating func pop() -> Int {
7 return items.removeLast()
8 }
9 }
This structure uses an Array property called items to store the values in the stack.
Stack provides two methods, push and pop, to push and pop values on and off the
stack. These methods are marked as mutating, because they need to modify (or
mutate) the structure’s items array.
The IntStack type shown above can only be used with Int values, however. It
would be much more useful to define a generic Stack structure, that can manage a
stack of any type of value.
1 struct Stack<Element> {
2 var items: [Element] = []
3 mutating func push(_ item: Element) {
4 items.append(item)
5 }
6 mutating func pop() -> Element {
7 return items.removeLast()
8 }
9 }
Note how the generic version of Stack is essentially the same as the nongeneric
version, but with a type parameter called Element instead of an actual type of Int.
This type parameter is written within a pair of angle brackets (<Element>)
immediately after the structure’s name.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 7 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
Element defines a placeholder name for a type to be provided later. This future type
can be referred to as Element anywhere within the structure’s definition. In this
case, Element is used as a placeholder in three places:
To specify that the push(_:) method has a single parameter called item,
which must be of type Element
To specify that the value returned by the pop() method will be a value of type
Element
Because it’s a generic type, Stack can be used to create a stack of any valid type in
Swift, in a similar manner to Array and Dictionary.
You create a new Stack instance by writing the type to be stored in the stack within
angle brackets. For example, to create a new stack of strings, you write
Stack<String>():
Here’s how stackOfStrings looks after pushing these four values on to the stack:
Popping a value from the stack removes and returns the top value, "cuatro":
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 8 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
Here’s how the stack looks after popping its top value:
The following example extends the generic Stack type to add a read-only computed
property called topItem, which returns the top item on the stack without popping it
from the stack:
1 extension Stack {
2 var topItem: Element? {
3 return items.isEmpty ? nil : items[items.count - 1]
4 }
5 }
The topItem property returns an optional value of type Element. If the stack is
empty, topItem returns nil; if the stack isn’t empty, topItem returns the final item in
the items array.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 9 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
Note that this extension doesn’t define a type parameter list. Instead, the Stack
type’s existing type parameter name, Element, is used within the extension to
indicate the optional type of the topItem computed property.
The topItem computed property can now be used with any Stack instance to
access and query its top item without removing it.
Extensions of a generic type can also include requirements that instances of the
extended type must satisfy in order to gain the new functionality, as discussed in
Extensions with a Generic Where Clause below.
Type Constraints
The swapTwoValues(_:_:) function and the Stack type can work with any type.
However, it’s sometimes useful to enforce certain type constraints on the types that
can be used with generic functions and generic types. Type constraints specify that
a type parameter must inherit from a specific class, or conform to a particular
protocol or protocol composition.
For example, Swift’s Dictionary type places a limitation on the types that can be
used as keys for a dictionary. As described in Dictionaries, the type of a dictionary’s
keys must be hashable. That is, it must provide a way to make itself uniquely
representable. Dictionary needs its keys to be hashable so that it can check
whether it already contains a value for a particular key. Without this requirement,
Dictionary couldn’t tell whether it should insert or replace a value for a particular
key, nor would it be able to find a value for a given key that’s already in the
dictionary.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 10 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
This requirement is enforced by a type constraint on the key type for Dictionary,
which specifies that the key type must conform to the Hashable protocol, a special
protocol defined in the Swift standard library. All of Swift’s basic types (such as
String, Int, Double, and Bool) are hashable by default. For information about
making your own custom types conform to the Hashable protocol, see Conforming
to the Hashable Protocol.
You can define your own type constraints when creating custom generic types, and
these constraints provide much of the power of generic programming. Abstract
concepts like Hashable characterize types in terms of their conceptual
characteristics, rather than their concrete type.
The hypothetical function above has two type parameters. The first type parameter,
T, has a type constraint that requires T to be a subclass of SomeClass. The second
type parameter, U, has a type constraint that requires U to conform to the protocol
SomeProtocol.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 11 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
The principle of finding the index of a value in an array isn’t useful only for strings,
however. You can write the same functionality as a generic function by replacing any
mention of strings with values of some type T instead.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 12 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
This function doesn’t compile as written above. The problem lies with the equality
check, “if value == valueToFind”. Not every type in Swift can be compared with
the equal to operator (==). If you create your own class or structure to represent a
complex data model, for example, then the meaning of “equal to” for that class or
structure isn’t something that Swift can guess for you. Because of this, it isn’t
possible to guarantee that this code will work for every possible type T, and an
appropriate error is reported when you try to compile the code.
All is not lost, however. The Swift standard library defines a protocol called
Equatable, which requires any conforming type to implement the equal to operator
(==) and the not equal to operator (!=) to compare any two values of that type. All of
Swift’s standard types automatically support the Equatable protocol.
Any type that’s Equatable can be used safely with the findIndex(of:in:) function,
because it’s guaranteed to support the equal to operator. To express this fact, you
write a type constraint of Equatable as part of the type parameter’s definition when
you define the function:
The findIndex(of:in:) function now compiles successfully and can be used with
any type that’s Equatable, such as Double or String:
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 13 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
Associated Types
When defining a protocol, it’s sometimes useful to declare one or more associated
types as part of the protocol’s definition. An associated type gives a placeholder
name to a type that’s used as part of the protocol. The actual type to use for that
associated type isn’t specified until the protocol is adopted. Associated types are
specified with the associatedtype keyword.
1 protocol Container {
2 associatedtype Item
3 mutating func append(_ item: Item)
4 var count: Int { get }
5 subscript(i: Int) -> Item { get }
6 }
The Container protocol defines three required capabilities that any container must
provide:
It must be possible to retrieve each item in the container with a subscript that
takes an Int index value.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 14 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
This protocol doesn’t specify how the items in the container should be stored or
what type they’re allowed to be. The protocol only specifies the three bits of
functionality that any type must provide in order to be considered a Container. A
conforming type can provide additional functionality, as long as it satisfies these
three requirements.
Any type that conforms to the Container protocol must be able to specify the type
of values it stores. Specifically, it must ensure that only items of the right type are
added to the container, and it must be clear about the type of the items returned by
its subscript.
To define these requirements, the Container protocol needs a way to refer to the
type of the elements that a container will hold, without knowing what that type is for
a specific container. The Container protocol needs to specify that any value passed
to the append(_:) method must have the same type as the container’s element
type, and that the value returned by the container’s subscript will be of the same
type as the container’s element type.
To achieve this, the Container protocol declares an associated type called Item,
written as associatedtype Item. The protocol doesn’t define what Item is—that
information is left for any conforming type to provide. Nonetheless, the Item alias
provides a way to refer to the type of the items in a Container, and to define a type
for use with the append(_:) method and subscript, to ensure that the expected
behavior of any Container is enforced.
Here’s a version of the nongeneric IntStack type from Generic Types above,
adapted to conform to the Container protocol:
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 15 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
13 self.push(item)
14 }
15 var count: Int {
16 return items.count
17 }
18 subscript(i: Int) -> Int {
19 return items[i]
20 }
21 }
The IntStack type implements all three of the Container protocol’s requirements,
and in each case wraps part of the IntStack type’s existing functionality to satisfy
these requirements.
Thanks to Swift’s type inference, you don’t actually need to declare a concrete Item
of Int as part of the definition of IntStack. Because IntStack conforms to all of the
requirements of the Container protocol, Swift can infer the appropriate Item to use,
simply by looking at the type of the append(_:) method’s item parameter and the
return type of the subscript. Indeed, if you delete the typealias Item = Int line
from the code above, everything still works, because it’s clear what type should be
used for Item.
You can also make the generic Stack type conform to the Container protocol:
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 16 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
12 self.push(item)
13 }
14 var count: Int {
15 return items.count
16 }
17 subscript(i: Int) -> Element {
18 return items[i]
19 }
20 }
This time, the type parameter Element is used as the type of the append(_:)
method’s item parameter and the return type of the subscript. Swift can therefore
infer that Element is the appropriate type to use as the Item for this particular
container.
Swift’s Array type already provides an append(_:) method, a count property, and a
subscript with an Int index to retrieve its elements. These three capabilities match
the requirements of the Container protocol. This means that you can extend Array
to conform to the Container protocol simply by declaring that Array adopts the
protocol. You do this with an empty extension, as described in Declaring Protocol
Adoption with an Extension:
Array’s existing append(_:) method and subscript enable Swift to infer the
appropriate type to use for Item, just as for the generic Stack type above. After
defining this extension, you can use any Array as a Container.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 17 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
1 protocol Container {
2 associatedtype Item: Equatable
3 mutating func append(_ item: Item)
4 var count: Int { get }
5 subscript(i: Int) -> Item { get }
6 }
To conform to this version of Container, the container’s Item type has to conform
to the Equatable protocol.
In this protocol, Suffix is an associated type, like the Item type in the Container
example above. Suffix has two constraints: It must conform to the
SuffixableContainer protocol (the protocol currently being defined), and its Item
type must be the same as the container’s Item type. The constraint on Item is a
generic where clause, which is discussed in Associated Types with a Generic Where
Clause below.
Here’s an extension of the Stack type from Generic Types above that adds
conformance to the SuffixableContainer protocol:
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 18 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
7 return result
8 }
9 // Inferred that Suffix is Stack.
10 }
11 var stackOfInts = Stack<Int>()
12 stackOfInts.append(10)
13 stackOfInts.append(20)
14 stackOfInts.append(30)
15 let suffix = stackOfInts.suffix(2)
16 // suffix contains 20 and 30
In the example above, the Suffix associated type for Stack is also Stack, so the
suffix operation on Stack returns another Stack. Alternatively, a type that conforms
to SuffixableContainer can have a Suffix type that’s different from itself—
meaning the suffix operation can return a different type. For example, here’s an
extension to the nongeneric IntStack type that adds SuffixableContainer
conformance, using Stack<Int> as its suffix type instead of IntStack:
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 19 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
It can also be useful to define requirements for associated types. You do this by
defining a generic where clause. A generic where clause enables you to require that
an associated type must conform to a certain protocol, or that certain type
parameters and associated types must be the same. A generic where clause starts
with the where keyword, followed by constraints for associated types or equality
relationships between types and associated types. You write a generic where clause
right before the opening curly brace of a type or function’s body.
The example below defines a generic function called allItemsMatch, which checks
to see if two Container instances contain the same items in the same order. The
function returns a Boolean value of true if all items match and a value of false if
they don’t.
The two containers to be checked don’t have to be the same type of container
(although they can be), but they do have to hold the same type of items. This
requirement is expressed through a combination of type constraints and a generic
where clause:
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 20 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
The following requirements are placed on the function’s two type parameters:
The Item for C1 must be the same as the Item for C2 (written as
C1.Item == C2.Item).
The first and second requirements are defined in the function’s type parameter list,
and the third and fourth requirements are defined in the function’s generic where
clause.
The items in someContainer can be checked with the not equal operator (!=)
to see if they’re different from each other.
The third and fourth requirements combine to mean that the items in
anotherContainer can also be checked with the != operator, because they’re
exactly the same type as the items in someContainer.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 21 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
After making this check, the function iterates over all of the items in someContainer
with a for-in loop and the half-open range operator (..<). For each item, the
function checks whether the item from someContainer isn’t equal to the
corresponding item in anotherContainer. If the two items aren’t equal, then the two
containers don’t match, and the function returns false.
If the loop finishes without finding a mismatch, the two containers match, and the
function returns true.
The example above creates a Stack instance to store String values, and pushes
three strings onto the stack. The example also creates an Array instance initialized
with an array literal containing the same three strings as the stack. Even though the
stack and the array are of a different type, they both conform to the Container
protocol, and both contain the same type of values. You can therefore call the
allItemsMatch(_:_:) function with these two containers as its arguments. In the
example above, the allItemsMatch(_:_:) function correctly reports that all of the
items in the two containers match.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 22 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
You can also use a generic where clause as part of an extension. The example below
extends the generic Stack structure from the previous examples to add an
isTop(_:) method.
This new isTop(_:) method first checks that the stack isn’t empty, and then
compares the given item against the stack’s topmost item. If you tried to do this
without a generic where clause, you would have a problem: The implementation of
isTop(_:) uses the == operator, but the definition of Stack doesn’t require its items
to be equatable, so using the == operator results in a compile-time error. Using a
generic where clause lets you add a new requirement to the extension, so that the
extension adds the isTop(_:) method only when the items in the stack are
equatable.
1 if stackOfStrings.isTop("tres") {
2 print("Top element is tres.")
3 } else {
4 print("Top element is something else.")
5 }
6 // Prints "Top element is tres."
If you try to call the isTop(_:) method on a stack whose elements aren’t equatable,
you’ll get a compile-time error.
1 struct NotEquatable { }
2 var notEquatableStack = Stack<NotEquatable>()
3 let notEquatableValue = NotEquatable()
4 notEquatableStack.push(notEquatableValue)
5 notEquatableStack.isTop(notEquatableValue) // Error
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 23 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
You can use a generic where clause with extensions to a protocol. The example
below extends the Container protocol from the previous examples to add a
startsWith(_:) method.
The startsWith(_:) method first makes sure that the container has at least one
item, and then it checks whether the first item in the container matches the given
item. This new startsWith(_:) method can be used with any type that conforms to
the Container protocol, including the stacks and arrays used above, as long as the
container’s items are equatable.
1 if [9, 9, 9].startsWith(42) {
2 print("Starts with 42.")
3 } else {
4 print("Starts with something else.")
5 }
6 // Prints "Starts with something else."
The generic where clause in the example above requires Item to conform to a
protocol, but you can also write a generic where clauses that require Item to be a
specific type. For example:
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 24 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
This example adds an average() method to containers whose Item type is Double.
It iterates over the items in the container to add them up, and divides by the
container’s count to compute the average. It explicitly converts the count from Int
to Double to be able to do floating-point division.
You can include multiple requirements in a generic where clause that’s part of an
extension, just like you can for a generic where clause that you write elsewhere.
Separate each requirement in the list with a comma.
1 extension Container {
2 func average() -> Double where Item == Int {
3 var sum = 0.0
4 for index in 0..<count {
5 sum += Double(self[index])
6 }
7 return sum / Double(count)
8 }
9 func endsWith(_ item: Item) -> Bool where Item:
Equatable {
10 return count >= 1 && self[count-1] == item
11 }
12 }
13 let numbers = [1260, 1200, 98, 37]
14 print(numbers.average())
15 // Prints "648.75"
16 print(numbers.endsWith(37))
17 // Prints "true"
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 25 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
This example adds an average() method to Container when the items are integers,
and it adds an endsWith(_:) method when the items are equatable. Both functions
include a generic where clause that adds type constraints to the generic Item type
parameter from the original declaration of Container.
If you want to write this code without using contextual where clauses, you write two
extensions, one for each generic where clause. The example above and the example
below have the same behavior.
In the version of this example that uses contextual where clauses, the
implementation of average() and endsWith(_:) are both in the same extension
because each method’s generic where clause states the requirements that need to
be satisfied to make that method available. Moving those requirements to the
extensions’ generic where clauses makes the methods available in the same
situations, but requires one extension per requirement.
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 26 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
1 protocol Container {
2 associatedtype Item
3 mutating func append(_ item: Item)
4 var count: Int { get }
5 subscript(i: Int) -> Item { get }
6
7 associatedtype Iterator: IteratorProtocol where
Iterator.Element == Item
8 func makeIterator() -> Iterator
9 }
The generic where clause on Iterator requires that the iterator must traverse over
elements of the same item type as the container’s items, regardless of the iterator’s
type. The makeIterator() function provides access to a container’s iterator.
For a protocol that inherits from another protocol, you add a constraint to an
inherited associated type by including the generic where clause in the protocol
declaration. For example, the following code declares a ComparableContainer
protocol that requires Item to conform to Comparable:
Generic Subscripts
Subscripts can be generic, and they can include generic where clauses. You write
the placeholder type name inside angle brackets after subscript, and you write a
generic where clause right before the opening curly brace of the subscript’s body.
For example:
1 extension Container {
2 subscript<Indices: Sequence>(indices: Indices) -> [Item]
3 where Indices.Iterator.Element == Int {
4 var result: [Item] = []
5 for index in indices {
6 result.append(self[index])
7 }
8 return result
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 27 of 28
Generics — The Swift Programming Language (Swift 5.7) 02.09.2022., 10:04
9 }
10 }
This extension to the Container protocol adds a subscript that takes a sequence of
indices and returns an array containing the items at each given index. This generic
subscript is constrained as follows:
The generic where clause requires that the iterator for the sequence must
traverse over elements of type Int. This ensures that the indices in the
sequence are the same type as the indices used for a container.
Taken together, these constraints mean that the value passed for the indices
parameter is a sequence of integers.
B E TA S O F T WA R E
https://docs.swift.org/swift-book/LanguageGuide/Generics.html Page 28 of 28