提出问题
优秀的泛型使用案例中,最多见的例子当属对栈(Stack) 的操做。栈做为容器有两种操做:一.压入(Push) 操做添加项到容器中;二.弹出(Pop) 操做将最近添加项从容器移除。首先咱们用非泛型方式设计栈 。最后代码以下所示:web
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class IntStack { private var stackItems:[Int ] = [] func pushItem (item:Int) { stackItems.append(item) } func popItem () ->Int ?{ let lastItem = stackItems.last stackItems.removeLast() return lastItem } }
该栈可以处理Int 类型数据。这看起来不错,可是假若要创建一个可以处理String
类型的栈 ,咱们又该如何实现呢?咱们须要替换全部Int
为String
,不过这显然是一个糟糕的解决方法。此外另一种方法乍看之下灰常不错,以下:编程
1 2 3 4 5 6 7 8 9 10 11 12 13 14
class AnyObjectStack { private var stackItems:[AnyObject ] = [] func pushItem (item:AnyObject) { stackItems.append(item) } func popItem () ->AnyObject ?{ let lastItem = stackItems.last stackItems.removeLast() return lastItem } }
此处,咱们合理地使用AnyObject
类型,那么如今可以将String
类型数据压入到栈中了,对么?不过这种状况下咱们就失去了数据类型的安全,而且每当咱们对栈进行操做时,都须要进行一系列繁琐的类型转换(casting
操做,使用as
来进行类型转换)。swift
解决方案
参照泛型的特性,咱们可以定义一个泛型类型,这看起来像一个占位符。使用泛型后的示例代码以下:数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class Stack <T > { private var stackItems: [T ] = [] func pushItem (item:T) { stackItems.append(item) } func popItem () -> T ? { let lastItem = stackItems.last stackItems.removeLast() return lastItem } }
泛型定义方式:由一对尖括号(<>
)包裹,命名方式一般为大写字母开头(这里咱们命名为T
)。在初始化阶段,咱们经过明确的类型(这里为Int
)来定义参数,以后编译器将全部的泛型T
替换成Int
类型:安全
1 2 3 4 5 6 7 8
let aStack = Stack <Int >()aStack.pushItem(10 ) if let lastItem = aStack.popItem() { print ("last item: \(lastItem) " ) }
如此实现的栈,最大优点在于可以匹配任何类型。app
类型约束
这里存在一个缺点:尽管泛型可以表明任何类型,咱们对它的操做也是比较有局限性的。仅仅是比较两个泛型都是不支持的,请看以下代码:编程语言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
class Stack <T > { private var stackItems: [T ] = [] func pushItem (item:T) { stackItems.append(item) } func popItem () -> T ? { let lastItem = stackItems.last stackItems.removeLast() return lastItem } func isItemInStack (item:T) -> Bool { var found = false for stackItem in stackItems { if stackItem == item { found = true } } return found } }
注意到函数isItemInSatck(item:T)
中,咱们获得了一个编译错误,由于两个参数没有实现Equtable
协议的话,类型值是不能进行比较的。实际上咱们能够为泛型增长约束条件来解决这个问题。在本例中,经过对第一行进行修改,咱们让泛型T
遵循Equatable
协议:函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
class Stack <T :Equatable > { private var stackItems: [T ] = [] func pushItem (item:T) { .append(item) } func popItem () -> T ? { let lastItem = stackItems.last stackItems.removeLast() return lastItem } func isItemInStack (item:T) -> Bool { var found = false for stackItem in stackItems { if stackItem == item { ound = true } } return found } }
总结
就像众多其余编程语言同样,你也可以在Swift
中利用泛型这一特性。假若你想要写一个库,泛型是很是好用的特性。ui