二,Kotlin之Lambda表达式详解

概览

  • Lambda介绍
  • Lambda使用
    • Lambda表达式的特点
    • Lambda语法
  • Lambda实践
    • it
    • 下划线(_)
    • 匿名函数
    • 带接收者的函数字面值
    • 闭包
  • 总结

1,Lambda介绍

Kotlin一经开源成熟就已经支持这种语法
Lambda表达式的本质其实是匿名函数,因为在其底层实现中还是通过匿名函数来实现的。Lambda作为函数式编程的基础,其语法也是相当简单的
举例:

tvAddTopic.setOnClickListener {
    TopicAddActivity.jumpTo(mContext)
}

2,Lambda使用

2.1,Lambda表达式的特点

  • Lambda表达式总是被大括号括着
  • 其参数(如果存在)在 -> 之前声明(参数类型可以省略)
  • 函数体(如果存在)在 -> 后面。

2.2、Lambda语法
Lambda语法如下

1. 无参数的情况 :
val/var 变量名 = { 操作的代码 }

2. 有参数的情况
val/var 变量名 : (参数的类型,参数类型,...) -> 返回值类型 = {参数1,参数2,... -> 操作参数的代码 }

可等价于
// 此种写法:即表达式的返回值类型会根据操作的代码自推导出来。
val/var 变量名 = { 参数1 : 类型,参数2 : 类型, ... -> 操作参数的代码 }

3. lambda表达式作为函数中的参数的时候,这里举一个例子:
fun test(a : Int, 参数名 : (参数1 : 类型,参数2 : 类型, ... ) -> 表达式返回类型){
    ...
}

实例

  • 无参数的情况
// 源代码
fun test(){ println("无参数") }

// lambda代码
val test = { println("无参数") }

// 调用
test()  => 结果为:无参数
  • 有参数的情况
// 源代码
fun test(a : Int , b : Int) : Int{
    return a + b
}

// lambda
val test : (Int , Int) -> Int = {a , b -> a + b}
// 或者
val test = {a : Int , b : Int -> a + b}

// 调用
fun main() {
    println(test(3, 5))
}
test(3,5) => 结果为:8
  • lambda表达式作为函数中的参数的时候
    // 源代码
fun test(a : Int , b : Int) : Int{
    return a + b
}

fun sum(num1 : Int , num2 : Int) : Int{
    return num1 + num2
}

//源代码调用
fun main() {
    // 结果为:18
    println(test(10,sum(3,5)))
}

// lambda

fun test(a : Int , b : (num1 : Int , num2 : Int) -> Int) : Int{
    return a + b.invoke(3,5)
}

//调用写法1
fun main() {
    // 结果为:18
    val value = test(10, { num1: Int, num2: Int -> num1 + num2 })
    println(value)
}

//调用写法2
fun main() {
    // 结果为:18
    val value = test(10) { num1: Int, num2: Int -> num1 + num2 }
    println(value)
}

语法的总结
1,lambda表达式总是被大括号括着。
2,定义完整的Lambda表达式,有其完整的参数类型标注,与表达式返回值。当我们把一些类型标注省略的情况下,就如上面实例中的语法2的另外一种类型。当它推断出的返回值类型不为'Unit'时,它的返回值即为->符号后面代码的最后一个(或只有一个)表达式的类型。
3,高阶函数,当Lambda表达式作为其一个参数时,只为其表达式提供了参数类型与返回类型,所以,我们在调用此高阶函数的时候我们要为该Lambda表达式写出它的具体实现。
4,invoke()函数:表示为通过函数变量调用自身,因为上面例子中的变量b是一个匿名函数。

Lambda实践

3.1、it

  • it并不是Kotlin中的一个关键字(保留字)。
  • it是在当一个高阶函数中Lambda表达式的参数只有一个的时候可以使用it来使用此参数。it可表示为单个参数的隐式名称,是Kotlin语言约定的。
    3.2、下划线(
    在使用Lambda表达式的时候,可以用下划线(
    )表示未使用的参数,表示不处理这个参数。
eet_search_friend.setOnEditorActionListener { _, actionId, _ ->
    if (actionId == EditorInfo.IME_ACTION_SEARCH) {
        KeyboardUtils.hideSoftInput(this)
        val retrieveInfo = eet_search_friend!!.text.toString().toLowerCase(Locale.ROOT)
        mViewModel.userSearch(retrieveInfo)
    }
    false
}

3.3 匿名函数

  • 匿名函数的特点是可以明确指定其返回值类型。
  • 它和常规函数的定义几乎相似。他们的区别在于,匿名函数没有函数名。
    //常规函数:
fun test(x: Int, y: Int): Int {
    return x + y
}

// 匿名函数

fun(x: Int, y: Int): Int {
    return x + y
}

常规函数简化 :

 fun test(x : Int , y : Int) : Int = x + y

匿名函数简化 :

fun(x : Int , y : Int) : Int = x + y

匿名函数与Lambda表达式的几点区别

  • 匿名函数的参数传值,总是在小括号内部传递。而Lambda表达式传值,可以有省略小括号的简写写法。
  • 在一个不带标签的return语句中,匿名函数时返回值是返回自身函数的值,而Lambda表达式的返回值是将包含它的函数中返回

3.4、带接收者的函数字面值

在kotlin中,提供了指定的接受者对象调用Lambda表达式的功能。在函数字面值的函数体中,可以调用该接收者对象上的方法而无需任何额外的限定符。它类似于扩展函数,它允你在函数体内访问接收者对象的成员。

  • 匿名函数作为接收者类型
    匿名函数语法允许你直接指定函数字面值的接收者类型,如果你需要使用带接收者的函数类型声明一个变量,并在之后使用它,这将非常有用。
fun main() {
    val iop = fun Int.(other: Int): Int = this + other
    println(2.iop(3))
    //结果:5
}
  • Lambda表达式作为接收者类型
    要用Lambda表达式作为接收者类型的前提是接收着类型可以从上下文中推断出来
class HTML {
    fun body() {
        println("body()")
    }
}

/**
 * 高阶函数接受一个lambda表达式作为参数.
 * @init:参数名称.
 * @return 返回HTML类型的对象.
 */
fun html(init: HTML.() -> Unit): HTML {
    // 创建接收者对象
    val html = HTML()
    // 将该接收者对象传给该 lambda
    html.init()
    return html
}

fun main() {
    // 带接收者的 lambda 由此开始
    html {
        // 调用该接收者对象的一个方法
        this.body()
    }
}

3.5 闭包

  • 所谓闭包,即是函数中包含函数,这里的函数我们可以包含(Lambda表达式,匿名函数,局部函数,对象表达式)。我们熟知,函数式编程是现在和未来良好的一种编程趋势。故而Kotlin也有这一个特性
  • 我们熟知,Java是不支持闭包的,Java是一种面向对象的编程语言,在Java中,对象是他的一等公民。函数和变量是二等公民
  • Kotlin中支持闭包,函数和变量是它的一等公民,而对象则是它的二等公民了
fun test1(){
    fun test2(){   // 正确,因为Kotlin中可以函数嵌套函数
    }
}

3.5.1、携带状态
让函数返回一个函数,并携带状态值

fun test(b: Int): () -> Int {
    var a = 3
    return fun(): Int {
        a++
        return a + b
    }
}

fun main() {
    val t = test(3)
    println(t())
    println(t())
    println(t())
}

3.5.2、引用外部变量,并改变外部变量的值

fun main() {
    var sum: Int = 0
    val arr = arrayOf(1, 3, 5, 7, 9)
    arr.filter {
        it < 7
    }.forEach {
        println("it:$it")
        sum += it
    }
    println("sum:$sum")
}

Android中的使用

class TestAdapter(val context: Context, val data: MutableList<String>)
    : RecyclerView.Adapter<TestAdapter.TestViewHolder>() {

    private var mListener: ((Int, String) -> Unit)? = null

    override fun onBindViewHolder(holder: TestViewHolder?, position: Int) {
        holder?.itemView?.setOnClickListener {
            mListener?.invoke(position, data[position])
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): TestViewHolder {
        return TestViewHolder(View.inflate(context, layoutId, parent))
    }

    override fun getItemCount(): Int {
        return data.size
    }

    fun setOnItemClickListener(mListener: (position: Int, item: String) -> Unit) {
        this.mListener = mListener
    }

    inner class TestViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
}

// 调用
TestAdapter(this,dataList).setOnItemClickListener {
    position, item ->
    Toast.makeText(this, "$position \t $item", Toast.LENGTH_SHORT).show()
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容