寒城攻略: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]()

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

items.append(item)

}

mutating
func pop() ->Int{

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

}

}

//_______________________________________________________________________________________________

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

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

var items = [T]()

mutating
func push(item:T){

items.append(item)

}

mutating
func pop() ->T{

return
items.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 == 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 == 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]()

mutating
func push(item:Int){

items.append(item)

}

mutating
func pop() ->Int {

return
items.removeLast()

}

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

mutating
func append(item:Int){

self.push(item)

}

var count:
Int{

return
items.count

}

subscript (i:
Int) ->Int{

return
items[i]

}

}

//_______________________________________________________________________________________________

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

struct Stacks<T>:Container{

var items = [T]()

mutating
func push(item:T){

items.append(item)

}

mutating
func pop() ->T{

return
items.removeLast()

}

mutating
func append(item:T){

self.push(item)

}

var count:
Int{

return
items.count

}

subscript(i:
Int) ->T{

return
items[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和 anotherContainer。someContainer参数是类型
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 {

return
false

}

for i
in 0..<someContainer.count {

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

return
false

}

}

return
true

}

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

}

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

时间: 2024-10-21 23:58:22

寒城攻略:Listo 教你 25 天学会 Swift 语言 - 24 Generics的相关文章

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

import Foundation /* Listo Han 出品 Swift 编程攻略 攻略参考:<The Swift Programming Language> 攻略适用:本攻略适合 Swift零基础,但要有至少其他任何一门编程语言基础,熟悉程序语句的用户 攻略格式: 知识模块://***********************************************************************************************/ 模块细节://_

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

import Foundation //*********************************************************************************************** //1.Hello world //_______________________________________________________________________________________________ //输出 "Hello, world&q

寒城攻略:Listo 教你 25 天学会 Swift 语言 - 03 The Basic

import Foundation //*********************************************************************************************** //1.The Basics(基础) //_______________________________________________________________________________________________ //介绍 //Swift 的类型是

寒城攻略:Listo 教你 25 天学会 Swift 语言 - 04 Basic Operators

import Foundation //*********************************************************************************************** //1.Basic Operators(基本操作符) //_______________________________________________________________________________________________ //简介 //操作

寒城攻略:Listo 教你 25 天学会 Swift 语言 - 25 Listo&#39;s Conclusion

import Foundation //*********************************************************************************************** //1.Listo's Conclusion(Listo 的编写总结) //_______________________________________________________________________________________________

寒城攻略:Listo 教你Linux Cent OS 服务器从搭建到配置

曾经也用过 Linux 服务器,也搭建过,一直浑浑噩噩的,但是今天突然帮朋友搭建一个服务器并使用,还是发现了很多问题,所以写一个详细的技术攻略供未来的朋友遇到问题后参考. 首先考虑到看这篇攻略的朋友可能层次都不同,所以 Listo 个人还是有强迫症的,我就从一个新手的角度来讲解服务器的使用. 首先 Listo 用的阿里云的服务器,这个大家可以去注册阿里云账号购买服务器即可.这里值得一提的是一个很重要的问题,就是各位购买服务器的朋友一定要记得在购买设置配置的时候要买公网 IP,这个很重要,公网和内

寒城攻略:Listo 教你用Swift 语言编写 IOS 平台流媒体播放器

先展示播放器效果: 依旧继承 Listo 本人的强迫症,还是从最初到完成完整的写一个攻略来记录一下,这里声明 Listo 本人也是看了很多的戴维营攻略才总结分享给大家这一篇攻略的. 首先,Listo 使用的是一个开源的第三方框架而不是使用系统本身带有的框架, 这个框架的名字叫做 MobileVLCKit 框架,至于框架的获取,Listo 这里也有截图,首先打开终端,执行命令 "$git clone https://github.com/wuqiong/MobileVLCKit-SDK.git&q

寒城攻略:Listo 教你用 Swift 写IOS UI 项目计算器

之前总结过 Swift 的语言攻略,这里就不做赘述了,现在做一个实例计算器项目来介绍一下 Swift 的应用.(注释已经完全,直接上代码) 先看一下效果图: 下面是具体的代码和解释: 分享快乐,开源中国,转载请声明出处

寒城攻略:Listo 教你用 Swift 写IOS UI 项目生活记事本

刚才用 Swift 写了一个记事本的应用,仅仅是简单的 UI 方向的开发,先来上产品的界面: 如今 Listo 给分享源码: 共同进步,开源中国.转载请声明出处