Menu
CoddyTech

定义协议

本课属于 Coddy Swift 学习旅程的“面向对象编程”单元。第 27 课,共 57 课。

协议列出要求(方法和属性),但不实现这些要求。类型通过提供所有要求来遵循协议,然后就可以在任何需要该协议的地方使用:

protocol Describable {
    func describe() -> String
}

struct Book: Describable {
    let title: String
    func describe() -> String { "Book: \(title)" }
}

print(Book(title: "Dune").describe())

输出:

Book: Dune

与继承不同,协议同样适用于结构体、类和枚举,而且一个类型可以遵循多个协议。协议只说明一个类型能做什么,每种类型自行决定怎么做:

protocol Describable {
    func describe() -> String
}

struct Point: Describable {
    var x = 0, y = 0
    func describe() -> String { "(\(x), \(y))" }
}

enum Level: Describable {
    case low, high
    func describe() -> String { self == .low ? "low" : "high" }
}

print(Point(x: 1, y: 2).describe())
print(Level.high.describe())

输出:

(1, 2)
high

属性要求会说明属性的类型,以及它是否为只读({ get })或也可写入({ get set })。存储属性或计算属性都可以满足 { get } 要求:

protocol Named {
    var name: String { get }
}

struct User: Named {
    let name: String
}

struct Planet: Named {
    var number: Int
    var name: String { "Planet \(number)" }
}

print(User(name: "ada").name)
print(Planet(number: 3).name)

输出:

ada
Planet 3

如果某个类型声明遵循协议,却没有满足某项要求,代码就无法编译。编译器会检查每一项遵循情况,因此使用该协议的代码可以依赖它:

protocol Priced {
    var price: Int { get }
    func discounted(by percent: Int) -> Int
}

// struct Ticket: Priced { var price = 10 }
// 错误:类型 'Ticket' 不符合协议 'Priced'
challenge icon

挑战

简单

声明一个协议 Shape,其中包含只读属性 name(String)和一个返回 Double 的方法 area()。让结构体 Rectangle(width、height)和 Circle(radius,使用 3.0 代替 π,让数字更简单)遵循该协议,并分别使用名称 rectangle 和 circle。

提供的代码会读取 r,3,4 或 c,2 这样的行,创建对应的形状并输出 rectangle: 12.0。

你的代码要写在 Shape.swift、Rectangle.swift 和 Circle.swift 中。main.swift 包含提供的输入/输出代码,不能编辑。

亲手试试

// 提供的输入/输出代码:保持原样。
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
    let p = line.split(separator: ",").map(String.init)
    if p[0] == "r" {
        let s = Rectangle(width: Double(p[1])!, height: Double(p[2])!)
        print("\(s.name): \(s.area())")
    } else {
        let s = Circle(radius: Double(p[1])!)
        print("\(s.name): \(s.area())")
    }
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Swift 在线编辑器