Skip to content
Generics and Protocols
step 1/6

Reading — step 1 of 6

Learn

~1 min readClosures and Generics

Generics parameterize types and functions over types:

func swap<T>(_ a: inout T, _ b: inout T) {
    let tmp = a
    a = b
    b = tmp
}

struct Stack<Element> {
    private var items: [Element] = []
    mutating func push(_ x: Element) { items.append(x) }
    mutating func pop() -> Element? { items.popLast() }
}

where clauses add constraints:

func largest<T: Comparable>(_ a: [T]) -> T? {
    a.max()
}

func allEqual<T: Equatable>(_ a: [T]) -> Bool where T: Hashable {
    Set(a).count <= 1
}

Protocols are interfaces — types declare conformance:

protocol Shape {
    func area() -> Double
}

struct Circle: Shape {
    let radius: Double
    func area() -> Double { 3.14 * radius * radius }
}

Protocol extensions — provide default implementations:

extension Shape {
    func describe() -> String { "area: \(area())" }
}

Now every Shape has describe() automatically — they only need to implement area(). This is Swift's main alternative to inheritance.

Protocol composition:

func process<T: Shape & CustomStringConvertible>(_ x: T) { ... }

Existential types with any:

let shapes: [any Shape] = [Circle(radius: 5), Square(side: 3)]

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…