3.3.1 扩展函数

原文链接: https://kotlinlang.org/docs/kotlin-tour-intermediate-extension-functions.html

3.3.1 扩展函数

本章将介绍一些能让代码更简洁、更易读的特殊 Kotlin 函数。了解它们如何帮助你使用高效的设计模式,把项目提升到新的水平。

扩展函数

在软件开发中,你常常需要在不改动原始源码的情况下修改程序的行为。例如,你可能想给第三方库中的某个类添加额外功能。

你可以通过添加扩展函数来扩展一个类。调用扩展函数的方式与调用类的成员函数相同,都使用句点 .。

在介绍扩展函数的完整语法之前,你需要先理解什么是接收者(receiver)。接收者就是函数被调用的那个对象。换句话说,接收者是共享信息的一方。

发送者与接收者的示例

在这个示例中,main() 函数调用 .first() 函数来返回列表中的第一个元素。.first() 函数是在 readOnlyShapes 变量上被调用的,因此 readOnlyShapes 变量就是接收者。

要创建扩展函数,请先写出你想扩展的类名,接着写一个 .,然后是函数名。之后继续写函数声明的其余部分,包括参数和返回类型。

例如:

1
2
3
4
5
6
7
fun String.bold(): String = "<b>$this</b>"

fun main() {
    // "hello" is the receiver
    println("hello".bold())
    // <b>hello</b>
}

在这个示例中:

  • String 是被扩展的类。
  • bold 是扩展函数的名称。
  • .bold() 扩展函数的返回类型是 String。
  • "hello" 是 String 的一个实例,作为接收者。
  • 在函数体内部通过关键字 this 访问接收者。
  • 使用字符串模板($)访问 this 的值。
  • .bold() 扩展函数接收一个字符串,并把它放在用于加粗文本的 HTML 元素 ** 中返回。

面向扩展的设计

你可以在任何地方定义扩展函数,这使你能够创造面向扩展的设计。这类设计把核心功能与有用但非必需的额外功能分离开来,让代码更易读、更易维护。

一个很好的例子是 Ktor 库中的 HttpClient 类,它用于执行网络请求。它的核心功能只有一个函数 request(),该函数接收一次 HTTP 请求所需的全部信息:

1
2
3
4
5
class HttpClient {
    fun request(method: String, url: String, headers: Map<String, String>): HttpResponse {
        // Network code
    }
}

实践中,最常用的 HTTP 请求是 GET 和 POST 请求。库为这些常见用法提供更简短的名字是合理的。不过它们并不需要新的网络代码,只需要一次特定的请求调用。换句话说,它们非常适合被定义为独立的 .get() 和 .post() 扩展函数:

1
2
fun HttpClient.get(url: String): HttpResponse = request("GET", url, emptyMap())
fun HttpClient.post(url: String): HttpResponse = request("POST", url, emptyMap())

这些 .get() 和 .post() 函数扩展了 HttpClient 类。它们可以直接使用 HttpClient 类中的 request() 函数,因为它们是以 HttpClient 类的实例作为接收者被调用的。你可以用这些扩展函数以合适的 HTTP 方法调用 request() 函数,从而简化代码并让它更易理解:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class HttpClient {
    fun request(method: String, url: String, headers: Map<String, String>): HttpResponse {
        println("Requesting $method to $url with headers: $headers")
        return HttpResponse("Response from $url")
    }
}

fun HttpClient.get(url: String): HttpResponse = request("GET", url, emptyMap())

fun main() {
    val client = HttpClient()

    // Making a GET request using request() directly
    val getResponseWithMember = client.request("GET", "https://example.com", emptyMap())

    // Making a GET request using the get() extension function
    // The client instance is the receiver
    val getResponseWithExtension = client.get("https://example.com")
}

这种面向扩展的方式在 Kotlin 的标准库和其他库中被广泛使用。例如,String 类就有许多扩展函数来帮助你处理字符串。

关于扩展函数的更多信息,请参阅扩展。

练习

习题 1

编写一个名为 isPositive 的扩展函数,它接收一个整数并检查它是否为正数。

1
2
3
4
5
6
fun Int.// Write your code here

fun main() {
    println(1.isPositive())
    // true
}
1
2
3
4
5
6
fun Int.isPositive(): Boolean = this > 0

fun main() {
    println(1.isPositive())
    // true
}

示例解答

习题 2

编写一个名为 toLowercaseString 的扩展函数,它接收一个字符串并返回其小写版本。

提示

对 String 类型使用 .lowercase() 函数。

1
2
3
4
5
6
fun // Write your code here

fun main() {
    println("Hello World!".toLowercaseString())
    // hello world!
}
1
2
3
4
5
6
fun String.toLowercaseString(): String = this.lowercase()

fun main() {
    println("Hello World!".toLowercaseString())
    // hello world!
}

示例解答

另请参阅

上一步

下一步