首页 > 代码库 > 寒城攻略:Listo 教你 25 天学会 Swift 语言 - 24 Generics

寒城攻略:Listo 教你 25 天学会 Swift 语言 - 24 Generics

import Foundation


//***********************************************************************************************

//1.Generics(泛型)

//_______________________________________________________________________________________________

//介绍

//泛型代码可以让你写出根据自我需求定义,适用于任何类型,灵活并且可以重用的函数和类型。它可以避免重复的代码,用一种清晰和抽象的方式来表达代码的意图

//泛型是 Swift强大特征中的一个,许多 Swift标准库都是通过泛型代码构建出来的。


//***********************************************************************************************

//2.The Problem That Generics Solve(泛型所解决的问题)

//_______________________________________________________________________________________________

//代码演示非泛型函数 swapTwoInts,用来交换两个 Int

func swapTwoInts(inout a:Int,inout b:Int){          //这个函数使用 inout来交换 a b的值

   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)")       //此时我们思考,swapTwoInt函数非常有用,但是它只交换 Int 值,如果我们想交换两个 String或者 Double,就不得不写更多的函数


func swapTwoStrings(inout a:String,inout b:String) {    //书写交换两个字符串的方法

   let temporaryA = a

    a = b

    b = temporaryA

}


func swapTwoDoubles(inout a:Double,inout b: Double) {    //书写交换两个 Double类型浮点数的方法,这时我们发现只有参数不同,函数结构都相同,使得代码变得庞大重复,这时我们可以使用泛型

   let temporaryA = a

    a = b

    b = temporaryA

}


//***********************************************************************************************

//3.Generic Functions(泛型函数)

//_______________________________________________________________________________________________

//介绍

//泛型函数可以工作与任何类型(实例代码)

func swapTwoValues<T>(inout a:T,inout b:T){      //使用泛型来优化代码

   let temporaryA = a

    a = b

    b = temporaryA

}

var someInt1 =4                               //整形数据测试泛型

var anotherInt1 =108

swapTwoValues(&someInt1, &anotherInt1)

println("someInt1 is now\(someInt1),and another is now\(anotherInt)")


var someString ="Hello"

var anotherString ="world"                    //字符串测试泛型

swapTwoValues(&someString, &anotherString)

println("someString is now\(someString),and another is now\(anotherString)")


//***********************************************************************************************

//4.Type Parameters(类型参数)

//_______________________________________________________________________________________________

//介绍

//类型参数指定并命名为一个占位类型,并且紧随在函数的后面,使用一对尖括号括起来


//***********************************************************************************************

//5.Naming Type Parameters(命名类型参数)

//_______________________________________________________________________________________________

//类型参数的命名规则使用首字母大写,并且驼峰式命名


//***********************************************************************************************

//6.Generic Types(泛型类型)

//_______________________________________________________________________________________________

//介绍

//通常在泛型函数中,Swift允许我么你自定义自己的泛型类型,这些自定义类,结构体和枚举作用于任何类型,如同 Array Dictionary的用法

//栈,一个栈是一系列值域的集合,和 Array类似,但其是一个比 Swift Array类型更多限制的集合。一个数组允许其里面的任何位置插入删除数据,而栈,只允许在集合的末端添加新的项,同样也只能在集合的末尾删除项


//_______________________________________________________________________________________________

//实例代码演示写一个非泛型版本的栈,Int值型的栈

struct IntStack{

   var items = [Int]()

   mutatingfunc push(item:Int){         //向数组存入元素到末尾

       items.append(item)

    }

   mutatingfunc pop() ->Int{

       returnitems.removeLast()          //移除末尾的元素

    }

}


//_______________________________________________________________________________________________

//实例代码演示写一个泛型版本的栈

struct Stack<T> {                          //泛型版本的类型紧跟着结构体名的后面 <T>

   var items = [T]()

   mutatingfunc push(item:T){

       items.append(item)

    }

   mutatingfunc pop() ->T{

       returnitems.removeLast()

    }

}

var stackOfString =Stack<String>()

stackOfString.push("Hello")

stackOfString.push("dos")

println(stackOfString.items)

stackOfString.pop()

println(stackOfString.items)


//***********************************************************************************************

//7.Type Constraints(类型约束)

//_______________________________________________________________________________________________

//介绍

//swapTwoValues 函数和 Stack类型可以作用于任何类型,不过有的时候在使用泛型函数和泛型类型上的类型强制约束为某种特定类型是非常必要的,这就是类型约束


//_______________________________________________________________________________________________

//类型约束语法

/*

func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {      //假定函数有两个类型参数。第一个类型参数 T,有一个需要 T必须是 SomeClass 子类的类型约束;第二个类型参数 U,有一个需要 U必须遵循 SomeProtocol协议的类型 约束

    // function body goes here

}

*/


//_______________________________________________________________________________________________

//类型约束行为(非泛型函数的类型约束行为)

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

   for (index, value)in enumerate(array){    //遍历索引固定字符串的下标

       if value =http://www.mamicode.com/= valueToFind{

       return index

        }

    }

    return nil

}

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

iflet foundIndex =findStringIndex(strings,"llama"){

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

}


//_______________________________________________________________________________________________

//类型约束行为(泛型函数的类型约束行为)

func findIndex<T: Equatable>(array: [T], valueToFind:T) -> Int? {     //这里的 <T: Equatable> 表示一种安全的形式,因为并不是所有的数据都可以用 == 来判断相等的,如果一个结构体或者类很复杂,系统无法判断等于的含义,所以如果不写 Equatable协议,程序无法运行,此时Equatable协议在这里充当了对参数类型 T 的类型约束,约束它可以被使用 ==运算

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

       if value =http://www.mamicode.com/= valueToFind {

           return index

        }

    }

    return nil

}

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

println(doubleIndex)


//***********************************************************************************************

//8.Associated Types(关联类型)

//_______________________________________________________________________________________________

//介绍

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


//_______________________________________________________________________________________________

//实例代码演示关联类型行为(非泛型代码)

protocol Container{            //定义 Container协议

   typealias ItemType         //定义 ItemType关联类型

    mutatingfunc append(item:ItemType)       //必须可能通过 append 方法添加一个新 item 到容器里

    var count:Int {get}               //必须可能通过使用 count属性获取容器里 items 的数量,并返回一个 Int

    subscript(i:Int) ->ItemType {get}        //必须可能通过容器的 Int索引值下标可以检索到每一个 item

}


struct IntStacks:Container{

   var items = [Int]()

   mutatingfunc push(item:Int){

       items.append(item)

    }

   mutatingfunc pop() ->Int {

       returnitems.removeLast()

    }

    

    typealias ItemType =Int           //将抽象的 typealias 类型定义为 Int 类型,类型可以自动判断,所以代码也可以删除

    

   mutatingfunc append(item:Int){

       self.push(item)

    }

   var count:Int{

       returnitems.count

    }

   subscript (i:Int) ->Int{

       returnitems[i]

    }

}


//_______________________________________________________________________________________________

//泛型代码演示关联类型行为

struct Stacks<T>:Container{

   var items = [T]()

   mutatingfunc push(item:T){

       items.append(item)

    }

   mutatingfunc pop() ->T{

       returnitems.removeLast()

    }

   mutatingfunc append(item:T){

       self.push(item)

    }

   var count:Int{

       returnitems.count

    }

   subscript(i:Int) ->T{

       returnitems[i]

    }

}


//_______________________________________________________________________________________________

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

extension Array:Container{}       //定义一个扩展,因为 Array 默认已经实现了 Container 协议中的所有功能,所以我们可以将任何 Array当作 Container来使用


//***********************************************************************************************

//9.Where Clauses(where 语句)

//_______________________________________________________________________________________________

//介绍

//类型约束中描述的类型约束确保你定义关于类型参数的需求和一泛型函数或类型有关联


//_______________________________________________________________________________________________

//实例代码演示 where语句的用法

func allItemsMatch<

    C1: Container, C2: Container

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

    (someContainer: C1, anotherContainer:C2) ->Bool {            //这个函数用了两个参数:someContainer anotherContainersomeContainer参数是类型 C1,anotherContainer 参数是类型 C2

       /*

            参数链解析

                C1 必须遵循 Container协议 (写作 C1: Container)

                C2 必须遵循 Container协议 (写作 C2: Container)

                C1 ItemType 同样是 C2 ItemType(写作 C1.ItemType == C2.ItemType)

                C1 ItemType 必须遵循 Equatable 协议 (写作 C1.ItemType: Equatable)

        */

        

       if someContainer.count != anotherContainer.count {

           returnfalse

        }

        

       for iin 0..<someContainer.count {

           if someContainer[i] != anotherContainer[i] {

               returnfalse

            }

        }

       returntrue

}

var stackOfStrings =Stacks<String>()

stackOfStrings.push("Listo")

stackOfStrings.push("Pin")

stackOfStrings.push("Melody")


var arrayOfString1 = ["Listo","Pin","Melody"]


if allItemsMatch(stackOfStrings,arrayOfString1){

    println("All items match")

}

else{

    println("Not all items match")

}