在 WWDC 2015上,苹果发布了 Swift 2.0 版本,这是自 Swift 发布以来进行的第二次重大改版,这次改进推出了很多新特性来帮助我等程序员写出更优雅的代码。
在这些新特性里面,最让人兴奋的莫过于 协议扩展(protocol extensions) 了。在第一版的 Swift 当中,我们可以使用扩展来为 类(class)、结构体(struct) 以及 枚举(enum) 增加新功能。在新版的 Swift 2.0 当中,我们也可以对 协议(protocol) 进行扩展了。
这乍看起来好像只是一个很小的改变,事实上,协议扩展的功能是相当强大的,它甚至能改变我们编写代码的方式。在本教程中,你不仅可以学习到创建和使用协议扩展的方法,同时还可以体会到这项新技术和面向协议编程范式给你带来的新视野。
同时还能看到 Swift 开发小组是如何使用协议扩展来对 Swift 的标准库进行改进,以及它将会对我们编写代码带来怎样的影响。
从这里开始(Getting Started)
我们先从新建一个 playground开始。打开 Xcode 7 选择 File\New\Playground… 并命名为 SwiftProtocols。可以选择任意的平台,因为本教程中的代码是与平台无关的。选择保存的位置后点击 Next,最后点击 Create。
打开 playground 后,添加如下代码:
1 2 3 4 5 6 7 8 |
protocol Bird { var name: String { get } var canFly: Bool { get } } protocol Flyable { var airspeedVelocity: Double { get } } |
这里定义了一个简单的 Bird 协议,它拥有 name 和 canFly 两个属性,同时还定义了一个拥有 airspeedVelocity 属性的 Flyable 协议。
在没有协议的远古时期,我们可能会将 Flyable 定义为一个基类,然后使用继承的方式来定义 Bird 以及其它会飞的东西,比如飞机之类的。然而这里并不用这么做,所有一切都是从协议开始的。
当我们接下来开始定义具体类型的时候,你将会看到这种方法将会使我们的整个系统更加灵活。
定义遵守协议的类型
在代码区底部增加如下的 结构体 定义:
1 2 3 4 5 6 7 8 9 |
struct FlappyBird: Bird, Flyable { let name: String let flappyAmplitude: Double let flappyFrequency: Double let canFly = true var airspeedVelocity: Double { return 3 * flappyFrequency * flappyAmplitude } } |
这里定义了一个新的结构体 Flappybird,这个结构体遵守了 Bird 和 Flyable 协议。它的 airspeedVelocity 属性的值是通过 flappyFrequency 和 flappyAmplitue 计算出来的。作为一只愤怒的小鸟,它的 canFly 当然是返回 true的 :]。
接着,再定义两个结构体:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
struct Penguin: Bird { let name: String let canFly = false } struct SwiftBird: Bird, Flyable { var name: String { return "Swift \(version)" } let version: Double let canFly = true // Swift 速度超群! var airspeedVelocity: Double { return 2000.0 } } |
企鹅(Penguin)是一种鸟(Bird),不过它是不能飞的。啊哈,应该庆幸我们没有采用继承的方法,使用继承会让所有的子类都拥有飞的能力。雨燕(SwiftBird)不仅能飞,它还拥有超快的速度!
我们可以发现,上面的代码里面有一些冗余。尽管我们已经有了 Flyable 的信息,但是我们还是得为每个 Bird 类型指定 canFly 属性来表明它是否可以飞行。
拥有默认实现的扩展协议
对于协议扩展,我们可以为它指定默认的实现。在定义 Bird 协议的下方增加如下代码:
1 2 3 4 |
extension Bird where Self: Flyable { // Flyable birds can fly! var canFly: Bool { return true } } |
这里通过对 Bird 协议进行扩展,为它增加了默认行为。当一个类同时遵守 Bird 和 Flyable 协议时,它的 canFly 属性就默认返回 true。即是说,所有遵守 Flyable 协议的鸟类都不必再显式指定它是否可以飞行了。
Swift 1.2 将 where 判断语法增加到了 if-let 绑定中,而 Swift 2.0 更进一步地将这个语法带到了协议扩展中。
将 FlappyBird 和 SwiftBird 结构体定义中的 let canFly = true 语句删除。可以看到,playground 可以顺利通过编译,因为扩展协议的默认实现已经帮你处理了这些琐事。
为何不使用基类?
或许你会发现,使用协议扩展和它的默认实现与使用基类,或者其它语言中的抽象类很相似,但是它有几个关键的优势:
- 因为一个类型可以遵守多个协议,所以它可以从各个协议中接收到不同的默认实现。与其它语言中所支持的多重继承不同(吐槽:说的就是C++吧),协议扩展不会为遵守它的类型增加额外的状态。
- 所有的类,结构体和枚举都可以遵守协议,而基类只能被类所继承。
换句说就是,协议拥有为值类型(value types)增加默认实现的能力,而不仅仅是类。
我们已经体验过了结构体的实战,接下来在 playground 的底部增加如下的枚举的定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
enum UnladenSwallow: Bird, Flyable { case African case European case Unknown var name: String { switch self { case .African: return "African" case .an> return "African" case .ܘ雅的代码。
在这些新特性里面,最让人兴奋的莫过于 协议扩展(protocol extensions) 了。在第一版的 Swift 当中,我们可以使用扩展来为 类(class)、结构体(struct) 以及 枚举(enum) 增加新功能。在新版的 Swift 2.0 当中,我们也可以对 协议(protocol) 进行扩展了。 这乍看起来好像只是一个很小的改变,事实上,协议扩展的功能是相当强大的,它甚至能改变我们编写代码的方式。在本教程中,你不仅可以学习到创建和使用协议扩展的方法,同时还可以体会到这项新技术和面向协议编程范式给你带来的新视野。 同时还能看到 Swift 开发小组是如何使用协议扩展来对 Swift 的标准库进行改进,以及它将会对我们编写代码带来怎样的影响。 从这里开始(Getting Started) 我们先从新建一个 playground开始。打开 Xcode 7 选择 File\New\Playground… 并命名为 SwiftProtocols。可以选择任意的平台,因为本教程中的代码是与平台无关的。选择保存的位置后点击 Next,最后点击 Create。 打开 playground 后,添加如下代码:
这里定义了一个简单的 Bird 协议,它拥有 name 和 canFly 两个属性,同时还定义了一个拥有 airspeedVelocity 属性的 Flyable 协议。 在没有协议的远古时期,我们可能会将 Flyable 定义为一个基类,然后使用继承的方式来定义 Bird 以及其它会飞的东西,比如飞机之类的。然而这里并不用这么做,所有一切都是从协议开始的。 当我们接下来开始定义具体类型的时候,你将会看到这种方法将会使我们的整个系统更加灵活。 定义遵守协议的类型 在代码区底部增加如下的 结构体 定义:
这里定义了一个新的结构体 Flappybird,这个结构体遵守了 Bird 和 Flyable 协议。它的 airspeedVelocity 属性的值是通过 flappyFrequency 和 flappyAmplitue 计算出来的。作为一只愤怒的小鸟,它的 canFly 当然是返回 true的 :]。 接着,再定义两个结构体:
企鹅(Penguin)是一种鸟(Bird),不过它是不能飞的。啊哈,应该庆幸我们没有采用继承的方法,使用继承会让所有的子类都拥有飞的能力。雨燕(SwiftBird)不仅能飞,它还拥有超快的速度! 我们可以发现,上面的代码里面有一些冗余。尽管我们已经有了 Flyable 的信息,但是我们还是得为每个 Bird 类型指定 canFly 属性来表明它是否可以飞行。 拥有默认实现的扩展协议 对于协议扩展,我们可以为它指定默认的实现。在定义 Bird 协议的下方增加如下代码:
这里通过对 Bird 协议进行扩展,为它增加了默认行为。当一个类同时遵守 Bird 和 Flyable 协议时,它的 canFly 属性就默认返回 true。即是说,所有遵守 Flyable 协议的鸟类都不必再显式指定它是否可以飞行了。 Swift 1.2 将 where 判断语法增加到了 if-let 绑定中,而 Swift 2.0 更进一步地将这个语法带到了协议扩展中。 将 FlappyBird 和 SwiftBird 结构体定义中的 let canFly = true 语句删除。可以看到,playground 可以顺利通过编译,因为扩展协议的默认实现已经帮你处理了这些琐事。 为何不使用基类? 或许你会发现,使用协议扩展和它的默认实现与使用基类,或者其它语言中的抽象类很相似,但是它有几个关键的优势:
换句说就是,协议拥有为值类型(value types)增加默认实现的能力,而不仅仅是类。 我们已经体验过了结构体的实战,接下来在 playground 的底部增加如下的枚举的定义:
|