第6章:函数基础——函数声明、参数、Unit返回类型、单表达式函数
函数,说白了就是一段有名字的代码块。你给它输入,它给你输出。Kotlin 的函数设计得特别灵活,我个人觉得这是它最舒服的地方之一。今天我们就来把函数的基础彻底捋一遍。
6.1 函数声明:fun 关键字
Kotlin 声明函数用 fun 关键字,这个很直接。基本格式是:
fun 函数名(参数列表): 返回类型 {
函数体
}
举个例子:
fun greet(name: String): String {
return "Hello, $name"
}
这里 greet 接收一个 String 参数,返回一个 String。没什么花哨的,但干净利落。
小提示:Kotlin 的函数参数是 val 的,你不能在函数体内修改参数的值。这是为了防止你无意中改变输入,减少 bug。
6.2 参数:默认参数与命名参数
这是 Kotlin 函数最实用的两个特性。我在项目中几乎每天都在用。
6.2.1 默认参数
你可以给参数指定默认值。调用时如果不传这个参数,就使用默认值。
fun createUser(name: String, age: Int = 18, city: String = "北京") {
println("姓名: $name, 年龄: $age, 城市: $city")
}
// 调用
createUser("张三") // 年龄默认18,城市默认北京
createUser("李四", 25) // 城市默认北京
createUser("王五", 30, "上海") // 全部指定
我个人习惯把最常用的参数放在前面,把有默认值的参数放在后面。这样调用时最简洁。
避坑指南:我曾经在项目中犯过一个错——给一个布尔参数设置了默认值 true,结果半年后另一个同事调用时没传这个参数,导致一个隐藏的 bug 上线了。所以,默认值虽然方便,但也要考虑语义是否清晰。如果这个参数的含义不是「绝大多数情况都用这个值」,那最好别设默认值。
6.2.2 命名参数
调用函数时,你可以显式指定参数名。这有两个好处:
- 代码可读性更高
- 可以跳过某些有默认值的参数
fun configDialog(title: String, width: Int = 400, height: Int = 300, resizable: Boolean = false) {
// 配置对话框
}
// 传统调用
configDialog("提示", 500, 400, true)
// 命名参数调用
configDialog(title = "提示", width = 500, height = 400, resizable = true)
// 跳过默认参数
configDialog(title = "警告", resizable = true) // width和height使用默认值
你想想看,如果一个函数有七八个参数,全是布尔值或者 Int,你不写参数名,谁能看懂每个数字是什么意思?命名参数在这里就是救星。
注意:一旦你开始使用命名参数,后面的参数也必须使用命名参数。不能混着来。比如 configDialog("提示", width = 500, 400) 是不允许的。
6.3 Unit 返回类型
如果一个函数不返回有意义的值,它的返回类型就是 Unit。这相当于 Java 里的 void,但 Unit 是一个真正的对象。
fun logMessage(msg: String): Unit {
println("[LOG]: $msg")
}
// 也可以省略 : Unit,Kotlin 会自动推断
fun logMessage(msg: String) {
println("[LOG]: $msg")
}
为什么 Kotlin 不直接用 void?因为 Unit 是一个单例对象,它可以被用在泛型中。比如:
interface Action<T> {
fun execute(): T
}
class LogAction : Action<Unit> {
override fun execute() {
println("执行日志操作")
}
}
这在 Java 里是做不到的——你不能把 void 当作泛型参数。Kotlin 用 Unit 解决了这个问题。嗯,这里要注意,虽然 Unit 是对象,但你不需要显式 return Unit,编译器会自动处理。
6.4 单表达式函数
如果一个函数体只有单个表达式,你可以省略花括号,直接用 = 连接。这就是单表达式函数。
// 传统写法
fun double(x: Int): Int {
return x * 2
}
// 单表达式写法
fun double(x: Int): Int = x * 2
// 返回类型也可以省略,让编译器推断
fun double(x: Int) = x * 2
单表达式函数特别适合简单的计算、转换、或者委托。我在项目中经常用它来写数据转换函数:
data class User(val id: Int, val name: String)
fun User.toDisplayString() = "用户[$id]: $name"
// 调用
val user = User(1, "小明")
println(user.toDisplayString()) // 输出: 用户[1]: 小明
单表达式函数配合扩展函数,写起来非常流畅。我个人觉得这是 Kotlin 函数式风格的起点。
小技巧:单表达式函数也可以和条件表达式结合。比如:
fun max(a: Int, b: Int) = if (a > b) a else b
这样写比传统写法简洁很多,而且意图一目了然。
6.5 知识体系总览
下面这张图把本章的核心知识点串起来了。你可以看到函数声明、参数机制、返回类型、单表达式函数之间的关系。
6.6 综合示例
把今天学的知识点串起来,写一个实际点的例子:
// 计算订单折扣
fun calculateDiscount(
amount: Double,
memberLevel: String = "普通",
couponCode: String? = null
): String {
val baseDiscount = when (memberLevel) {
"黄金" -> 0.15
"白银" -> 0.10
else -> 0.05
}
val couponDiscount = if (couponCode != null) 0.05 else 0.0
val finalDiscount = baseDiscount + couponDiscount
val finalAmount = amount * (1 - finalDiscount)
return "原价: ¥${amount}, 折扣: ${(finalDiscount * 100).toInt()}%, 实付: ¥${finalAmount}"
}
// 调用
println(calculateDiscount(100.0)) // 普通会员,无优惠券
println(calculateDiscount(100.0, memberLevel = "黄金")) // 黄金会员
println(calculateDiscount(100.0, couponCode = "SAVE5")) // 普通会员+优惠券
println(calculateDiscount(100.0, "黄金", "SAVE5")) // 黄金会员+优惠券
这个例子用到了默认参数、命名参数、when 表达式、字符串模板。你看,Kotlin 的函数设计就是让你用最少的代码表达最清晰的意图。
总结一下:
- 函数声明:用
fun,参数是 val,不可修改 - 默认参数:减少重载,调用更灵活
- 命名参数:提高可读性,跳过默认参数
- Unit:替代 void,支持泛型
- 单表达式函数:简洁优雅,适合简单逻辑
函数是 Kotlin 的基石。把这些基础打牢了,后面学高阶函数、Lambda、作用域函数才会顺手。今天就到这里,下次见。