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 关键字,我们后面在协程中会讲到 它其实就是挂起的意思。用到协程,就离不开它

相关推荐
来来走走34 分钟前
Flutter开发 webview_flutter的基本使用
android·flutter
Jerry说前后端1 小时前
Android 组件封装实践:从解耦到架构演进
android·前端·架构
大王派来巡山的小旋风2 小时前
Kotlin基本用法《四》-又想到了一些
kotlin
louisgeek2 小时前
Android OkHttp Interceptor
android
Jerry说前后端3 小时前
Android 移动端 UI 设计:前端常用设计原则总结
android·前端·ui
bytebeats3 小时前
Jetpack Compose 1.9: 核心新特性简介
android·android jetpack
Icey_World3 小时前
Mysql笔记-错误条件\处理程序
android
大王派来巡山的小旋风4 小时前
Kotlin基本用法之集合(一)
android·程序员·kotlin
用户2018792831674 小时前
智能广播系统(RemoteCallbackList)的诞生
android