Reusable code with Swift generics
Reduce duplication with generic functions, generic types, and type constraints while preserving type safety.
Read the Korean original on Velog ↗English translation

When several functions do the same work for different types, duplication quickly becomes more noticeable than the implementation itself. Generics let us write the shared behavior once and supply the concrete type later.
Generic functions
A type parameter such as <T> lets a function work with different types without giving up type safety.
var a = 2
var b = 3
var apple = "apple"
var banana = "banana"
func swapElements<T>(_ first: inout T, _ second: inout T) {
let temp = first
first = second
second = temp
}
swapElements(&a, &b) // Int values
swapElements(&apple, &banana) // String values
Separate type parameters with commas when a function needs more than one.
func someFunction<One, Two>(_ first: One, _ second: Two) { ... }
Generic types
Structures, classes, and enumerations can have type parameters too.
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
When creating an instance, provide the concrete type, either explicitly or through type inference where possible.
let stack1: Stack<Int> = .init() // An instance with Int elements
let stack2 = Stack<String>.init() // An instance with String elements
Extending generic types
An extension can use the generic type's existing type parameters. It does not redeclare them.
extension Array {
mutating func pop() -> Element {
return self.removeLast()
}
}
Type constraints
Constraints can require a type parameter to inherit from a particular class or conform to a protocol.
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { ... }