详解 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 什么是作用域函数?

作用域函数letrunwithapplyalso)在对象的上下文中执行代码块。

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 使用场景

  • 集合操作mapfilterforEach
  • 回调函数:事件处理、异步回调
  • ComposeonClickonValueChange

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 代码!

相关推荐
生活很暖很治愈2 小时前
Pytest-order插件
python·测试工具·测试用例·pytest
啊阿狸不会拉杆2 小时前
《数字信号处理》第5章-数字滤波器的基本结构
python·算法·机器学习·matlab·信号处理·数字信号处理·dsp
逄逄不是胖胖2 小时前
《动手学深度学习》-56GRN实现
pytorch·python·深度学习
waves浪游2 小时前
Ext系列文件系统
linux·服务器·开发语言·c++·numpy
独自破碎E2 小时前
LCR003-比特位计数
java·开发语言
naruto_lnq2 小时前
用户认证与授权:使用JWT保护你的API
jvm·数据库·python
cq林志炫2 小时前
PHP实现数据动态写入word模板文件里面
开发语言·php
m0_581124192 小时前
Python数据库操作:SQLAlchemy ORM指南
jvm·数据库·python
2401_841495642 小时前
【LeetCode刷题】二叉树的中序遍历
数据结构·python·算法·leetcode··递归·遍历