Enum giúp mã của bạn trở nên rõ ràng, dễ đọc và dễ bảo trì hơn bằng cách giới hạn các giá trị có thể có của một biến. Dưới đây, chúng ta sẽ cùng nhau khám phá sâu hơn về Enum trong Swift, từ cơ bản đến nâng cao.
Enum là gì?
Enum (enumeration) trong Swift là một kiểu dữ liệu giá trị (value type) cho phép bạn định nghĩa một tập hợp các giá trị liên quan. Mỗi giá trị trong Enum được gọi là một case. Nó thường được sử dụng để biểu diễn một tập hợp các giá trị cố định, ví dụ như các ngày trong tuần, các hướng, các trạng thái của một đối tượng, v.v.
Tại sao sử dụng Enum?
- Tăng tính đọc hiểu: Enum giúp code trở nên rõ ràng hơn bằng cách giới hạn các giá trị có thể của một biến.
- An toàn: Việc sử dụng enum giúp tránh các lỗi do nhập liệu sai giá trị.
- Switch case: Enum kết hợp rất tốt với câu lệnh switch-case để thực hiện các hành động khác nhau dựa trên giá trị của enum.
- Associated values: Enum có thể chứa các giá trị liên kết, giúp lưu trữ thêm thông tin cho từng trường hợp.
enum DayOfWeek {
case monday
case tuesday
case wednesday
case thursday
case friday
case saturday
case sunday
}
Khai Báo và Sử Dụng Enum
2.1. Khai Báo Enum
Bạn khai báo Enum bằng từ khóa enum
theo sau là tên Enum và các case
bên trong cặp ngoặc nhọn {}
.
enum Direction {
case north
case south
case east
case west
}
2.2. Sử Dụng Enum
Bạn có thể tạo biến hoặc hằng từ Enum và gán một case
cụ thể cho nó.
let currentDirection = Direction.north
Raw Values (Giá Trị Nguyên Thủy)
3.1. Enum với Raw Values
Enum trong Swift có thể có raw values (giá trị nguyên thủy), cho phép mỗi case
có một giá trị cố định thuộc kiểu dữ liệu cụ thể như String
, Int
, hoặc Double
.
enum Planet: Int {
case mercury = 1
case venus
case earth
case mars
case jupiter
case saturn
case uranus
case neptune
}
Trong ví dụ trên, nếu không chỉ định giá trị nguyên thủy cho các case
sau mercury
, chúng sẽ tự động tăng dần từ giá trị trước đó. Ví dụ, venus
sẽ có giá trị 2
, earth
là 3
, v.v.
3.2. Truy Xuất Giá Trị Nguyên Thủy Bạn có thể truy xuất giá trị nguyên thủy từ một case
bằng cách sử dụng thuộc tính rawValue
.
let earthOrder = Planet.earth.rawValue
print("Trái Đất là hành tinh thứ \(earthOrder)") // Kết quả: Trái Đất là hành tinh thứ 3
3.3. Khởi Tạo Enum Từ Raw Value
Bạn có thể khởi tạo một Enum từ một raw value bằng cách sử dụng trình khởi tạo init?(rawValue:)
.
if let planet = Planet(rawValue: 4) {
print("Hành tinh thứ 4 là \(planet)")
} else {
print("Không tìm thấy hành tinh với giá trị đó")
}
// Kết quả: Hành tinh thứ 4 là mars
Associated Values (Giá Trị Liên Kết)
4.1. Enum với Associated Values
Enum cũng hỗ trợ associated values , cho phép mỗi case
chứa một hoặc nhiều giá trị liên kết với nó. Đây là cách để thêm dữ liệu vào các case
của Enum.
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
4.2. Sử Dụng Enum với Associated Values
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
print("QR Code: \(productCode).")
}
// Kết quả: QR Code: ABCDEFGHIJKLMNOP.
Methods Trong Enum
Bạn có thể thêm các phương thức (methods) vào Enum để thực hiện các hành động liên quan đến các case
.
5.1. Thêm Method vào Enum
enum CompassPoint {
case north
case south
case east
case west
func description() -> String {
switch self {
case .north:
return "North"
case .south:
return "South"
case .east:
return "East"
case .west:
return "West"
}
}
}
let direction = CompassPoint.east
print(direction.description()) // Kết quả: East
Conforming to Protocols (Tuân Thủ Giao Thức)
Enum có thể tuân thủ các protocol, cho phép chúng tích hợp sâu hơn vào hệ thống của Swift. 6.1. Enum Tuân Thủ Protocol
protocol Describable {
func describe() -> String
}
enum Beverage: Describable {
case coffee
case tea
case juice
func describe() -> String {
switch self {
case .coffee:
return "A hot beverage made from coffee beans."
case .tea:
return "A hot or cold beverage made by steeping tea leaves."
case .juice:
return "A liquid naturally contained in fruit."
}
}
}
let drink = Beverage.tea
print(drink.describe()) // Kết quả: A hot or cold beverage made by steeping tea leaves.
Recursive Enums (Enum Đệ Quy)
Swift cho phép Enum đệ quy, nghĩa là một case
có thể chứa một giá trị của chính Enum đó.
7.1. Enum Đệ Quy
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
7.2. Tính Toán Giá Trị Enum Đệ Quy
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case .number(let value):
return value
case .addition(let left, let right):
return evaluate(left) + evaluate(right)
case .multiplication(let left, let right):
return evaluate(left) * evaluate(right)
}
}
print(evaluate(product)) // Kết quả: (5 + 4) * 2 = 18
Khi Nào Nên Sử Dụng Enum?
Enum là công cụ tuyệt vời khi bạn cần:
-
Định nghĩa các trạng thái cố định : Ví dụ như trạng thái của một đơn hàng (
pending
,shipped
,delivered
). -
Làm việc với các lựa chọn có liên quan : Như các lựa chọn trong một biểu mẫu (
male
,female
,other
). -
Nhóm các giá trị liên quan nhưng khác kiểu dữ liệu : Như trong ví dụ về
Barcode
hoặcArithmeticExpression
.
So Sánh Enum với Struct và Class
Đặc điểm | Enum | Struct | Class |
---|---|---|---|
Kiểu dữ liệu | Định nghĩa các giá trị liên quan | Định nghĩa các kiểu dữ liệu tùy chỉnh | Định nghĩa các kiểu dữ liệu tùy chỉnh |
Kiểu truyền | Giá trị (Value Type) | Giá trị (Value Type) | Tham chiếu (Reference Type) |
Hỗ trợ kế thừa | Không | Không | Có |
Associated Values | Có | Không | Không, nhưng có thể sử dụng Composition |
Phương thức | Có thể chứa | Có thể chứa | Có thể chứa |
Raw Values | Có thể có | Không | Không, nhưng có thể sử dụng Composition hoặc Protocol |
Lưu ý : Enum không hỗ trợ kế thừa nhưng có thể tuân thủ các protocol, trong khi Struct và Class có những ưu điểm riêng biệt trong các tình huống khác nhau.
Hạn Chế Của Enum
- Không hỗ trợ kế thừa : Enum không thể kế thừa từ các Enum khác hoặc từ Struct/Class.
- Giới hạn trong giá trị liên kết : Mỗi
case
có thể chứa các giá trị liên kết nhưng không thể chứa các thuộc tính lưu trữ. - Không thể mở rộng : Bạn không thể thêm các
case
mới vào Enum sau khi nó đã được định nghĩa.
Kết Luận
Enum là một trong những tính năng mạnh mẽ và linh hoạt của Swift, giúp bạn quản lý các giá trị liên quan một cách hiệu quả và rõ ràng. Từ việc định nghĩa các trạng thái cố định, làm việc với các lựa chọn có liên quan, đến việc xử lý các biểu thức phức tạp, Enum cung cấp giải pháp tối ưu cho nhiều tình huống trong lập trình. Việc hiểu và sử dụng enum một cách hiệu quả sẽ giúp bạn viết code Swift rõ ràng và dễ bảo trì hơn.
Thực Hành Thêm
Để làm quen sâu hơn với Enum, hãy thử các bài tập sau:
- Định nghĩa Enum cho các loại phương tiện giao thông :
enum Transportation {
case car(String)
case bicycle
case train(String, Int) // Tên đường sắt và số toa
}
- Sử dụng Enum để quản lý các trạng thái của một ứng dụng :
enum AppState {
case launched
case active
case inactive
case background
case terminated
}
- Tạo Enum để xử lý các loại lỗi trong ứng dụng :
enum NetworkError: Error {
case badURL
case requestFailed
case unknown
}