Mở rộng giao thức
Thuộc phần Lập trình hướng đối tượng trong hành trình Swift của Coddy. Bài học 29 trên 57.
Phần mở rộng giao thức cung cấp cách triển khai mặc định cho các phương thức của một giao thức. Mọi kiểu tuân theo giao thức đều có sẵn cách triển khai này, và một kiểu vẫn có thể cung cấp phiên bản riêng:
protocol Greeter {
var name: String { get }
func greet() -> String
}
extension Greeter {
func greet() -> String { "Hello, \(name)!" }
}
struct English: Greeter { let name: String }
struct Pirate: Greeter {
let name: String
func greet() -> String { "Ahoy, \(name)!" }
}
print(English(name: "Ada").greet())
print(Pirate(name: "Ada").greet())Đầu ra:
Hello, Ada!
Ahoy, Ada!Phần mở rộng cũng có thể thêm các phương thức mới, chỉ dựa trên những yêu cầu. Kiểu dữ liệu tuân thủ chỉ cần viết phần nhỏ bắt buộc và nhận được phần còn lại:
protocol Scored {
var points: [Int] { get }
}
extension Scored {
var total: Int { points.reduce(0, +) }
var best: Int { points.max() ?? 0 }
func summary() -> String { "total \(total), best \(best)" }
}
struct Player: Scored {
let points: [Int]
}
print(Player(points: [3, 9, 4]).summary())Đầu ra:
total 16, best 9Cách này chia sẻ hành vi giữa struct, class và enum mà không cần kế thừa. Thư viện chuẩn cũng hoạt động theo cách tương tự: mọi Collection đều có isEmpty, first và map nhờ các phần mở rộng giao thức.
extension Collection {
// isEmpty, first, map, filter, ... đều chỉ cần định nghĩa một lần ở đây
// và mọi mảng (array), tập hợp (set), từ điển (dictionary) và chuỗi (string) đều có thể dùng chúng
}Một phần mở rộng có ràng buộc chỉ bổ sung phương thức cho một số kiểu tuân thủ giao thức, được viết bằng where:
protocol Container {
associatedtype Item
var items: [Item] { get }
}
extension Container where Item == Int {
var sum: Int { items.reduce(0, +) }
}
struct Box: Container {
var items: [Int]
}
print(Box(items: [2, 5]).sum)Đầu ra:
7Thử thách
DễKhai báo một giao thức Priced yêu cầu var price: Int { get } (tính bằng xu) và var formatted: String { get }. Trong phần mở rộng giao thức, đặt giá trị mặc định cho formatted là $4.50, rồi thêm phương thức isAffordable(budget:) để trả về kết quả cho biết giá có nằm trong ngân sách hay không. Cho các cấu trúc Coffee (giá 450) và Sandwich (có thuộc tính price được lưu trữ) tuân theo giao thức này. Coffee phải thay thế giá trị mặc định của formatted bằng coffee $4.50.
Code được cung cấp đọc ngân sách rồi đọc các dòng coffee hoặc sandwich,650. Với mỗi món, code in ra formatted và yes hoặc no.
Viết code trong các tệp Priced.swift, Coffee.swift và Sandwich.swift. main.swift chứa code đầu vào/đầu ra được cung cấp và bạn không thể chỉnh sửa tệp này.
Tự làm thử
// Đoạn code đầu vào/đầu ra có sẵn: giữ nguyên
var input: [String] = []
while let line = readLine() { input.append(line) }
let budget = Int(input[0])!
for line in input.dropFirst() {
let item: any Priced = line == "coffee" ? Coffee() : Sandwich(price: Int(line.split(separator: ",")[1])!)
print("\(item.formatted) \(item.isAffordable(budget: budget) ? "yes" : "no")")
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Lớp và đối tượng
Làm việc với tệpĐịnh nghĩa lớpPhương thức và selfHàm khởi tạoLớp là tham chiếuÔn tập: Thẻ thư viện2Struct và kiểu giá trị
StructNgữ nghĩa giá trịPhương thức thay đổiStruct hay classÔn tập: mặt hàng trong kho5Kế thừa
Lớp conGhi đè phương thứcHàm khởi tạo và superfinal và hệ phân cấpÔn tập: hệ phân cấp nhân viên8Các giao thức tiêu chuẩn
CustomStringConvertibleEquatableComparableHashableÔn tập: Sắp xếp tùy chỉnh3Tìm hiểu sâu về thuộc tính
Thuộc tính tính toánQuan sát thuộc tínhThành viên tĩnhEnum với phương thứcÔn tập: Nhật ký nhiệt độ6Giao thức
Định nghĩa giao thứcCác kiểu tuân thủMở rộng giao thứcGiao thức dưới dạng kiểuÔn tập: hệ thống thanh toánTự luyện tập: Playground Swift