How to use Swift generics: A quick guide

What are Swift generics?

Swift generics allow you to write code that can be used with different types of data. This makes your code more reusable and flexible.

Generics are defined using type parameters, which are placeholders for specific types of data. For example, the following function is generic because it uses a type parameter T to represent the type of data that the function can work with:

func myFunction<T>(value: T) -> T {
  return value
}

This function can be called with any type of data, such as Int, String, or Double. For example:

let myInt = myFunction(value: 10)
let myString = myFunction(value: "Hello, world!")
let myDouble = myFunction(value: 3.14)

The compiler will infer the type of T based on the type of data that is passed to the function.

Constraints on type parameters

You can also add constraints to type parameters. This allows you to specify that the type parameter must conform to a certain protocol or have certain properties.

For example, the following code defines a generic function called findMax() that finds the maximum value in an array:

func findMax<T: Comparable>(array: [T]) -> T? {
    guard let firstElement = array.first else { return nil }

    var maxElement = firstElement
    for element in array {
        if element > maxElement {
            maxElement = element
        }
    }

    return maxElement
}

The T type parameter must conform to the Comparable protocol. This ensures that the findMax() function can only be used with types of data that can be compared using the > and < operators.

Benefits of using Swift generics

There are a number of benefits to using generics in Swift, including:

  • Reusability: Generic code can be reused with different types of data, which makes it more efficient and maintainable.
  • Flexibility: Generic code is more flexible than non-generic code because it can be used with a wider range of data types.
  • Readability: Generic code is often more readable than non-generic code because it makes the code’s intention more explicit.

Here are some examples of how to use Swift generics:

// Create a generic function to print the elements of an array:
func printArray<T>(array: [T]) {
    for element in array {
        print(element)
    }
}

// Use the `printArray()` function to print an array of integers:
printArray(array: [1, 2, 3, 4, 5])

// Use the `printArray()` function to print an array of strings:
printArray(array: ["Hello", "world!"])

// Create a generic class to represent a stack of elements:
class Stack<T> {
    private var elements: [T] = []

    func push(element: T) {
        elements.append(element)
    }

    func pop() -> T? {
        return elements.removeLast()
    }

    func peek() -> T? {
        return elements.last
    }
}

// Create a stack of integers:
var intStack = Stack<Int>()

// Push some elements onto the stack:
intStack.push(element: 1)
intStack.push(element: 2)
intStack.push(element: 3)

// Pop an element off the stack:
let poppedElement = intStack.pop()

// Print the popped element:
print(poppedElement) // 3

Conclusion

Swift generics are a powerful tool that can help you to write more reusable, flexible, and readable code. If you are not already using generics in your Swift code, I encourage you to start experimenting with them.

A pat on the back !!