Hàm khởi tạo có thể thất bại
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 20 trên 57.
Một số giá trị không thể được tạo từ mọi đầu vào. Một hàm khởi tạo có thể thất bại, được viết là init?, trả về nil thay vì một đối tượng khi đầu vào không hợp lệ, vì vậy sẽ không bao giờ tồn tại đối tượng không hợp lệ nào:
struct Percentage {
let value: Int
init?(_ value: Int) {
guard value >= 0, value <= 100 else { return nil }
self.value = value
}
}
print(Percentage(42)?.value ?? -1)
print(Percentage(150)?.value ?? -1)Đầu ra:
42
-1Kết quả của hàm khởi tạo có thể thất bại là một giá trị tùy chọn, vì vậy bên gọi phải mở gói giá trị đó, thường dùng if let hoặc guard let:
struct Email {
let address: String
init?(_ text: String) {
let parts = text.split(separator: "@")
guard parts.count == 2, parts[1].contains(".") else { return nil }
address = text.lowercased()
}
}
for text in ["Ada@Mail.com", "not-an-email"] {
if let email = Email(text) {
print("valid: \(email.address)")
} else {
print("invalid: \(text)")
}
}Đầu ra:
valid: ada@mail.com
invalid: not-an-emailCác kiểu dữ liệu của Swift cũng dùng cùng ý tưởng này: Int("42") và Double("x") là các hàm khởi tạo có thể thất bại, và init(rawValue:) của enum cũng vậy. Hàm khởi tạo có thể thất bại có thể gọi những hàm này và chuyển tiếp lỗi:
struct Coordinate {
let lat: Double
let lon: Double
init?(text: String) {
let parts = text.split(separator: ",")
guard parts.count == 2,
let lat = Double(parts[0]), let lon = Double(parts[1]),
abs(lat) <= 90, abs(lon) <= 180 else { return nil }
self.lat = lat
self.lon = lon
}
}
print(Coordinate(text: "51.5,-0.1") != nil)
print(Coordinate(text: "95,10") != nil)Đầu ra:
true
falseDùng init? khi chỉ cần biết giá trị bị thiếu. Dùng hàm khởi tạo có thể ném ngoại lệ, init(...) throws, khi bên gọi cần biết quy tắc nào đã không được đáp ứng:
struct Username {
let text: String
init(_ text: String) throws {
guard text.count >= 3 else { throw NameError.tooShort }
guard text.allSatisfy({ $0.isLetter }) else { throw NameError.badCharacters }
self.text = text
}
}Thử thách
DễHoàn thiện struct Rgb, struct này lưu màu dưới dạng red, green và blue với giá trị từ 0 đến 255. Hàm khởi tạo có thể thất bại init?(hex:) đọc văn bản như #FF8000: hàm trả về nil trừ khi văn bản là # theo sau bởi đúng sáu chữ số thập lục phân. Dùng Int(text, radix: 16) cho từng cặp. Thêm thuộc tính được tính toán label trả về rgb(255, 128, 0).
Code được cung cấp đọc một màu trên mỗi dòng và in nhãn hoặc invalid: text.
Code của bạn nằm trong Rgb.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 đã cho: giữ nguyên
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
if let color = Rgb(hex: line) {
print(color.label)
} else {
print("invalid: \(line)")
}
}
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ện4Đóng gói
Kiểm soát quyền truy cậpChỉ đọc từ bên ngoàiBảo vệ trạng tháiHàm khởi tạo có thể thất bạiÔn tập: Tài khoản ngân hàng2Struct 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ỉnhTự luyện tập: Playground Swift