12/08/2018, 14:07

Pattern Matching in Swift

Introduction Pattern matching là một tính năng mạnh mẽ ở bất kì ngôn ngữ lập trình nào, bởi vì nó cho phép bạn có thể thiết kế ra được các rules để match được cái giá trị, Pattern matching làm cho code trở lên linh hoạt và đơn giản. Trong bài viết này chúng ta sẽ tìm hiểu các pattern sau: ...

Introduction

Pattern matching là một tính năng mạnh mẽ ở bất kì ngôn ngữ lập trình nào, bởi vì nó cho phép bạn có thể thiết kế ra được các rules để match được cái giá trị, Pattern matching làm cho code trở lên linh hoạt và đơn giản. Trong bài viết này chúng ta sẽ tìm hiểu các pattern sau:

  • Tuple pattern
  • Type-casting patterns
  • Wildcard pattern
  • Optional pattern
  • Enumeration case pattern
  • Expression pattern

Để có thể thấy được sự tiện ích của pattern matching, trong tutorial này chúng ta sẽ sử dụng pattern matching để schedule và publish các tutorials trên trang raywenderlick.com. Chú ý: tutorial này yêu cầu Xcode 8 và Swift 3, người đọc yêu cầu phải có kiến thức cơ bản về Swift.

Download : https://koenig-media.raywenderlich.com/uploads/2016/07/starter-project.playground-2.zip Sau đó mở file starter project.playground bằng Xcode File play ground này gồm 2 thành phần:

  • Hàm random_uniform(value:) tạo ngày ngẫu nhiên cho việc lập lịch.
  • Code đọc thông tin file tutorials.json trả về thông tin lập lịch các bài viết.

Mỗi bài tutorial sẽ được lập lịch gồm 2 thuộc tính: title và scheduled day. Mỗi ngày chỉ được publish 1 bài tutorial, xem lại thông tin của file tutorials.json chúng ta sẽ thấy có 2 tutorials được lập lịch publish cùng 1 ngày. Chúng ta cần sửa nó sử dụng Pattern matching.

Pattern Matching Types

Các loại Pattern Matching:

  • Tuple patterns được sử dụng để match giá trị kiểu tuple.
  • Type-casting patterns cho phép bạn cast hoặc match types.
  • Wildcard patterns dùng để match và ignore các loại giá trị khác nhau.
  • Optional patterns sử dụng để match các giá trị optional.
  • Enumeration case patterns sử dụng để match kiểu enumeration.
  • Expression patterns cho phép so sánh các giá trị vơi các biểu thức.

Chúng ta sẽ sử dụng tất cả các pattern này trong bài viết này.

Tuple Pattern

Đầu tiên chúng ta sẽ tạo tupple pattern để tạo mảng các tutorials. Trong file playground, thêm đoạn code sau

enum Day: Int {
  case monday, tuesday, wednesday, thursday, friday, saturday, sunday
}

Đoạn code trên sẽ tạo ra enumeration cho các ngày trong tuần. Giá trị raw là kiểu Int nên các ngày sẽ được gán giá trị từ 0-6 tương ứng thứ 2 - thứ 6

Thêm đoạn code dưới đây vào sau phần khai báo enumeration:

class Tutorial {

  let title: String
  var day: Day?

  init(title: String, day: Day? = nil) {
    self.title = title
    self.day = day
  }
}

Ở đây chúng ta đã định nghĩa kiểu tutorial với 2 thuộc tính: title, scheduled day. day là kiểu optional vì nó có thể nil trong các trường hợp tutorials chưa được lập lịch. Chúng ta implement CustomStringConvertible để có thể dễ dàng in ra giá trị tutorial:

extension Tutorial: CustomStringConvertible {
  var description: String {
    var scheduled = ", not scheduled"
    if let day = day {
      scheduled = ", scheduled on (day)"
    }
    return title + scheduled
  }
}

Bây giờ chúng ta sẽ tạo mảng để lưu các giá trị tutorial này:

var tutorials: [Tutorial] = []

Tiếp theo, thêm đoạn code sau vào cuối file playground để chuyển mảng các dictionaries sang mảng các đối tượng tutorials

for dictionary in json {
  var currentTitle = ""
  var currentDay: Day? = nil

  for (key, value) in dictionary {
    // todo: extract the information from the dictionary
  }

  let currentTutorial = Tutorial(title: currentTitle, day: currentDay)
  tutorials.append(currentTutorial)
}

Ở đây chúng ta sử dụng tupple pattern, trong vòng lặp for in sử dụng tupple (key, value) để lấy ra giá trị từ dictionary. Tiếp theo chúng ta sẽ thiết lập các giá trị này vào thuộc tính của tutorial bằng cách sử dụng Type-Casting Patterns Type-Casting Patterns Thêm đoạn code sau vào trong vòng lặp (key, value) ở trên

// 1
switch (key, value) {
  // 2
  case ("title", is String):
    currentTitle = value as! String
  // 3
  case ("day", let dayString as String):
    if let dayInt = Int(dayString), let day = Day(rawValue: dayInt - 1) {
      currentDay = day
  }
  // 4
  default:
    break
}

Các bước lần lượt như :sau Sử dụng câu lệnh: switch (key, value) => tupple pattern được sử dụng lần nữa. Chúng ta kiểm tra xem thuộc tính title của tutorial có phải là kiểu String hay không sử dụng type-casting pattern, sau đó chúng ta ép kiểu nếu điều kiện trên là đúng. Tương tự với thuộc tính day của tutorial, chúng ta cũng sử dụng type-casting pattern để kiểm tra và ép kiểu cho giá trị này. Thêm dòng lệnh print vào cuối file playground để in ra thông tin của tutorials.

print(tutorials)

Nhìn vào màn hình console chúng ta sẽ thấy được mỗi một tutorial trong mảng có 1 giá trị title và scheduled day tương ứng. Mọi thứ đã được thiết lập, bây giờ chúng ta sẽ thực hiện việc lập lịch sao cho mỗi ngày chỉ publish một tutorial.

Wildcard Pattern Chúng ta sẽ sử dụng wildcard pattern để lập lịch cho các bài tutorials này, tuy nhiên chúng ta cần unscheduled chúng trước:

tutorials.forEach { $0.day = nil }

Đoạn code trên sẽ unscheduled tất cả các tutorial bằng cách thiết lập giá trị day cho các tutorial này = nil. Để lập lịch cho các tutorial them đoạn code sau vào cuối file playground:

// 1
let days = (0...6).map { Day(rawValue: $0)! }
// 2
let randomDays = days.sorted { _ in random_uniform(value: 2) == 0 }
// 3
(0...6).forEach { tutorials[$0].day = randomDays[$0] }

Let’s break it down: Đầu tiên chúng ta tạo mảng days, mỗi ngày của một tuần sẽ xảy ra đúng 1 lần. Sắp xếp lại mảng. Hàm random_uniform(value:) sử dụng để ngẫu nhiên quyết định một element sẽ được sắp xếp trước hay sau element tiếp theo ở trong mảng. Cuối cùng, chúng ta gán 7 tutorials đầu tiền với các giá trị ngẫu nghiên này. Thêm dòng code sau:

print(tutorials)

Quan sát, chúng ta sẽ thấy được các tutorial đã được thiết lập lịch cho mỗi 1 ngày trong tuần, và không có trường hợp lặp như ban đầu.

Optional Pattern Để sắp xếp mảng tutorials theo thứ tự ngày :

// 1
tutorials.sort {
  // 2
  switch ($0.day, $1.day) {
    // 3
    case (nil, nil):
      return $0.title.compare($1.title, options: .caseInsensitive) == .orderedAscending
    // 4
    case (let firstDay?, let secondDay?):
      return firstDay.rawValue < secondDay.rawValue
    // 5
    case (nil, let secondDay?):
      return true
    case (let firstDay?, nil):
      return false
  }
}

Step-by-step: Chúng ta sắp xếp mảng tutorials sử dụng hàm sort(_            </div>
            
            <div class=

0