当前位置: 首页 > news >正文

解析Kotlin中的Lambda【笔记摘要】

先看实例:

fun b(param: Int): String {return param.toString()
}fun a(funParam: (Int) -> String): String {return funParam(1)
}
a(::b)
val d = ::b

1.双冒号 ::method 到底是什么?答:一个指向和该函数具有相同功能的对象的引用

因为加了两个冒号,这个函数才变成了一个对象。函数不是对象,它也没有类型,函数就是函数,它和对象是两个维度的东西。
在 Kotlin 里,一个函数名的左边加上双冒号,它就不表示这个函数本身了,而表示一个对象,或者说一个指向对象的引用,但,这个对象可不是函数本身,而是一个和这个函数具有相同功能的对象。

b(1) // 调用函数
d(1) // 用对象 a 后面加上括号来实现 b() 的等价操作
(::b)(1) // 用对象 :b 后面加上括号来实现 b() 的等价操作

对象是不能加个括号来调用的,对吧?但是函数类型的对象可以。为什么?因为这其实是个假的调用,它是 Kotlin 的语法糖,实际上你对一个函数类型的对象加括号、加参数,它真正调用的是这个对象的 invoke() 函数

d(1) // 实际上会调用 d.invoke(1)
(::b)(1) // 实际上会调用 (::b).invoke(1)

所以你可以对一个函数类型的对象调用 invoke(),但不能对一个函数这么做:

b.invoke(1) // 报错

2.匿名函数

要传一个函数类型的参数,或者把一个函数类型的对象赋值给变量,除了用双冒号来拿现成的函数使用,你还可以直接把这个函数挪过来写:

a(fun b(param: Int): String {return param.toString()
});
val d = fun b(param: Int): String {return param.toString()
}

另外,这种写法的话,函数的名字其实就没用了,所以你可以把它省掉:

a(fun(param: Int): String {return param.toString()
});
val d = fun(param: Int): String {return param.toString()
}

这种写法叫做匿名函数。(实际上函数的名字是必须省略的,这是Kotlin规定的)

3.Lambda 表达式

 A.如果 Lambda 是函数的最后一个参数,你可以把 Lambda 写在括号的外面:

view.setOnClickListener() { v: View ->switchToNextPage()
}

 B.而如果 Lambda 是函数唯一的参数,你还可以直接把括号去了:

view.setOnClickListener { v: View ->switchToNextPage()
}

 C.如果参数的类型可以推断,那么可以将类型去掉

view.setOnClickListener { v ->switchToNextPage()
}

 D.如果这个 Lambda 是单参数的,它的这个参数也可以省略掉不写:(因为 Kotlin 的 Lambda 对于省略的唯一参数有默认的名字:it)

view.setOnClickListener {switchToNextPage()
}

为什么C可以省略参数类型?靠上下文的推断。我调用的函数在声明的地方有明确的参数信息吧?所以 Lambda 才不用写的。

fun setOnClickListener(onClick: (View) -> Unit) {this.onClick = onClick
}

当把Lambda赋值给变量时,就不能省略掉 Lambda 的参数类型了,因为它无法从上下文中推断出这个参数的类型

//报错:Cannot infer a type for this parameter. Please specify it explicitly.
val h = { param ->  param.toString()
}

如果你出于场景的需求或者个人偏好,就是想在这里省掉参数类型,那你需要给左边的变量指明类型:

val h: (Int) -> String = { param ->param.toString()
}

注意: Lambda 的返回值不是用 return 来返回,而是直接取最后一行代码的值。如果你写了return,它会用这个return返回它外层的函数

4.Kotlin 里匿名函数和 Lambda 表达式的本质

双冒号加函数名、Kotlin 的匿名函数和 Lambda 表达式的本质,它们都是函数类型的对象,它们和函数不是一回事。函数并不能传递,传递的是对象


参考文章:
Kotlin 的 Lambda 表达式,大多数人学得连皮毛都不算

http://www.lryc.cn/news/390417.html

相关文章:

  • rust单元测试顺序执行
  • 力扣-744. 寻找比目标字母大的最小字母
  • 一篇文章搞懂弹性云服务器和轻量云服务器的区别
  • 横穿自动驾驶
  • 为什么网上商店需要翻译成其他语言
  • 【高考志愿】交通运输工程
  • 【深度学习】【Lora训练3】StabelDiffusion,Lora训练过程,秋叶包,Linux,SDXL Lora训练
  • ubuntu系统下如何安装python
  • 邦芒攻略:职场中学会这五种管好情绪的方法
  • Linux各种命令——tac命令,more 命令, less命令,head命令,tail命令,file 命令, stat 命令
  • 【Rust入门教程】hello world程序
  • 激活函数、向前传播、损失函数、梯度下降
  • three.js - MeshStandardMaterial(标准网格材质)- 金属贴图、粗糙贴图
  • 算法-位图与底层运算逻辑
  • 黑马点评-Redis的缓存击穿,缓存雪崩,缓存穿透,互斥锁,逻辑过期
  • 8624 多项式系数累加和
  • 使用 C# 和 OpenXML 读取大型 Excel 文件
  • 【基于R语言群体遗传学】-5-扩展到两个以上等位基因及多基因位点
  • 重采样(上采样或下采样)是什么?
  • AI与Python共舞:如何利用深度学习优化推荐系统?(2)
  • ChatGPT:Java中的对象引用实现方式
  • 云渗透实战手册:云API攻防之云服务端点侦查
  • PHP 爬虫之使用 Curl库抓取淘宝商品列表数据网页的方法
  • Python基础小知识问答系列-可迭代型变量赋值
  • 主流 Canvas 库对比:Fabric.js、Konva.js 和 Pixi.js
  • backbone是什么?
  • 四十篇:内存巨擘对决:Redis与Memcached的深度剖析与多维对比
  • HTML5的多线程技术:Web Worker API
  • Java | Leetcode Java题解之第206题反转链表
  • 660错题