Lambda定义
lambda 表达式总是括在花括号中, 完整语法形式的参数声明放在花括号内,并有可选的类型标注, 函数体跟在一个 -> 符号之后。如果推断出的该 lambda 的返回类型不是 Unit,那么该 lambda 主体中的最后一个(或可能是单个) 表达式会视为返回值。
意思就是说lambda表达式一定要放在花括号 { } 中 , -> 前面是参数,后面是方法体就是你要拿这个参数进行的操作。如果你的lambda是有返回值的,-> 后面最后一个表达式会被视为返回值,代码如下:
Lambda就像一个简化的函数,如下: lam1 对应的就是method1 ,两个参数,返回一个Int值。x+y 作为 -> 后面最后一个表达式返回 var lam1: (Int, Int) -> Int = { x: Int, y: Int -> x + y } fun method1(x: Int, y: Int): Int { return x + y } lam2 对应的就是method2,如果表达式不需要返回值,x+y 只是做了一次运算,并没有返回 var lam2: (Int, Int) -> Unit = { x: Int, y: Int -> x + y } fun method2(x: Int, y: Int): Unit { x + y }lambda 主体中的最后一个(或可能是单个) 表达式会视为返回值。为啥非要这么说呢
var lam1: (Int, Int) -> Int = { x: Int, y: Int -> 1操作 ➺ val sum = x + y 2操作 ➺ println(sum) 3操作 ➺ sum } 注意:Kotlin不像java用 ; 作为结束标志,所以要每行写一个操作,如果放在一行编译就会报错!-> 后面有 1 ,2 , 3 三个操作,最后3处的表达式作为返回值返回。
那如果
var lam = { x: Int, y: Int -> x + y }前面声明不指定有没有返回值,x+y 会不会作为返回值返回呢?
var lam = { x: Int, y: Int -> x + y } fun main() { println(lam(2, 3)) } 打印结果: D:\AndroidStudio\android-studio\jre\bin\java.exe - 5 Process finished with exit code 0结果是会作为返回值,如果不指定,会根据-> 后面返回表达式自动推算返回值,代码如下
修改1: var lam = { x: Int, y: Int -> x > y } 打印结果 D:\AndroidStudio\android-studio\jre\bin\java.exe - false Process finished with exit code 0 修改2: var lam = { x: Int, y: Int -> "Result $x $y" } 打印结果 D:\AndroidStudio\android-studio\jre\bin\java.exe - Result 2 3 Process finished with exit code 0=======================================================================
Lambda规则
我们通常看到的lambda印象最深就是,精简,最后简化到只剩一个 { } 都可以,虽然看不懂,就好厉害的感觉
那如何将一个函数方法改成一个lambda表达式呢?这就和下面lambda非常重要的几个规则有关
1 在 Kotlin 中有一个约定:如果函数的最后一个参数是函数,那么作为相应参数传入的 lambda 表达式可以放在圆括号之外 ,这种语法也称为拖尾 lambda 表达式。
fun main() { method3( "hello" , { x -> x + 6 } ) : 正常调用, ↓ ↓ ↓ 根据拖尾原则,如果lambda表达式在参数的最后一个位置 ↓ 可以拿到圆括号外面 ↓ method3("hello") { x -> x + 6 } } fun method3(msg: String, lamParams: (Int) -> Int) { 两个参数:一个String,一个lambda表达式 }2 如果一个 lambda 表达式只有一个参数,可以省略这个参数并忽略 ->。而这个被省略的参数可以用it代替
还是接着上面的代码继续修改 fun main() { method3( "hello" , { x -> x + 6 } ) : 正常调用, ↓ ↓ ↓ 根据拖尾原则,如果lambda表达式在参数的最后一个位置 ↓ 可以拿到圆括号外面 ↓ method3("hello") { x -> x + 6 } ↓ ↓ 根据单参数省略原则: ↓ 参数 x 省略, ↓ -> 省略 ↓ x可用 it 代替 ↓ method3("hello") { it + 6 } } fun method3(msg: String, lamParams: (Int) -> Int) { 两个参数:一个String,一个lambda表达式 }这样经过简化的之后,看起来很厉害的样子就出来了: method3("hello") { it + 6 }
3 如果 lambda 表达式的参数未使用,那么可以用下划线取代其名称:
fun main() { method("") { _, str -> str } 分析: 1 lambda表达式位置在method方法中参数最后一个可以拿到括号外面 2 lambda表达式有两个参数,所以不能省略 3 Int参数 在箭头后面的操作中没有用到,可以用 _ 代替 } fun method(msg: String, lam: (Int, String) -> String) { }这样就可以将函数精简为Lambda表达式了。
fun method5(str: String, x: Int, bool: Boolean) { str + x + bool } ↓ ↓ 精简 ↓ { str: String, x: Int, bool: Boolean -> str + x + bool } 然后将这个Lambda表达式赋值给lam5 var lam5 = { str: String, x: Int, bool: Boolean -> str + x + bool } main(){ method6是用method5 的函数形式作为参数 我们分别传递 method5 和 lambda5 到method6中,完全没有问题,说明精简是对的 method6(lam5) method6(::method5) } fun method6(m: (String, Int, Boolean) -> Unit) { 参数是(String, Int, Boolean) -> Unit这么一个表达式 }=======================================================================
Lambda显示声明返回值:
Lambda 禁止直接使用return关键字,我们可以使用限定的返回语法: return@函数名 从Lambda 显式返回一个值。 否则,将隐 式返回最后一个表达式的值。
lambda默认将 -> 最后一个表达式作为返回值返回 method("") { _, str -> str } 也可以显示的 return 返回值 method("") { _, str -> return@method str }=======================================================================
匿名函数:
当想要显示指定lambda 表达式的返回类型,我们可以使用匿名函数的形式
fun(x: Int, y: Int): Int = x + yfun关键词后面并没有和普通函数一样有一个函数名,所以叫匿名函数。
而且如果返回值可以推算得出返回值也是可以省略的,即:fun(x: Int, y: Int) = x + y 也是可以的
注意:
1 匿名函数参数必须放在括号里面,不能像lambda表达式一样简化处理。
2 Lambda表达式与匿名函数之间的另一个区别是非局部返回的行为:这是什么意思呢?
官方文档是这样说的:一个不带标签的 return 语句总是在用 fun 关键字声明的函数中返回。这意味着 lambda 表达式中的 return 将从包含它的函数返回,而匿名函数中的 return 将从匿名函数自身返回。
非局部返回,这就牵扯到了 inline 内联函数
说的是 内联函数 如果被处理成了Lambda表达式的时候,return 返回的是外部那个调用内联函数的函数,而不是内联函数本身。(注意:前面说过Lambda是禁止直接使用return关键字,要使用必须是:return@函数名 这种形式。但是内联函数使用Lambda就可以直接使用 return关键字)。看代码:
fun song(f: (String) -> Unit) { } inline fun speak(f: (String) -> Unit) { } fun behavior() { song { println("song $it") return //此处报错: 'return' is not allowed here } speak { println("speak $it") return //此处没问题 } } fun main() { behavior() } song() 方法没有内联不允许在 Lambda 中直接 return 所以报错。而我们函数调用顺序为
main() -> behavior() -> speak这样我们在 speak的参数lambda表达式里面 return,结束的是哪个函数呢?
结束的是 behavior 函数。因为 speak 是内联函数。编译的时候就变成下面样子,。
调用处大体示意: 编译时大体示意: fun main() { fun main() { behavior { behavior { speak { println("speak $it") println("speak $it") return return } } } } }所以 return 的就是 behavior 函数了。
(注:内联函数能不能return还有其他限制,这里就不说了。)
上面说 lambda 表达式中的 return 将从包含它的函数返回,而匿名函数中的 return 将从匿名函数自身返回。说的是Lambda在内联函数的情况下。