(1)匿名函数和普通函数没什么区别,只是没有名字而已
(2)如果是单表达式的函数体,可以用赋值运算符代替大括号,而且可以省略返回值类型,编译器可以推断出是否有返回值,如果有类型是什么类型。这个其实和匿名函数没关系,普通函数也通用
(3)如果编译器可以推断出匿名函数的形参类型,可以将形参类型省略
(4)匿名函数是可以作为函数参数的,在实际使用中函数参数的类型是lambda函数类型,可是传个匿名函数是没问题的,这也能说明,lambda的底层实现是匿名函数,比如filter方法
class FirstKotlinClass {
//普通函数
// fun add(x : Int, y : Int) : Int {
// return x + y
// }
//匿名函数,赋值给add变量
// var add = fun (x : Int, y : Int) : Int {
// return x + y
// }
//匿名函数单表达式函数体,简写,可以省略返回值类型
var add = fun (x : Int, y : Int) = x + y
//
var count = 5
// fun generateAnswerString(countThreshold: Int): String {
// return if (count > countThreshold) {
// "I have the answer."
// } else {
// "The answer eludes me."
// }
// }
//普通函数单表达式函数体,简写,可以省略返回值类型
fun generateAnswerString(countThreshold : Int) = if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
var filteredList = listOf(3, 5, 20, 100, -25).filter(
//编译器能推断出匿名函数形参的类型,可以省略
// fun(el):Boolean {
// return Math.abs(el) > 20
// }
//单表达式的匿名函数
fun (el) = Math.abs(el) > 20
)
}
lambda表达式的底层实现式匿名函数,lambda表达式的出现式进一步对匿名函数简化,我是这样理解的
在kotlin语言,对类型这个概念进一步抽象了,类、基本类型都是类型,匿名函数也能抽象出类型(叫函数类型),而且类型在kotlin中是放在变量名+冒号(:)后面的,函数类型就需要和lambda表达式一块使用了。看一个例子
var add1 : (Int, Int) -> Int = {a, b -> a + b} //a和b的类型省略了,是因为等号前面说明了
//进一步简化
var add2 = {a : Int, b : Int -> a + b}
(Int, Int) -> Int 这个叫函数类型,add1叫函数类型的变量,{a, b -> a + b}是变量的值。这里大家不要混淆了,本质上这个还是函数,只是使用lambda语法简化了,要想使用函数还是得调用才行呀!
既然函数可以抽象成一个类型,那么函数类型就可以作为方法的参数传,这样的话,就给编程带来极大的灵活性
//(Int, Int) -> Int 函数类型
fun test(a : Int, b : (Int, Int) -> Int) : Int {
return a + b(2, 3)
}
//{num1, num2 -> num1 + num2} 函数类型的值
var res1 = ins.test(10, {num1, num2 -> num1 + num2})
println(res1)
这些写代码是不是很爽呀,比java没lambda表达式前,传一个类对象,调用类对象方法,简洁多了。
上面的调用,会有个下划线提示 Lambda argument should be moved out of parentheses,这个意思就是说,需要把lambda表达式移到括号外面 。这是因为,如果lambda表达式是函数参数的最后一个参数,它可以写到括号外面
var res1 = ins.test(10) { num1, num2 -> num1 + num2}
我理解Lambda表达式,是由函数类型、变量和值 三者组成的,有时也把函数类型变量的值叫做lambda表达式,不知道自己理解的对不对。
只有单表达式或者语句的函数才能转换成lambda的形式,也不知道这句话对不对。
上面这句话是不对的,发现了有多条语句的lambda表达式
val mTvBtn = findViewById<TextView>(R.id.text)
mTvBtn.run{
text = "kotlin"
textSize = 13f
}
“表达式“是有结果的,也就是说可以作为等号的右值。“语句”就是一行执行代码,没有返回值
Lambda表达式的出现,把函数提升到了和类一样的地位,函数不需要再依附于类才能使用,我觉得这是Lambda表达式最重要的意义。同时Lambda还带来一个好处就是使代码简洁了,看看上面的lambda表达式的使用就知道了。
为了简洁,lambda一个参数的,还可以更简洁,用it代替(注意it不是kotlin的关键字,只是约定),->和左边的参数变量都可以省略了
fun test(num1 : Int, bool : (Int) -> Boolean) : Int{
return if (bool(num1)){ num1 } else 0
}
println(test(10,{it > 5}))
println(test(4,{it > 5}))
虽然lambda表达式的底层式匿名函数,可是还是有不一样的地方。
匿名函数的本质依旧是函数,因此匿名函数的return则用于返回该函数本身。
而Lambda表达式的return用于返回它所在的函数,而不是返回Lambda表达式。
还有一个概念是函数字面值(量),其实就是指一个函数体,或者说是一段代码,本身没有名字,我们可以把它绑定到一个变量上,通过这个变量操作它,lambda表达式和匿名函数都叫函数字面值。
这里说一句题外话,kotlin不管怎么写,本质上脱离不了jvm字节码的,这个是根本,只不过kotlin是让大家写代码更自由更简洁一些。
我们在java中定义一些工具类方法的时候,我们一般把这类方法定义成类方法。在kotlin中就不用这样干了,直接在文件中定义方法就行,不用类包裹了,不过编译器最后还是把它编译成了类方法。
(在Object C中的Block,可以类比于Kotlin的匿名函数,因为整个函数的结构还在,只是没有方法名而已。它没有抽象成lambda表达式)
kotlin中的匿名函数和js中一样,可以灵活使用,不过,js里面的函数是没有返回类型的,在kotlin匿名函数有返回类型的一定要说明,不写默认是Unit,Unit就是java中void的意思。
//匿名函数不需要赋给变量,也能直接调用,和js一样方便
var res = (fun (y : Int, x : Int) : Int {
return y + x
})(1, 2)
println(res)
//lambda表达式直接调用
({x : Int, y : Int -> x + y})(1, 2)
//闭包
var funInner = (fun ():() -> Unit {
var i = 10
return fun () {
println(++i)
}
})()
funInner()
funInner()
Kotlin——高级篇(二):高阶函数详解与标准的高阶函数使用