7. 函数基础:从定义到玩出花
函数这东西,说白了就是一段有名字的代码块。你给它点输入,它给你点输出。我刚开始学 Kotlin 的时候,觉得函数不就是 Java 那套嘛,结果发现 Kotlin 的函数灵活得多,写起来也爽快不少。
今天我们就来聊聊 Kotlin 函数的那些事儿。我会结合自己踩过的坑,给你讲清楚定义、参数、返回值,还有那些让你代码更简洁的小技巧。
7.1 函数的定义与调用
Kotlin 的函数定义很直接。用 fun 关键字开头,后面跟函数名、参数列表、返回类型,最后是函数体。
fun greet(name: String): String {
return "Hello, $name"
}
// 调用
val message = greet("Kotlin")
println(message) // 输出: Hello, Kotlin
你看,参数是 name: String,返回类型写在参数列表后面,用冒号隔开。如果函数体只有一行表达式,还可以更简洁:
fun greet(name: String): String = "Hello, $name"
这种写法叫「单表达式函数」。我个人习惯在简单函数里用这种,代码看起来干净。
Unit(相当于 Java 的 void),可以省略返回类型。比如:
fun log(message: String) {
println(message)
}
7.2 参数与返回值
参数可以有多个,用逗号隔开。返回值可以是任意类型,包括 null(只要声明为可空类型)。
fun add(x: Int, y: Int): Int = x + y
fun nullableReturn(flag: Boolean): String? {
return if (flag) "有值" else null
}
我在项目中遇到过一个问题:返回值类型没写对,导致调用方一直做非空判断。后来我养成了习惯——如果返回值不可能为 null,就明确声明非空类型,这样调用方也省心。
7.3 默认参数与命名参数
这是 Kotlin 函数的一大亮点。你可以给参数指定默认值,调用时如果不传,就用默认值。
fun createUser(name: String, age: Int = 18, city: String = "北京") {
println("用户: $name, 年龄: $age, 城市: $city")
}
// 调用
createUser("张三") // 年龄默认18,城市默认北京
createUser("李四", 25) // 城市默认北京
createUser("王五", city = "上海") // 命名参数,跳过 age
看到没?第三个调用用了命名参数 city = "上海",跳过了 age。命名参数的好处是:参数多了以后,你不需要记住顺序,直接按名字传就行。
createUser(name = "赵六", 30) 会报错,因为 30 没有用命名。
我曾经在写一个配置函数时,有 6 个参数,大部分都有默认值。调用方只需要传一两个参数,其他用默认值,代码瞬间清爽很多。你想想看,如果用 Java 的重载,得写多少个重载方法?
7.4 可变参数
有时候你希望函数能接受任意数量的参数。Kotlin 用 vararg 关键字实现。
fun sum(vararg numbers: Int): Int {
var total = 0
for (n in numbers) {
total += n
}
return total
}
// 调用
println(sum(1, 2, 3)) // 6
println(sum(1, 2, 3, 4, 5)) // 15
可变参数本质上是一个数组。在函数内部,你可以把它当作数组来遍历。注意,一个函数只能有一个 vararg 参数,而且通常放在最后。
fun example(vararg items: String, prefix: String) {
// ...
}
// 调用时必须: example("a", "b", prefix = "c")
7.5 局部函数
Kotlin 允许在函数内部再定义函数,这就是局部函数。局部函数只能在其所在的函数内部访问,外部看不到。
fun calculateTotal(price: Double, quantity: Int): Double {
// 局部函数
fun applyDiscount(p: Double): Double {
return if (p > 100) p * 0.9 else p
}
val discountedPrice = applyDiscount(price)
return discountedPrice * quantity
}
局部函数的好处是:把复杂的逻辑拆分成小步骤,但又不暴露给外部。我在写一些算法时经常用,比如递归函数,或者需要重复使用的辅助逻辑。
嗯,这里要注意:局部函数可以访问外部函数的参数和变量,所以有时候可以省去传参的麻烦。但别滥用,如果局部函数太长,还是抽成独立函数比较好。
知识体系一览
下面这张图帮你梳理了本章的核心内容。你可以看到函数定义的骨架,以及各种参数形式的区别。
总结一下
函数是 Kotlin 的基本组成单元。今天我们聊了:
- 定义与调用:
fun关键字,参数和返回类型的位置 - 参数与返回值:多参数、可空返回、Unit 省略
- 默认参数与命名参数:减少重载,提高可读性
- 可变参数:用
vararg接收任意数量参数 - 局部函数:函数内部定义函数,封装辅助逻辑
我个人觉得,默认参数和命名参数是 Kotlin 函数最实用的特性之一。你想想看,Java 里为了一个参数的不同组合,要写一堆重载方法,Kotlin 一行就搞定了。至于局部函数,虽然用得不多,但在某些场景下真的能帮你保持代码整洁。