Lesson 92Advanced Topics
Generic Types
Generic Data Structures
Generic types let you create reusable data structures like Stack, Queue, and LinkedList that work with any type while maintaining type safety.
Common Generic Types
Stack<T>
LIFO - Last In, First Out
push(), pop(), top
Queue<T>
FIFO - First In, First Out
enqueue(), dequeue(), front
LinkedList<T>
Chain of nodes
append(), remove(), traverse
Box<T>
Reference wrapper
Wrap value types in class
Extending Generic Types
extension Stack where Element: Equatable {
func contains(_ item: Element) -> Bool
}
func contains(_ item: Element) -> Bool
}
Add conditional functionality based on type constraints.
Swift Standard Library Generics
Array<Element>- Dynamic arrayDictionary<Key, Value>- Key-value pairsSet<Element>- Unique collectionOptional<Wrapped>- Optional valuesResult<Success, Failure>- Success or error
Type Alias
typealias IntStack = Stack<Int>
typealias JSON = Dictionary<String, Any>
typealias JSON = Dictionary<String, Any>
main.swift
// GENERIC TYPES
// Create reusable data structures that work with any type
// ===== GENERIC STRUCT =====
struct Stack<Element> {
private var items: [Element] = []
var isEmpty: Bool { items.isEmpty }
var count: Int { items.count }
var top: Element? { items.last }
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element? {
return items.popLast()
}
}
// Usage with different types
var intStack = Stack<Int>()
intStack.push(1)
intStack.push(2)
intStack.push(3)
print(intStack.pop()!) // 3
var stringStack = Stack<String>()
stringStack.push("Hello")
stringStack.push("World")
print(stringStack.top!) // World
// ===== GENERIC CLASS =====
class Box<T> {
var value: T
init(_ value: T) {
self.value = value
}
}
let intBox = Box(42)
let stringBox = Box("Hello")
print(intBox.value) // 42
print(stringBox.value) // Hello
// ===== GENERIC ENUM =====
enum Result<Success, Failure: Error> {
case success(Success)
case failure(Failure)
func map<NewSuccess>(_ transform: (Success) -> NewSuccess) -> Result<NewSuccess, Failure> {
switch self {
case .success(let value):
return .success(transform(value))
case .failure(let error):
return .failure(error)
}
}
}
// ===== GENERIC WITH CONSTRAINTS =====
struct SortedArray<Element: Comparable> {
private var elements: [Element] = []
var sorted: [Element] { elements }
mutating func insert(_ element: Element) {
let index = elements.firstIndex { $0 > element } ?? elements.count
elements.insert(element, at: index)
}
}
var sortedNums = SortedArray<Int>()
sortedNums.insert(3)
sortedNums.insert(1)
sortedNums.insert(2)
print(sortedNums.sorted) // [1, 2, 3]
// ===== GENERIC LINKED LIST =====
class Node<T> {
var value: T
var next: Node<T>?
init(_ value: T) {
self.value = value
}
}
class LinkedList<T> {
var head: Node<T>?
func append(_ value: T) {
let newNode = Node(value)
if head == nil {
head = newNode
return
}
var current = head
while current?.next != nil {
current = current?.next
}
current?.next = newNode
}
func printAll() {
var current = head
while let node = current {
print(node.value, terminator: " -> ")
current = node.next
}
print("nil")
}
}
let list = LinkedList<Int>()
list.append(1)
list.append(2)
list.append(3)
list.printAll() // 1 -> 2 -> 3 -> nil
// ===== GENERIC TYPE ALIAS =====
typealias StringDictionary<T> = Dictionary<String, T>
var scores: StringDictionary<Int> = [:]
scores["Alice"] = 95
scores["Bob"] = 87
// ===== EXTENDING GENERIC TYPES =====
extension Stack {
func peek() -> Element? {
return items.last
}
}
extension Stack where Element: Equatable {
func contains(_ item: Element) -> Bool {
return items.contains(item)
}
}
extension Stack where Element: Numeric {
func sum() -> Element {
return items.reduce(0, +)
}
}
var numStack = Stack<Int>()
numStack.push(1)
numStack.push(2)
numStack.push(3)
print(numStack.sum()) // 6
// ===== GENERIC QUEUE =====
struct Queue<Element> {
private var elements: [Element] = []
var isEmpty: Bool { elements.isEmpty }
var front: Element? { elements.first }
mutating func enqueue(_ element: Element) {
elements.append(element)
}
mutating func dequeue() -> Element? {
return isEmpty ? nil : elements.removeFirst()
}
}
var queue = Queue<String>()
queue.enqueue("First")
queue.enqueue("Second")
print(queue.dequeue()!) // FirstTry It Yourself!
Create a generic BinaryTree<T: Comparable> with insert, search, and inorder traversal!