# 扩展函数
在这一章中, 你将探索一些特殊的 Kotlin 函数, 它们能够让你的代码更加简洁, 更加易读. 学习这些函数能够如何帮助你使用高效的设计模式, 将你的项目提升到更高水平.
## 扩展函数
在软件开发中, 你经常需要修改一个程序的行为, 但又不能修改原来的源代码. 例如, 你可能想要向一个来自第三方库的类添加额外的功能.
你可以通过添加 扩展函数 来扩展一个类. 调用扩展函数的方式与调用类的成员函数一样, 使用点号 `.`.
在介绍扩展函数的完整语法之前, 你需要理解什么是 接受者(Receiver). 接受者(Receiver)是指函数对哪个对象调用. 换句话说, 接受者就是共享信息的来源.

在这个示例中, `main()` 函数调用 [.first()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/first.html) 函数, 得到列表中的第 1 个元素. `.first()` 函数 对 `readOnlyShapes` 变量调用, 因此 `readOnlyShapes` 变量就是接受者.
要创建扩展函数, 请写下你想要扩展的类名称, 之后是一个 `.` 号, 之后是你的函数名称. 后面是函数声明的其余部分, 包括它的参数和返回类型.
例如:
```KOTLIN
fun String.bold(): String = "$this"
fun main() {
// "hello" 是接受者
println("hello".bold())
// 输出结果为: hello
}
```
在这个示例中:
* `String` 是被扩展的类.
* `bold` 是扩展函数的名称.
* `.bold()` 扩展函数的返回类型是 `String`.
* `"hello"`, 一个 `String` 实例, 是接受者.
* 在函数的 body 部, 访问接受者时使用了 [关键字](keyword-reference.html): `this`.
* 使用了字符串模板 (`$`) 来访问 `this` 的值.
* `.bold()` 扩展函数接受一个字符串, 并将它包含在 `` HTML 元素内返回, 用于显示粗体文字.
## 面向扩展的设计
你可以在任何地方定义扩展函数, 因此可以创建面向扩展的设计. 这样的设计将核心功能与便利但并非必须的功能分离开, 让你的代码易于阅读和维护.
一个很好的例子是 Ktor 库的 [HttpClient](https://api.ktor.io/ktor-client-core/io.ktor.client/-http-client/index.html) 类, 它帮助你执行网络请求. 它的核心功能是单个函数 `request()`, 它的参数是一个 HTTP 请求需要的所有信息 :
```KOTLIN
class HttpClient {
fun request(method: String, url: String, headers: Map): HttpResponse {
// 网络代码
}
}
```
在实际运用中, 最常用的 HTTP 请求是 GET 或 POST 请求. 库为这些常见的使用场景提供更短的名称是很合理的. 但是, 不需要编写新的网络代码, 只需要特定的请求调用. 换句话说, 这些请求很适用定义为单独的 `.get()` 和 `.post()` 扩展函数:
```KOTLIN
fun HttpClient.get(url: String): HttpResponse = request("GET", url, emptyMap())
fun HttpClient.post(url: String): HttpResponse = request("POST", url, emptyMap())
```
这些 `.get()` 和 `.post()` 函数扩展了 `HttpClient` 类. 由于它们是在 `HttpClient` 类的实例上调用的, 也就是使用 `HttpClient` 类的实例作为接受者, 因此它们可以直接使用来自 `HttpClient` 类的 `request()` 函数. 你可以通过这些扩展函数, 使用适当的 HTTP 方法调用 `request()` 函数, 这样可以简化你的代码, 让代码更加易于理解:
```KOTLIN
class HttpClient {
fun request(method: String, url: String, headers: Map): 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()
// 直接使用 request(), 发起 GET 请求
val getResponseWithMember = client.request("GET", "https://example.com", emptyMap())
// 使用 get() 扩展函数, 发起 GET 请求
// client 实例是接受者
val getResponseWithExtension = client.get("https://example.com")
}
```
在 Kotlin 的 [标准库](https://kotlinlang.org/api/latest/jvm/stdlib/) 和其他库中, 大量使用了这种面向扩展的方案. 例如, `String` 类有很多 [扩展函数](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/#extension-functions) 帮助你处理字符串.
关于扩展函数, 详情请参见 [扩展](extensions.html).
## 实际练习
### 习题 1
编写一个扩展函数, 名为 `isPositive`, 接受一个整数参数, 判断它是不是正数.
```KOTLIN
fun Int.// 请在这里编写你的代码
fun main() {
println(1.isPositive())
// 输出结果为: true
}
```
```KOTLIN
fun Int.isPositive(): Boolean = this > 0
fun main() {
println(1.isPositive())
// 输出结果为: true
}
```
### 习题 2
编写一个扩展函数, 名为 `toLowercaseString`, 接受一个字符串参数, 返回它的小写形式.
提示
: 使用 `String` 类型的 [.lowercase()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/lowercase.html) 函数.
```KOTLIN
fun // 请在这里编写你的代码
fun main() {
println("Hello World!".toLowercaseString())
// 输出结果为: hello world!
}
```
```KOTLIN
fun String.toLowercaseString(): String = this.lowercase()
fun main() {
println("Hello World!".toLowercaseString())
// 输出结果为: hello world!
}
```
## See also
* [上一步](kotlin-tour-null-safety.html)
* [下一步](kotlin-tour-intermediate-scope-functions.html)