Generics in Swift
Swift Generics allow us to write reusable functions and data structures that can work with any type. We can write clear and concise code that works for any type, this reduces the risk of introducing bugs.
Generic Functions
In Swift, we can create a function that works with any type. For example, suppose we want to create a function that swaps two values of any type.
In the example above, we have created a generic function called swapValues()
that takes two values of any type and swaps them. The placeholder T
is a generic type parameter, meaning it can be any type (e.g. Int
, String
, etc.).
We can provide more than one type parameter by writing multiple type parameters names within the angle brackets, separated by commas: func foo<T, U>(a: T, b: U)
.
It's traditional to name the type parameters using single letters such as T
, U
and V
, but we can use any upper camel case names (such as MyType
or MyOtherType
) to indicate that they are a placeholder for a type.
Generic Data Structures
Generics are not limited to functions. We can use them to define generic data structures like classes, structs, and enums.
In the example above, Box
is a generic data structure that can hold any type of value. We create two instances of Box
, one with an Int
value and one with a String
value.
Constraints on Generics
Sometimes, we want to add some restrictions to what types can be used with a generic. Swift allows us to specify constraints on generics to ensure they conform to a certain protocol.
In the example above, the generic function sum()
is created with type constraints. This means sum()
can only work with types that conform to the Numeric
protocol (e.g. Int
, Double
, etc.).
If we want to pass a type that does not conform to the Numeric
protocol like String
, we'll get an error: function 'sum' requires that 'String' conform to Numeric
Generic Protocols
Generic can also be used with protocols. This allows for even more flexible and reusable code.
In the example above, the Storage
protocol has an associatedtype
called Item
. The SimpleStorage
class conforms to the Storage
protocol with a specific type T
that is determined when the class is instantiated.
Associated type are used in protocols to define a placeholder for a type that will be specified later. They act as a generic placeholder. The exact type isn't defined in the protocol itself; instead, it's determined when a class, struct, or enum conforms to the protocol.
Generic Typealiases
Generic typealiases allow us to create a new name for an existing type (i.e., they would not introduce a new type). Let's see an example below.
Last updated