Generics are one of the most powerful features of Swift.
They allow you to write flexible, reusable functions and types that can work with any data type, subject to requirements that you define.
In fact, much of the Swift standard library is built using generic code. For example, arrays and dictionaries are generic collections!
Imagine you want to write a function that swaps the values of two integers.
You write the function for Int. But later, you realize you need to swap two String values.
Without generics, you would have to write a completely new function for Strings, duplicating your logic entirely.
To create a generic function, you place a placeholder type name (often <T>) inside angle brackets right after the function name.
This tells Swift that T is a placeholder for a type that will be determined when the function is actually called.
// The <T> makes this function generic
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
var x = 5
var y = 10
swapTwoValues(&x, &y)
print("x: \(x), y: \(y)")
Now, swapTwoValues can be used with Integers, Strings, Doubles, or any custom Structs you create!
You can also create your own custom generic types, like generic classes, structs, or enums.
A classic example is creating a custom Stack data structure that can hold any type of element.
struct Stack<Element> {
var items: [Element] = []
mutating func push(_ item: Element) {
items.append(item)
}
}
// We explicitly define this stack to hold Strings
var stringStack = Stack<String>()
stringStack.push("First")
stringStack.push("Second")
print(stringStack.items)
Sometimes you don't want your generic to accept any type. You want it to only accept types that conform to a specific protocol.
You can enforce this by adding a type constraint. For example, <T: Equatable> ensures the type passed in can be compared using ==.
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind { return index }
}
return nil
}
Which syntax is used to denote a generic placeholder type in Swift?