let,run,with,also,apply...

Prerequisites:

Lambda參數與傳回值

Lambda參數為呼叫Lambda函式(let, run, with, also, apply)的物件。

Lambda函式 參數 傳回值
let it 最後一行決定
run this 最後一行決定
with this 最後一行決定
also it 呼叫它的物件
apply this 呼叫它的物件

let

  • it,為呼叫Lambda函式的物件。
  • 傳回值是lambda最後一行。

setWritable() 和 setExecutable() 這些方法的返回值是 Boolean,表示操作是否成功

1
2
3
4
5
6
7
val var1 = File("/Users/cici/testc/file_test").let {
    it.setWritable(true)
    it.setWritable(true)
    it.setExecutable(true) //最後一行的結果才是傳回值
}
println("var1 = $var1")
println(var1::class)
file1 = true
boolean (Kotlin reflection is not available)

run

  • this,為呼叫Lambda函式的物件。
  • 傳回值是lambda最後一行。
1
2
3
4
5
6
7
val var3 = File("/Users/cici/testc/file_test").run {
    setWritable(true)
    setWritable(true)
    setExecutable(true) //最後一行的結果才是傳回值
}
println("var3 = $var3")
println(var3::class)
var3 = true
boolean (Kotlin reflection is not available)

run可以呼叫函式參考

with

  • this,為呼叫Lambda函式的物件。
  • 傳回值是lambda最後一行。
  • 使用參數的方式代入,with(參數) {}
1
2
3
4
5
6
7
val var5 = with(File("/Users/cici/testc/file_test")) {
    setWritable(true)
    setWritable(true)
    setExecutable(true) //最後一行的結果才是傳回值
}
println("var5 = $var5")
println(var5::class)
var5 = true
boolean (Kotlin reflection is not available)

also

  • it,為呼叫Lambda函式的物件。
  • 傳回值是呼叫它的物件,此處是File。
1
2
3
4
5
6
7
val file2 = File("/Users/cici/testc/file_test").apply {
    setWritable(true)
    setWritable(true)
    setExecutable(true)
}
println("file2 = $file2")
println(file2::class)
file2 = /Users/cici/testc/file_test
class java.io.File (Kotlin reflection is not available)

apply

  • it,為呼叫Lambda函式的物件。
  • 傳回值是呼叫它的物件,此處是File。
1
2
3
4
5
6
7
val file4 = File("/Users/cici/testc/file_test").also {
    it.setWritable(true)
    it.setWritable(true)
    it.setExecutable(true)
}
println("file4 = $file4")
println(file4::class)
file4 = /Users/cici/testc/file_test
class java.io.File (Kotlin reflection is not available)

用法

Lambda參數為呼叫Lambda函式(let, run, with, also, apply)的物件。

Lambda函式 參數 傳回值 用法
let it 最後一行決定 null安全呼叫、修改內容
run this 最後一行決定 運算、判斷true或false、函式參考
with this 最後一行決定 與run功能相同,但沒有函式參考
also it 呼叫它的物件 鏈式呼叫(Method chaining)對同一個物件進行一系列的操作
apply this 呼叫它的物件 初始化、config設定

初始化、config設定

1
2
3
4
val file = File("/Users/cici/testc/file_test").apply {
    setWritable(true)
    setReadable(true)
}

取出資料

1
2
3
val lines = file.let {
    it.readLines()
}

對同一個物件進行一系列的操作。

1
2
3
4
5
6
7
file.also {
    println("file size = ${it.length()}")
}.also {
    println("file path = ${it.path}")
}.also {
    println("file content= ${it.readText()}")
}
file size = 30
file path = /Users/cici/testc/file_test
file content= 測試程式

java程式設計

計算、判斷true或false

1
2
3
4
val res = file.run {
    this.readText().contains("Java")
}
println("res = $res")
res = false

with與run功能相同

1
2
3
4
5
val res2 = with(file) {
    //"file name = ${name}  length = ${length()} byte."
    this.readText().contains("Java")
}
println("res2 = $res2")
res2 = false

也可作為多行程式碼運算,或資料整理,最後一行回傳最後結果。

1
2
3
4
val fileInfo = with(file) {
    "file name = ${name}  length = ${length()} byte."
}
println(fileInfo)
file name = file_test  length = 30 byte.

let與null

配合安全呼叫問號?,不是null才呼叫let花括號{}中的內容,最後再配合:?貓王運算子,得到null結果時指定預設值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fun main() {
    // String類型後面加上問號?代表可以是null
    var msg: String? = null;
    println("${showMsg(msg)}")
    println("=================")
    msg = "Hello World!"
    println("${showMsg(msg)}")
}
fun showMsg(arg1: String?) : String {
    // 若為null,就不執行let{}中的內容,顯示預設值null data
    return arg1?.let {
        "Your msg is $arg1"
    } ?: "null data"
}
null data
=================
Your msg is Hello World!

also與null

配合安全呼叫問號?,若file為空值,後面的also就不會再執行了。

1
2
3
4
5
6
7
file?.also {
    println("file size = ${it.length()}")
}.also {
    println("file path = ${it.path}")
}.also {
    println("file content= ${it.readText()}")
}

run與函式參考

鏈式呼叫與函式參考二者結合,都會把Lambda最後一行,傳到下一個函式中,最後把showMsg2()的結果印出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun main() {
    "abcdefegdddffdfd"
        .run(::isLong)
        .run(::showMsg2)
        .run(::println)
}

fun isLong(str: String): Boolean = str.length > 10

fun showMsg2(isLong: Boolean): String {
    return if (isLong) {
        "String is too long"
    } else {
        "String is not too long"
    }
}
String is too long

其它

以下為有條件的Lambda

takeIf

  • it,為呼叫Lambda函式的物件。
  • 根據條件傳回呼叫它的物件,或null。

判斷是否符合條件,符合條件傳回呼叫它的物件,否則傳回null,takeIf{…}?,後面要加上問號?,因為有可能會為null,是空值類型。

以下範例是做鏈式呼叫,若條件成立,會傳回File物件,然後呼叫readText(),若條件不成立,就直接傳回null,不繼續執行readText。

1
2
var result = File("/Users/cici/adbd").takeIf { it.exists() }?.readText()
println(result)
null

takeUnless

  • it,為呼叫Lambda函式的物件。
  • 根據條件傳回呼叫它的物件,或null。

與takeIf相反,不符合條件,才會進入let{}中。

1
2
3
4
var result2 = File("/Users/cici/adbd").takeUnless { it.exists() }.let {
    "file is not exist."
}
println("result = $result2")
result = file is not exist.

results matching ""

    No results matching ""