ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

kotlin 扩展函数的作用域

kotlin 扩展函数的作用域 核心规则一句话扩展函数定义在哪里决定了它在哪里可见、在哪里可调。Kotlin 里有三种定义位置作用域行为完全不同。三种定义位置① 顶层扩展——最常见到处可用// StringUtils.kt 文件顶层 fun String.shout(): String uppercase() !!! // 任何地方import 后都能调 hello.shout()② 类内扩展成员扩展——作用域受限的“特权函数”class Density { fun fontScale: Float 1f // 定义在 Density 类内部的 String 扩展 fun String.scaleByFont(): Float this.length * fontScale }关键限制成员扩展只能在这个类的内部或其子类调用with(density) { abc.scaleByFont() // ✅ this 是 Density在作用域内 } // abc.scaleByFont() // ❌ 编译错误外面解析不到这个扩展这就是为什么 minHeight.toPx() 必须包在 with(density) { } 里——toPx() 是 Density 的成员扩展出了这个作用域就不存在。③ object/companion 内扩展——只在那个对象作用域内object Validators { fun String.isValidEmail(): Boolean matches(Regex(^[\\w.-][\\w.-]$)) } with(Validators) { ab.com.isValidEmail() // ✅ }成员扩展的“双接收者”机制成员扩展同时携带两个接收者class Density { val density: Float 2.75f fun Dp.toPx(): Float { // └── extension receiverDpthis 也指向它 return value * density // └────── 这里隐式访问的是 dispatch receiver 的属性 } }两个接收者冲突时extension receiver 优先需要 dispatch receiver 时用标签限定class Outer { val size 10 fun String.f() { val ext length // String 的成员优先 val disp thisOuter.size // 显式拿 Outer 的 } }作用域如何决定“能调哪个扩展”Kotlin 解析 a.foo() 时的优先级1. 类自身/父类的成员函数 ← 永远赢过扩展 2. 当前作用域内可见的扩展 ├─ 本文件/本类内的定义 ← 就近优先 ├─ 显式 import 的扩展 └─ 同包顶层的扩展同名冲突时更内层作用域的扩展胜出fun String.info() 顶层版本 class A { fun String.info() A 内版本 fun test(s: String) { s.info() // 输出 A 内版本——内层作用域优先 } }Compose 大量利用这一点Dp.toPx()、DrawScope 里的 drawCircle()、Modifier.Node 里的各种操作——不是能力被藏起来了而是语义上必须绑定上下文。像素换算离开 Density 就没有意义编译器通过作用域强制你提供它。扩展函数没有“注入到类里”它始终是外挂的静态函数定义位置顶层 / 类内 / 对象内决定它的可见作用域其中成员扩展只能在宿主类的作用域内调用——这是 Kotlin 用作用域模拟“上下文依赖 API”的核心手法。
返回列表