这一篇,其实已经不算基本了,我打算介绍kotlin的高阶用法和一些额外补充
1、## Lambda 表达式和高阶函数
kotlin
// Lambda 表达式
val sum = { x: Int, y: Int -> x + y }
println(sum(1, 2)) // 输出 3
// 高阶函数
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
return operation(x, y)
}
val result = calculate(10, 5) { a, b -> a * b } // 输出 50
先看下上面的代码,能否看懂? 看不懂,我再贴一段代码
kotlin
protected fun requestWriteCacheFilePermission(onAction: () -> Unit) {
PermissionUtils.requestWriteFilePermission(this, object : PermissionListener {
override fun onGranted() {
onAction()
}
override fun onDenied() {
showShortToast("为保证功能正常使用,请开启相关权限~")
}
})
}

简单点,说法的方式简单点?
在 Kotlin 中,高阶函数(Higher-Order Function) 是指可以接收函数作为参数,或者返回一个函数作为结果的函数。简单来说,就是能 "操作函数" 的函数 ------ 把函数当作另一种数据类型来传递和使用。
说人话就是,一个fun的函数,它的参数现在可以让另一个函数作为它的参数传入
这个就很牛逼了,为啥,来我们回忆下,让你用java来实现,你怎么做 是不是要传入一个回调,然后在onGranted 和 onDenied 里让回调来通知用户在requestWriteCacheFilePermission 这个函数中操作的结果。
回答我,是不是,那么这就是kotlin 高阶函数的魅力,直接避免了回调地狱,用不用,你用不?

我保存图片,我这么写,舒不舒服,我不光传1个高阶函数,我传多个
kotlin
fun saveMultipleImages(
context: Context, bitmaps: List<Bitmap>,
onSuccess: (List<String>) -> Unit,
onError: (Throwable) -> Unit
) {
showLoadingView()
SaveImgUtil.saveMultipleImagesToGallery(context, bitmaps)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ files ->
// 所有图片保存成功
onSuccess(files)
hideLoadingView()
},
{ error ->
// 保存失败
onError(error)
hideLoadingView()
error.printStackTrace()
}
).let { addSubscribe(it) }
}
如果我的高阶函数没有返回值,我就如下面这样写:其中onAction: () -> Unit 这个意思就是,没有返回值,你可以理解为,返回值为void的, 而onCheck: (() -> Unit)? = null 这么写,意思是,返回值为void,并且我这个onCheck高阶函数默认是null,意味着,我外部调用的地方,这个参数可传可不传
kotlin
protected fun showGenerateWorksV2Dialog(
title: String? = null,
subTitle: String? = null,
onAction: () -> Unit,
onCheck: (() -> Unit)? = null
) {
if (mGenerateWorksV2Dialog == null) {
onCheck?.let { it() }
mGenerateWorksV2Dialog =
DialogHelper.showLoadingTransformV2Dialog(
requireContext()
) { viewHolder ->
loadGif(
requireContext(),
com.ltmb.common.R.raw.loading,
viewHolder.getView<ImageView>(com.ltmb.common.R.id.iv_loading_gif)
)
viewHolder.getView<View>(com.ltmb.common.R.id.tv_confirm).setOnClickListener {
mGenerateWorksV2Dialog?.dismiss()
onAction()
}
}
}
}
正常我都传,就是下面这样:
kotlin
showGenerateWorksV2Dialog("视频审核中",
onAction = {
GoRouter.getInstance().build(RouteTable.MAIN_ATY)
.go(this, object : GoCallbackImpl() {
override fun onArrival(card: Card?) {
finish()
}
}) //这个是跳转某个页面,
},
onCheck = {
checkVideoExamineLimitedStatus(mReviewSource)
})
如果我onCheck不传,就是下面:
kotlin
showGenerateWorksV2Dialog("视频审核中",
onAction = {
GoRouter.getInstance().build(RouteTable.MAIN_ATY)
.go(this, object : GoCallbackImpl() {
override fun onArrival(card: Card?) {
finish()
}
}) //这个是跳转某个页面,
})
常见函数类型示例:
函数类型 | 含义 |
---|---|
() -> Unit |
无参数,无返回值(Unit 类似 void) |
(Int) -> String |
接收 Int 参数,返回 String |
(String, Int) -> Boolean |
接收 String 和 Int,返回 Boolean |
(Int) -> (Int) -> Int |
接收 Int,返回一个 "接收 Int 并返回 Int" 的函数 |
明白了啵。

----------------------------下面说说拓展函数---------------------------------
二、拓展函数可牛逼了
先看下代码:
kotlin
fun View.gone() {
this.visibility = View.GONE
}
fun View.visible() {
this.visibility = View.VISIBLE
}
fun View.invisible() {
this.visibility = View.INVISIBLE
}
我外面调用就是textView.gone() 或 textView.visible()
kotlin
fun value(editText: EditText?) :String {
return if (editText == null || editText.text.isNullOrEmpty()) {
""
} else {
editText.text.toString().trim()
}
}
在 Kotlin 中,扩展函数(Extension Function) 是一种特殊的函数,允许你在不修改原有类代码的情况下,为已存在的类(包括系统类、第三方库类或自定义类)添加新的函数。简单来说,就是 "给别人的类'打补丁'",但又不会破坏原类的封装性。
kotlin
fun Int.toPx(): Int = (this * Resources.getSystem().displayMetrics.density).toInt()
fun Double.toPx(): Int = (this * Resources.getSystem().displayMetrics.density).toInt()
fun Float.toPx(): Int = (this * Resources.getSystem().displayMetrics.density).toInt()
外部你就可以直接调
scss
12.toPx()
舒不舒服? 前几篇,kotlin官方对集合的过滤,转换操作其实你看源码就能发现,它就是高阶函数 + 拓展函数的综合运用。
能帮我们省代码,优雅是我们指尖艺术家的极致追求。
------------------------------------闭包的概念 --------------------------------
三、闭包
闭包,说人话,就是一个大括号包裹的区域内,是一个封闭的区域,局部作用域。 eg: kotlin
kotlin
fun main() {
var count = 0 // 外部变量
// 定义一个 lambda 闭包,捕获并修改 count
val increment = {
count++ // 修改外部变量
println("当前计数: $count")
}
// 调用闭包,观察外部变量的变化
increment() // 输出:当前计数: 1
increment() // 输出:当前计数: 2
increment() // 输出:当前计数: 3
println("最终计数: $count") // 输出:最终计数: 3(外部变量被修改)
}
这里有个特殊的一点,可能会颠覆javaer 的认知
Kotlin 的局部函数(定义在其他函数内部的函数)也是闭包,能访问外部函数的参数和变量: 翻译下就是,一个函数fun 内部可以再写一个fun。
kotlin
fun calculateTotal(prices: List<Double>, discount: Double): Double {
var total = 0.0 // 外部变量(calculateTotal 的局部变量)
// 局部函数(闭包):捕获 total 和 discount
fun addPrice(price: Double) {
val discounted = price * (1 - discount) // 使用外部参数 discount
total += discounted // 修改外部变量 total
}
// 调用闭包,累加计算
for (price in prices) {
addPrice(price)
}
return total
}
// 调用
val prices = listOf(100.0, 200.0, 300.0)
val total = calculateTotal(prices, 0.1) // 10% 折扣
println("总价: $total") // 输出:总价: 540.0((100+200+300)*0.9)
上面代码中addPrice 定义在了calculateTotal函数内部,当然我一般不这么写,这块仁者见仁智者见智了。
闭包的 "记忆" 能力
kotlin
fun createCounter(): () -> Int {
var count = 0 // 外部变量(createCounter 的局部变量)
// 返回一个闭包,捕获 count
return {
count++ // 每次调用闭包,count 自增
count
}
}
fun main() {
val counter = createCounter() // 获取闭包
// 多次调用闭包,观察它"记住"的状态
println(counter()) // 输出:1
println(counter()) // 输出:2
println(counter()) // 输出:3
}
这里我提一下,return { count++ // 每次调用闭包,count 自增 count } 这个代码,闭包这个代码区域,默认返回最后一行,即返回count 这个值
解析 :createCounter
函数执行完毕后,其局部变量 count
本应被销毁,但由于闭包捕获了它,count
的生命周期被延长,每次调用闭包都会基于上一次的状态自增。
闭包与高阶函数结合
下面这个🌰能看懂么
kotlin
// 高阶函数:接收一个闭包作为参数
fun processNumbers(numbers: List<Int>, action: (Int) -> Unit) {
for (num in numbers) {
action(num) // 执行闭包
}
}
fun main() {
var sum = 0 // 外部变量
val numbers = listOf(1, 2, 3, 4)
// 传递闭包给高阶函数,捕获并修改 sum
processNumbers(numbers) { num ->
sum += num // 累加求和
}
println("总和: $sum") // 输出:总和: 10
}
解析 :lambda 闭包捕获了外部变量 sum
,在高阶函数 processNumbers
中被调用时,持续修改 sum
的值,最终实现求和逻辑。
----------------------------------占用课间5分钟,额外再补充一下 ------------------ 有兴趣的同学可以拓展了解下 data class inner class suspend 关键字 集合操作符还有,first(), firstNotNull(), find(), findNotNull, any()
这里我简单讲下data class
在 Kotlin 中,data class
(数据类)是一种专门用于存储数据 的类,编译器会自动为其生成一系列常用方法(如 toString()
、equals()
、hashCode()
等),大幅减少模板代码的编写。
这个我们可以在Androidstudio中直接创建这个类型的文件

这是kotlin相对于java 独有的
为什么需要 data class?
在传统编程中,我们经常需要定义只用于存储数据的类(如实体类、模型类),并手动实现 toString()
(便于打印)、equals()
(判断相等)、hashCode()
(用于哈希集合)等方法。而 data class
可以自动生成这些方法,让代码更简洁。 有了它,我们可以在接口请求中,这么接收数据
kotlin
data class User(
val id: Int,
val name: String,
val age: Int
)
不需要什么其他三方插件了
data class 的限制
主构造函数至少有一个参数:不能定义无参数据类(若需无参,可给所有参数设默认值)
kotlin
// 允许:所有参数有默认值,可无参创建
data class User(
val id: Int = 0,
val name: String = "",
val age: Int = 0
)
val emptyUser = User() // 合法
总结
data class
是 Kotlin 中简化数据存储类定义的强大工具,自动生成 toString()
、equals()
、hashCode()
、copy()
等方法,减少模板代码。适用于所有以存储数据为主要目的的类,配合解构和 copy()
功能,让数据处理更简洁高效。
至于 suspend 关键字,我们后面在协程中会讲到 它其实就是挂起的意思。用到协程,就离不开它