Hướng dẫn sử dụng Swift Enum
Công ty Vĩnh Cửu tuyển dụng lập trình viên Java

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_ATURDAY = 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.
  1. 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.
  2. 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

// Định nghĩa Enum WeekDay, một tập hợp đặc biệt.
enum WeekDay
{
   // Các phần tử
   case MONDAY
   case TUESDAY
   case WEDNESDAY
   case THURSDAY
   case FRIDAY
   case SATURDAY
   case SUNDAY
 
}
Ví dụ sử dụng Enum:
WeekDayTest.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 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
 
 
   // Hằng số tĩnh, chứa tất các phần tử 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ụ:

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 file main.swift:
main.swift
import Foundation

test_switchEnum()
Chạy ví dụ:

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 hợp các tháng trong năm
// Nó mở rộng từ kiểu dữ liệu Int
enum Month : Int  {
   
   // Gán các giá trị thô (raw value) cho các phần tử
   // (Nếu phần tử không được gán giá trị thô,
   // mặc định giá trị thô của nó bằng giá trị thô của phần tử trước cộng 1).
   case January = 1,
   
   February, March, April, May, June,
   
   July, August, September, October, November, December
   
   
   // Hằng số tĩnh chứa tất cả các giá trị của Enum Month.
   static let allValues = [January,February, March,
                           April, May, June, July, August,
                           September, October, November, December]
   
}

// 4 chất (Rô, Cơ, Bích, Tép) trong tú lơ khơ.

enum Suit:String {
   
   case Spades = "♠"
   
   case Hearts = "♥"
   
   case Diamonds = "♦"
   
   case Clubs = "♣"
   
   // Hằng số tĩnh chứa tất cả các giá trị 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 ra các phần tử và các giá trị thô (raw value)
   
   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 ra các phần tử và các giá trị thô (raw value)
   
   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ụ:

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:
  1. GIFT: Tặng quà
  2. DISCOUNT: Giảm giá
  3. MONEY: Tặng tiền
  4. 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


// Tập hợp liệt kê các hình thức 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 giảm giá: 0 - 100)
   case DISCOUNT(percent: Int)
 
   // Tặng tiền (Số tiền tặng)
   case MONEY(amount : Int)
 
   // Miễn phí vận chuyển
   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 được khuyến mại.
// (Ngẫu nhiên)
func getRandomPromotion() -> Promotion {
 
  // Một số nguyên không âm 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 file main.swift:
main.swift
import Foundation

test_Promotion()
Chạy ví dụ:

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



// Các loại tiền tệ
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"
       }
   }
 
}