Higher-Order Function và Lambda Expression trong Kotlin

Lambda Expression

Lambda Expression về cơ bản là các hàm ẩn danh (anonymous function) mà bạn có thể coi là một giá trị. Ví dụ, ta có thể truyền chúng làm tham số cho các phương thức, trả về chúng hoặc làm bất kỳ điều gì khác mà chúng ta có thể làm với một đối tượng bình thường.

Ví dụ về một Lambda Expression:

val square : (Int) -> Int = { value -> value * value }

Để sử dụng phương thức trên:

val nine = square(3)

Bây giờ, hãy tìm hiểu nó thông qua một ví dụ đơn giản hơn:

val doNothing: (Int) -> Int = {value -> value}

Lambda Expression ở trên không hề làm nhiệm vụ gì cả. Vế:

{value -> value}

đã là một phương thức hoàn chỉnh. Nó lấy một số int làm tham số và trả về một giá trị cũng dưới dạng int. Trong vế:

(Int) -> Int

(Int) đại diện cho kiểu dữ liệu của tham số đầu vào.
Int đại diện cho kiểu dữ liệu trả về.

Vì vậy doNothing chính là một phương thức lấy một giá trị int và trả về giá trị tương đương duới dạng int.

Hãy xem xét một ví dụ khác:

val add: (Int, Int) -> Int = {a, b -> a + b}

Đây cũng là một Lambda Expression lấy hai số int làm tham số, cộng chúng với nhau và trả về một giá trị int. Tương tự như trên thì vế

{a, b -> a + b}

cũng chính là một phuơng thức lấy hai số int làm tham số, cộng chúng và trả về một giá trị int.

Trong

(Int, Int) -> Int

(Int, Int) đại diện cho hai tham số đầu vào có kiểu int.
Int đại diện cho kiểu trả về cũng là int.

Ta có thể gọi phương thức này như sau:

val result = add (2,3)

Higher-Order Function

Higher-Order Function là các phương thức có thể sử dụng các phương thức như một tham số hay trả về một phương thức.

Higher-Order Function có thể thực hiện hai việc sau:

  • Có thể lấy các phương thức làm tham số.
  • Có thể trả về một phương thức.
    Chúng ta sẽ kiểm chức từng thứ một trước.

Đặc điểm đầu tiên - Một phương thức có thể lấy các phương thức làm tham số.

fun passMeFunction(abc: () -> Unit) {
    // I can take function
    // do something here
    // execute the function
    abc()
}

Phương thức passMeFunction() nhận phương thức

abc: () -> Unit

làm tham số của nó (abc chỉ là tên của tham số, bạn có thể đặt chúng theo ý của mình).

() -> Unit

là một thành phần rất quan trọng.
() thể hiện rằng phương thức truyền vào không có tham số.

Unit thể hiện rằng phương thức truyền vào không trả về giá trị gì.

Như ta thấy passMeFunction có thể lấy một phương thức khác (không có tham số) và không trả về giá trị gì cả (Unit).

Cùng thử truyền cho passMeFunction một phương thức:

passMeFunction (
    {
         val user = User()
         user.name = "ABC"
         println("Lambda is awesome")
    }
)

Ở đây {} là một phương thức trong chính nó.

Nó không có tham số và không trả về bất kì giá trị nào. Nó chỉ tạo ra mộtUser, gán tên cho user đó và in một dòng chữ.

Kotlin cung cấp cho chúng ta một cách ngắn gọn để xử lý trong trường hợp này, ta có thể rút gọn đoạn code trên bằng cách bỏ đi ():

passMeFunction {
    val user = User()
    user.name = "ABC"
    println("Lambda is awesome")
}

Bây giờ, chúng ta đã hiểu làm thế nào để truyền một phương thức dưới dạng tham số cho một phương thức.

Hãy chuyển sang đặc điểm thứ hai - Một phương thức mà có thể trả về một phương thức.

Giả sử chúng ta có một hàm add có hai tham số và trả về một giá trị int.

fun add(a: Int, b: Int): Int = a + b

Cùng với phương thức returnMeAddFunction không có tham số nào và trả về một hàm như sau ((Int, Int) -> Int).

fun returnMeAddFunction(): ((Int, Int) -> Int) {
     // can do something and return function as well
     // returning function
     return ::add
}

(Int, Int) có nghĩa là phương thức này cần hai tham số có giá trị int.

Int có nghĩa là hàm sẽ trả về giá trị dưới dạng int.

Bây giờ, chúng ta có thể gọi hàm returnMeAddFunction, lấy hàm add và gọi nó như bên dưới:

val add = returnMeAddFunction()

val result = add(2, 2)

Đây chính là Higher-Order Function trong Kotlin.

Chúc các bạn học tập vui vẻ!