浅谈 Swift 中的泛型
2016-05-05 11:29
543 查看
浅谈 Swift 中的泛型
2015-09-16 1055作者:Thomas Hanning,原文链接,原文日期:2015-09-09
译者:pmst;校对:numbbbbb;定稿:shanks
Objective-C缺乏一个重要特性:不支持泛型。幸运地是,
Swift拥有这一特性。泛型允许你声明的函数、类以及结构体支持不同的数据类型。
提出问题
优秀的泛型使用案例中,最常见的例子当属对栈(Stack)的操作。栈作为容器有两种操作:一.压入(Push)操作添加项到容器中;二.弹出(Pop)操作将最近添加项从容器移除。首先我们用非泛型方式设计栈。最后代码如下所示:class IntStack{ // 采用数组作为容器保存数据 类型为Int private var stackItems:[Int] = [] // 入栈操作 即Push 添加最新数据到容器最顶部 func pushItem(item:Int){ stackItems.append(item) } // 出栈操作 即Pop 将容器最顶部数据移除 func popItem()->Int?{ let lastItem = stackItems.last stackItems.removeLast() return lastItem } } |
String类型的栈,我们又该如何实现呢?我们需要替换所有
Int为
String,不过这显然是一个糟糕的解决方法。此外另外一种方法乍看之下灰常不错,如下:
class AnyObjectStack{ // 采用数组作为容器保存数据 类型为AnyObject private var stackItems:[AnyObject] = [] // 入栈操作 即Push 添加最新数据到容器最顶部 func pushItem(item:AnyObject){ stackItems.append(item) } // 出栈操作 即Pop 将容器最顶部数据移除 func popItem()->AnyObject?{ let lastItem = stackItems.last stackItems.removeLast() return lastItem } } |
AnyObject类型,那么现在能够将
String类型数据压入到栈中了,对么?不过这种情况下我们就失去了数据类型的安全,并且每当我们对栈进行操作时,都需要进行一系列繁琐的类型转换(
casting操作,使用
as来进行类型转换)。
解决方案
参照泛型的特性,我们能够定义一个泛型类型,这看起来像一个占位符。使用泛型后的示例代码如下: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类型:
// 指定了泛型T 就是 Int // 编译器会替换所有T为Int let aStack = Stack<Int>() aStack.pushItem(10) if let lastItem = aStack.popItem() { print("last item: \(lastItem)") } |
类型约束
这里存在一个缺点:尽管泛型能够代表任何类型,我们对它的操作也是比较有局限性的。仅仅是比较两个泛型都是不支持的,请看如下代码: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协议:
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中利用泛型这一特性。倘若你想要写一个库,泛型是非常好用的特性。
本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg。
FROM: http://swift.gg/2015/09/16/swift-generics/
相关文章推荐
- Swift代理方法反向传值
- Swift的unowned字段
- Swift-控制流
- Swift下的Lazy懒加载模式
- Swift学习笔记二:常用类型的注意事项
- Swift学习笔记一:语言特性
- swift设置返回按钮图标
- 1.swift_初体验
- 对照Java学习Swift--下标(Subscripts)
- Swift中的分类
- Swift中TextField
- Swift解读专题一——Swift2.2语言预览
- Swift 仿简书、淘宝App的弹出view效果
- swift 基本语法(二)
- Swift开发:Swift项目调用OC代码
- swift闭包
- IOS8中SWIFT 弹出框的显示
- Swift 中 10 个震惊小伙伴的单行代码
- Swift2.x编写NavigationController动态缩放titleView
- Swift 中的内存管理详解