[Kotlin] Cùng tìm hiểu về let, apply, with, run & also
Bài đăng này đã không được cập nhật trong 3 năm
Giới thiệu
Trong số chúng ta khi đã sử dụng hoặc tìm hiểu về Kotlin đều có thể sẽ gặp một số đoạn code có chứa các function như (let
, run
, with
,apply
, also
). Chúng được nằm trong Standard.kt - là một phần của Kotlin library .
Những function này rất hữu ích giúp cho ta có thể sử dụng các objects trong một ngữ cảnh cụ thể giúp cho đoạn code của bạn trông gọn gàng, clean hơn.
Giờ chúng ta hãy cùng tìm hiểu về một số functions rất hữu ích này nhé:
let()
fun <T, R> T.let(f: (T) -> R): R = f(this)
let()
là một hàm phạm vi (scoping function): Sử dụng nó khi bạn muốn định nghĩa một biến trong một phạm vi cụ thể trong đoạn code. Nó cực kì hữu dụng giúp cho đoạn code "tự đóng gói" vì thế bạn sẽ không lo những biến này bị "leak" ra ngoài. Nghe thì khá khó hiểu phải không, hãy xem ví dụ dưới đây nhé:
DbConnection.getConnection().let { connection ->
}
// biến connection sẽ không còn xuất hiện ở đây nữa
let()
được sử dụng khá nhiều trong trường hợp checking null
val map : Map<String, Config> = ...
val config = map[key]
// config là một "Config?" - Biến có thể null
config?.let {
// toàn bộ block trong này sẽ không được chạy nếu `config` null và trong trường hợp `config` khác null
// thì ta có thể sử dụng biến config thông qua "it", khi này "it" là một "Config" (không chứa chấm hỏi)
}
apply()
fun <T> T.apply(f: T.() -> Unit): T { f(); return this }
apply()
định nghĩa một extension function cho tất cả các loại Object. Khi bạn gọi nó, nó sẽ gọi đoạn closure đã được truyền vào trong tham số và sau đó trả về đối tượng sau khi đoạn closure đó được chạy. Hãy thử xem ví dụ sau nhé:
File(dir).apply { mkdirs() }
Đoạn code trên truyền một String dir
vào trong một đối tượng File
, gọi hàm mkdirs()
trong đó và trả về file
Code Java tương ứng sẽ là:
File makeDir(String path) {
File result = new File(path);
result.mkdirs();
return result;
}
apply()
giúp cho đoạn code dài kia chỉ còn một dòng, khá gọn phải không nào!
with()
fun <T, R> with(receiver: T, f: T.() -> R): R = receiver.f()
with()
khá thuận tiện khi bạn có thể gọi nhiều methods khác nhau trong cùng một đối tượng. Thay vì phải liên tục lặp lại việc gọi biến mỗi dòng, bạn có thể dễ dàng với with()
val w = Window()
with(w) {
setWidth(100)
setHeight(200)
setBackground(RED)
}
run()
fun <T, R> T.run(f: T.() -> R): R = f()
run()
cùng là một hàm khá là thú vị và ta có thể hiểu đơn giàn hàm này là một sự kết hợp giữa with()
và let()
.
Kết hợp các functions
Ta có thể kết hợp các function này:
fun configurationFor(id: String) = map[id]?.let { config ->
config.apply {
buildType = "DEBUG"
version = "1.2"
}
}
Đoạn code trên tìm một object Config
theo id và nếu tìm thấy thì sẽ set thêm một vài thông số(buildType, version) và cuối cùng là trả về object đó.
Đoạn code trên có thể sửa lại cho ngắn gọn hơn, bạn có thể tự sửa và chạy thử đoạn code bằng công cụ Try Kotlin và copy đoạn code sau:
class Config(var buildType: String, var version: String)
val map = hashMapOf<String, Config>()
fun configurationFor(id: String) = map[id]?.let { config ->
config.apply {
buildType = "DEBUG"
version = "1.2"
}
}
Đoạn code trên có thể viết lại ngắn gọn hơn như sau:
fun configurationFor(id: String) = map[id]?.apply {
buildType = "DEBUG"
version = "1.2"
}
Hãy cùng tìm hiểu rõ hơn ý nghĩa đoạn code trên nhé:
- Đầu tiên ta tìm giá trị trong hash map, có thể dùng hàm
get()
hoặc dùng "[ ]" key
có thể không có trong map, vì thế ta sử dụng?.
để chắc chắn rằng giá trị trả về khác null mới chạy tiếp hàmapply()
- bên trong
apply()
block,this
object là một đối tượngConfig
, ta có thể gọi các hàm, thuộc tính trong đối tượng này mà không cần tiền tố nào. Trong trường hợp này là ta gọi đếnbuildType
vàversion
- Sau khi đoạn code được chạy, trả về đối tượng
Config
Trên đây là giới thiệu về các hàm cơ bản trong Kotlin standard library, mong là sẽ hữu ích với bạn! Bài viết được tham khảo từ: http://beust.com/weblog/2015/10/30/exploring-the-kotlin-standard-library/
All rights reserved