Optional là một khái niệm cực kỳ quen thuộc đối với lập trình viên Swift, tuy nhiên thì bản chất của nó không chỉ dừng lại ở ? hay ! như chúng ta vẫn hay định nghĩa. Bản thân tôi khi đi phỏng vấn đã được hỏi một câu hỏi như tiêu đề, và tôi đã không thể trả lời được. Vì vậy bài viết hôm nay sẽ giúp chúng ta hiểu rõ về bản chất của Optional, nó là kiểu (type) gì?

Trong lập trình Swift, có nhiều cách để sử dụng case bên cạnh switch. Dưới đây là một ví dụ minh họa cho điều đó với trường hợp chúng cần xử lý các phần tử non-nil trong một array chứa gồm cả các phần tử optional.

Mở playground lên và chúng ta khai báo một string Array như sau:

let names = ["Tom", nil, "Fred"]

 

Giả dụ tôi muốn chạy một vài tác vụ nào đó trên từng phần tử chứa giá trị của array này, func doSomeThing muốn truyền vào parameter là một giá trị non-nil, do đó tôi phải duyệt qua từng phần tử trong array và bốc ra phần tử non-nil bằng if-let

 

func doSomething(_ name: String) {
  print(name)
}

 

for name in names {
  if let name = name { doSomething(name) }
}
// Tom
// Fred

Hoặc là chúng ta cũng có thể sử dụng flatMap để code gọn hơn.

for name in names.flatMap({ $0 }) {
  doSomething(name)
}
// Tom
// Fred

2 cách trên là không tồi tuy nhiên thì chúng ta vẫn có thể sử dụng thêm một cách khác nữa đó là sử dụng case với các phần tử optional:

for case let name? in names {
  doSomething(name)
}
// Tom
// Fred

Cách này sẽ hoạt động như là một enum với 2 giá trị: .none và .some(T). Việc khai báo let name? là tương ứng với case .some, hoặc chúng ta có thể viết rõ hơn ra như sau:

for case .some(let name) in names {
  doSomething(name)
}

Tương tự với trường hợp nil:

for case .none in names {
  print("found nil")
}

Đọc đến đây thì có lẽ các bạn đã tìm ra được câu trả lời cho tiêu đề rồi. Kiểu (type) của Optional chính là Enum.

Bạn cần thêm dấu ? để match với giá trị optional trong mảng. Ví dụ như tôi muốn print ra giá trị optional Fred:

for case "Fred"? in names {
  print("Found Fred")
}

 

Sử dụng where với case

Ngoài ra thì bạn có thể sử dụng where như một filter trong array:

let scores = [1,5,8,3,10,nil,7]
for case let score? in scores where score > 6 {
  print(score)
}
// 8
// 10
// 7

Hoặc dùng flatMap để gỡ bỏ những phần tử nil trước khi filter.

for score in scores.flatMap({ $0 }).filter({ $0 > 6 }) {
  print(score)
}