在 Swift 中,协议(Protocol)是一种为方法、属性和其他需求定义蓝图的方式。协议本身并不实现这些需求,它只是向遵循协议的类型(类、结构体、枚举等)规定这些需求应该存在并实现。
协议用来定义一组接口,这些接口可以被多个不同类型遵循并实现,从而实现多态性和接口分离、灵活扩展的目标。
定义协议#
你可以用 protocol 关键字来定义协议,协议可以包含方法、属性、下标等需求。
protocol Drawable {
func draw()
}
protocol Identifiable {
var id: String { get }
}在这个例子中,Drawable 协议要求任何遵循它的类型都必须实现一个 draw 方法。Identifiable 协议要求任何遵循它的类型都必须有一个 id 属性。
遵循协议#
类、结构体或枚举遵循协议时,需要在类型声明中使用 :协议名称 来表明遵循某个协议,并实现协议中定义的所有需求。
struct Circle: Drawable {
func draw() {
print("Drawing a circle")
}
}
class User: Identifiable {
var id: String
init(id: String) {
self.id = id
}
}在这个例子中,Circle 结构体遵循了 Drawable 协议,实现了 draw 方法。User 类遵循了 Identifiable 协议,实现了 id 属性。
多个协议#
Swift 允许一个类型同时遵循多个协议,以逗号分隔。
struct UserProfile: Identifiable, Drawable {
var id: String
func draw() {
print("Drawing user profile with id: \(id)")
}
}协议的属性要求#
协议可以要求属性具有特定的 getter 和 setter。如果属性是只读的,只需要指定 { get };如果属性是可读写的,则需要指定 { get set }。
protocol FullyNamed {
var fullName: String { get }
}
protocol Person {
var name: String { get set }
var age: Int { get set }
}协议中的 Mutating 方法#
当协议中的方法可能改变类型的实例时,需要在方法前加上 mutating 关键字,通常用于结构体和枚举。
protocol Toggleable {
mutating func toggle()
}
enum LightSwitch: Toggleable {
case off, on
mutating func toggle() {
switch self {
case .off:
self = .on
case .on:
self = .off
}
}
}协议的继承#
协议能继承一个或多个其他协议,要求实现多个协议的需求。
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
protocol Person: Named, Aged { }Person 协议继承了 Named 和 Aged 协议,遵循 Person 协议的类型需要同时实现 Named 和 Aged 的需求。
协议组合#
协议组合允许你将多个协议组合成一个单一的要求,使用特殊的 & 语法。
func describe<T: Named & Aged>(person: T) {
print("\(person.name) is \(person.age) years old.")
}协议扩展#
协议扩展允许你为协议添加默认实现,使得遵循协议的类型可以仅实现一些而非全部的需求。
protocol Greetable {
func greet()
}
extension Greetable {
func greet() {
print("Hello!")
}
}
struct Person: Greetable {}
let person = Person()
person.greet() // 输出: Hello!关联类型#
协议可以包含关联类型要求,通过 associatedtype 关键字定义,用于在协议中使用泛型。
protocol Container {
associatedtype Item
var count: Int { get }
subscript(i: Int) -> Item { get }
}
struct Stack<Element>: Container {
var items: [Element] = []
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}在这个例子中,Container 协议包含一个关联类型 Item,Stack 结构体遵循了 Container 协议,并将 Item 关联类型具体化为 Element。
小结#
- 定义协议:使用
protocol关键字定义包含方法、属性、下标等需求的协议。 - 遵循协议:类型通过在声明中使用
:协议名称表明遵循协议,并实现所有的需求。 - 多个协议:类型可以同时遵循多个协议。
- 属性要求:协议可以要求属性具有特定的 getter 和 setter。
- Mutating 方法:用于需要改变自身实例的方法,通常用于结构体和枚举。
- 协议继承:协议可以继承一个或多个其他协议。
- 协议组合:使用
&将多个协议组合成一个单一要求。 - 协议扩展:为协议提供默认实现。
- 关联类型:使用
associatedtype在协议中定义泛型。
协议是 Swift 强大而灵活的类型系统的一部分,广泛用于定义接口并实现多态性、灵活扩展和接口分离。