+13

[Kotlin] Cùng tìm hiểu về let, apply, with, run & also

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()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àm apply()
  • bên trong apply() block, this object là một đối tượng Config, 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 đến buildTypeversion
  • 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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí