Kotlin基本用法三

这一篇,其实已经不算基本了,我打算介绍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 关键字,我们后面在协程中会讲到 它其实就是挂起的意思。用到协程,就离不开它

相关推荐
恋猫de小郭7 分钟前
Flutter 3.38 发布,快来看看有什么更新吧
android·前端·flutter
百锦再6 小时前
第11章 泛型、trait与生命周期
android·网络·人工智能·python·golang·rust·go
会跑的兔子7 小时前
Android 16 Kotlin协程 第二部分
android·windows·kotlin
键来大师7 小时前
Android15 RK3588 修改默认不锁屏不休眠
android·java·framework·rk3588
精装机械师8 小时前
在IntelliJ IDEA编辑器中基于Gradle编译器搭建Kotlin开发环境遇到的各种坑
kotlin·gradle·intellij-idea
江上清风山间明月9 小时前
Android 系统超级实用的分析调试命令
android·内存·调试·dumpsys
百锦再10 小时前
第12章 测试编写
android·java·开发语言·python·rust·go·erlang
用户693717500138413 小时前
Kotlin 协程基础入门系列:从概念到实战
android·后端·kotlin
SHEN_ZIYUAN14 小时前
Android 主线程性能优化实战:从 90% 降至 13%
android·cpu优化
曹绍华14 小时前
android 线程loop
android·java·开发语言