您的位置:首页 > 移动开发 > Swift

Swift 泛型(十九)

2016-05-05 11:33 537 查看
泛型

泛型代码可根据自定义需求,写出适用于任何类型、灵活且可重用的函数和类型,避免重复的代码,用一种清晰和抽象的思维表达代码的意思

1.泛型用途

[objc] view
plain copy

 





// 普通的函数,用来交换两个值  

func swapTwoInts(inout a: Int, inout b: Int) {  

    let temporaryA = a  

    a = b  

    b = temporaryA  

}  

  

var someInt = 3  

var anotherInt = 107  

swapTwoInts(&someInt, &anotherInt)  

println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")  

// prints "someInt is now 107, and anotherInt is now 3"  

  

func swapTwoStrings(inout a: String, inout b: String) {  

    let temporaryA = a  

    a = b  

    b = temporaryA  

}  

   

func swapTwoDoubles(inout a: Double, inout b: Double) {  

    let temporaryA = a  

    a = b  

    b = temporaryA  

}  

以上都是转换两个数的值,但他们代码都是一样的,只不过传入类型不一样,同一份代码就要写了三次,使用泛型就可以忽略传入值的类型,只使用一份代码

2.泛型函数

占位符T是一种类型参数的示例,类型参数指定命名为一个占位类型,并且紧随在函数名后面,使用一对尖括号括起来,一旦类型参数被确定,就可以用来定义函数的参数类型(a,b),或作为函数的返回类型,或作为函数主题的注释类型,此时类型参数所代表的占位符不管函数任何时候被调用,都会被实际类型所替代

[objc] view
plain copy

 





func swapTwoValues<T>(inout a: T, inout b: T) {  

    let temporaryA = a  

    a = b  

    b = temporaryA  

}  

泛型版本的函数使用占位符(T)来替代实际类型名,占位符并没有提示T必须是什么类型,但a和b必须是用一种类型,在swapTwoValues被调用时才能确定T所表示的类型

[objc] view
plain copy

 





func swapTwoInts(inout a: Int, inout b: Int)  

func swapTwoValues<T>(inout a: T, inout b: T)  

  

var someInt = 3  

var anotherInt = 107  

swapTwoValues(&someInt, &anotherInt)  

// someInt is now 107, and anotherInt is now 3  

   

var someString = "hello"  

var anotherString = "world"  

swapTwoValues(&someString, &anotherString)  

// someString is now "world", and anotherString is now "hello"  

3.泛型类型

Swift允许自定义泛型类型,这些自定义类、结构体和枚举作用于任何类型

[objc] view
plain copy

 





// 以下是一个用泛型写的栈Stack,模拟栈的push和pop  

struct IntStack {  

    var items = Int[]()  

    mutating func push(item: Int) {  

        items.append(item)  

    }  

    mutating func pop() -> Int {  

        return items.removeLast()  

    }  

}  

  

// Stack提供两个方法,push和pop,从栈中压进一个值和弹出一个值,但只能用于int值,下面定义一个泛型Stack类,可处理任何类型的栈  

struct Stack<T> {  

    var items = T[]()  

    mutating func push(item: T) {  

        items.append(item)  

    }  

    mutating func pop() -> T {  

        return items.removeLast()  

    }  

}  

  

var stackOfStrings = Stack<String>()  

stackOfStrings.push("uno")  

stackOfStrings.push("dos")  

stackOfStrings.push("tres")  

stackOfStrings.push("cuatro")  

// the stack now contains 4 strings  

  

let fromTheTop = stackOfStrings.pop()  

// fromTheTop is equal to "cuatro", and the stack now contains 3 strings  

4.类型约束

有时候对使用在泛型函数和泛型类型上的类型强制约束为某种特定的类型是非常有用的,可以指定一个必须继承自指定类的类型参数,或者遵循一个特定的协议或协议构成

4.1语法

[objc] view
plain copy

 





// 假定函数有两个类型参数,类型参数T必须是SomeClass子类的类型约束,类型参数U必须遵循SomeProtocol协议的类型约束  

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {  

    // function body goes here  

}  

4.2实例

非泛型函数,查找以给定的String数组,若找到匹配的字符串,返回下标

[objc] view
plain copy

 





func findStringIndex(array: String[], valueToFind: String) -> Int? {  

    for (index, value) in enumerate(array) {  

        if value == valueToFind {  

            return index  

        }  

    }  

    return nil  

}  

  

  

let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]  

if let foundIndex = findStringIndex(strings, "llama") {  

    println("The index of llama is \(foundIndex)")  

}  

// prints "The index of llama is 2"  

  

  

// 使用泛型实现相同功能,但是下面这个泛型函数不会被编译,在等式 value == valueToFind 里,不是所有的类型都可以用等式 == 来进行比较,如果是自己创建的自定义类型,Swfit就无法猜到这个等于的意思,所以编译下面代码的时候就会报错  

func findIndex<T>(array: T[], valueToFind: T) -> Int? {  

    for (index, value) in enumerate(array) {  

        if value == valueToFind {  

            return index  

        }  

    }  

    return nil  

}  

 Swift标准库定义了一个Equatable协议,要求任何遵循的类型实现等式 == 和不等式 != 对两个该类型进行比较。所有的Swift标准类型自动支持Equatable协议

[objc] view
plain copy

 





func findIndex<T: Equatable>(array: T[], valueToFind: T) -> Int? {  

    for (index, value) in enumerate(array) {  

        if value == valueToFind {  

            return index  

        }  

    }  

    return nil  

}  

  

let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)  

// doubleIndex is an optional Int with no value, because 9.3 is not in the array  

let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")  

// stringIndex is an optional Int containing a value of 2  

5.关联类型

定义一个协议的时候,声明一个或多个关联类型作为协议定义的一部分是非常有用的,一个关联类型给定作用于协议部分的类型一个节点名。作用于关联类型上实际是不需要指定的,直到该协议接受。关联类型为 typealias关键字

5.1实例

定义ItemType关联类型,1. append方法添加一个新的item 2. count方法获取数量 3. 通过索引值检索到每一个item

[objc] view
plain copy

 





protocol Container {  

    typealias ItemType  

    mutating func append(item: ItemType)  

    var count: Int { get }  

    subscript(i: Int) -> ItemType { get }  

}  

  

// IntStack的非泛型版本,实现Container协议的所有三个要求  

struct IntStack: Container {  

    // original IntStack implementation  

    var items = Int[]()  

    mutating func push(item: Int) {  

        items.append(item)  

    }  

    mutating func pop() -> Int {  

        return items.removeLast()  

    }  

    // conformance to the Container protocol  

    typealias ItemType = Int  

    mutating func append(item: Int) {  

        self.push(item)  

    }  

    var count: Int {  

    return items.count  

    }  

    subscript(i: Int) -> Int {  

        return items[i]  

    }  

}  

  

// 遵循Container协议的泛型版本  

struct Stack<T>: Container {  

    // original Stack<T> implementation  

    var items = T[]()  

    mutating func push(item: T) {  

        items.append(item)  

    }  

    mutating func pop() -> T {  

        return items.removeLast()  

    }  

    // conformance to the Container protocol  

    mutating func append(item: T) {  

        self.push(item)  

    }  

    var count: Int {  

    return items.count  

    }  

    subscript(i: Int) -> T {  

        return items[i]  

    }  

}  

5.2扩展一个存在的类型为已指定关联类型

Swift中的Array已经提供了一个append方法,一个count属性和通过下标查找元素的功能,都已满足Container协议的要求,就意味着可以扩展Array去遵循Container协议,只要通过简单声明Array适用于该协议就可以了

[objc] view
plain copy

 





extension Array: Container {}  

6.Where语句

where语句要求一个关联类型遵循一个特定的协议,或那个特定的类型参数和关联类型可以是相同的

[objc] view
plain copy

 





// 定义allItemsMatch的泛型函数检查两个Container单例是否包含相同顺序的相同元素,如果匹配返回ture,否则返回false  

func allItemsMatch<  

    C1: Container, C2: Container  

    where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>  

    (someContainer: C1, anotherContainer: C2) -> Bool {  

          

        // 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 stackOfStrings = Stack<String>()  

stackOfStrings.push("uno")  

stackOfStrings.push("dos")  

stackOfStrings.push("tres")  

   

var arrayOfStrings = ["uno", "dos", "tres"]  

   

if allItemsMatch(stackOfStrings, arrayOfStrings) {  

    println("All items match.")  

} else {  

    println("Not all items match.")  

}  

// prints "All items match."  

FROM:  http://blog.csdn.net/huangchentao/article/details/32718325
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: