//: Playground - noun: a place where people can play
import UIKit
// # 泛型解决的问题
/*
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
*/
// # 泛型函数
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
// trick: swap(_:_:)Swift库已实现
// # 类型形式参数
// 类型形式参数指定并且命名一个占位符类型,紧挨着写在函数名后面的一对尖括号里(比如 <T> )
// # 命名类型形式参数
// 用大写驼峰命名法,表明是一个占位符
// # 泛型类型
struct Stack<Element> {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
init() {
// just do nothing here
}
init(items: [Element]) {
self.items = items
}
}
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
let fromTheTop = stackOfStrings.pop()
var stackOfInts = Stack(items: [1, 2, 7]) // '<Int>' can be inferred so is omittd.
// *** 泛型的类可以被继承为非泛型
let view = UIView()
let label = UILabel()
let topConstraint = label.topAnchor.constraint(equalTo: view.topAnchor)
// YAnchor is a subclass of anchor. Anchor is a generic class.
// 参见泛型1.playground
// # 扩展一个泛型类型
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
if let topItem = stackOfStrings.topItem {
print("The top item on the stack is \(topItem).")
}
// # 类型约束
// For example, Hashable: a type that provides an integer hash value.
/*
func findIndex(ofString valueToFind: String, in array: [String]) -> Int? {
// trick: array.enumerated() 返回了一个元组的数组,用for-in提取每个元素(n, x)
// 若为数组,n是从零开始的序列,x是对应的元素
// 若为字符串,n是从零开始的序列,x是对应的字符
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findIndex(ofString: "llama", in: strings) {
print("The index of llama is \(foundIndex)")
}
*/
func findIndex<T: Equatable>(of valueToFind: T, in array:[T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
let doubleIndex = findIndex(of: 9.3, in: [3.3424, 0.1, 0.25])
let stringIndex = findIndex(of: "Andrea", in: ["Mike", "Malcolm", "Andrea"])
// # 关联类型
protocol Container {
associatedtype ItemType // ItemType 是一个占位符
mutating func append(_ item: ItemType)
var count: Int { get }
// trick: 下标在协议中的使用
subscript(i: Int) -> ItemType { get }
}
struct IntStack: Container {
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
typealias ItemType = Int // ???
mutating func append(_ item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
struct StackAgain<Element>: Container {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
mutating func append(_ item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
// 扩展现有类型来指定关联类型
extension Array: Container {}
// now we can use an Array as a Container type.
// # 泛型where分句
// where语句,冒号+协议语句都是对泛型类型的限制
func allItemsMatch<C1: Container, C2: Container>(_ someContainer: C1, _ anotherContainer: C2) -> Bool where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
// Check that both containers contain the same number of items.
if someContainer.count != anotherContainer.count {
return false
}
// Check each pair of items to see if they are equivalent.
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
// All items match, so return true.
return true
}
var stackOfStringsAgain = StackAgain<String>()
stackOfStringsAgain.push("uno")
stackOfStringsAgain.push("dos")
stackOfStringsAgain.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
if allItemsMatch(stackOfStringsAgain, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
// # 带有泛型Where分句的扩展
extension Stack where Element: Equatable {
func isTop(_ item: Element) -> Bool {
// trick: .last如果为空返回nil,否则返回包裹最后一个元素的可选项
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
if stackOfStrings.isTop("tres") {
print("Top element is tres.")
} else {
print("Top element is something else.")
}
struct NotEquatable { }
var notEquatableStack = Stack<NotEquatable>()
let notEquatableValue = NotEquatable()
notEquatableStack.push(notEquatableValue)
// Error when: notEquatableStack.isTop(notEquatableValue)
extension Container where ItemType: Equatable {
func startsWith(_ item: ItemType) -> Bool {
return count >= 1 && self[0] == item
}
}
if [9, 9, 9].startsWith(42) {
print("Starts with 42.")
} else {
print("Starts with something else.")
}
extension Container where ItemType == Double {
func average() -> Double {
var sum = 0.0
for index in 0..<count {
sum += self[index]
}
return sum / Double(count)
}
}
print([1260.0, 1200.0, 98.6, 37.0].average())
// 注意: 多要求用逗号隔开
// # 关联类型的泛型where分句
protocol NewContainer {
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
}
protocol ComparableContainer: NewContainer where Item: Comparable { }
// # 泛型下标
extension NewContainer {
subscript<Indices: Sequence>(indices: Indices) -> [Item] where Indices.Iterator.Element == Int {
var result = [Item]()
for index in indices {
result.append(self[index])
}
return result
}
}
网友评论