Generics - RaduG/swift_learning GitHub Wiki

Basic example

struct Queue<T> {
  var items = [T]()

  mutating func push(_ element: T) {
    items.append(element)
  }

  mutating func pop() -> T {
    return items.removeFirst()
  }
}

var q = Queue<String>()
q.push("abc")
q.push("def")
print(q.pop())
print(q.pop())

Extending a generic

Instead of declaring the extension as having a generic type, the generic type in the original class's declaration is available in the extension automatically.

extension Queue {
  func toList() -> [T] {
    return items
  }
}

var q = Queue<String>()
q.push("abc")
q.push("def")
print(q.toList())

Generic type constraints

func someFunc<T: SoneType, U: SomeProtocol & SomeOtherProtocol>(_ x: T, _ y: U) {}

Associated types

protocol Container {
  associatedtype Item

  var size: Int { get }
  mutating func push(_ item: Item)
  mutating func pop() -> Item
}


struct IntQueue: Container {
  typealias Item = Int

  var items = [Int]()
  var size: Int {
    items.count
  }

  mutating func push(_ item: Int) {
    items.append(item)
  }

  mutating func pop() -> Int {
    return items.removeFirst()
  }
}


struct Queue<Item> {
  var items = [Item]()
  var size: Int {
    items.count
  }

  mutating func push(_ element: Item) {
    items.append(element)
  }

  mutating func pop() -> Item {
    return items.removeFirst()
  }
}

Associated types can also have constraints:

associatedtype Item: Equatable
protocol SuffixableContainer: Container {
  associatedtype Suffix: SuffixableContainer where Suffix.Item == Item
  func suffix(_ size: Int) -> Suffix
}
extension Queue where Item == Int {
  func average() -> Int {
    var sum: Int = 0

    for index in 0..<size {
      sum += self[index]
    }

    return sum / size  
  }
}

var queue = Queue<Int>()
queue.push(12)
queue.push(13)

print(queue.average())

Where clauses can also be written on a method-by-method basis:

extension Queue {
  func average() -> Int where Item == Int {
    var sum: Int = 0

    for index in 0..<size {
      sum += items[index]
    }

    return sum / size  
  }
}

Associated types can also have where clauses:

protocol Container {
  associatedtype Item
  mutating func append(_ item: Item)
  var count: Int { get }
  subscript(i: Int) -> Item { get }

  associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
  func makeIterator() -> Iterator
}

Generic subscripts

extension Container {
  subscript<Indices: Sequence>(indices: Indices) -> [Item]
    where Indices.Iterator.Element == Int {
      var result = [Item]()
      for index in indices {
        result.append(self[index])
      }
      return result
  }
}
⚠️ **GitHub.com Fallback** ⚠️