当前位置: 首页 > news >正文

Kotlin 2.1.0 入门教程(十)if、when

if 表达式

if 是一个表达式,它会返回一个值。

不存在三元运算符(condition ? then : else),因为 if 在这种场景下完全可以胜任。

var max = aif (a < b) max = bif (a > b) {max = a
} else {max = b
}max = if (a > b) a else bval maxLimit = 1val maxOrLimit = if (maxLimit > a) maxLimit else if (a > b) a else b

if 表达式的分支可以是代码块。在这种情况下,代码块中的最后一个表达式就是该代码块的值。

val max = if (a > b) {print("Choose a")a
} else {print("Choose b")b
}

如果使用 if 作为表达式,例如用于返回它的值或将它赋值给一个变量,那么 else 分支是必需的。

when 表达式和语句

when 是一种基于多个可能的值或条件运行代码的条件表达式。它类似于 JavaC 等语言中的 switch 语句。

val x = 2when (x) {1 -> print("x == 1")2 -> print("x == 2")else -> print("x is neither 1 nor 2")
}

when 会依次将它的参数与所有分支的条件进行匹配,直到某个分支的条件被满足为止。

你可以以几种不同的方式使用 when。首先,你可以将 when 用作表达式或语句。作为表达式,when 会返回一个值,供你在代码中后续使用。作为语句,when 用于完成某个操作,而不会返回任何进一步使用的值。

// 表达式。
// 返回一个字符串,该字符串被赋值给变量 text。
val text = when (x) {1 -> "x == 1"2 -> "x == 2"else -> "x is neither 1 nor 2"
}
// 语句。
// 不返回任何值,但会触发一个打印语句。
when (x) {1 -> print("x == 1")2 -> print("x == 2")else -> print("x is neither 1 nor 2")
}

可以使用带有或不带有对象的 when。无论是否在 when 中使用对象,表达式或语句的行为都是相同的。我们建议在可能的情况下使用带有对象的 when,因为它清晰地展示你在检查什么,使你的代码更易于阅读和维护。

// 带对象。
when (x) { ... }
// 不带对象。
when { ... }

根据你如何使用 when,对于是否需要在分支中覆盖所有可能的情况有不同的要求。

如果你将 when 用作语句,你不需要覆盖所有可能的情况。在下面的例子中,并没有覆盖所有情况,因此当不匹配任何分支时,不会发生任何事情。但也不会出现错误:

val x = 3
when (x) {// 并未覆盖所有情况。1 -> print("x == 1")2 -> print("x == 2")
}

when 语句中,各个分支的值会被忽略。就像 if 一样,每个分支可以是一个代码块,而代码块的值是块中最后一个表达式的值。

如果你将 when 用作表达式,那么你必须覆盖所有可能的情况,也就是说,它必须是穷尽的。第一个匹配分支的值将成为整个表达式的值。如果你没有覆盖所有情况,编译器会报错。

如果你的 when 表达式有一个对象,你可以使用 else 分支来确保覆盖所有可能的情况,但这并不是强制性的。例如,如果对象是一个布尔类型、枚举类、密封类,或者它们的可空类型,那么你可以不使用 else 分支来覆盖所有情况。例如:

enum class Bit {ZERO, ONE
}val numericValue = when (getRandomBit()) {// 不需要 else 分支,因为所有可能的情况都已经被覆盖了。Bit.ZERO -> 0Bit.ONE -> 1
}

如果你的 when 表达式没有对象,那么你必须有一个 else 分支,否则编译器会报错。当没有其他分支条件被满足时,else 分支会被执行。例如:

val number = 5val result = when {number > 0 -> "Positive"number < 0 -> "Negative"// 必须有 else 分支,因为没有对象。else -> "Zero" 
}

when 表达式和语句提供了多种方法来简化代码、处理多个条件以及执行类型检查。
你可以通过在单行中用逗号分隔多个条件,为多个案例定义共同的行为。例如:

val x = 2when (x) {1, 2, 3 -> println("x is 1, 2, or 3")4, 5, 6 -> println("x is 4, 5, or 6")else -> println("x is not in the range 1 to 6")
}

你可以使用任意表达式(不仅仅是常量)作为分支条件。例如:

val x = 5
val y = 10when (x) {y -> println("x is equal to y")y + 5 -> println("x is equal to y + 5")y - 5 -> println("x is equal to y - 5")else -> println("x is not equal to y, y + 5, or y - 5")
}

在这个例子中,yy + 5y - 5 都是作为分支条件的表达式。when 会根据 x 的值与这些表达式的结果进行比较,从而选择对应的分支。这种方式使得 when 的条件更加灵活,可以用于更复杂的逻辑判断。

你还可以通过 in!in 关键字来检查一个值是否包含在某个范围或集合中:

when (x) {in 1 .. 10 -> print("x is in the range")in validNumbers -> print("x is valid")!in 10 .. 20 -> print("x is outside the range")else -> print("none of the above")
}

此外,你可以通过 is!is 关键字来检查一个值是否是某种特定类型。由于智能类型转换,你可以直接访问该类型的成员函数和属性,而无需额外的检查。

fun hasPrefix(x: Any) = when(x) {is String -> x.startsWith("prefix")else -> false
}

你可以将 when 用作 if-else if 链的替代品。如果没有对象,分支条件就是布尔表达式。第一个条件为 true 的分支会被执行:

when {x.isOdd() -> print("x is odd")y.isEven() -> print("y is even")else -> print("x + y is odd")
}

你可以通过以下语法在变量中捕获对象:

fun Request.getBody() =when (val response = executeRequest()) {is Success -> response.bodyis HttpError -> throw HttpException(response.status)}

when 表达式或语句的主体中引入的变量的作用域仅限于该 when 表达式或语句的内部。

when 表达式中的守护条件

守护条件是一个实验性功能,可能会随时发生变化。

守护条件允许你在 when 表达式的分支中包含多个条件,从而使复杂的控制流程更加明确和简洁。你可以在带有对象的 when 表达式或语句中使用守护条件。

要在分支中包含守护条件,请将其放在主条件之后,并用 if 分隔。

sealed interface Animal {data class Cat(val mouseHunter: Boolean) : Animaldata class Dog(val breed: String) : Animal
}fun feedAnimal(animal: Animal) {when (animal) {is Animal.Dog -> feedDog()is Animal.Cat if !animal.mouseHunter -> feedCat()else -> println("Unknown animal")}
}

在一个 when 表达式中,你可以同时使用带有守护条件和没有守护条件的分支。带有守护条件的分支中的代码只有在主条件和守护条件都为 true 时才会执行。如果主条件不满足,守护条件不会被评估。

如果你在没有 else 分支的 when 语句中使用守护条件,并且没有任何条件匹配,那么没有任何分支会被执行。

否则,如果你在没有 else 分支的 when 表达式中使用守护条件,编译器会要求你声明所有可能的情况,以避免运行时错误。

此外,守护条件还支持 else if 的功能。

when (animal) {// 检查 animal 是否是 Dog。is Animal.Dog -> feedDog()// 检查 animal 是否是 Cat 并且不是 mouseHunter。is Animal.Cat if !animal.mouseHunter -> feedCat()// 如果前面的条件都不匹配,并且 animal.eatsPlants 为 true,则此。else if animal.eatsPlants -> giveLettuce()// 如果前面的条件都不匹配,则此。else -> println("Unknown animal")
}

你可以在一个分支中通过使用布尔运算符 &&|| 组合多个守护条件。为了避免混淆,请使用括号将布尔表达式括起来。

when (animal) {is Animal.Cat if (!animal.mouseHunter && animal.hungry) -> feedCat()
}

你可以在任何带有对象的 when 表达式或语句中使用守护条件,但有一个例外,当你的条件是通过逗号分隔的多个值时,例如 0, 1 -> print("x == 0 or x == 1"),这种情况下不能使用守护条件。

要在命令行界面中启用守护条件,运行以下命令:

kotlinc -Xwhen-guards main.kt

要在 Gradle 中启用守护条件,将以下代码添加到 build.gradle.kts 文件中:

kotlin {compilerOptions {freeCompilerArgs.add("-Xwhen-guards")}
}
http://www.lryc.cn/news/534108.html

相关文章:

  • AJAX项目——数据管理平台
  • 华为云搭建微信小程序商城后台
  • 5、大模型的记忆与缓存
  • Windows下AMD显卡在本地运行大语言模型(deepseek-r1)
  • 代码随想录day09
  • Racecar Gym 总结
  • 【C++高并发服务器WebServer】-15:poll、epoll详解及实现
  • Visual Studio 2022 中使用 Google Test
  • Office/WPS接入DeepSeek等多个AI工具,开启办公新模式!
  • Meta AI 最近推出了一款全新的机器学习框架ParetoQ,专门用于大型语言模型的4-bit 以下量化
  • 操作系统—进程与线程
  • 团队:前端开发工期参考 / 防止工期不足、过足、工期打架
  • APL语言的云计算
  • idea启动报错# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffccf76e433
  • C++拷贝构造函数与运算符重载应该注意的一个问题?
  • [7] 游戏机项目说明
  • “深入浅出”系列之C++:(20)C++17
  • .net一些知识点5
  • (七)QT——消息事件机制&绘图&文件
  • 【虚幻引擎UE】AOI算法介绍与实现案例
  • python学opencv|读取图像(六十)先后使用cv2.erode()函数和cv2.dilate()函数实现图像处理
  • AI能帮谷歌SEO做什么?
  • SSA-TCN麻雀算法优化时间卷积神经网络时间序列预测未来Matlab实现
  • 【机器学习】数据预处理之数据归一化
  • 【专题】2024-2025人工智能代理深度剖析:GenAI 前沿、LangChain 现状及演进影响与发展趋势报告汇总PDF洞察(附原数据表)
  • 非递减子序列(力扣491)
  • 网站快速收录策略:提升爬虫抓取效率
  • 系统思考—自我超越
  • 苍穹外卖-菜品分页查询
  • 子集II(力扣90)