kotlin之匿名函数、lambda表达式

(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
    )
}

Kotlin匿名函数

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——高级篇(一):Lambda表达式详解

Kotlin——高级篇(二):高阶函数详解与标准的高阶函数使用

【Kotlin】—— 函数字面值(量)补充

kotlin 之 函数的定义与调用

发布了189 篇原创文章 · 获赞 25 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/lizhongyisailang/article/details/105240947