Kotlin 语言参考文档 中文版 Help

函数

在 Kotlin 中, 你可以使用 fun 关键字声明你自己的函数.

fun hello() { return println("Hello, world!") } fun main() { hello() // 输出结果为 Hello, world! }

在 Kotlin 中:

  • 函数参数写在小括号 () 之内.

  • 每个参数必须指定类型, 多个参数必须用逗号 , 隔开.

  • 返回值类型写在函数的小括号 () 之后, 用冒号 : 隔开.

  • 函数的 body 部写在大括号 {} 之内.

  • return 关键字用来退出函数, 或从函数返回某个值.

在下面的示例中:

  • xy 是函数参数.

  • xy 类型为 Int.

  • 函数的返回值类型为 Int.

  • 函数被调用时返回 xy 的和.

fun sum(x: Int, y: Int): Int { return x + y } fun main() { println(sum(1, 2)) // 输出结果为 3 }

命名参数

为了让代码更简洁, 调用函数时, 你不必指定参数名称. 但是, 指定参数名称可以让你的代码更易于阅读. 这种方式称为 命名参数(named argument). 如果你指定了参数名称, 那么可以用任意的顺序来写这些参数.

fun printMessageWithPrefix(message: String, prefix: String) { println("[$prefix] $message") } fun main() { // 使用命名参数, 交换了参数的顺序 printMessageWithPrefix(prefix = "Log", message = "Hello") // 输出结果为 [Log] Hello }

默认的参数值

你可以为函数参数定义默认值. 调用你的函数时, 有默认值的参数可以省略. 要声明默认值, 请在参数类型之后使用赋值操作符 =:

fun printMessageWithPrefix(message: String, prefix: String = "Info") { println("[$prefix] $message") } fun main() { // 使用两个参数调用函数 printMessageWithPrefix("Hello", "Log") // 输出结果为 [Log] Hello // 只使用 message 参数调用函数 printMessageWithPrefix("Hello") // 输出结果为 [Info] Hello printMessageWithPrefix(prefix = "Log", message = "Hello") // 输出结果为 [Log] Hello }

没有返回值的函数

如果你的函数不返回任何有用的值, 那么它的返回值类型为 Unit. Unit 类型只有唯一的一个值 – Unit. 你不必在你的函数 body 部明确的声明返回值为 Unit. 因此你不必使用 return 关键字, 也不必声明返回值类型:

fun printMessage(message: String) { println(message) // `return Unit` 或 `return` 都是可选的 } fun main() { printMessage("Hello") // 输出结果为 Hello }

单一表达式函数

为了让代码更加简洁, 你可以使用单一表达式函数. 例如, sum() 函数可以写得更短一些:

fun sum(x: Int, y: Int): Int { return x + y } fun main() { println(sum(1, 2)) // 输出结果为 3 }

你可以删除大括号 {}, 使用赋值操作符 = 来声明函数的 body 部. 当你使用赋值操作符 = 时, Kotlin 会使用类型推断, 因此你也可以省略返回值类型. 这样, sum() 函数就变成只有 1 行:

fun sum(x: Int, y: Int) = x + y fun main() { println(sum(1, 2)) // 输出结果为 3 }

但是, 如果你想让你的代码能够被其他开发者快速理解, 那么即使使用赋值操作符 =, 也还是明确定义返回值类型更好一些.

函数中的提前返回 (Early Return)

如果想要你的函数中的代码在某个点之后不再进行后续处理, 请使用 return 关键字. 这个示例使用 if 判断, 如果条件表达式为真, 就从一个函数中提前返回:

// 注册的用户名列表 val registeredUsernames = mutableListOf("john_doe", "jane_smith") // 注册 EMail 列表 val registeredEmails = mutableListOf("john@example.com", "jane@example.com") fun registerUser(username: String, email: String): String { // 如果用户名已被使用, 则提前返回 if (username in registeredUsernames) { return "Username already taken. Please choose a different username." } // 如果 EMail 已被注册, 则提前返回 if (email in registeredEmails) { return "Email already registered. Please use a different email." } // 如果用户名和 EMail 都没有被使用, 则进行注册处理 registeredUsernames.add(username) registeredEmails.add(email) return "User registered successfully: $username" } fun main() { println(registerUser("john_doe", "newjohn@example.com")) // 输出结果为: Username already taken. Please choose a different username. println(registerUser("new_user", "newuser@example.com")) // 输出结果为: User registered successfully: new_user }

函数的实际练习

习题 1

写一个名为 circleArea 的函数, 接受一个整数参数, 表示圆的半径, 输出圆的面积大小.

import kotlin.math.PI fun circleArea() { // 在这里编写你的代码 } fun main() { println(circleArea(2)) }
import kotlin.math.PI fun circleArea(radius: Int): Double { return PI * radius * radius } fun main() { println(circleArea(2)) // 输出结果为 12.566370614359172 }

习题 2

将前一个习题中的 circleArea 函数重写为单一表达式函数.

import kotlin.math.PI // 在这里编写你的代码 fun main() { println(circleArea(2)) }
import kotlin.math.PI fun circleArea(radius: Int): Double = PI * radius * radius fun main() { println(circleArea(2)) // 输出结果为 12.566370614359172 }

习题 3

你有一个函数, 它接受一个时/分/秒单位给定的时间间隔, 然后翻译为秒单位. 大多数情况下, 你只需要传递 1 个或 2 个参数, 而其它参数为 0. 改进这个函数以及调用它的代码, 使用默认参数值和命名参数, 让代码更加易于阅读.

fun intervalInSeconds(hours: Int, minutes: Int, seconds: Int) = ((hours * 60) + minutes) * 60 + seconds fun main() { println(intervalInSeconds(1, 20, 15)) println(intervalInSeconds(0, 1, 25)) println(intervalInSeconds(2, 0, 0)) println(intervalInSeconds(0, 10, 0)) println(intervalInSeconds(1, 0, 1)) }
fun intervalInSeconds(hours: Int = 0, minutes: Int = 0, seconds: Int = 0) = ((hours * 60) + minutes) * 60 + seconds fun main() { println(intervalInSeconds(1, 20, 15)) println(intervalInSeconds(minutes = 1, seconds = 25)) println(intervalInSeconds(hours = 2)) println(intervalInSeconds(minutes = 10)) println(intervalInSeconds(hours = 1, seconds = 1)) }

Lambda 表达式

Kotlin 允许你使用 Lambda 表达式, 为函数编写更加简洁的代码.

例如, 下面的 uppercaseString() 函数:

fun uppercaseString(text: String): String { return text.uppercase() } fun main() { println(uppercaseString("hello")) // 输出结果为 HELLO }

可以写成一个 Lambda 表达式:

fun main() { val upperCaseString = { text: String -> text.uppercase() } println(upperCaseString("hello")) // 输出结果为 HELLO }

Lambda 表达式初看起来可能难于理解, 所以我们将它分解成各个部分. Lambda 表达式写在大括号 {} 之内.

在 Lambda 表达式之内, 你会写以下内容:

  • 参数, 在 -> 之前.

  • 函数 body 部, 在 -> 之后.

在上面的示例中:

  • text 是函数参数.

  • text 类型为 String.

  • 函数返回对 text 调用 .uppercase() 函数的结果.

  • 整个 Lambda 表达式通过赋值操作符 = 赋值给变量 upperCaseString.

  • 象函数一样使用 upperCaseString 变量, 字符串 "hello" 作为参数, 就会调用 Lambda 表达式.

  • println() 函数打印输出结果.

可以用很多方式使用 Lambda 表达式. 你可以:

传递给另一个函数

将 Lambda 表达式传递给另一个函数, 这个功能是很有用的, 一个很好的例子是对集合(Collection)使用 .filter() 函数:

fun main() { //sampleStart val numbers = listOf(1, -2, 3, -4, 5, -6) val positives = numbers.filter ({ x -> x > 0 }) val isNegative = { x: Int -> x < 0 } val negatives = numbers.filter(isNegative) println(positives) // 输出结果为 [1, 3, 5] println(negatives) // 输出结果为 [-2, -4, -6] //sampleEnd }

.filter() 函数接受一个 Lambda 表达式, 作为判定条件:

  • { x -> x > 0 } 接受 List 中的每个元素, 只返回正数.

  • { x -> x < 0 } 接受 List 中的每个元素, 只返回负数.

这个示例演示了将 Lambda 表达式传递给函数的两种方式:

  • 对于正数, 示例直接在 .filter() 函数中添加 Lambda 表达式.

  • 对于负数, 示例将 Lambda 表达式赋值给 isNegative 变量. 然后将 isNegative 变量用作 .filter() 函数的参数. 这种情况下, 你必须在 Lambda 表达式中指定函数参数 (x) 的类型.

另一个好的例子是, 使用 .map() 函数, 对集合中的元素进行变换:

fun main() { //sampleStart val numbers = listOf(1, -2, 3, -4, 5, -6) val doubled = numbers.map { x -> x * 2 } val isTripled = { x: Int -> x * 3 } val tripled = numbers.map(isTripled) println(doubled) // 输出结果为 [2, -4, 6, -8, 10, -12] println(tripled) // 输出结果为 [3, -6, 9, -12, 15, -18] //sampleEnd }

.map() 函数接受一个 Lambda 表达式, 作为变换函数:

  • { x -> x * 2 } 接受 List 中的每个元素, 返回这个元素乘以 2 的结果.

  • { x -> x * 3 } 接受 List 中的每个元素, 返回这个元素乘以 3 的结果.

函数类型

在从一个函数返回一个 Lambda 表达式之前, 你首先需要理解 函数类型.

你已经学习了基本类型, 但函数本身也有它的类型. Kotlin 的类型推断功能能够通过参数类型推断一个函数的类型. 但有的时候你需要明确指定函数类型. 编译器需要函数类型, 然后才能知道对这个函数允许什么, 不允许什么.

函数类型的语法包括:

  • 每个参数的类型, 写在小括号 () 之内, 以逗号 , 分隔.

  • 返回值类型, 写在 -> 之后.

例如: (String) -> String, 或 (Int, Int) -> Int.

如果为 upperCaseString() 定义一个函数类型, 那么 Lambda 表达式如下:

val upperCaseString: (String) -> String = { text -> text.uppercase() } fun main() { println(upperCaseString("hello")) // 输出结果为 HELLO }

如果你的 Lambda 表达式没有参数, 那么小括号 () 保留为空. 例如: () -> Unit

从函数中返回

可以从函数中返回 Lambda 表达式. 为了让编译器知道返回的 Lambda 表达式 的类型, 你必须声明一个函数类型.

在下面的示例中, toSeconds() 函数返回的函数类型是 (Int) -> Int, 因为它总是返回一个 Lambda 表达式, 这个 Lambda 表达式接受一个 Int 类型的参数, 并返回一个 Int 值.

这个示例使用 when 表达式, 来确定在调用 toSeconds() 时返回哪个 Lambda 表达式:

fun toSeconds(time: String): (Int) -> Int = when (time) { "hour" -> { value -> value * 60 * 60 } "minute" -> { value -> value * 60 } "second" -> { value -> value } else -> { value -> value } } fun main() { val timesInMinutes = listOf(2, 10, 15, 1) val min2sec = toSeconds("minute") val totalTimeInSeconds = timesInMinutes.map(min2sec).sum() println("Total time is $totalTimeInSeconds secs") // 输出结果为 Total time is 1680 secs }

单独调用

Lambda 表达式可以单独调用, 方法是在大括号 {} 之后添加小括号 (), 并在小括号中加上参数:

fun main() { //sampleStart println({ text: String -> text.uppercase() }("hello")) // 输出结果为 HELLO //sampleEnd }

尾缀 Lambda 表达式(Trailing Lambda)

你已经看到, 如果一个 Lambda 表达式是函数的唯一参数, 你可以去掉函数的小括号 (). 如果一个 Lambda 表达式是函数的最后一个参数, 那么 Lambda 表达式可以写在函数的小括号 () 之外. 对这两种情况, 这样的语法称为 尾缀 Lambda 表达式(Trailing Lambda).

例如, .fold() 函数接受一个初始值, 以及一个操作:

fun main() { //sampleStart // 初始值为 0. // 操作是对初始值累加 List 中的每个元素. println(listOf(1, 2, 3).fold(0, { x, item -> x + item })) // 输出结果为 6 // 或者, 也可以写成 尾缀 Lambda 表达式的形式 println(listOf(1, 2, 3).fold(0) { x, item -> x + item }) // 输出结果为 6 //sampleEnd }

关于 Lambda 表达式, 更多详情请参见 Lambda 表达式与匿名函数(Anonymous Function).

本教程的下一章是学习 Kotlin 中的 .

Lambda 表达式的实际练习

习题 1

你有一个 Web Service 支持的动作列表, 所有请求的一个共通前缀, 某个资源的一个 ID. 要对资源 ID 5 请求 title 动作, 你需要创建下面的 URL: https://example.com/book-info/5/title. 使用一个 Lambda 表达式, 从动作列表创建对应的 URL 列表.

fun main() { val actions = listOf("title", "year", "author") val prefix = "https://example.com/book-info" val id = 5 val urls = // 在这里编写你的代码 println(urls) }
fun main() { val actions = listOf("title", "year", "author") val prefix = "https://example.com/book-info" val id = 5 val urls = actions.map { action -> "$prefix/$id/$action" } println(urls) }

习题 2

编写一个函数, 接受一个 Int 值和一个动作 (一个 () -> Unit 类型的函数), 然后重复执行这个动作指定的次数. 然后使用这个函数打印 “Hello” 5 次.

fun repeatN(n: Int, action: () -> Unit) { // 在这里编写你的代码 } fun main() { // 在这里编写你的代码 }
fun repeatN(n: Int, action: () -> Unit) { for (i in 1..n) { action() } } fun main() { repeatN(5) { println("Hello") } }

下一步

最终更新: 2024/11/17