Kotlin智能转换因接口属性被禁用,除!!外还有其他解决办法吗?
解决方案:Smart cast disabled 错误处理(非
!!断言方式) 错误原因
Kotlin无法对接口的open属性做智能转换——接口属性默认是open的,子类可重写其getter方法,Kotlin无法保证你在检查request.title == null后,再次调用request.title时它不会变为null。
方案1:将属性赋值给局部变量
把接口属性赋值给局部val变量,局部变量不可变,Kotlin可以安全完成智能转换:
override fun validate(request: SendMessageRequestBase?): ValidationResult { val errors = ValidationResult() request ?: run { errors.addError(ValidationError.create("Request body is required")) return errors } val title = request.title if (title == null) { errors.addError(ValidationError.create("title (including NL title) is required")) } else if (title.nl.isNullOrEmpty()) { errors.addError(ValidationError.create("NL title is required")) } val body = request.body if (body == null) { errors.addError(ValidationError.create("body (including NL body) is required")) } else if (body.nl.isNullOrEmpty()) { errors.addError(ValidationError.create("NL body is required")) } return errors }
方案2:使用let/run作用域函数
利用作用域函数在非空分支内安全访问属性,避免重复调用接口属性:
override fun validate(request: SendMessageRequestBase?): ValidationResult { val errors = ValidationResult() request ?: run { errors.addError(ValidationError.create("Request body is required")) return errors } // 处理title逻辑 request.title?.run { if (nl.isNullOrEmpty()) { errors.addError(ValidationError.create("NL title is required")) } } ?: run { errors.addError(ValidationError.create("title (including NL title) is required")) } // 处理body逻辑 request.body?.run { if (nl.isNullOrEmpty()) { errors.addError(ValidationError.create("NL body is required")) } } ?: run { errors.addError(ValidationError.create("body (including NL body) is required")) } return errors }
方案3:修改接口为抽象类并限制属性重写
如果确定所有实现类的属性都是不可变的(比如你的数据类),可以将接口改为抽象类,把属性标记为final,让Kotlin能安全进行智能转换:
abstract class SendMessageRequestBase( final override val title: TextLocalization?, final override val body: TextLocalization?, final override val data: Map<String, String>? ) { val title: TextLocalization? val body: TextLocalization? val data: Map<String, String>? } // 数据类实现抽象类 data class SendMessageRequest( val pushId: String, override val title: TextLocalization?, override val body: TextLocalization?, override val data: Map<String, String>? ) : SendMessageRequestBase(title, body, data)
注:此方案会降低代码灵活性(接口改为抽象类),仅在无需多实现场景下使用。
内容的提问来源于stack exchange,提问作者MrAndre
相关产品推荐
相关产品推荐

