|
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
|