第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 知识体系总览

下面这张图把本章的核心知识点串起来了。你可以看到函数声明、参数机制、返回类型、单表达式函数之间的关系。

Kotlin 函数基础 · 知识体系 函数声明 fun 默认参数 命名参数 Unit 返回类型 单表达式函数 参数是 val,不可修改 省略花括号,用 = 连接 核心思想:简洁、安全、表达力强

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、作用域函数才会顺手。今天就到这里,下次见。


公众号:蓝海资料掘金营,微信deep3321