定义协议
本课属于 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'挑战
简单声明一个协议 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())")
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Swift 在线编辑器