
Trong hướng dẫn này, chúng ta sẽ triển khai một số hàm phạm vi trong Kotlin. Thư viện kotlin-stdlib cung cấp nhiều hàm bậc cao hữu ích, hiện thực các mẫu lập trình mang tính đặc trưng. Chúng ta sẽ thấy cách mà chúng giúp việc lập trình với Kotlin trở nên dễ dàng và nhanh chóng hơn. Các hàm sẽ được thảo luận bên dưới bao gồm:
letrunalsoapplywith
Các hàm phạm vi trong Kotlin
1. Kotlin let
Hàm let nhận đối tượng mà nó được gọi lên làm tham số và trả về kết quả của biểu thức lambda. let trong Kotlin là một scoping function, nghĩa là các biến được khai báo bên trong biểu thức không thể sử dụng bên ngoài phạm vi của nó. Một ví dụ minh họa cách hàm let hoạt động như sau:
fun main(args: Array<String>) {
var str = "Hello World"
str.let { println("$it!!") }
println(str)
}
//Prints
//Hello World!!
//Hello World
Từ khóa it chứa một bản sao của thuộc tính bên trong let. Giá trị cuối cùng từ khối let sẽ được trả về như một đối số, bạn có thể xem ví dụ dưới đây:
var strLength = str.let { "$it function".length }
println("strLength is $strLength") //prints strLength is 25

Chuỗi các hàm let
Chúng ta có thể nối nhiều hàm let với nhau để thực hiện một chuỗi các thao tác:
var a = 1
var b= 2
a = a.let { it + 2 }.let { val i = it + b
i}
println(a) //5
Như bạn thấy, chúng ta đã khai báo một biến cục bộ “i” bên trong hàm let thứ hai. Việc đặt câu lệnh cuối cùng của hàm let là i sẽ trả về thuộc tính này cho thuộc tính bên ngoài a.

Lồng hàm let
Chúng ta có thể lồng một biểu thức let bên trong một biểu thức let khác như sau:
var x = "Anupam"
x.let { outer -> outer.let { inner -> print("Inner is $inner and outer is $outer") } }
//Prints
//Inner is Anupam and outer is Anupam
Đối với let lồng nhau, chúng ta không thể sử dụng từ khóa it mặc định. Chúng ta cần gán tên rõ ràng cho it trong cả hai hàm let. Chỉ let bên ngoài cùng trả về giá trị, như ví dụ dưới đây:
var x = "Anupam"
x = x.let { outer ->
outer.let { inner ->
println("Inner is $inner and outer is $outer")
"Kotlin Tutorials Inner let"
}
"Kotlin Tutorials Outer let"
}
println(x) //prints Kotlin Tutorials Outer let
let để kiểm tra null
Ngoài ra, let rất hữu ích cho việc kiểm tra các thuộc tính Nullable như ví dụ dưới đây:
var name : String? = "Kotlin let null check"
name?.let { println(it) } //prints Kotlin let null check
name = null
name?.let { println(it) } //nothing happens
Mã bên trong biểu thức let sẽ chỉ được thực thi khi thuộc tính không null. Như vậy, let giúp chúng ta loại bỏ những khối kiểm tra null if-else dài dòng!
2. Kotlin run
Kotlin run là một hàm khác cũng rất thú vị. Ví dụ sau đây minh họa các trường hợp sử dụng của nó:
var tutorial = "This is Kotlin Tutorial"
println(tutorial) //This is Kotlin Tutorial
tutorial = run {
val tutorial = "This is run function"
tutorial
}
println(tutorial) //This is run function

Biểu thức run trong Kotlin có thể thay đổi thuộc tính bên ngoài. Do đó, trong đoạn code trên, chúng ta đã định nghĩa lại nó cho phạm vi cục bộ.
- Tương tự như hàm
let, hàmruncũng trả về câu lệnh cuối cùng. - Không giống
let, hàmrunkhông hỗ trợ từ khóait.
Kết hợp let và run (let and run)
Hãy cùng nhau kết hợp các hàm let và run:
var p : String? = null
p?.let { println("p is $p") } ?: run { println("p was null. Setting default value to: ")
p = "Kotlin"}
println(p)
//Prints
//p was null. Setting default value to:
//Kotlin
Trong ví dụ này, chúng ta sử dụng ?.let để kiểm tra p có null không. Nếu p không null, nó sẽ in giá trị của p. Nếu p là null, toán tử Elvis (?:) sẽ chuyển quyền điều khiển sang khối run, nơi chúng ta in ra thông báo và gán giá trị mặc định cho p.
3. Kotlin also
Đúng như tên gọi, biểu thức also thực hiện một số xử lý bổ sung trên đối tượng mà nó được gọi. Không như let, nó trả về chính đối tượng gốc thay vì một dữ liệu trả về mới. Do đó, dữ liệu trả về luôn có cùng kiểu. Giống let, also cũng sử dụng it.
var m = 1
m = m.also { it + 1 }.also { it + 1 }
println(m) //prints 1

Ở ví dụ trên, mặc dù chúng ta đã thực hiện it + 1 hai lần, giá trị của m vẫn là 1 vì also luôn trả về đối tượng gốc (ở đây là m) chứ không phải kết quả của biểu thức lambda.

So sánh Kotlin let và also
Đoạn code sau đây cho thấy một ví dụ tuyệt vời để phân biệt giữa let và also.
data class Person(var name: String, var tutorial : String)
var person = Person("Anupam", "Kotlin")
var l = person.let { it.tutorial = "Android" }
var al = person.also { it.tutorial = "Android" }
println(l)
println(al)
println(person)

Trong đoạn code trên, chúng ta đã sử dụng Data classes. Biểu thức also trả về đối tượng data class đã được sửa đổi, trong khi biểu thức let trả về Unit vì chúng ta không chỉ định bất cứ điều gì một cách rõ ràng để nó trả về.
4. Kotlin apply
Kotlin apply là một extension function trên một kiểu dữ liệu. Nó thực thi trên đối tượng tham chiếu (còn gọi là receiver) vào biểu thức và trả về chính đối tượng tham chiếu đó khi hoàn thành.
data class Person(var name: String, var tutorial : String)
var person = Person("Anupam", "Kotlin")
person.apply { this.tutorial = "Swift" }
println(person)
// Prints: Person(name=Anupam, tutorial=Swift)

So sánh apply và also
data class Person(var n: String, var t : String)
var person = Person("Anupam", "Kotlin")
person.apply { t = "Swift" }
println(person) // Person(n=Anupam, t=Swift)
person.also { it.t = "Kotlin" }
println(person) // Person(n=Anupam, t=Kotlin)
Lưu ý: Trong apply, từ khóa it không được phép. Nếu tên thuộc tính của data class là duy nhất trong hàm, bạn có thể bỏ qua this. Chúng ta nên sử dụng also chỉ khi chúng ta không muốn che khuất this và muốn truy cập đối tượng bằng it. apply rất hữu ích để cấu hình đối tượng.
5. Kotlin with
Giống apply, with được sử dụng để thay đổi các thuộc tính của instance mà không cần phải gọi toán tử dấu chấm (.) trên đối tượng tham chiếu mỗi lần.
data class Person(var name: String, var tutorial : String)
var person = Person("Anupam", "Kotlin")
with(person)
{
name = "No Name"
tutorial = "Kotlin tutorials"
}
println(person) // Prints: Person(name=No Name, tutorial=Kotlin tutorials)

Một lần nữa, with tương tự apply nhưng có một vài điểm khác biệt chính.
So sánh Kotlin apply và with
withchạy mà không cần một đối tượng (receiver) để gọi, nó nhận đối tượng làm đối số. Trong khiapplylà một extension function nên nó cần một đối tượng để gọi.applychạy trên đối tượng tham chiếu (this), trong khiwithchỉ truyền đối tượng đó như một đối số đầu tiên.- Biểu thức cuối cùng của hàm
withtrả về một kết quả.
var xyz = with(person)
{
name = "No Name"
tutorial = "Kotlin tutorials"
val xyz = "End of tutorial"
xyz
}
println(xyz) //End of tutorial
Trong ví dụ này, xyz sẽ nhận giá trị “End of tutorial” vì đó là câu lệnh cuối cùng trong khối with.
Kết luận
Chúng ta vừa hoàn thành một hành trình thú vị qua các hàm tiện ích mạnh mẽ của kotlin-stdlib. Chúng ta thấy rõ cách let, run, also, apply, và with giúp chúng ta viết code Kotlin một cách gọn gàng hơn, dễ đọc hơn và an toàn hơn, đặc biệt là khi làm việc với các đối tượng và xử lý null. Việc làm chủ các hàm này chắc chắn sẽ nâng cao kỹ năng lập trình Kotlin của bạn lên một tầm cao mới.