Generics
21.1 Generic Functions
func swapTwo<T>(_ a: inout T, _ b: inout T) { (a, b) = (b, a) }
func largest<T: Comparable>(_ items: [T]) -> T? {
guard var best = items.first else { return nil }
for item in items where item > best { best = item }
return best
}
largest([3, 9, 2]); largest(["b", "a"])21.2 Generic Types
struct Queue<Element> {
private var inbox: [Element] = []
private var outbox: [Element] = []
mutating func enqueue(_ e: Element) { inbox.append(e) }
mutating func dequeue() -> Element? {
if outbox.isEmpty { outbox = inbox.reversed(); inbox.removeAll() }
return outbox.popLast()
}
var isEmpty: Bool { inbox.isEmpty && outbox.isEmpty }
}
enum Either<Left, Right> {
case left(Left)
case right(Right)
}
struct Pair<A, B> { let first: A; let second: B }
extension Pair: Equatable where A: Equatable, B: Equatable {}21.3 Constraints and where Clauses
func allEqual<C: Collection>(_ c: C) -> Bool where C.Element: Equatable {
guard let first = c.first else { return true }
return c.allSatisfy { $0 == first }
}
func merge<C1: Sequence, C2: Sequence>(_ a: C1, _ b: C2) -> [C1.Element]
where C1.Element == C2.Element, C1.Element: Comparable {
(Array(a) + Array(b)).sorted()
}
extension Collection where Element: Numeric {
func sum() -> Element { reduce(0, +) }
}
extension Array where Element == String {
func joinedWithCommas() -> String { joined(separator: ", ") }
}
protocol Cache {
associatedtype Key: Hashable
associatedtype Value
subscript(key: Key) -> Value? { get set }
}21.4 Generic Specialization and Performance
Swift generics are compiled with specialization where the concrete types are visible (no boxing overhead). Use @inlinable to allow cross-module specialization in libraries.
Unspecialized generic code uses witness tables (dynamic dispatch through protocols).