-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathgenerics.swift
144 lines (107 loc) · 2.94 KB
/
generics.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import Foundation
// Generic functions can operate on any type.
//
// Type parameters specify a placeholder type
// in brackets after the function name.
// Thereafter, that placeholder can be used
// as a type parameter or within the function.
func log<ToBeLogged>(a: ToBeLogged) {
print(a)
}
log("les filles")
log(1)
// # Generic Types
// Generic types are your own structs, classes,
// and enums that work with any type.
// This is how all of Swift's built-in types work.
struct Bucket<Bucketable> {
var items = [Bucketable]()
mutating func add(item: Bucketable) {
items.append(item)
}
mutating func remove() {
items = []
}
}
var bucket = Bucket<Int>()
bucket.add(1)
var bucket2 = Bucket<String>()
bucket2.add("special")
class Basket<Basketable> {
var items = [Basketable]()
func add(item: Basketable) {
items.append(item)
}
func remove() {
items = []
}
}
var basket = Basket<Int>()
basket.add(1)
var basket2 = Basket<String>()
basket2.add("control")
// # Type Constraints
// You can ensure that a generic type
// conforms to a protocol or is a subclass
// of a specific type.
// Without adding the `Equatable` type constraint,
// the compiler doesn't know whether `==` will work
// and thus won't compile this func.
func equal<T: Equatable>(a: T, b: T) -> Bool {
return a == b
}
// # Associated Types
// Protocols can define placeholder names (aliases)
// to types that are used as part of the protocol.
protocol Vase {
typealias Plant
mutating func add(item: Plant)
var size: Int { get set }
mutating func remove() -> Plant
}
class GrecianUrn : Vase {
typealias Plant = String
var size = 10
var plantName = ""
func add(item: String) {
plantName = item
}
func remove() -> String {
let name = plantName
plantName = ""
return name
}
}
// # Where clauses
// You can impose more rigorous conformance between types using
// a `where` clause after the list of type params within the brackets.
var a = ["a"]
print(a.dynamicType)
print(object_getClassName(a))
protocol Container {
typealias Thing
func size() -> Int
func add(thing: Thing)
}
class Crate<Thing> : Container {
var items = [Thing]()
func size() -> Int {
return items.count
}
func add(thing: Thing) {
items.append(thing)
}
}
func similarCrates<C1: Container, C2: Container where C1.Thing == C2.Thing> (crate1: C1, crate2: C2) -> Bool {
return crate1.size() == crate2.size()
}
var stringCrate = Crate<String>()
stringCrate.add("stickers")
var intCrate = Crate<Int>()
intCrate.add(22)
// This fails: 'String' is not identical to 'Int'
/* similarCrates(stringCrate, intCrate) */
var anotherStringCrate = Crate<String>()
similarCrates(stringCrate, crate2: anotherStringCrate) // false
anotherStringCrate.add("goo")
similarCrates(stringCrate, crate2: anotherStringCrate) // true