You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中protected成员扩展的with调用失效问题及解决办法咨询

Kotlin protected成员扩展方法委托调用失效问题分析与解决

问题场景

在自定义Jetpack Compose的Painter装饰器时,试图通过with(delegate)调用委托对象的onDraw方法,却意外触发了自身的onDraw实现;后续用StringPrinter的示例验证发现,当把抽象扩展方法设为protected后,委托调用完全失效,而public状态下一切正常。

核心原因

Kotlin的成员扩展方法本质上绑定到宿主类,当方法标记为protected时,其可见性被限制在类及子类内部:

  • 当在子类中使用with(delegate)时,代码块上下文虽为delegate实例,但编译器会优先匹配子类自身override的protected扩展方法(因为子类可访问该方法),而非委托对象的实现。
  • 若扩展方法是public,编译器会优先匹配上下文对象(delegate)的实现,因为此时方法可见性是全局的,不会被子类的override覆盖上下文调用。

解决方案

1. 针对自定义Painter场景

Compose的Painter.onDraw是DrawScope的扩展成员方法,直接通过显式传入DrawScope上下文调用委托对象的onDraw即可:

class MyPainter(private val delegate: Painter) : Painter() {

    override fun DrawScope.onDraw() {
        // 直接传入当前DrawScope,调用委托对象的onDraw
        delegate.onDraw(this)
        // 后续添加自定义绘制逻辑
        drawCircle(Color.Blue, radius = 30f)
    }

    override val intrinsicSize: Size get() = delegate.intrinsicSize
}

2. 针对StringPrinter类场景

方案一:替换为普通成员方法(推荐)

放弃扩展方法,改用普通成员方法避免作用域混淆:

abstract class StringPrinter {
    protected abstract fun printString(value: String)
    fun print(value: String) = printString(value)
}

class StringConsolePrinter : StringPrinter() {
    override fun printString(value: String) {
        println(value)
    }
}

class StringBackwardsPrinter(private val delegate: StringPrinter) : StringPrinter() {
    override fun printString(value: String) {
        delegate.printString(value.reversed())
    }
}

方案二:显式指定扩展方法的宿主对象

若必须保留扩展方法,可通过Kotlin成员扩展方法的编译本质(静态方法,第一个参数为宿主实例)显式调用:

class StringBackwardsPrinter(private val delegate: StringPrinter) : StringPrinter() {
    override fun String.getPrinted() {
        // 显式指定宿主为delegate,调用其扩展方法
        delegate.run { reversed().getPrinted() }
    }
}

内容的提问来源于stack exchange,提问作者Jezor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 19:27:44