Kotlin Academy · 课时

何时使用哪个函数

权衡取舍

第 4 / 4 课13 个步骤

何时使用哪个函数 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。

两个工具,各司其职

中缀函数关注的是可读性;尾递归函数关注的是安全且高效的递归。它们解决的是互不相关的问题。

infix fun Int.add(o: Int) = this + o

tailrec fun sum(n: Int, acc: Int = 0): Int =
    if (n == 0) acc else sum(n - 1, acc + n)

fun main() {
    println(2 add 3)
    println(sum(10))
}

为流畅接口选择中缀函数

当省略点号和括号后调用读起来更好时,尤其是在 DSL 和构建二元组时,请考虑使用中缀函数。

fun main() {
    val pair = "id" to 100
    println(pair)
}

为深度递归选择尾递归

当递归算法可能深入到足以导致栈溢出时,请使用尾递归。

tailrec fun count(n: Int, acc: Int = 0): Int =
    if (n == 0) acc else count(n - 1, acc + 1)

fun main() {
    println(count(50000))
}

中缀函数的权衡

中缀函数会移除标点,这可能降低不熟悉它的读者的理解度,也会使优先级更复杂。请仅在它明确有帮助时使用。

infix fun Int.scaledBy(f: Int) = this * f

fun main() {
    println(5 scaledBy 3)
}

尾递归的权衡

将代码改为尾递归通常需要累加器,这可能不如普通循环直接。请在表达力与简单性之间进行权衡。

tailrec fun product(n: Int, acc: Long = 1): Long =
    if (n <= 1) acc else product(n - 1, acc * n)

fun main() {
    println(product(6))
}

循环更简单的情况

如果普通的 for 或 while 循环比尾递归更清楚,请优先使用循环。递归是一种工具,而不是硬性要求。

fun sumLoop(n: Int): Int {
    var total = 0
    for (i in 1..n) total += i
    return total
}

fun main() {
    println(sumLoop(10))
}

命名调用更清楚的情况

如果中缀名称并不能明显表示二元关系,普通的方法调用能更好地传达意图。

data class Temp(val c: Int) {
    fun isWarmerThan(o: Temp) = c > o.c
}

fun main() {
    println(Temp(30).isWarmerThan(Temp(20)))
}

结合使用两者

这两个特性彼此独立;同一个程序可以使用中缀函数实现可读的调用,并使用尾递归实现安全的递归。

infix fun Int.upto(n: Int) = (this..n).toList()

tailrec fun last(list: List<Int>): Int =
    if (list.size == 1) list[0] else last(list.drop(1))

fun main() {
    println(last(1 upto 5))
}

可读性检查清单

请思考:中缀函数是否让初学者更容易理解调用?尾递归是否能避免实际的栈溢出风险?如果不能,请优先使用普通函数和循环。

fun main() {
    val r = (1..5).sum()
    println(r)
}

性能说明

尾递归可以在固定栈空间下提供类似循环的性能。中缀函数没有运行时开销;它纯粹是语法层面的特性。

tailrec fun pow(base: Int, exp: Int, acc: Long = 1): Long =
    if (exp == 0) acc else pow(base, exp - 1, acc * base)

fun main() {
    println(pow(2, 10))
}

选择总结

中缀函数:流畅的单参数二元风格调用。尾递归:必须安全扩展的递归。二者都不是默认选择,而是经过考虑后的决定。

infix fun String.joinWith(o: String) = "$this-$o"

fun main() {
    println("a" joinWith "b")
}

快速检查

请检验您对何时使用各个特性的理解。

回顾

您学会了何时使用各个特性:

  • 使用 infix 实现流畅、易读的二元风格调用和 DSL。
  • 使用 tailrec 实现能够扩展且不会栈溢出的递归。
  • 如果普通循环或命名函数更清楚,请优先使用它们。
  • 这两个特性彼此独立,也可以结合使用。
infix fun Int.by(o: Int) = this * o
tailrec fun dec(n: Int): Int = if (n == 0) 0 else dec(n - 1)

fun main() {
    println(3 by 4)
    println(dec(1000))
}
免费开始

用 AI 导师学习 Kotlin — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
51
课程
203

常见问题解答

「何时使用哪个函数」课时是免费的吗?

是的 — 「何时使用哪个函数」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。

「何时使用哪个函数」这节课中我会学到什么?

权衡取舍 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Kotlin Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「何时使用哪个函数」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Kotlin Academy 课中编写并运行代码吗?

能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 中缀函数
  2. 构建类似 DSL 的 API
  3. tailrec 函数
  4. 何时使用哪个函数
← 返回 Kotlin Academy