openplanning

Hướng dẫn và ví dụ Swift Enum

  1. Swift Enum là gì?
  2. Duyệt trên các phần tử của Enum
  3. Enum trong câu lệnh switch
  4. Enum với các dữ liệu thô (raw value)
  5. Enum với các giá trị liên hợp
  6. Phương thức trong Enum

1. Swift Enum là gì?

Trong Swift, sử dụng từ khóa enum để định nghĩa một tập hợp có số phần tử cố định và liệt kê sẵn, bạn không thể thêm hoặc bớt số phần tử. Ví dụ bạn có thể định nghĩa ra một tập hợp các ngày trong tuần (Thứ 2, thứ 3,... , chủ nhật).
Nếu không có enum, để có một tập hợp các ngày trong tuần, bạn có thể định nghĩa ra 7 hằng số đại diện cho các ngày trong tuần.
WeekDayConstants.swift
import Foundation 

// Định nghĩa ra 7 hằng số, đại diện cho các ngày trong tuần.
let CONST_MONDAY = 2;
let CONST_TUESDAY = 3;
let CONST_WEDNESDAY = 4;
let CONST_THURSDAY = 5; 
let CONST_FRIDAY = 6;
let CONST_SATURDAY = 7;
let CONST_SUNDAY = 1;
Một hàm mô phỏng lấy ra tên công việc sẽ làm ứng với ngày cụ thể trong tuần. (Giống kiểu thời khóa biểu)
GetJobByDay.swift
import Foundation

// Tham số truyền vào là ngày trong tuần.
// Trả về tên công việc sẽ làm.
func getJobByDay(dayInWeek: Int) -> String { 
    if (dayInWeek == CONST_SATURDAY
        || dayInWeek == CONST_SUNDAY) {
        return "Nothing";
    }
    return "Coding"; 
}
Có thể nhận thấy rằng việc code như trên mang tính không an toàn. Chẳng hạn như khi bạn gõ các giá trị cho ngày trong tuần chẳng may trùng nhau. Hoặc gọi hàm getJobByDay(Int) mà truyền vào giá trị nằm ngoài các giá trị định nghĩa trước.
  • Không phải là kiểu an toàn: Đầu tiên thấy rằng nó là kiểu không an toàn, bạn có thể gọi method getJobByDay(Int) và truyền vào bất kỳ giá trị Int nào.
  • Không có ý nghĩa trong in ấn: Nếu bạn muốn in ra các ngày trong tuần nó sẽ là các con số,thay vì một chữ có ý nghĩa như "MONDAY".
Và đây là cách bạn tạo enum, một tập hợp đặc biệt.
WeekDay.swift
import Foundation

// Một tập liệt kê (Enumeration)
enum WeekDay {
    // Các phần tử (Element)
    case MONDAY
    case TUESDAY
    case WEDNESDAY
    case THURSDAY
    case FRIDAY
    case SATURDAY
    case SUNDAY 
}
Ví dụ sử dụng Enum:
WeekDayTest.swift
import Foundation 

// Trả về tên công việc sẽ làm.
func getJob(weekDay: WeekDay) -> String  { 
    if (weekDay == WeekDay.SATURDAY || weekDay == WeekDay.SUNDAY) { 
        return "Nothing" 
    }
    return "Coding" 
} 
func test_getJob()   { 
    var weekDay = WeekDay.TUESDAY 
    print("Day = \(weekDay)")
    
    var job = getJob(weekDay) 
    print("Job = \(job)") 
}

2. Duyệt trên các phần tử của Enum

Không có một hàm hoặc một phương thức sẵn có nào cho phép bạn lấy ra danh sách các phần tử của một Enum bất kỳ, nhưng bạn có thể tự định nghĩa một biến chứa tất cả các phần tử của Enum.
Ví dụ dưới đây định nghĩa một Enum, trong Enum này cũng định nghĩa một hằng số chứa tất cả các phần tử của nó.
Season.swift
import Foundation

// Các mùa trong năm.
enum Season  { 
    case Spring 
    case Summer 
    case Autumn 
    case Winter 
    
    // Một hằng số tĩnh, chứa tất cả các phần tử (element) của Enum.
    static let allValues = [Spring, Summer, Autumn, Winter]  
}
GetAllSeasons.swift
import Foundation 

func test_getAllSeasons()   { 
   for season in Season.allValues  {
       print(season)
   }
}
Kết quả chạy ví dụ:
Spring
Summer
Autumn
Winter

3. Enum trong câu lệnh switch

Cũng giống với các kiểu dữ liệu nguyên thủy (Int,Float,..) Enum có thể sử dụng như một tham số trong câu lệnh switch.
Hãy xem một ví dụ:
SwitchDemo.swift
import Foundation

func test_switchEnum() {
    var day = WeekDay.THURSDAY;
    switch (day) {
    case .MONDAY: 
        print("Working day");
    case .SATURDAY, .SUNDAY :
        print("Holiday");
    default:
        print(day);
    }
}
Sửa code của main.swift:
main.swift
import Foundation

test_switchEnum()
Chạy ví dụ:
THURSDAY

4. Enum với các dữ liệu thô (raw value)

Bạn có thể định nghĩa một Enum với các giá trị thô (raw values), các giá trị thô ở đây có thể là kiểu String, character, Int, Number,... Một Enum như vậy mở rộng một trong các kiểu String, Character, Int,..

Ví dụ bạn có thể định nghĩa một Enum là tập hợp các tháng của năm, tập hợp này sẽ chứa các giá trị thô từ 1 đến 12.
RawValueEnum.swift
import Foundation

// Định nghĩa một Enum là tập liệt kê các tháng trong năm.
// Nó mở rộng (extends) từ Int
enum Month : Int  { 
    // Gán giá trị thô (raw value) cho phần tử đầu tiên.
    // (Nếu một phần tử không được gán giá trị thô,
    // Theo mặc định giá trị của nó là giá trị của phần tử đứng trước cộng thêm 1).
    case January = 1, 
    February, March, April, May, June, 
    July, August, September, October, November, December
    
    // Một hằng số tĩnh chứa tất cả các phần tử của enum Month.
    static let allValues = [January,February, March,
                            April, May, June, July, August,
                            September, October, November, December] 
} 
// 
enum Suit:String { 
    case Spades = "♠" 
    case Hearts = "♥" 
    case Diamonds = "♦" 
    case Clubs = "♣"
    
    // Một hằng số tĩnh chứa tất cả các phần tử của enum Suit.
    static let allValues = [Spades,Hearts,Diamonds,Clubs] 
}
In ra các phần tử của enum Month, và các giá trị thô (raw value) tương ứng.
RawValueEnumTest.swift
import Foundation 

func test_MonthEnum()   { 
    // In tất cả các phần tử và giá trị thô (raw value) của Enum.
    print("All element/raw value of Month enum"); 
    for e in Month.allValues  { 
        let rawValue = e.rawValue 
        print("Element \(e), raw value: \(rawValue)"  );
    } 
    print("---------------------");
    
    // In tất cả các phần tử và giá trị thô (raw value) của Enum.
    print("All element/raw value of Suit enum");
    
    for e in Suit.allValues  { 
        let rawValue = e.rawValue 
        print("Element \(e), raw value: \(rawValue)"  );
    } 
}
Chạy ví dụ:
All element/raw value of Month enum
Element January, raw value: 1
Element February, raw value: 2
Element March, raw value: 3
Element April, raw value: 4
Element May, raw value: 5
Element June, raw value: 6
Element July, raw value: 7
Element August, raw value: 8
Element September, raw value: 9
Element October, raw value: 10
Element November, raw value: 11
Element December, raw value: 12
---------------------
All element/raw value of Suite enum
Element Spades, raw value: ♠
Element Hearts, raw value: ♥
Element Diamonds, raw value: ♦
Element Clubs, raw value: ♣

5. Enum với các giá trị liên hợp

Bạn có thể tạo ra một Enum với các phần tử có thể chứa các giá trị liên hợp với nó.
Tôi đưa ra một tình huống, bạn tạo ra một Enum chứa các hình thức khuyến mại:
  • GIFT: Tặng quà
  • DISCOUNT: Giảm giá
  • MONEY: Tặng tiền
  • SHIPPING: Miễn phí vận chuyển.
Vấn đề ở chỗ mỗi hình thức khuyến mại lại có các giá trị liên hợp với nó, chẳng hạn tặng quà (GIFT) thì tặng gì, và số lượng bao nhiêu. Hoặc tặng tiền (MONEY) thì số tiền tặng là bao nhiêu,...

Như vậy mỗi phần tử của Enum lại có các tham số khác nhau. Hãy xem ví dụ:
Promotion.swift
import Foundation

// Các kiểu khuyến mại.
enum Promotion   { 
    // Tặng quà (Tên quà tặng và số lượng)
    case GIFT (name: String, quantity: Int)
    
    // Giảm giá (phần trăm: 0 - 100)
    case DISCOUNT(percent: Int)
    
    // Tặng tiền (Số tiền).
    case MONEY(amount : Int)
    
    // Miễn phí giao hàng.
    case SHIPPING 
}
Enum Promotion chỉ có 4 phần tử, bạn không thể thêm bớt các phần tử của nó, các giá trị liên hợp với các phần tử được xác định tại thời điểm chạy của chương trình.
PromotionTest.swift
import Foundation

// Mô phỏng việc mua hàng, và nhận khuyến mại.
func getRandomPromotion() -> Promotion { 
    // Một giá trị ngẫu nhiên
    var random: UInt32 = arc4random()
    
    // Phép chia cho 4 và lấy số dư (0, 1, 2, 3).
    random = random % 4
    
    switch random  { 
    case 0:
        return Promotion.DISCOUNT(percent: 10)
    case 1:
        return Promotion.GIFT(name: "Doll", quantity: 1)
    case 2:
        return Promotion.MONEY(amount: 100)
    case 3:
        return Promotion.SHIPPING
    default:
        return Promotion.SHIPPING
    } 
} 
func test_Promotion()   {  
    var myProm = getRandomPromotion() 
    print("Get Promotion: \(myProm)")  
    switch myProm {
    case .DISCOUNT(let percent):
        print("Percent is: \(percent)")
    case .GIFT(let name, let quantity ):
        print("Gift name: \(name), quantity: \(quantity)")
    case .MONEY(let amount) :
        print("Amount: \(amount)")
    default:
        print(myProm)
    }
}
Sửa main.swift:
main.swift
import Foundation

test_Promotion()
Chạy ví dụ:
Get Promotion: GIFT("Doll", 1)
Gift name: Doll, quantity: 1

6. Phương thức trong Enum

Bạn có thể định nghĩa các phương thức trong Enum, hãy xem ví dụ:
Currency.swift
import Foundation 

// Tiền tệ (Currency).
enum Currency   { 
    case USD
    case YEN
    case VND  
    func description() -> String  { 
        switch self {
        case USD:
            return "America's currency"
        case YEN:
            return "Japan's currency"
        case VND :
            return "Vietnam's currency"
        }
    } 
}