SWIFT
Swift Generics: Syntax, Usage, and Examples
Swift generics let you write flexible and reusable code by allowing types to be specified later. Instead of writing separate implementations for different data types, generics let you define a single function, class, struct, or protocol that works with any type.
How to Use Generics in Swift
To define a generic function or type, use angle brackets (<T>), where T represents a placeholder type.
Learn Swift on Mimo
Generic Function
Swift
func swapValues<T>(a: inout T, b: inout T) {
let temp = a
a = b
b = temp
}
var x = 5
var y = 10
swapValues(a: &x, b: &y)
print(x, y) // Output: 10 5
The T placeholder lets this function work with any type, whether it's an integer, string, or custom struct.
Generic Class
You can create a generic class to store different types while keeping your code reusable.
Swift
class Box<T> {
var value: T
init(value: T) {
self.value = value
}
}
let intBox = Box(value: 42)
let stringBox = Box(value: "Hello")
print(intBox.value) // Output: 42
print(stringBox.value) // Output: Hello
Generic Struct
Similar to a class, a generic struct can hold any type.
Swift
struct Pair<T, U> {
let first: T
let second: U
}
let pair = Pair(first: "Alice", second: 30)
print(pair.first) // Output: Alice
print(pair.second) // Output: 30
Generic Enum
You can use generics in enums, which is especially useful for type-safe APIs.
Swift
enum Result<T> {
case success(T)
case failure(String)
}
let successResult = Result.success(100)
let failureResult = Result.failure("Something went wrong")
When to Use Generics in Swift
Avoiding Code Duplication
Generics let you write a single, reusable function instead of separate versions for different types.
Swift
func printValue<T>(_ value: T) {
print("Value:", value)
}
printValue(10) // Output: Value: 10
printValue("Swift") // Output: Value: Swift
Working with Collections
Swift generics make it possible to create flexible collection types.
Swift
struct Stack<T> {
private var elements: [T] = []
mutating func push(_ element: T) {
elements.append(element)
}
mutating func pop() -> T? {
return elements.popLast()
}
}
var intStack = Stack<Int>()
intStack.push(5)
intStack.push(10)
print(intStack.pop()!) // Output: 10
Protocols with Associated Types
Swift generics work with protocols using associated types to allow flexibility in implementation.
Swift
protocol Container {
associatedtype Item
mutating func add(_ item: Item)
func count() -> Int
}
struct Bag<T>: Container {
private var items: [T] = []
mutating func add(_ item: T) {
items.append(item)
}
func count() -> Int {
return items.count
}
}
var bag = Bag<String>()
bag.add("Apple")
bag.add("Banana")
print(bag.count()) // Output: 2
Examples of Generics in Swift
Generic Function with Constraints
You can constrain generics to specific types using where.
Swift
func findLargest<T: Comparable>(in array: [T]) -> T? {
return array.max()
}
let numbers = [3, 7, 2, 9]
print(findLargest(in: numbers)!) // Output: 9
Here, T: Comparable ensures that only types that conform to the Comparable protocol can be used.
Using Generics in Protocols
A Swift generic protocol allows flexibility while enforcing specific behavior.
Swift
protocol Identifiable {
associatedtype ID
var id: ID { get }
}
struct User: Identifiable {
let id: Int
}
let user = User(id: 101)
print(user.id) // Output: 101
Generic Type Alias
A generic type alias provides a shorthand for commonly used generic types.
Swift
typealias StringDictionary<T> = Dictionary<String, T>
let userAges: StringDictionary<Int> = ["Alice": 30, "Bob": 25]
print(userAges["Alice"]!) // Output: 30
Learn More About Generics in Swift
Generic Parameters vs. Associated Types
- A generic parameter (
<T>) is defined in functions, structs, and classes. - An associated type (
associatedtype) is used in protocols to allow type flexibility.
Generic Constraints
You can use where to constrain a generic to certain types or protocols.
Swift
func printIfEqual<T: Equatable>(_ a: T, _ b: T) {
if a == b {
print("Equal")
} else {
print("Not equal")
}
}
printIfEqual(5, 5) // Output: Equal
printIfEqual("Hi", "Hello") // Output: Not equal
Generic Functions with Multiple Parameters
You can use multiple generic types to handle different kinds of data.
Swift
func combine<A, B>(_ a: A, _ b: B) -> String {
return "\(a) and \(b)"
}
print(combine(5, "Apples")) // Output: 5 and Apples
Extending Generic Types
You can extend generic types to add extra functionality.
Swift
extension Stack {
func peek() -> T? {
return elements.last
}
}
var numberStack = Stack<Int>()
numberStack.push(20)
print(numberStack.peek()!) // Output: 20
Optional Generics
A Swift optional generic lets you work with optional types in generics.
Swift
func unwrap<T>(_ value: T?) -> T {
return value ?? fatalError("Unexpected nil value")
}
let number: Int? = 42
print(unwrap(number)) // Output: 42
Generic Properties
A generic property allows you to define a property with any type.
Swift
struct Wrapper<T> {
var value: T
}
let wrappedInt = Wrapper(value: 99)
let wrappedString = Wrapper(value: "Swift")
print(wrappedInt.value) // Output: 99
print(wrappedString.value) // Output: Swift
Using Generics in Arrays
A Swift generic array allows type safety while storing different objects of the same type.
Swift
func printArray<T>(items: [T]) {
for item in items {
print(item)
}
}
printArray(items: [1, 2, 3])
printArray(items: ["Swift", "Generics"])
Best Practices for Using Generics in Swift
- Use generics when writing reusable, type-safe code.
- Avoid overcomplicating code with excessive generic constraints.
- Use
whereclauses for precise type restrictions. - When working with protocols, prefer associated types over generic parameters when flexibility is needed.
- Extend generic types to add additional functionality instead of modifying existing generic structures.
Looking to dive deeper into generics and other essential Swift concepts? Check out our Swift programming course.
Join 35M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot