Swift最强大的功能之一就是能够同时扩展整个数据类型。 这被称为协议扩展,它们通常用于在大型应用程序中构建灵活性。
您已经了解了协议如何使我们定义遵循协议类型必须采用的约定。好的,协议扩展使我们可以定义协议内部事物的实现,从而将功能添加到符合协议的所有类型中。
为了演示它是如何工作的,让我们看一下Int
数据类型的另一个简单扩展:我们将添加一个clamp()
方法,以确保一个数字落在指定的上下限之内:
extension Int {
func clamp(low: Int, high: Int) -> Int {
if (self > high) {
// if we are higher than the upper bound, return the upper bound
return high
} else if (self < low) {
// if we are lower than the lower bound, return the lower bound
return low
}
// we are inside the range, so return our value
return self
}
}
let i: Int = 8
print(i.clamp(low: 0, high: 5))
因为8高于上限的5,所以将打印5。
我明确地将i
设为Int
是有原因的:Swift中还有其他类型的整数可用。例如,UInt
是一个无符号整数,这意味着它牺牲了保持负数的能力来换取保持更大的正数的能力。
也有不同大小的整数,例如Int8
包含一个由8个二进制数字组成的整数,最大值为127,而UInt64
是最大的整数类型,最多可容纳18,446,744,073,709,551,615,即[0 - 2^64]。
我们的扩展程序专门修改了Int
数据类型,而不是整数的所有变体,这意味着这样的代码将不起作用,因为UInt64
没有扩展:
let j: UInt64 = 8
print(j.clamp(low: 0, high: 5))
Swift的解决方案是让我们创建协议扩展:这些扩展可以一次修改多种数据类型。
您已经了解了self
关键字如何让我们引用当前值,因此self * self
的意思是“将我的当前数字乘以自己。”嗯,还有一个带有大写字母S的Self
,它的含义稍有不同:它表示“我当前的数据类型”。因此,self
表示“我的当前值”,而Self
表示“我的当前数据类型”。
对于扩展协议,这很重要,因为声明了我们的clamp()
方法。再看一遍:
func clamp(low: Int, high: Int) -> Int {
if (self > high) {
return high
} else if (self < low) {
return low
}
return self
}
如果我们想将clamp()
应用于所有类型的整数,就不能很好地使它返回Int
——大小不足以容纳UInt64
的全部范围,因此Swift会拒绝构建。相反,我们需要使该方法返回Self
,这意味着“我将返回使用过的任何数据类型。”
这是改写的扩展程序:
代码语言:javascript复制extension BinaryInteger {
func clamp(low: Self, high: Self) -> Self {
if (self > high) {
return high
} else if (self < low) {
return low
}
return self
}
}
这次,我将其应用于BinaryInteger
,这是Swift所有整数类型都遵循的协议。这意味着所有整数类型都可以访问clamp()
方法,并且可以按预期工作——我们不需要单独扩展它们。
例如,我们可以为Employee
协议定义一个扩展,以便所有符合条件的类型都自动获得doWork()
方法:
protocol Employee {
var name: String { get set }
var jobTitle: String { get set }
func doWork()
}
extension Employee {
func doWork() {
print("I'm busy!")
}
}
结语
到此结束有关Swift编程语言的旅程。我没有尝试用语言来介绍所有内容,但这没关系,因为您拥有所有重要的东西,所有有时重要的东西以及所有容易理解的东西——您在以后的项目或通过对该语言的长时间体验中可能会遇到的许多其他功能。
本文来自Hacking with Swift 给 swift 初学者的入门课程 Swift for Complete Beginners 的 Protocol extensions