Generics are an advanced feature in Swift that allow developers to write flexible and reusable code. They provide a way to write functions, structures, and classes that work with any type without knowing beforehand what that type is.
A generic function is a function that can work with any type. You can declare a generic function using the <T>
syntax to define a placeholder type that will be replaced by the actual type when the function is called.
func swapTwoValues(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
In this example, the function swapTwoValues()
takes two arguments a
and b
, both of type T
, which is a placeholder for any type. The &inout
keyword means that the arguments are passed by reference, which allows the function to modify their values. The function then creates a temporary variable to hold the value of a
, assigns b
to a
, and finally assigns the temporary variable to b
. This effectively swaps the values of a
and b
.
Similar to generic functions, you can also create generic types in Swift, such as generic structures and classes. These types can work with any type, just like generic functions.
struct Stack {
var items = [T]()
mutating func push(_ item: T) {
items.append(item)
}
mutating func pop() -> T? {
return items.isEmpty ? nil : items.removeLast()
}
func peek() -> T? {
return items.last
}
var count: Int {
return items.count
}
}
In this example, we create a generic structure Stack
that can work with any type. The structure has an items
array property of type T
, a mutating push()
function that adds an item to the stack, a mutating pop()
function that removes the last item from the stack, a peek()
function that returns the top item from the stack without removing it, and a count
property that returns the number of items in the stack.
While you can use any type with generic functions and types, sometimes you may want to constrain the types that can be used. Swift provides the option to place constraints on generic types and functions, using the where
clause.
func allEqual(_ array: [T]) -> Bool {
guard let first = array.first else {
return true
}
for element in array {
if element != first {
return false
}
}
return true
}
In this example, the function allEqual()
takes an array of values of type T
, which we constrain to conform to the Equatable
protocol using T: Equatable
. The function then uses the first
property of the array to get the first element, and iterates over the remaining elements of the array, checking if they are equal to the first element using the !=
operator. If any element is not equal to the first element, the function returns false
. Otherwise, it returns true
.
Generics are a powerful feature of Swift that enable developers to write flexible and reusable code. They allow functions, structures, and classes to work with any type, and provide the option to constrain the types that can be used. By leveraging the power of generics, you can write code that can be used with a wide variety of types and avoid duplicating code.