0Pricing
Kotlin Academy · 课时

作用域扩展与伴生对象扩展

限制扩展的可见性,并为伴生对象添加扩展。

作用域扩展与伴生对象扩展 是 CoddyKit 上的免费 Kotlin Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Kotlin Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Kotlin Academy 课程共包含 4 节课。

为什么要使用作用域扩展

默认情况下,只要导入扩展,就可以在任何地方看到它。限定作用域可以将可见性限制在类、文件或上下文中,从而减少命名空间污染并提高可发现性。

文件私有扩展

在文件级别将扩展函数标记为 private,即可将其作用域限制为该文件。

private fun String.shout() = uppercase() + "!"
fun main() {
    println("hello".shout()) // HELLO!
}

内部可见性

使用 internal 将扩展限制在当前模块内,这非常适合不打算供外部使用的库内部功能。

internal fun List<Int>.sumIfPositive(): Int = filter { it > 0 }.sum()
fun main() {
    println(listOf(-1, 2, 3, -4).sumIfPositive()) // 5
}

成员扩展函数

请在类内部声明扩展,使其仅在该类的实例处于作用域内时可用。它有两个接收者:分派接收者(所属类)和扩展接收者(目标对象)。

class StringHelper(val prefix: String) {
    fun String.withPrefix() = prefix + this
    fun build(): String = "world".withPrefix() // calls extension via instance
}
fun main() {
    println(StringHelper("hello ").build()) // hello world
}

成员扩展的可见性

从分派类外部无法访问成员扩展。这对于封装很有用。

class Repo {
    fun List<Int>.allPositive() = all { it > 0 }
    fun check(xs: List<Int>) = xs.allPositive()
}
fun main() {
    val r = Repo()
    println(r.check(listOf(1, 2, 3))) // true
    // listOf(1).allPositive() // ERROR — no access
}

伴生对象上的扩展

向类的伴生对象添加扩展。对调用者来说,它看起来像静态方法,但实际位于类外部。

class Greeter {
    companion object
}
fun Greeter.Companion.morning() = "Good morning!"
fun main() {
    println(Greeter.morning())
}

为什么使用伴生对象扩展

这对于从原始类外部添加工厂方法或辅助函数很有用,而且无需修改原始类。

class User(val name: String) {
    companion object
}
fun User.Companion.guest() = User("Guest")
fun User.Companion.system() = User("System")
fun main() {
    println(User.guest().name)
    println(User.system().name)
}

必须存在空的伴生对象

类必须声明一个伴生对象(即使它为空),伴生对象扩展才能附加到它上面。否则,扩展目标不存在。

class Box {
    companion object // required, even if empty
}
fun Box.Companion.create(): Box = Box()
fun main() {
    println(Box.create())
}

通过导入限定扩展作用域

您可以只在特定文件中导入扩展,从而限定其使用范围。不导入它的文件无法看到它。

// File A:
// fun String.shout() = uppercase()
// File B imports:
// import com.example.shout
// Only File B can call shout()
fun String.shout() = uppercase() + "!"
fun main() { println("hi".shout()) }

通过作用域函数使用扩展函数

使用 with 或 apply,可以临时将对象引入作用域以使用扩展。

class StringTools {
    fun String.greet() = "Hello, $this!"
    fun process(name: String) = with(this) {
        name.greet()
    }
}
fun main() {
    println(StringTools().process("Ada"))
}

伴生对象上的扩展属性

伴生对象扩展也可以是属性——从类外部添加命名常量。

class HttpStatus {
    companion object
}
val HttpStatus.Companion.OK_CODE: Int get() = 200
val HttpStatus.Companion.NOT_FOUND: Int get() = 404
fun main() {
    println(HttpStatus.OK_CODE)
    println(HttpStatus.NOT_FOUND)
}

最佳实践

使用 private 定义文件级辅助函数,使用 internal 定义仅限模块使用的 API,使用成员扩展实现封装,并使用伴生对象扩展从外部添加工厂式辅助函数。

class StringUtils {
    companion object
}
fun StringUtils.Companion.isAlpha(s: String) = s.all { it.isLetter() }
fun main() {
    println(StringUtils.isAlpha("hello"))
    println(StringUtils.isAlpha("hi5"))
}

快速检查

要从外部为某个类添加伴生对象扩展,该类必须具备什么?

回顾

在类内部使用 private、internal 或成员扩展限制扩展的作用域。从外部为类添加伴生对象扩展(函数或属性)时,应将其附加到该类声明的伴生对象上。这样可以减少命名空间污染,同时保持代码模块化。

常见问题解答

「作用域扩展与伴生对象扩展」课时是免费的吗?

是的 — 「作用域扩展与伴生对象扩展」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Kotlin Academy 课程的其余内容,请升级到 CoddyKit PRO。 Kotlin Academy 课程共包含 4 节课。

「作用域扩展与伴生对象扩展」这节课中我会学到什么?

限制扩展的可见性,并为伴生对象添加扩展。 你通过在浏览器中直接运行的动手代码来练习 Kotlin Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Kotlin Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Kotlin Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「作用域扩展与伴生对象扩展」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Kotlin Academy 课中编写并运行代码吗?

能。每节 Kotlin Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 扩展函数:语法与分派规则
  2. 扩展属性与计算扩展
  3. 作用域扩展与伴生对象扩展
  4. 实用扩展:Context、View 与 String 辅助函数
← 返回 Kotlin Academy