Kotlin 函数引用

一、基本概念与语法‌

Kotlin 函数引用(Function Reference)通过双冒号操作符 :: 实现,允许将具名函数作为‌高阶函数的参数或返回值 ‌使用,其本质是将函数转换为‌函数类型实例‌‌14。

kotlin 复制代码
fun sum(x: Int, y: Int) = x + y
val sumRef: (Int, Int) -> Int = ::sum  // 函数引用赋值给变量‌:ml-citation{ref="4" data="citationList"}

‌二、核心使用场景‌

  1. ‌替代 Lambda 表达式 ‌

    当 Lambda 仅调用单一具名函数时,可用函数引用简化代码,提升可读性‌46:

    erlang 复制代码
    listOf(1, 3, 5).forEach(::println)  // 替代 { x -> println(x) }‌:ml-citation{ref="3" data="citationList"}
  2. ‌动态传递函数逻辑 ‌

    函数引用可作为参数传递给高阶函数,实现灵活的行为控制:

    kotlin 复制代码
    fun applyOp(x: Int, y: Int, op: (Int, Int) -> Int) = op(x, y)
    applyOp(2, 3, ::sum)  // 输出 5‌:ml-citation{ref="4" data="citationList"}
  3. ‌构建函数工厂 ‌

    函数类型作为返回值时,可基于条件返回不同函数引用:

    kotlin 复制代码
    fun getMathOp(isAdd: Boolean): (Int, Int) -> Int = 
        if (isAdd) ::sum else ::subtract‌:ml-citation{ref="1" data="citationList"}

‌三、不同引用类型的语法‌

‌引用类型‌ ‌语法示例‌ ‌说明‌
类静态方法 MyClass::methodName 需类名限定,参数包含类实例‌35
实例方法 myInstance::methodName 绑定实例,调用时无需传递接收者‌35
扩展函数 String::isEmpty 接收者类型作为第一个参数‌34
构造函数 ::MyClass 生成类实例的工厂函数‌5

‌四、注意事项与最佳实践‌

  1. ‌类型匹配严格性 ‌

    函数引用需与目标函数类型完全匹配(参数数量、类型、返回值),否则编译报错‌46。

    sql 复制代码
    // 错误:sum 函数类型为 (Int, Int) -> Int,与 (Int) -> Int 不匹配
    val invalidRef: (Int) -> Int = ::sum  
  2. ‌反射依赖库问题 ‌

    若需通过反射获取函数引用元信息(如 KFunction),需添加 kotlin-reflect 依赖‌5。

  3. ‌性能优化建议‌

    • 优先使用函数引用替代匿名类或反射调用;
    • 高频调用的场景可结合 inline 关键字消除 Lambda 开销‌6。

‌五、综合示例‌

kotlin 复制代码
kotlinCopy Code
// 类方法引用
class Logger(val tag: String) {
    fun log(msg: String) = println("$tag: $msg")
}
val logger = Logger("App")
val logRef: (String) -> Unit = logger::log  // 绑定实例的引用‌:ml-citation{ref="3,5" data="citationList"}

// 扩展函数引用
fun String?.safeIsEmpty(): Boolean = this.isNullOrEmpty()
val isEmptyRef: (String?) -> Boolean = String?::safeIsEmpty‌:ml-citation{ref="3,4" data="citationList"}

// 函数引用作为返回值
fun createComparator(reverse: Boolean): Comparator<Int> = 
    if (reverse) ::compareDescending else ::compareAscending‌:ml-citation{ref="6" data="citationList"}

案例

kotlin 复制代码
const val LOGIN_NAME1 = "xingmo"
const val LOGIN_PWD2 = "123456"

fun main(){
    login("xingmo","123456",::methodResponseResult) //实例方法的引用
    login("xingmo","123456",obj2)

    logRef.invoke("Hello")
}

// 类方法引用
class Logger(val tag: String) {
    fun log(msg: String) = println("$tag: $msg")
}
val logger = Logger("App")
val logRef: (String) -> Unit = logger::log  // 绑定实例的引用‌:ml-citation{ref="3,5" data="citationList"}

val obj1 = :: methodResponseResult //函数引用赋值给变量
val obj2 = obj1
//函数实现部分
fun methodResponseResult(msg: String, code: String) {
    println("最终登录的成果是:msg:$msg, code:$code")
}
const val USER_NAME_SAVE_DB4 = "xingmo"
const val USER_PWD_SAVE_DB4= "123456"

inline fun login(name: String, pwd: String, responseResult: (String, String) -> Unit) {
    if (USER_NAME_SAVE_DB4 == name && USER_PWD_SAVE_DB4 == pwd) {
        // 登录成功
        // 做很多的事情 校验成功信息等
        responseResult("登录成功", 200)
        // ...
    } else {
        // 登录失败
        // 做很多的事情 登录失败的逻辑处理
        // ...
        responseResult("登录失败错了", 444)
    }
}

‌总结 ‌:Kotlin 函数引用通过 :: 操作符实现函数逻辑的‌一级公民化‌,适用于代码简化、动态逻辑分发等场景,需注意类型匹配和性能优化‌

相关推荐
Patrick在香港1 小时前
一个斜杠,把毫秒变成十几秒
android·数据库·python·性能优化·正则表达式·回溯·redos
海雅达手持终端PDA3 小时前
工业手持终端的“去手机化”演进:看海雅达如何以“同轴扫摄”终结工程妥协,重塑工业PDA新范式
android·物联网·智能手机·硬件工程·能源·制造·iot
booboosui4 小时前
删掉一个住在本机的 agent:8 处要清,顺序不能反
android
hcgeng4 小时前
Android获取崩溃日志
android
aqi004 小时前
AI编程让鸿蒙开发电子书APP更加快捷
android·华为·harmonyos·鸿蒙·harmony
GY-934 小时前
【Android】Android Studio 中的协程
android
Geek-Chow4 小时前
移动 App 侧载攻击:Android 与 iOS 的信任链、突破口与防护
android
Android小码家6 小时前
framework&framework-minus-apex&android.jar的区别
android·python·jar
技术风向解码者6 小时前
安卓跨端选型:为什么优先看 Kuikly
android