Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

扩展函数

假设你发现了一个几乎能满足你所有需求的库,但如果它再多提供一个或两个额外的成员函数,就能完美解决你的问题。

但这并不是你的代码,要么你无法访问源代码,要么你无法控制它。每当新版本发布时,你都必须重复进行修改。

Kotlin 的扩展函数可以有效地向现有类添加成员函数。你所扩展的类型被称为 接收者。要定义一个扩展函数,你需要在函数名之前加上接收者类型:

fun ReceiverType.extensionFunction() { ... }

这将为String类添加两个扩展函数:

// ExtensionFunctions/Quoting.kt
package extensionfunctions
import atomictest.eq

fun String.singleQuote() = "'$this'"
fun String.doubleQuote() = "\"$this\""

fun main() {
  "Hi".singleQuote() eq "'Hi'"
  "Hi".doubleQuote() eq "\"Hi\""
}

您可以像调用类成员一样调用扩展函数。

要使用来自另一个包的扩展函数,您必须先导入它们:

// ExtensionFunctions/Quote.kt
package other
import atomictest.eq
import extensionfunctions.doubleQuote
import extensionfunctions.singleQuote

fun main() {
  "Single".singleQuote() eq "'Single'"
  "Double".doubleQuote() eq "\"Double\""
}

您可以使用关键字 this 访问成员函数或其他扩展函数。与类内部一样,您也可以省略 this 关键字,因此无需显式限定:

// ExtensionFunctions/StrangeQuote.kt
package extensionfunctions
import atomictest.eq

// Apply two sets of single quotes:
fun String.strangeQuote() =
  this.singleQuote().singleQuote()  // [1]

fun String.tooManyQuotes() =
  doubleQuote().doubleQuote()       // [2]

fun main() {
  "Hi".strangeQuote() eq "''Hi''"
  "Hi".tooManyQuotes() eq "\"\"Hi\"\""
}
  • [1] this 指的是 String 接收器。
  • [2] 我们省略了第一个 doubleQuote() 函数调用的接收器对象(this)。

创建自己类的扩展有时可以产生更简洁的代码:

// ExtensionFunctions/BookExtensions.kt
package extensionfunctions
import atomictest.eq

class Book(val title: String)

fun Book.categorize(category: String) =
  """title: "$title", category: $category"""

fun main() {
  Book("Dracula").categorize("Vampire") eq
    """title: "Dracula", category: Vampire"""
}

categorize() 内部,我们可以直接访问 title 属性,无需显式限定。

请注意,扩展函数只能访问被扩展类型的 public 元素。因此,扩展函数只能执行与普通函数相同的操作。您可以将 Book.categorize(String) 重写为 categorize(Book, String)。使用扩展函数的唯一原因是语法,但这种语法糖非常强大。对于调用代码而言,扩展函数看起来与成员函数相同,而且IDE在列出对象可调用的函数时会显示扩展函数。

练习和解答可以在 www.AtomicKotlin.com 找到。