Scala – Pattern Matching

scala

Có rất nhiều trường hợp khi chúng ta cần đưa ra một quyết định trong chương trình dựa trên các điều kiện hoặc giá trị. Ý tưởng đầu tiên nghĩ đến trong đầu là toán tử IF ELSE hoặc cái gì đó giống như SWITCH trong Java. Nhưng Scala đã đưa ra một cách tiếp cận mạnh mẽ và đơn giản hơn để xử lý các trường hợp như vậy. Hãy cùng xem cách mà Pattern Matching có thể giúp bạn

Đây là một ví dụ đơn giản sử dụng Pattern Matching:

1 + 2 - 3 + 4 - 5 match {
  case -1 => "minus one"
  case 0  => "zero"
  case 1  => "one"
  case _  => "unknown" 
} 
//minus one

Tại hàng đầu tiên chúng ta định nghĩa một biểu thức toán học, sau đó chúng ta sử dụng từ khoá đặc biệt match. Sau đó trong dấu ngoặc, tại hàng 2, 3, 4 và 5 chúng ta đặt các giá trị có thể xảy ra. Chúng tượng trưng cho các trường hợp mà chúng ta mong đợi nhận được như là kết quả của biểu thức tính toán. Cuối cùng, dấu ngoặc được đóng.

Sau đây là tóm tắt cú pháp chung cho Pattern Matching

Chúng ta có thể match bất kỳ biểu thức nào, sau đó vị trí case diễn tả những gì chúng ta mong muốn nhận được.  Nếu biểu thức phù hợp với một số trường hợp cụ thể, Pattern Matching sẽ dừng lại và trả về một biểu thức mà tương ứng với trường hợp được phù hợp. Nếu không có trường hợp nào phù hợp, thì một lỗi MatchError được đưa ra. Nó là lý do tại sao, như một quy tắc, đối với trường hợp case cuối cùng lập trình viên thường đặt dấu gạch dưới, nó phục vụ cho biểu thức mặc định nếu các trường hợp trên không xảy ra.

Ví dụ

Chúng ta hãy cùng xem xét một vài mẫu Pattern Matching sử dụng. Ví dụ đầu tiên là đơn giản nhất, chúng ta sẽ thử tìm biểu thức phù hợp cho một hằng số

val boo: Boolean = 5 < 10
boo match {
  case true => 1
  case false => 0
}
//1

Trong ví dụ tiếp theo, chúng ta sẽ đặt Pattern Matching trong một hàm và sử dụng dấu gạch ngang nếu tất cả các trường hợp bên trên đều không phù hợp

def matchFunction(v: Int) = v match {
  case 1 => "one"
  case 2 => "two"
  case _ => "unknown number"
}
matchFunction(2) //two
matchFunction(5) //unknown number

Tiếp theo là một ví dụ phức tạp hơn. Chúng ta sẽ áp dụng Pattern Matching cho một Class tuỳ chỉnh

trait Payment {
  def pay(amount: Double): Unit
}
class Cash extends Payment {
  def pay(amount: Double): Unit = println(s"Pay with cash $amount")
}
class CreditCard extends Payment {
  def pay(amount: Double): Unit = println(s"Pay with credit card $amount")
  def verify(): Unit = println("Verification...")
}
def processPayment(amount: Double, method: Payment) = method match {
  case c: Cash => c.pay(amount)
  case cc: CreditCard => cc.verify(); cc.pay(amount)
  case _ => println("Unknown payment method")
}
val paymentA = new Cash
val paymentB = new CreditCard
processPayment(10, paymentA) 
//Pay with cash 10.0
processPayment(50, paymentB)
//Verification...
//Pay with credit card 50.0

Dựa trên 3 ví dụ chúng ta đã bao hàm được hầu hết các kịch bản có thể xảy ra trong thực tế. Ngoài ra, Pattern Matching có thể được lồng vào nhau. Nhưng cũng giống như IF ELSE khi lồng vào nhau nhiều hơn 2 mức, code sẽ trở nên khó đọc.

Collection

Chúng ta có thể áp dụng Pattern Matching cho các Collection. Nó rất là hữu ích để xử lý các phần tử Collection sử dụng Pattern Matching. Sau đây là ví dụ cơ bản

val commonList = List(1, 2, 3, 4, 5)
val emptyList = Nil
val oneElement = 'a' :: Nil
def checkList[T](list: List[T]): String = list match {
  case Nil => "Empty list"
  case list :: Nil => "One element"
  case _ => "More than one element"
}
checkList(emptyList) //Empty list
checkList(oneElement) //One element
checkList(commonList) //More than one element

Sau đây là một ví dụ khác về cách chúng ta sử dụng Pattern Matching để tính tổng các số nguyên sử dụng đệ quy

val commonList = List(1, 2, 3, 4, 5)
def sum(list: List[Int]): Int = {
  def recursion(sum: Int, list: List[Int]): Int = list match {
    case Nil => sum
    case el :: tail => (recursion(sum + el, tail))
  }
  recursion(0, list)
}
sum(commonList) //15

Đây là lý do tại sao Pattern Maching vô cùng hữu ích trong Scala. Nó rất là tiện dụng để chạy với các giá trị mà không cần xác định chúng sử dụng instanceof. Ngoài ra nó cũng dễ đọc hơn IF ELSE

 

You May Also Like

About the Author: Nguyen Dinh Thuc

Leave a Reply

Your email address will not be published.