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 的基本组成单元。今天我们聊了:

  • 定义与调用fun 关键字,参数和返回类型的位置
  • 参数与返回值:多参数、可空返回、Unit 省略
  • 默认参数与命名参数:减少重载,提高可读性
  • 可变参数:用 vararg 接收任意数量参数
  • 局部函数:函数内部定义函数,封装辅助逻辑

我个人觉得,默认参数和命名参数是 Kotlin 函数最实用的特性之一。你想想看,Java 里为了一个参数的不同组合,要写一堆重载方法,Kotlin 一行就搞定了。至于局部函数,虽然用得不多,但在某些场景下真的能帮你保持代码整洁。

一句话记住:函数是代码的积木,Kotlin 给了你更灵活的搭法。

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