Giới thiệu let, run, also, apply và with trong kotlin

Dù đã làm việc với kotlin nhiều, nhưng đôi khi chúng ta vẫn dễ nhầm lần giữa let, run, also, apply và with. Trong bài viết này hãy cùng tìm hiểu và phần biệt chúng.

1. let

Kotlin let là một scoping function, các biến và giá trị được khai báo bên trong phạm vi của scope sẽ không có giá trị cũng như không thể sử dụng được ở bên ngoài scope.

let lấy đối tượng mà gọi nó làm tham số truyền vào cho function và trả về kết quả của biểu thức lambda.

fun main() {
    var strSample = "Kotlin sample"
    strSample.let { println("$it inside scope!") }
    println(strSample)
}

Từ khoá it đóng vai trò là một bản copy giá trị tham số đầu vào, ở ví dụ trên it sẽ chứa các giá trị của strSample. Kết quả của đoạn code trên sẽ là:

Kotlin sample inside scope!
Kotlin sample

let trả về giá trị như một function bình thường

fun main() {
    var strSample = "Kotlin sample!!"
    val lengthSample = strSample.let { 
        println("Sample in scope $strSample")
        "Sample has length is ${it.length}"
    }
    println(lengthSample)
}
Sample in scope Kotlin sample!!
Sample has length is 15

Chúng ta có thể sử dụng các let liên tiếp nhau

fun main() {
    var a = 1
    a = a.let { 
        	it + 1
    	}.let { 
        	val i = it + 3
        	i
    	}
    println("a = ${a}")
}
a = 5

Sử dụng lồng các let vào nhau, tuy nhiên ta cần lưu ý khi lồng các let thì ta không thể sử dụng it mà thay vào đó ta hãy gán một tên biến cụ thể cho từng it trong mỗi scope function.

fun main() {
    var str = "Kotlin let"
    str = str.let { var1 ->
        val lv1 = "Level 1: $var1"
        println(lv1)
        var1.let { var2 ->
            val lv2 = "Level 2: $var2"
            println("$lv1 and $lv2")
            "Kotlin level 2"
        }
        "Kotlin level 1"
    }
    println("Out scope: $str")
}
Level 1: Kotlin let
Level 1: Kotlin let and Level 2: Kotlin let
Out scope: Kotlin level 1

let được sử dụng để check null

fun main() {
    var name: String? = "Kotlin"
    name?.let { println(it) }
    name = null
    name?.let { println("nothing")}
}
Kotlin

2. run

run function được sử dụng để thực thi một đoạn (block) code trên một đối tượng và trả về kết quả khi block được thực thi.

Khác với let, run không hỗ trợ sử dụng it.

fun main() {
   val name = "hello"
   val hi = name.run {
      "${uppercase()} Kotlin!!"
   }
   println(hi)
}
HELLO Kotlin!!

3. also

also là biểu thức được gọi để thực thi câu lệnh trong một block đối với đối tượng (object) sử dụng nó. Không giống như let, also sẽ trả về giá trị của chính object thay vì một giá trị mới.

fun main() {
    val name = "hello"
    val hi = name.also {
        "$name Kotlin!!"
    }
    println(hi)
}
hello

Ví dụ phân biệt giữa letalso

data class Employee(var name: String, var salary: Int)

fun main() {
    val staff = Employee("A", 100)
   	val st1 = staff.let { it.name = "B" }
    val st2 = staff.also { it.name = "C" }
    println("staff $staff")
    println("staff 1: $st1")
    println("staff 2: $st2")
}
staff Employee(name=C, salary=100)
staff 1: kotlin.Unit
staff 2: Employee(name=C, salary=100)

4. apply

Là một extension function được sử dụng để thay đổi giá trị các thuộc tính của một đối tượng (object) và sau đó trả về chính đối tượng đó.

data class Person(var name: String, var age: Int)

fun main() {
    val person = Person("Ann", 10)
    person.apply {
        this.name = "Jinn"
    }
    println(person)
}
Person(name=Jinn, age=10)

Qua ví dụ trên ta có thể cảm thấy applyalso giống nhau, tuy nhiên chúng lại có khác biệt rõ ràng: Với apply thì it không được sử dụng, việc truy cập vào các thuộc tính của đối tượng là trực tiếp (trong trường hợp tên các thuộc tính là duy nhất, nếu không để rõ ràng ta có thể dùng this). Nếu không muốn dùng this trong khối lệnh (block of code) ta sẽ sử dụng also thay cho apply.

5. with

Giống với apply, with được sử dụng để truy cập vào các thuộc tính của đối tượng (object) trực tiếp và thực hiện các xử lý lên trên đối tượng đó.

data class Person(var name: String, var age: Int)

fun main() {
    val person = Person("Ann", 10)
    val info = with(person) {
        name = "Jinn"
        "You are $name and $age years old"
    }
    println(person)
    println(info)
}
Person(name=Jinn, age=10)
You are Jinn and 10 years old

Sự khác biệt giữa applywith qua ví dụ sau:

data class Person(var name: String, var age: Int)

fun main() {
    val person = Person("Ann", 10)
    val infoWith = with(person) {
        name = "Hann"
        "You are $name and $age years old"
    }
    
    val infoApply = person.apply {
         name = "Jinn"
         "You are $name and $age years old"
    }
    
    println(person)
    println("with: $infoWith")
    println("apply: $infoApply")
}
Person(name=Jinn, age=10)
with: You are Hann and 10 years old
apply: Person(name=Jinn, age=10)

Sự khác biệt giữa withrun:

  • run là một extension function còn with thì không.
  • Với run ta có thể thực hiện việc gọi liên tiếp.
foo.run { bar }.run { baz }

Leave a Reply

Your email address will not be published. Required fields are marked *