如何定义Kotlin扩展函数限制可空与非空类型的调用?
Kotlin 限制扩展函数仅适用于可空/非空类型
问题场景
希望实现两个扩展函数,使得以下代码中标记的两处调用无法通过编译:
fun f(nullString: String?, nonNullString: String) { nullString.ext() // 预期错误:非空扩展不能直接用在可空接收者上 nullString.nullExt() // 正常:可空扩展匹配可空接收者 nonNullString.ext() // 正常:非空扩展匹配非空接收者 nonNullString.nullExt() // 预期错误:可空扩展不能用在非空接收者上 }
当前写法仅能实现第一处报错,最后一处因String是String?的子类型仍可编译:
fun String.ext(): Unit = TODO() fun String?.nullExt(): Unit = TODO()
解决方案
通过泛型约束结合Nothing?,可以让nullExt仅对String?类型生效,同时拒绝非空String:
fun String.ext(): Unit = TODO() // 泛型约束限定T必须是String?,且同时是Nothing?的子类型 fun <T : String?> T.nullExt(): Unit where T : Nothing? = TODO()
原理说明
Nothing?是Kotlin中所有可空类型的父类型,但只有null是它的唯一实例。- 当接收者为
String?时,编译器可以推导出T为String?,满足T : String?和T : Nothing?的双重约束,因此可以正常调用。 - 当接收者为非空
String时,String并非Nothing?的子类型,无法满足约束条件,编译器会报错找不到匹配的扩展函数。
验证效果
使用上述定义后:
nullString.ext():因String?无法直接调用String的非空扩展,必须使用安全调用?.或非空断言!!.,编译报错。nonNullString.nullExt():非空String不满足泛型约束,编译报错。- 其余两处调用均正常通过编译,完全符合需求。
内容的提问来源于stack exchange,提问作者TWiStErRob
相关产品推荐
相关产品推荐

