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

使用||判断密封接口实现类时调用copy报Unresolved reference错误

Kotlin密封接口类型判断中copy方法报错问题

定义的密封接口:

sealed interface BusStopsDBScreenUiState {
    val message: StringResource?
    data class Loading(override val message: StringResource? = null) : BusStopsDBScreenUiState
    data class Error(override val message: StringResource? = null) : BusStopsDBScreenUiState
    data class Success(val data: List<BusStop>, override val message: StringResource? = null) : BusStopsDBScreenUiState
}

报错的条件判断代码:

if ((currentState is BusStopsDBScreenUiState.Success) || (currentState is BusStopsDBScreenUiState.Error)) {
    _uiState.value = currentState.copy(message = null)
}

问题现象:

执行上述代码时会报错:

Unresolved reference: copy

但如果移除||运算符,只保留if (currentState is BusStopsDBScreenUiState.Success)判断,copy方法调用就正常,不会报错。


原因分析:

Kotlin的智能类型转换只在编译器能明确确定变量具体类型的情况下生效。当用||同时判断两种不同的data class类型时,编译器只能推断currentState的类型是它们的共同父类BusStopsDBScreenUiState——而这个密封接口本身并没有定义copy方法,只有data class会自动生成copy方法。所以编译器找不到copy方法,就会报错。

而单独判断currentState is Success时,编译器能确定变量就是Success类型,自然能识别到它的copy方法,所以不会报错。


解决方法:

方法1:用when表达式分别处理(推荐,符合密封接口的使用场景)

密封接口的最佳实践就是用when做穷尽判断,这样编译器能准确识别每个分支的类型:

when(currentState) {
    is BusStopsDBScreenUiState.Success -> {
        _uiState.value = currentState.copy(message = null)
    }
    is BusStopsDBScreenUiState.Error -> {
        _uiState.value = currentState.copy(message = null)
    }
    else -> {} // Loading或其他状态无需处理
}

方法2:给密封接口添加抽象copy方法

在密封接口中定义抽象的copy方法,让每个data class实现(data class的自动生成copy会匹配签名,只需声明):

sealed interface BusStopsDBScreenUiState {
    val message: StringResource?
    fun copy(message: StringResource?): BusStopsDBScreenUiState

    data class Loading(override val message: StringResource? = null) : BusStopsDBScreenUiState {
        override fun copy(message: StringResource?): Loading = copy(message = message)
    }
    data class Error(override val message: StringResource? = null) : BusStopsDBScreenUiState {
        override fun copy(message: StringResource?): Error = copy(message = message)
    }
    data class Success(val data: List<BusStop>, override val message: StringResource? = null) : BusStopsDBScreenUiState {
        override fun copy(message: StringResource?): Success = copy(message = message)
    }
}

这样原来的if判断就能正常调用copy方法了,因为接口现在有了copy的定义。

方法3:拆分if判断,分别处理两种类型

把原来的逻辑拆成两个独立的if分支,让编译器在每个分支里都能智能转换类型:

if (currentState is BusStopsDBScreenUiState.Success) {
    _uiState.value = currentState.copy(message = null)
}
if (currentState is BusStopsDBScreenUiState.Error) {
    _uiState.value = currentState.copy(message = null)
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:02:12