码迷,mamicode.com
首页 > 其他好文 > 详细

Swift语言中的泛型编程 【Generic】【Part 1】

时间:2014-06-07 21:57:16      阅读:358      评论:0      收藏:0      [点我收藏+]

标签:c   style   class   blog   a   http   

泛型 

泛型编程让你可以编写更具扩展性、易重用的功能,代码使用时的类型取决于你所定义的业务需求。你可以编写避免重复的代码,目标更加清晰明确,风格抽象。

泛型是Swift语言的一项强大的特性,基本上所有的swift标准库都建立在泛型代码上。实际上,你在这本书的时候不知不觉地接触到泛型,它贯穿始终。例如Swift的数组和字典类型都是泛型集合。你可以创建用于存放整数值的数组,也创建数组存储字符串,其他所有能在Swift中创建的类型都可以创建到数组中。类似的,你可以创建字典来存储数值或其他指定的类型,毫无拘束。

 

泛型编程所解决的问题

这里是一个标准的,没有使用泛型的swapTwoInts函数,使用两个整数输入参数:

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

         let temporaryA = a

         a = b

         b = temporaryA

     }

这个函数使用可读写的输入参数作为交换变量(变量a,变量b),该语法具体见“In-Out Parameters”章节

swapTwoInts函数交换两个输入参数的初始值(将a和b交换),先将b置入a,再将a置入b。你可以调用这个函数去交换两个整数变量。

     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"

swapTwoInts函数是有用的,但它只能用于整数(Int)的类型,如果你想用它来交换两个字符串,或两个长整数类型,你就需要写更多的函数,命名出诸如swapTwoStrings或swapTwoDoubles这样的函数名字来,例如下面这两个函数:

     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

     }

你可能注意到函数过程主体上,swapTwoInts, swapTwoStrings和 swapTwoDoubles是一样的,只是他们所接入的输入值有所区别(Int,String和Double)。

所以我们把想把它改得更加有用,更具延展性,有没有办法编写一个可以交换任何类型的单一函数? Okay, 泛型就是用来解决这一类的问题。(下面就来设计这几个函数的泛型版本)

 

批注:

对于上面的三个函数,最主要的一点是a、b两个值的定义类型是相同的。如果a和b两个值不是相同类型,就无法在函数内对其进行交换。Swift是一个类型安全的语言,举例来说,它不允许字符串类型和长整数类型的两个变量直接进行交换,尝试这样做将会得到一个编译时的错误信息。

  

泛型函数

泛型函数可以适应各种类型,这个是泛型版本的swapTwoInts函数,命名为swapTwoValues:

 

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

         let temporaryA = a

         a = b

         b = temporaryA

     }

swapTwoValues函数主体和swapTwoInts函数主体是一样的,但是程序的swapTwoValues和swapTwoInts的第一行程序是有点点区别的,我们对比一下:

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

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

 

泛型版本的函数使用了一个占位符类型(在这里命名为T)规范为一个实际的命名值(比如Int String 或Double).占位符并不说明T一定是某个类型,但它说明a和b一定是相同的T类型,不论T代表什么,实际产生的类型取决于调用的时候参数所传值的类型。

其他的区别在于泛型函数名称swapTwoValues后面跟随一个<T>。括号告诉Swift占位符T代表用于swapTwoValues的泛类。因为T已被说明是一个占位符,Swift并不立即查找名为“T”类型,等调用的时候才判断。

现在,swapTwoValues函数可以像swapTwoInts一样调用了,表面上它可以传入任何两个数值,只要数值的类型是一样就可以了。每次swapTwoValues调用的时候,类型T就替换为输入参数值所使用的类型。

正如下面的两个例子程序一样,T分别被置换为Int和string类型。

     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" 

批注:上面的定义swapTwoValue函数设计想法来自一个泛型函数,叫swap,它已经是Swift的标准库函数,可供我们在app开发中调用,如果真需要一个叫swapTwoValues的函数的话,最好还是使用现有的swap函数,我们无须自行设计一个。

 

类型参数

在上文swapTwoValues示例函数中,占位符T是一个类型参数的例子。类型参数指定、命名占位符类型,定义上跟随函数的名字并使用括号包含“如<T>”

一个类型参数可以用于解释函数的参数属于什么类型(比如swapTwoValues函数的a和b参数的类型);可以解释函数返回的泛型,也可以解释函数执行体中所使用的泛型,在这些应用场景中,占位符所代表的类型将在调用到的时候被实际类型代替。(在swapTwoValues示例程序中,类型T在函数第一次调用的时候就被Int这个具体类型所代替,然后在第二次调用的时候却被string类型所代替)

你可以在括号(<T>)中写入更多的类型参数,之间使用逗号隔开(如<T1,T2,T3>)。

 

命名类型参数

在上文简单的例子下你可以写单个占位符实现泛型函数或泛型类型(比如上文swapTwoValues泛型函数,或存储单种类型的泛型集合,比如Array),通常我们使用T来命名类型参数,但你可以使用任何符合规则的标识符来命名类型参数。

如果你在定义复杂的泛型函数,或具体多种参数的泛型类型,你可以使用更长更详细的名字命名类型参数。比如Swift的Dictionary类型有两个类型参数,keys和values,分别代表键和值。如果你自已写一个Dictionary类,可以把这两个类型参数命名为KeyType和ValueType ,这样就更方便你记住它们在代码中是用来做什么用途了。

批注:

经通常使用首字母为大写的骆驼式命名法(UpperCamelCase),比如(T或KeyType),这样我们可以直观判断这个符号是类型占位符,而不是数值。

 

泛类型

除了定义泛型函数,Swift允许你定义自已的泛类型,可以是自定义的类,结构体,或枚举。就象Array和Dictionary类。

本章将向你展示如写编写一个泛型堆栈Stack类。堆栈是一堆有序的数值,类似数组,但相对Array数组它有更严格的操作要求。 数组允许你存储和删除数组中任一位置的元素。而堆栈只允许你添加新的内容到它的栈顶(就是push新值到栈中),同样的,堆栈允许你删除元素,但也只能是从栈顶删除(这个叫poping操作)

 

批注:

堆栈的概念在UINavigationController类用于视图控制器处理。你可以调用UINavigationController的pushViewController:animated: 方法来把一个视图控制器压入视图导航堆栈(navigation stack),使用popViewControllerAnimated: 方法取回(弹出)之前的视图控制器。堆栈可以让你实现“最进,先出”的集合管理需求。

 

下图描述了堆栈如何实现压入和弹出(push/pop)的行为:

  bubuko.com,布布扣

1、         现在堆栈里面有三个数值

2、         第四个数值使用压入操作“Push”进入堆栈的顶部

3、         现在堆栈中有四个值,最后压入的在最顶上。

4、         最顶上的值可以移出或叫做“弹出”(poped)

5、         在弹出一个数值之后,堆栈又是只有三个数值

这样就是非泛型的堆栈的工作情况,我们举例堆栈使用的数值是整数类型

     struct IntStack {

         var items = Int[]()

         mutating func push(item: Int) {

             items.append(item)

         }

         mutating func pop() -> Int {

             return items.removeLast()

         }

     }

这个结构有一个属性是数组Array,还有一个存储数值的item用于表示堆栈存储的内容,堆栈提供两个方法,push和pop,表示压栈和弹出,这些方法标置了mutating,因为它们需要修改结构里面的item元素数组。

在IntStack整型堆栈中,工作类型是Int整理,但是,如果把它定义成一个泛型的堆栈类将会更有意义,我们能够通过它处理多种类型的数据。

下面是泛型版本的堆栈代码:

     struct Stack<T> {

         var items = T[]()

         mutating func push(item: T) {

             items.append(item)

         }

         mutating func pop() -> T {

             return items.removeLast()

         }

     }

重申一下泛型版本的Stack结构体和非泛型版本的基本一样,只是把Int类型置换成T占位符,这个东西每每加上一个菱形括号,写在结构体名称后面,定义、实例化的时候都用上。

T代表占位符表示将有一个具体的类型在后面会提供置换,这个未知类型T用在了结构体的诸多地方,我们总结一下有三个地方:

1、  创建属性items,存储堆栈数据,用T类型进行了初始化,虽然是空的。

2、  声明push方法有一个参数item,它是T类型,这样才能压入堆栈。

3、  声明pop函数返回值与压入栈是一样的T类型。

实例化Stack的方法和Array数组、Dictionary字典的实例化是一样的,把Stack中的元素需要泛化成什么样的类型写在菱括号中,跟在Stack类名后面。下面是示例代码。

     var stackOfStrings = Stack<String>()

     stackOfStrings.push("uno")

     stackOfStrings.push("dos")

     stackOfStrings.push("tres")

     stackOfStrings.push("cuatro")

     // the stack now contains 4 strings

下面是stackOfStrings字符串在堆栈在内存中的实际样子,我们将压入四个值。

 bubuko.com,布布扣

从堆栈中pop弹出数值将取回最后压入的元素,栈顶的“cuatro”

     let fromTheTop = stackOfStrings.pop()

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

 

下面是弹出一个元素后的堆栈情况:

 bubuko.com,布布扣 

因为是泛化类型,堆栈能够使用Swift中各种类型来实例化,使用起来的风格和Array数组、Dictionary字典一样。

 

未完待续,今天学习和翻译自《The Swift Programming Language》电子书)【Generic】章节

Swift语言中的泛型编程 【Generic】【Part 1】,布布扣,bubuko.com

Swift语言中的泛型编程 【Generic】【Part 1】

标签:c   style   class   blog   a   http   

原文地址:http://www.cnblogs.com/bailey/p/3774839.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!