Generic Parameters and Arguments
Generics let you write code that works over many types while staying type-safe.
This reference covers the grammar that makes that possible: the generic
parameter clause that declares type parameters, the constraints that restrict
them, where clauses, and the argument clause that supplies concrete
types.
Generic parameter clause
A generic parameter clause follows a declaration's name and lists one or more type parameters in angle brackets. Each parameter is a placeholder type usable throughout the declaration.
func swapValues<T>(_ a: inout T, _ b: inout T) { ... }
struct Pair<First, Second> { let first: First; let second: Second }
Type constraints
A type constraint in the parameter clause requires a parameter
to inherit from a class or conform to a protocol (or protocol composition). Write
it as T: Constraint, separating multiple parameters with commas.
func max<T: Comparable>(_ xs: [T]) -> T? { xs.max() }
struct Cache<Key: Hashable, Value> { ... }
Generic where clauses
A where clause expresses constraints that the
bracket syntax cannot — in particular, requirements on a parameter's associated
types and same-type requirements written with ==. It appears after
the signature (or after an associated type, or on an extension).
func allEqual<C: Collection>(_ c: C) -> Bool
where C.Element: Equatable { ... }
extension Array where Element == String {
func joinedWithCommas() -> String { joined(separator: ", ") }
}
Constraints in the parameter clause and in a where clause are
equivalent in power for protocol conformance; the where form is
required for associated-type and same-type requirements. You can also attach a
where clause to a single member (a contextual
where) so it applies only to that method or subscript.
Tip: the lightweight some Collection<Int>
syntax is sugar for a generic parameter plus a same-type constraint on the
primary associated type — handy when a full where clause would be
overkill.
Generic argument clause
A generic argument clause supplies concrete types to a generic type at the point of use, in angle brackets after the type name. It applies to types, not functions — for generic functions, the compiler infers the type arguments from the call.
let scores = Dictionary<String, Int>()
let pair = Pair<Int, String>(first: 1, second: "a")
let doubled = swapValues(&x, &y) // T inferred — no argument clause
Note: [Int] and [String: Int] are
shorthand for the argument clauses Array<Int> and
Dictionary<String, Int>.
Summary
The generic parameter clause introduces placeholder types and their inline
constraints; where clauses add associated-type and same-type
requirements that the bracket syntax can't express; and the generic argument
clause plugs concrete types into generic types at the use site (with inference
handling generic functions). Together they give Swift generics that are both
flexible and fully type-checked.