使用||判断密封接口实现类时调用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
相关产品推荐
相关产品推荐

