Lambda

Prerequisites:

Lambda就是匿名函式,沒有名字的函式。

Lambda是變數類型

Lambda的類型是由「傳入的參數」與「傳回值類型」所決定的。

此處的Lambda與C++的函式指標有相同的概念。

有名字的函式

有名字的函式要用return傳回值。

fun 函式名(參數): 傳回值類型 {
    return 傳回值
}
1
2
3
fun sum(a: Int, b: Int): Int {
    return a + b
}

沒有名字的函式Lambda

用花括號{}開始跟結束,使用->將參數跟函式內容分開,參數可以1個、多個、或沒有。

函式內容可以有多行,最後計算的運算式作為Lambda傳回值,例如下面程式碼傳回x + 5的結果。

->用於分隔任何參數。

->後面要傳回的結果,Lambda不用有return。

如果Lambda沒有參數,可以省略->

Lambda

1
{ x: Int -> "The value is $x" }

把Lambda指派給變數,並執行。

1
2
3
val msg = { x: Int -> "The value is $x" }
// 執行Lambda有代入參數,要用${運算式}
println("pass 6 to msg:${msg(6)}")
pass 6 to msg:The value is 6

Lambda類型

變數的類型是Lambda,Lambda類型是「傳入的參數類型與個數」+「傳回值類型」所組合。

Lambda可以指派給變數,以下把{ x: Int, y: Int -> x + y }指派給變數sum。

img

{}大括號是函式主體body,函式主體中有「參數」與「傳回值」,與Lambda類型是一致的。

1
2
3
//  變數: (傳入的參數類型) -> 傳回值類型 = {參數: 類型, 參數: 類型 -> 傳回值}
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
println(sum(10, 20));
30

自動推導Lambda類型

變數的Lambda類型是可以自動推導的,就可以省略Lambda類型。

1
2
3
4
// 省略Lambda類型(Int, Int) -> Int
val sum = { x: Int, y: Int -> x + y }
// 有帶參數記得加上花括號印出${}
println("sum = ${sum(15, 25)}");
sum = 40

sendMsg1的Lambda類型是可以自動推導,就可以省略Lambda類型。

1
2
3
4
5
6
// 省略Lambda類型() -> String
val sendMsg1 = {
    val appendMsg = "nice to meet you."
    "傳回訊息1 = $appendMsg"
}
println(sendMsg1())
傳回訊息1 = nice to meet you.

省略函式主體參數類型

如果Lambda類型沒有省略,{}大括號稱為函式主體body,函式主體中的參數「類型」是可以省略。

1
2
//  變數: (傳入的參數類型) -> 傳回值類型 = {參數, 參數 -> 傳回值}
val sum: (Int, Int) -> Int = { x, y -> x + y }

參數只有一個,使用it

參數只有一個。

1
2
3
//  變數: (傳入的參數類型) -> 傳回值類型 = {參數 -> 傳回值}
val sendMsg: (String) -> String = { msg -> "傳回訊息 = $msg" }
println(sendMsg("Hello world!"))
傳回訊息 = Hello world!

省略msg參數,省略->箭頭,把$msg變成$it,只針對「參數只有一個」。

1
2
val sendMsg: (String) -> String = { "傳回訊息 = $it" }
println(sendMsg("Hello world!"))
傳回訊息 = Hello world!

多行程式碼,最後一行是傳回值

在函式主體{}中,可以有多行程式碼,最後一行是傳回值。

1
2
3
4
5
val sendMsg: (String) -> String = { 
    val appendMsg = "${it} nice to meet you."
    "傳回訊息 = $appendMsg" 
}
println(sendMsg("Hello world!"))
傳回訊息 = Hello world! nice to meet you.

Lambda參數是Lambda

Lambda也是匿名函式,匿名函式的參數是匿名函式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
val callback: (Int) -> String = {
    when (it) {
        404 -> "找不到網頁"
        500 -> "Server error!"
        else -> "其它錯誤"
    }
}

val sendMsg3: (Int, (Int) -> String) -> String = 
    { code, function1 ->
        function1(code)
    }

println("Lambda參數是Lambda,結果 = ${sendMsg3(404, callback)}")
Lambda參數是Lambda,結果 = 找不到網頁

解釋:

  • callback變數的Lambda類型是,參數是Int,傳回值是String。
  • sendMsg3變數的Lambda類型是,參數有二個,分別是Int與Lambda,傳回值是String類型。
  • sendMsg3(),參數2的Lambda類型是(Int) -> String,參數是Int,傳回值是String。
1
println("Lambda參數是Lambda,結果 = ${sendMsg3(404, callback)}")
  • 使用字串模板運算式${}
  • 呼叫sendMsg3()函式
  • 參數1,404
  • 參數2,callback變數

有名字的函式參數是Lambda

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fun sendMsg4(code:Int, function1: (Int) -> String): String {
    return function1(code)
}

fun main() {
val callback: (Int) -> String = {
    when (it) {
        404 -> "找不到網頁"
        500 -> "Server error!"
        else -> "其它錯誤"
    }
}

println("有名字的函式的參數是Lambda,結果 = ${sendMsg4(500, callback)}");    
有名字的函式的參數是Lambda,結果 = Server error!

解釋:

  • callback變數的Lambda類型是,參數是Int,傳回值是String。
  • sendMsg4()定義在main()函式之外。
  • sendMsg4(),傳回值是String類型,參數有二個,分別是Int與Lambda。
  • sendMsg4(),參數2的Lambda的類型是(Int) -> String,參數是Int,傳回值是String類型。
  • sendMsg4()是有名字的函式,要有return關鍵字。

最後一個參數是Lambda

  • sendMsg5()Lambda類型是,參數1是Int類型,參數2是Lambda,傳回值是Unit,沒有傳回值。
  • sendMsg5(),參數2的Lambda的類型是(Int) -> String,參數是Int,傳回值是String類型。

code是參數1的變數名,function1是參數2的變數名。

1
2
3
4
val sendMsg5: (Int, (Int) -> String) -> Unit = 
    { code, function1 ->
        println("Lambda在參數最後 = ${function1(code)}")
    }

把函式主體{}移出圓括號,花括號{}是Lambda,是參數2。

1
2
3
4
5
6
7
sendMsg5(200) {
    if (it == 200) {
        "網頁正常"
    } else {
        "其它錯誤"
    }
}
Lambda在參數最後 = 網頁正常

參數只有一個Lambda,去掉圓括號

sendMsg6(),參數1的Lambda類型為(Int) -> String,參數是Int,傳回值是String類型。

1
2
3
val sendMsg6: ((Int) -> String) -> Unit = {
    println("參數只有一個Lambda = ${it(200)}")
}

未省略圓括號前。

1
2
3
4
5
6
7
sendMsg6 ({
    if (it == 200) {
        "網頁正常"
    } else {
        "其它錯誤"
    }
})

省略圓括號,花括號{}是Lambda,是參數。

1
2
3
4
5
6
7
sendMsg6 {
    if (it == 200) {
        "網頁正常"
    } else {
        "其它錯誤"
    }
}

完整程式碼

1
2
3
4
5
6
7
8
9
10
11
val sendMsg6: ((Int) -> String) -> Unit = {
    println("參數只有一個Lambda = ${it(200)}")
}

sendMsg6 {
    if (it == 200) {
        "網頁正常"
    } else {
        "其它錯誤"
    }
}
參數只有一個Lambda = 網頁正常

透過Lambda把標準函式重寫(覆寫)

1
2
3
4
var str = "Hello World"
val o_count = str.count ({ letter ->
    letter == 'o'
})
  • letter是參數。
  • 只要計算字母為o的字元數量。
1
letter == 'o'

簡化2,圓括號去掉

1
2
3
4
var str = "Hello World"
val o_count = str.count { letter ->
    letter == 'o'
}

簡化3,letter與->箭頭去掉,因為只有一個參數,可以去掉,默認用it代替一個參數。

1
2
3
4
var str = "Hello World"
val o_count = str.count {
    it == 'o'
}

印出字元個數

1
2
3
var str = "Hello World"
println("字元個數 = ${str.count()}")
println("o字元個數 = ${o_count}")
字元個數 = 11
o字元個數 = 2

傳回值是Lambda

以下是有名字的函式,所以會用到return,注意,它的傳回值是Lambda類型(Int) -> String,函式參數是url。

1
2
3
4
5
6
7
8
9
10
fun sendMsg7(url: String) : (Int) -> String {
    val contact = "xxx@xxx.mail.com"
    return { code: Int ->
        when (code) {
            404 -> "${url} 找不到網頁, please contact ${contact}"
            500 -> "${url} Server error!, please contact ${contact}"
            else -> "${url} 其它錯誤, please contact ${contact}"
        }
    }
}

傳回值解說:

{}大括號就是Lambda主體body,參數是code,會傳回String,Lambda可以用外部函式sendMsg7()的參數url與變數contact。

1
2
3
4
5
6
7
    return { code: Int ->
        when (code) {
            404 -> "${url} 找不到網頁, please contact ${contact}"
            500 -> "${url} Server error!, please contact ${contact}"
            else -> "${url} 其它錯誤, please contact ${contact}"
        }
    }

msgfun變數接收到的是傳回值函式,就是上面大括號{}包住的程式碼,傳回值函式的類型是(Int) -> String。
msgfun(404)是把參數代入,傳回值是String

1
2
3
4
fun main() {
    val msgfun = sendMsg7("http://www.xxx.com")
    println(msgfun(404))
}
http://www.xxx.com 找不到網頁, please contact xxx@xxx.mail.com

img

參數沒使用,用_代表

1
2
3
4
val useLambda2: (Int, Int) -> Unit = { x, _ ->
    println("First:$x")
}
useLambda2(6, 9)
First:6

results matching ""

    No results matching ""