详解 Kotlin 的函数

目录

  1. 函数基础
  2. 函数参数
  3. 扩展函数
  4. 高阶函数
  5. 作用域函数
  6. 内联函数
  7. 中缀函数
  8. 运算符重载
  9. [函数类型和 Lambda](#函数类型和 Lambda)
  10. 实际应用场景

1. 函数基础

1.1 基本语法

Kotlin
kotlin 复制代码
fun add(a: Int, b: Int): Int {
    return a + b
}
Java 对比
java 复制代码
public int add(int a, int b) {
    return a + b;
}

关键差异:

  • Kotlin:fun 关键字,类型在参数名后面
  • Java:类型在参数名前面

1.2 单表达式函数

Kotlin
kotlin 复制代码
fun add(a: Int, b: Int): Int = a + b

// 类型推断
fun add(a: Int, b: Int) = a + b
Java 对比
java 复制代码
// Java 没有单表达式函数,必须写完整
public int add(int a, int b) {
    return a + b;
}

使用场景:

  • 简单的计算函数
  • 属性 getter
  • 工具函数

1.3 Unit 类型(无返回值)

Kotlin
kotlin 复制代码
fun printMessage(message: String): Unit {
    println(message)
}

// Unit 可以省略
fun printMessage(message: String) {
    println(message)
}
Java 对比
java 复制代码
public void printMessage(String message) {
    System.out.println(message);
}

关键点:

  • Kotlin 的 Unit 等价于 Java 的 void
  • Unit 可以省略不写

2. 函数参数

2.1 默认参数

Kotlin
kotlin 复制代码
fun greet(name: String, greeting: String = "Hello") {
    println("$greeting, $name!")
}

// 使用
greet("Tom")                    // Hello, Tom!
greet("Tom", "Hi")              // Hi, Tom!
Java 对比
java 复制代码
// Java 不支持默认参数,需要方法重载
public void greet(String name) {
    greet(name, "Hello");
}

public void greet(String name, String greeting) {
    System.out.println(greeting + ", " + name + "!");
}

使用场景:

  • 减少方法重载
  • 提供常用默认值
  • 简化 API 调用

2.2 命名参数

Kotlin
kotlin 复制代码
fun createUser(
    name: String,
    age: Int = 0,
    email: String = "",
    phone: String = ""
) {
    // ...
}

// 使用命名参数,可以跳过中间参数
createUser(
    name = "Tom",
    phone = "123456789"  // 跳过 age 和 email
)
Java 对比
java 复制代码
// Java 不支持命名参数,必须按顺序传参
createUser("Tom", 0, "", "123456789");

使用场景:

  • 参数很多时,提高可读性
  • 跳过某些默认参数
  • Builder 模式的替代方案

2.3 可变参数

Kotlin
kotlin 复制代码
fun sum(vararg numbers: Int): Int {
    return numbers.sum()
}

// 使用
sum(1, 2, 3, 4, 5)  // 15
Java 对比
java 复制代码
public int sum(int... numbers) {
    return Arrays.stream(numbers).sum();
}

关键差异:

  • Kotlin:vararg 关键字
  • Java:... 语法

使用场景:

  • 工具函数:max(), min(), sum()
  • 日志函数:log("tag", "msg1", "msg2")

3. 扩展函数

3.1 什么是扩展函数?

扩展函数 允许你为已有的类添加新方法,而无需修改原类。

Kotlin
kotlin 复制代码
// 为 String 添加扩展函数
fun String.removeSpaces(): String {
    return this.replace(" ", "")
}

// 使用
val text = "Hello World"
val result = text.removeSpaces()  // "HelloWorld"
Java 对比
java 复制代码
// Java 没有扩展函数,需要工具类
public class StringUtils {
    public static String removeSpaces(String str) {
        return str.replace(" ", "");
    }
}

String result = StringUtils.removeSpaces("Hello World");

3.2 使用场景

场景1:工具函数
kotlin 复制代码
// 扩展函数
fun String.isEmail(): Boolean {
    return this.contains("@") && this.contains(".")
}

// 使用
if (email.isEmail()) {
    // ...
}
场景2:Android View 扩展
kotlin 复制代码
// 为 View 添加扩展函数
fun View.show() {
    this.visibility = View.VISIBLE
}

fun View.hide() {
    this.visibility = View.GONE
}

// 使用(在传统 View 系统中)
button.show()
textView.hide()
场景3:集合操作
kotlin 复制代码
// 为 List 添加扩展函数
fun <T> List<T>.secondOrNull(): T? {
    return if (this.size >= 2) this[1] else null
}

// 使用
val list = listOf(1, 2, 3)
val second = list.secondOrNull()  // 2

3.3 关键点

  • 扩展函数是静态的:编译时确定,不是运行时多态
  • 可以访问 public 成员:但不能访问 private 成员
  • 优先级:类自己的方法优先于扩展函数

4. 高阶函数

4.1 什么是高阶函数?

高阶函数 是参数或返回值是函数的函数。

Kotlin
kotlin 复制代码
// 函数作为参数
fun processNumbers(
    numbers: List<Int>,
    operation: (Int) -> Int
): List<Int> {
    return numbers.map(operation)
}

// 使用
val doubled = processNumbers(listOf(1, 2, 3)) { it * 2 }
Java 对比
java 复制代码
// Java 8+ 使用 Function
public List<Integer> processNumbers(
    List<Integer> numbers,
    Function<Integer, Integer> operation
) {
    return numbers.stream()
        .map(operation)
        .collect(Collectors.toList());
}

4.2 使用场景

场景1:集合操作
kotlin 复制代码
// map、filter、forEach 都是高阶函数
val numbers = listOf(1, 2, 3, 4, 5)

numbers.map { it * 2 }           // [2, 4, 6, 8, 10]
numbers.filter { it % 2 == 0 }   // [2, 4]
numbers.forEach { println(it) }  // 打印每个元素
场景2:回调函数
kotlin 复制代码
fun fetchData(
    onSuccess: (String) -> Unit,
    onError: (Exception) -> Unit
) {
    try {
        val data = "数据内容"
        onSuccess(data)
    } catch (e: Exception) {
        onError(e)
    }
}

// 使用
fetchData(
    onSuccess = { data -> println("成功: $data") },
    onError = { error -> println("错误: ${error.message}") }
)
场景3:Compose 中的使用
kotlin 复制代码
@Composable
fun Button(
    onClick: () -> Unit,  // 高阶函数参数
    content: @Composable () -> Unit
) {
    // ...
}

// 使用
Button(onClick = { println("点击") }) {
    Text("按钮")
}

5. 作用域函数

5.1 什么是作用域函数?

作用域函数 (let、run、with、apply、also)在对象的上下文中执行代码块。

5.2 let:安全调用 + 转换

kotlin 复制代码
val name: String? = "Kotlin"

val length = name?.let {
    println("名字是 $it")
    it.length  // 返回值
}

使用场景:

  • 空安全调用
  • 转换对象
  • 链式调用

5.3 run:在对象上下文中执行

kotlin 复制代码
val result = "Kotlin".run {
    println(this)  // this 是 "Kotlin"
    this.length + this.uppercase().length
}

使用场景:

  • 在对象上下文中执行代码
  • 返回计算结果

5.4 with:非扩展函数

kotlin 复制代码
val builder = StringBuilder()

val result = with(builder) {
    append("Hello ")
    append("World")
    toString()  // 返回值
}

使用场景:

  • 对同一个对象做多个操作
  • 不需要链式调用时

5.5 apply:配置对象

kotlin 复制代码
val person = Person().apply {
    name = "张三"
    age = 25
    email = "zhangsan@example.com"
}

使用场景:

  • 对象初始化
  • Builder 模式
  • 配置对象属性

5.6 also:执行副作用

kotlin 复制代码
val numbers = mutableListOf(1, 2, 3)
    .also { println("初始: $it") }
    .apply { add(4) }
    .also { println("添加后: $it") }

使用场景:

  • 调试日志
  • 副作用操作
  • 链式调用中的中间步骤

5.7 选择指南

函数 访问对象 返回值 使用场景
let it Lambda 结果 空安全、转换
run this Lambda 结果 对象上下文执行
with this Lambda 结果 非扩展,多操作
apply this 对象本身 对象配置
also it 对象本身 副作用、调试

6. 内联函数

6.1 什么是内联函数?

内联函数 在编译时将函数体直接插入调用处,避免函数调用的开销。

Kotlin
kotlin 复制代码
inline fun <T> measureTime(block: () -> T): T {
    val start = System.currentTimeMillis()
    val result = block()
    val end = System.currentTimeMillis()
    println("耗时: ${end - start}ms")
    return result
}

// 使用
val result = measureTime {
    // 执行代码
}

6.2 使用场景

场景1:性能优化
kotlin 复制代码
// 高阶函数默认会创建 Lambda 对象
// 使用 inline 可以避免创建对象
inline fun <T> List<T>.forEach(action: (T) -> Unit) {
    for (element in this) action(element)
}
场景2:reified 类型参数
kotlin 复制代码
// 只有内联函数可以使用 reified
inline fun <reified T> Gson.fromJson(json: String): T {
    return fromJson(json, T::class.java)
}

// 使用
val user: User = gson.fromJson(jsonString)

6.3 关键点

  • 性能优化:减少函数调用开销
  • reified 支持 :内联函数可以使用 reified 类型参数
  • 代码膨胀:内联会增加代码体积,谨慎使用

7. 中缀函数

7.1 什么是中缀函数?

中缀函数 允许你使用中缀表示法调用函数(类似运算符)。

Kotlin
kotlin 复制代码
infix fun Int.times(str: String): String {
    return str.repeat(this)
}

// 使用
val result = 3 times "Hello"  // "HelloHelloHello"

7.2 使用场景

场景1:DSL(领域特定语言)
kotlin 复制代码
infix fun String.shouldBe(expected: String) {
    if (this != expected) {
        throw AssertionError("Expected $expected but got $this")
    }
}

// 使用
"hello" shouldBe "hello"
场景2:集合操作
kotlin 复制代码
infix fun <T> List<T>.containsAll(other: List<T>): Boolean {
    return other.all { this.contains(it) }
}

// 使用
val list1 = listOf(1, 2, 3)
val list2 = listOf(1, 2)
val result = list1 containsAll list2  // true

7.3 关键点

  • 可读性:让代码更接近自然语言
  • DSL 构建:常用于构建 DSL
  • 限制:必须是成员函数或扩展函数,只能有一个参数

8. 运算符重载

8.1 什么是运算符重载?

运算符重载允许你为类定义运算符的行为。

Kotlin
kotlin 复制代码
data class Point(val x: Int, val y: Int) {
    operator fun plus(other: Point): Point {
        return Point(x + other.x, y + other.y)
    }
}

// 使用
val p1 = Point(1, 2)
val p2 = Point(3, 4)
val p3 = p1 + p2  // Point(4, 6)
Java 对比
java 复制代码
// Java 不支持运算符重载
Point p3 = p1.add(p2);

8.2 常用运算符

运算符 函数名 示例
+ plus a + b
- minus a - b
* times a * b
/ div a / b
== equals a == b
[] get a[i]
in contains a in b

8.3 使用场景

场景1:数学运算
kotlin 复制代码
data class Money(val amount: Double) {
    operator fun plus(other: Money): Money {
        return Money(amount + other.amount)
    }
}

val total = Money(10.0) + Money(20.0)  // Money(30.0)
场景2:集合操作
kotlin 复制代码
operator fun <T> List<T>.get(index: Int): T {
    return this[index]
}

val list = listOf(1, 2, 3)
val item = list[0]  // 1

9. 函数类型和 Lambda

9.1 函数类型

Kotlin
kotlin 复制代码
// 函数类型
val add: (Int, Int) -> Int = { a, b -> a + b }

// 使用
val result = add(1, 2)  // 3
Java 对比
java 复制代码
// Java 使用 Function 接口
Function<Integer, Function<Integer, Integer>> add = 
    a -> b -> a + b;

9.2 Lambda 表达式

Kotlin
kotlin 复制代码
// Lambda 语法
val numbers = listOf(1, 2, 3, 4, 5)

numbers.filter { it > 3 }        // [4, 5]
numbers.map { it * 2 }           // [2, 4, 6, 8, 10]
numbers.forEach { println(it) }  // 打印每个元素
Java 对比
java 复制代码
numbers.stream()
    .filter(x -> x > 3)
    .map(x -> x * 2)
    .forEach(System.out::println);

9.3 使用场景

  • 集合操作 :map、filter、forEach
  • 回调函数:事件处理、异步回调
  • Compose :onClick、onValueChange 等

10. 实际应用场景

10.1 场景1:工具函数库

kotlin 复制代码
// 扩展函数
fun String.isEmail(): Boolean {
    return this.matches(Regex("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"))
}

fun View.show() {
    this.visibility = View.VISIBLE
}

fun View.hide() {
    this.visibility = View.GONE
}

// 使用
if (email.isEmail()) {
    // ...
}
button.show()

10.2 场景2:Compose 中的高阶函数

kotlin 复制代码
@Composable
fun MyScreen() {
    var count by remember { mutableStateOf(0) }
    
    // onClick 是高阶函数参数
    Button(onClick = { count++ }) {
        Text("计数: $count")
    }
    
    // LaunchedEffect 是高阶函数
    LaunchedEffect(count) {
        println("Count changed: $count")
    }
}

10.3 场景3:Repository 模式

kotlin 复制代码
interface UserRepository {
    suspend fun getUser(id: Int): Result<User>
}

class UserRepositoryImpl : UserRepository {
    override suspend fun getUser(id: Int): Result<User> {
        return try {
            val user = apiService.getUser(id)
            Result.success(user)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }
}

10.4 场景4:作用域函数优化代码

kotlin 复制代码
// 使用 apply 初始化对象
val paint = Paint().apply {
    isAntiAlias = true
    color = Color.RED
    strokeWidth = 4f
}

// 使用 let 安全调用
val length = nullableString?.let {
    println("处理: $it")
    it.length
}

// 使用 also 调试
val result = calculate()
    .also { println("计算结果: $it") }
    .also { logToFile(it) }

总结

函数特性速查表

特性 说明 使用场景
默认参数 参数有默认值 减少重载、简化 API
命名参数 按名称传参 参数多时提高可读性
扩展函数 为类添加方法 工具函数、DSL
高阶函数 参数/返回值是函数 回调、集合操作
作用域函数 在对象上下文中执行 链式调用、对象配置
内联函数 编译时内联 性能优化、reified
中缀函数 中缀表示法 DSL 构建
运算符重载 定义运算符行为 数学运算、集合操作

核心原则

  1. 优先使用扩展函数:为已有类添加功能
  2. 合理使用默认参数:减少方法重载
  3. 高阶函数简化代码:回调、集合操作
  4. 作用域函数提高可读性:链式调用、对象配置
  5. 谨慎使用内联函数:只在性能关键处使用

记忆口诀

  • 扩展函数 = "为类添加方法,无需修改原类"
  • 高阶函数 = "参数或返回值是函数"
  • 作用域函数 = "在对象上下文中执行代码"
  • 内联函数 = "编译时插入,避免调用开销"
  • 中缀函数 = "中缀表示法,类似运算符"

掌握这些,你就能写出更优雅、更简洁的 Kotlin 代码!

相关推荐
第九序言T6 小时前
Python 数据处理进阶(十八)批量处理同结构文件:一个文件夹一次跑完
开发语言·python·自动化·pandas·数据处理
Java后端的Ai之路6 小时前
CAS并发控制-从CPU指令到企业级乐观锁
vue.js·人工智能·python·cas·乐观锁
qq_426003966 小时前
UI自动化高频次登录login限流解决方案
python·ui·自动化
Sakura_j_h_7 小时前
EasyEDA PCB 快速设计Skills
c++·python·github
龙亘川8 小时前
构建城市公共安全数字底座:亘川智城智慧安防系统全维度解读
java·大数据·开发语言·人工智能·信息可视化
程序喵大人8 小时前
【C++入门】内存模型与资源管理 - 09 shared_ptr 和 weak_ptr 解决共享,也带来代价
开发语言·c++·资源管理·智能指针·内存模型
quantdash_cc8 小时前
如何验证历史行情的交易日期是否完整覆盖研究区间?
python·数据分析·pandas·量化交易·股票数据·quantdash
I Am a robert girl8 小时前
当智能体学会“串通”:从长程交互中读懂涌现式合谋
python·多智能体系统·多智能体协作·llm agent·涌现式合谋·对齐问题·激励机制设计
Raas1008 小时前
AI网关部署方案?从部署到上线全流程
java·开发语言·人工智能·gateway·ai网关·企业级ai网关·企业级ai产品
云和数据.ChenGuang9 小时前
光哥说Python RAG 系统需要哪些评估指标:从检索到生成的全链路评测指南
网络·人工智能·python·算法·langchain