Tại sao Swift Enum có giá trị liên kết không thể có RawValue?
Bài đăng này đã không được cập nhật trong 3 năm
Giới thiệu
Trong lập trình Swift, chắc hẳn chúng ta sử dụng chắc hẳn sử dụng rất nhiều kiểu dữ liệu Enum. Enum trong swift dùng để định nghĩa một tập hợp có số phần tử cố định và liệt kê sẵn, chúng ta không thể không thể thêm hoặc bớt được số phần tử. Trong bài viết này tôi muốn giới thiệu đến các bạn cách dùng Enum một trường hợp của enum có chứa giá trị liên kết (Associated Values ) mà chúng ta không thể gán cho chúng được RawValue cho chúng được.
Raw Values
Với Enums, bạn có thể định nghĩa mỗi Enum cho một giá trị Inter, Double, String hay Character ...:
enum Airport: Int {
case munich = 0
case sanFrancisco = 1
case singapore = 2
}
enum Airport: String {
case munich = "MUC"
case sanFrancisco = "SFO"
case singapore = "SIN"
}
Ở đây, các giá trị được được gắn cho mỗi Enum được gọi là Rawvalue.
Associated Values
Bây giờ bạn có một list các sân bay được gán với tên của thành phố nơi chúng được đặt. Nhưng sau đó bạn nhận ra rằng có một số thành phố có nhiều sân bay: ví dụ như London. Trong trường hợp này, bạn phải đổi tên tất cả các trường hợp enum để đạt được tên phù hợp, ví dụ như:
enum Airport: String {
case munichFranzJosephStrauss = "MUC"
case sanFranciscoInternational = "SFO"
case singaporeChangi = "SIN"
case londonStansted = "STN"
case londonHeathrow = "LHR"
case londonGatwick = "LGW"
}
Nhưng chúng ta thấy rằng điều này là không phù hợp với cách liệt kê như chúng ta dự định ban đầu, bài toán của chúng ta là có một Enum chứa các sân bay với tên thành phố. Nếu sử dụng Enum như trên thì chúng ta đang bị trộn lẫn hai loại thông tin khác nhau: thành phố nơi có sân bay (như ban đầu) + sân bay của thành phố đó, đây rốt cuộc chỉ là một danh sách. May mắn thay, Swift đưa ra cách giải quyết vấn đề này: Nó cho phép bạn ràng buộc một (hoặc nhiều) các giá trị bổ sung vào một trường hợp enum. Các giá trị này được gọi là các giá trị liên kết (associated values). Ví dụ: Chúng tôi có thể sử dụng String để xác định sân bay cụ thể và vì nó chỉ cần cho thành phố London trong danh sách hiện tại của chúng tôi, chúng tôi chỉ thêm giá trị liên quan này vào trường hợp ở Lodon:
enum Airport {
case munich
case sanFrancisco
case singapore
case london(airportName: String)
}
Bây giờ chúng a trở lại với enum clear hơn và chỉ sử dụng một giá trị bổ sung để xác định các sân bay cụ thể khi cần thiết. Nhưng một String không phải là an toàn và dễ bị lỗi, chúng ta có thể đi thêm một bước nữa và thay thế bằng một enum khác:
enum LondonAirportName {
case stansted
case heathrow
case gatwick
}
Bây giờ enum Airport của chúng tôi sẽ như sau:
enum Airport {
case munich
case sanFrancisco
case singapore
case london(airportName: LondonAirportName)
}
Và khi định nghĩa giá trị của Enum chúng ta có thể chỉ định giá trị cho Enum đó như sau
var airport: Airport
airport = .munich
airport = .london(airportName: .heathrow)
hoặc
var airport: Airport
airport = .london(.heathrow)
The Problem with Associated Values
Bạn có thể nhận ra rằng với Enum có chứa Associated Values như ví dụ bên trên chúng ta không hề có giá trị Rawvalue. Tại vì trong Swift không cho phép chúng ta có cả hai: rawValue và Associated Values trong cùng một enum. Một Swift enum có thể có cả raw values hoặc associated values. Tại sao lại như vậy? Đó là vì định nghĩa của raw values: raw values là một cái gì đó nhận dạng duy nhất một giá trị của một loại cụ thể. "Duy nhất" có nghĩa là bạn không mất bất kỳ thông tin nào bằng cách sử dụng giá trị nguyên thay vì giá trị ban đầu. Nó được chính thức hoá trong Swift với giao thức RawRepresentable mà tài liệu của nó nêu rõ:
Với kiểu RawRepresentable, bạn có thể chuyển qua lại giữa một kiểu tùy chỉnh và một kiểu RawValue có liên quan mà không làm mất giá trị của kiểu RawRepresentable ban đầu. Để hiểu rõ hơn, chúng ta cùng nhau đi vào các ví dụ cụ thể.
Enums Without Associated Values
Enum ban đầu của chúng ta không có bất kỳ Associated Values nào, chỉ có Raw Value:
enum Airport: String {
case munich = "MUC"
case sanFrancisco = "SFO"
case singapore = "SIN"
}
Chúng ta dễ dàng chuyển đổi giữa rawvalue và kiểu Enum của nó từ Raw Value
let airport = .sanFrancisco
let airportRawValue = airport.rawValue // "SFO"
let reconstructedAirport = Airport(rawValue: airportRawValue)! // .sanFrancisco
Enums With Associated Values
Bây giờ chúng ta thử làm tương tự như trên với trường hợp enum với Associated Values
enum Airport: String {
case munich = "MUC"
case sanFrancisco = "SFO"
case singapore = "SIN"
case london(airportName: LondonAirportName) = "LON"
}
⚠️ This is not possible in Swift. Chúng ta vẫn có thể đặt biến cho trường hợp này:
let airport = .london(airportName: .stansted)
let airportRawValue = airport.rawValue // “LON”
Tuy nhiên, chúng ta không thể lấy lại giá trị Enum ban đầu từ rawvalue đó bởi vì không có cách nào để cho biết giá trị liên quan nào được lựa chọn:
let reconstructedAirport = Airport(rawValue: airportRawValue)! // .london(💥❓)
How to Get Your Raw Values Back
Khi chúng ta không thể lấy giá trị Rawvalue ban đầu theo cách trên, chúng ta cần phải định nghĩa một giá trị thay thế tương tự:
enum Airport {
case munich
case sanFrancisco
case singapore
case london(airportName: LondonAirportName)
var cityIdentifier: String {
switch self {
case .munich:
return "MUC"
case .sanFrancisco:
return "SFO"
case .singapore:
return "SIN"
case .london:
return "LON"
}
}
}
Và thực hiện khai báo:
var airport: Airport = .london(airportName: .heathrow)
Lúc này bạn muốn lấy Rawvalue thay vì bạn gọi airport.rawValue thì bạn gọi* airport.cityIdentifier*.
Tổng kết
Trên đây tôi đã giới thiệu với các bạn về cách sử dụng Enum với trường hợp Enum đó có Associated Values (giá trị liên kết), nếu có bất kì câu hỏi nào hoặc góp ý gì, vui lòng comment bên dưới. Cám ơn các bạn! Nguồn: Medium
All rights reserved