协议和扩展
协议和扩展
协议 (Protocol)
协议是一种描述某物必须具有的属性和方法的方式。告诉Swift哪些类型使用该协议——这个过程被称为采用协议。 编写一个函数来接受具有id属性的东西,但我们并不关心使用哪种类型的数据。 首先创建一个Identifiable协议,该协议将要求所有符合要求的类型都有一个可以读取(“get”)或写入(“set”)的id字符串:
protocol Identifiable {
var id: String { get set }
}
创建一个采用该协议的结构:
struct User: Identifiable {
var id: String
}
编写一个接受任何Identifiable对象的displayID()函数:
func displayID(thing: Identifiable) {
print("My ID is \(thing.id)")
}
协议继承
一个协议可以从另一个协议继承。与类不同,可以同时继承多个协议。
protocol Payable {
func calculateWages() -> Int
}
protocol NeedsTraining {
func study()
}
protocol HasVacation {
func takeVacation(days: Int)
}
可以创建一个单一Employee协议,将他们聚集在一个协议中。可以使新类型符合单一协议,而不是三个单独的协议。
protocol Employee: Payable, NeedsTraining, HasVacation { }
扩展 (Extension)
扩展允许向现有类型添加方法,做最初不打算做的事情。 例如,为Int类型添加一个扩展,以便它有一个squared()方法,返回当前数字平方:
extension Int {
func squared() -> Int {
return self * self
}
}
创建一个整数,调用squared()方法:
let number = 8
number.squared()
Swift不允许在扩展中添加存储的属性,因此必须使用计算属性。
extension Int {
var isEven: Bool {
return self % 2 == 0
}
}
协议扩展
协议允许描述某物应该拥有哪些方法,但不提供里面的代码。 扩展允许在方法中提供代码,但不能同时将方法添加到许多类型中。 协议扩展解决了这两个问题:它们就像常规扩展,除了扩展像Int这样的特定类型,而是扩展整个协议,以便所有符合的类型都得到更改。 例如,这里有一个包含一些名称的数组和一个集合:
let pythons = ["Eric", "Graham", "John", "Michael", "Terry", "Terry"]
let beatles = Set(["John", "Paul", "George", "Ringo"])
Swift的数组和集合都符合一个名为Collection的协议,因此可以为该协议编写一个扩展,以添加一个summarize()方法来整齐地打印集合
extension Collection {
func summarize() {
print("There are \(count) of us:")
for name in self {
print(name)
}
}
}
Array和Set现在都有这个方法:
pythons.summarize()
beatles.summarize()
面向协议编程
协议扩展可以为自己的协议方法提供默认实现。这使得类型很容易符合协议,并允许一种称为“面向协议的编程”的技术——围绕协议和协议扩展制作代码。
首先,这是一个名为Identifiable的协议,它要求任何符合要求的类型具有id属性和identify()方法:
protocol Identifiable {
var id: String { get set }
func identify()
}
可以让每个符合要求的类型编写identify()方法,但协议扩展允许提供默认值:
extension Identifiable {
func identify() {
print("My ID is \(id).")
}
}
现在,当创建一个符合Identifiable的类型时,会自动获得identify():
struct User: Identifiable {
var id: String
}
let twostraws = User(id: "twostraws")
twostraws.identify()