参考URL: https://qiita.com/shoheiyokoyama/items/31eca0d4b27bc9608eb8
/* Generics */
/* Generics - Generic Types */
// struct
struct S<T> {}
let s = S<Int>() /* S<Int> */
let ss = S<String>() /* S<String> */
// class
class C<T> {}
let c = C<Int>() /* C<Int> */
let cc = C<String>() /* C<String> */
// enum
enum E<T> {
case e(T)
}
let e = E.e(1) /* E<Int> */
let ee = E.e("a") /* E<String> */
struct Queue<Element> {
private var elements: [Element] = []
mutating func enqueue(_ newElement: Element) {
elements.append(newElement)
}
mutating func dequeue() -> Element? {
guard !elements.isEmpty else { return nil }
return elements.removeFirst()
}
}
var intQueue = Queue<Int>()
intQueue.enqueue(3) /* Queue<Int>(elements: [3]) */
intQueue.enqueue(5) /* Queue<Int>(elements: [3, 5]) */
intQueue.dequeue() /* 3 */
intQueue.dequeue() /* 5 */
intQueue.dequeue() /* nil */
var stringQueue = Queue<String>()
stringQueue.enqueue("Generics") /* Queue<String>(elements: ["Generics"]) */
stringQueue.enqueue("Generic Types") /* Queue<String>(elements: ["Generics", "Generic Types"]) */
// extension
extension Queue {
func peek() -> Element? {
return elements.first
}
}
stringQueue.peek() /* "Generics" */
/* --- Generics - 継承 --- */
class BaseClass_1<T> {}
// 継承したクラスもGenerics
class InheritClass<T>: BaseClass_1<T> {}
// 親のクラスをString型にしてそれを継承
class StringClass: BaseClass_1<String> {}
// Protocol - Associated Types
protocol Container {
associatedtype ItemType
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
// Protocol継承 - Non-generic type
struct IntStack: Container {
typealias ItemType = Int
var items: [Int] = []
mutating func append(item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
var intStack = IntStack()
intStack.append(item: 2)
intStack.append(item: 3)
intStack.append(item: 4)
intStack.count
let result = intStack[2]
/* Generics Types - Protocol Associates Types */
struct Queue1<Element>: Container {
private var elements: [Element] = []
mutating func enqueue(_ newElement: Element) {
elements.append(newElement)
}
mutating func dequeue() -> Element? {
guard !elements.isEmpty else { return nil }
return elements.removeFirst()
}
mutating func append(item: Element) {
enqueue(item)
}
var count: Int {
return elements.count
}
subscript(i: Int) -> Element {
return elements[i]
}
}
var intQueue1 = Queue1<Int>()
intQueue1.append(item: 3)
intQueue1.append(item: 5)
intQueue1[1]
intQueue1.count
var stringQueue1 = Queue1<String>()
stringQueue1.append(item: "Generics")
stringQueue1.append(item: "Generic Types")
stringQueue1[0]
stringQueue1.count
/* Generic Functions */
// Non Generic Function
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var intValue1 = 2
var intValue2 = 5
swapTwoInts(&intValue1, &intValue2)
intValue1 /* 5 */
intValue2 /* 2 */
// Generic Function
func swapToValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
var stringValue1 = "a"
var stringValue2 = "b"
swapToValues(&stringValue1, &stringValue2)
stringValue1 /* b */
stringValue2 /* a */
var doubleValue1 = 0.12
var doubleValue2 = 3.45
swapToValues(&doubleValue1, &doubleValue2)
doubleValue1 /* 3.45 */
doubleValue2 /* 0.12 */
/* Type Constraints */
protocol MyProtocol {}
class MyClass {}
// MyClassとMyProtocolの引数
func myFunction<T: MyClass, U: MyProtocol>(someT: T, someU: U) {
// function body goes here
}
class BaseClass {}
class MyClass1: BaseClass {} /* BseClass Only */
class MyClass2: BaseClass, MyProtocol {} /* BseClass & MyProtocol */
class MyClass3: MyProtocol {} /* MyProtocol Only */
// where条件付き Tは BaseClass & MyProtocol
func myFunction<T>(value: T) where T: BaseClass, T: MyProtocol {
// function body goes here
}
let myClass1 = MyClass1()
// myFunction(value: myClass1) /* Error */
let myClass2 = MyClass2()
myFunction(value: myClass2)
let myClass3 = MyClass3()
// myFunction(value: myClass3) /* Error */
// TがComparableに準拠していること
func findLargestInArray<T: Comparable>(array: [T]) -> T? {
guard var largestValue = array.first else { return nil }
array.forEach { val in
largestValue = val > largestValue ? val : largestValue
}
return largestValue
}
let intArray = [1, 2, 3, 4, 5]
let largestValue1 = findLargestInArray(array: intArray)
//=> 5
let stringArray = ["a", "b", "c", "d", "e"]
let largestValue2 = findLargestInArray(array: stringArray)
//=> "e"
/* Where Clauses */
// Containerプロとコトルに準拠する配列Itemが、すべての同じかどうかを判定するメソッド true: 同じ, false: 違う
func allItemsMatch<C1: Container, C2: Container>(someContainer: C1, _ anotherContainer: C2) -> Bool where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
if someContainer.count != anotherContainer.count {
return false
}
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
return true
}
// 既存のProtocolの要素に条件をつけてメソッドを定義
extension Collection where Element: Comparable {
func largestValue() -> Element? {
guard var largestValue = first else { return nil }
for item in self {
if item > largestValue {
largestValue = item
}
}
return largestValue
}
}
let largestInt = [1, 2, 3, 4, 5].largestValue() /* 5 */
let largestCharacter = "Generics".largestValue() /* "s" */
let largestValue = (0...100).largestValue() /* 100 */