Kotlin使用泛型时如何防止隐式向上转型为Any的类型转换?
解决方案
方案1:双泛型约束(推荐,无兼容性风险)
直接修改函数定义,拆分泛型约束,让编译器优先识别接收者的元素类型:
fun <T, R : T> Iterable<T>.find2(elem: R) = this.find { it == elem }
原理说明
原来的单泛型写法中,编译器会同时参考接收者类型和参数类型,推导两者的最小公共超类型作为泛型实参,Int和String的公共超类型为Any,因此调用不会报错。
拆分泛型后,T的类型完全由接收者Iterable<T>的实际元素类型决定,参数的类型R被约束为必须是T的子类型,编译器会先确定T的类型再校验参数类型是否符合要求,不会主动向上推导公共超类型规避类型校验。
效果验证
- 合法调用正常编译:
listOf(1, 2, 3).find2(2) - 非法调用直接触发编译错误:
listOf(1, 2, 3).find2("foo")会提示类型不匹配,String不属于Int的子类型
方案2:使用@InputTypes注解
如果你不想拆分泛型,可以使用Kotlin内部提供的@InputTypes注解,直接标记泛型优先从接收端推导:
import kotlin.internal.InputTypes fun <@InputTypes T> Iterable<T>.find2(elem: T) = this.find { it == elem }
注意事项
该注解属于Kotlin内部API,标准库中contains等函数均使用该注解实现同类类型校验,但不排除后续版本调整的可能,兼容性略低于方案1。
内容的提问来源于stack exchange,提问作者Aleksandar Stefanović
相关产品推荐
相关产品推荐

