```html
Intro to Swift Generics: A Clear and Concise Guide
Intro to Swift Generics: A Clear and Concise Guide
Swift provides powerful generics features that allow you to write flexible and reusable code. Generics enable you to write functions and types that can work with any type, subject to requirements that you define.
What Are Generics?
Generics allow you to write flexible, reusable functions and types that can work with any type. The Swift standard library extensively uses generics. For example, Swift's `Array` and `Dictionary` types are both generic collections.
Generic Functions
To declare a generic function, place the generic parameter in angle brackets (`
`) after the function name.
func swap(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
// Usage
var x = 5
var y = 10
swap(&x, &y)
print(x) // 10
print(y) // 5}
Here, `T` is a placeholder type that will be replaced by an actual type when the function is called.
Generic Types
You can also declare your own generic types, such as classes, structures, and enumerations.
struct Stack {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
// Usage
var stack = Stack()
stack.push(1)
stack.push(2)
print(stack.pop()) // 2
print(stack.pop()) // 1}
Here, `Element` is a placeholder type within the `Stack` structure.
Type Constraints
Type constraints specify that a type parameter must inherit from a specific class or conform to a particular protocol.
func findIndex(of valueToFind: T, in array: [T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
// Usage
let numbers = [1, 2, 3, 4, 5]
if let index = findIndex(of: 3, in: numbers) {
print("Index: \(index)") // Index: 2
}
In this example, the `findIndex` function's type parameter `T` must conform to the `Equatable` protocol.
Associated Types
Protocols can have associated types, which help define a placeholder name for a type used as part of the protocol.
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
struct IntStack: Container {
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// Conformance to Container
mutating func append(_ item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
Generics are a powerful feature that enhances the flexibility and reusability of your code. With a solid understanding of generics, you can write more abstract and kind code that's capable of working with any type.
```