Kotlin泛型子类传入ListRunner时的类型不匹配问题
Kotlin泛型接口列表参数兼容问题解决
我定义了一个带泛型的接口,单类扩展功能运行正常,但无法将该接口子类的列表作为参数传入目标类。
可正常运行的代码如下:
interface Runnable class FirstRunnable : Runnable class SecondRunnable : Runnable interface Runner<in T> where T : Runnable { fun run(runnable: T) } class FirstRunner : Runner<FirstRunnable> { override fun run(runnable: FirstRunnable) = println("first runner") } class SecondRunner : Runner<SecondRunnable> { override fun run(runnable: SecondRunnable) = println("second runner") }
问题出在以下代码块:
class ListRunner(private val runners: List<Runner<Runnable>>) val runner = ListRunner(listOf(FirstRunner(), SecondRunner()))
此时编译器报错:
Type mismatch. Required: List<Runner<Runnable>> Found: List<Runner<{FirstRunnable & SecondRunnable}>>
需求是将该列表注入ListRunner,实现一次性运行所有runner,且每个runner内部有规则确保只处理可接受的Runnable实例。
解决方案
结合两位答主的建议,最终解决方案如下:
步骤1:为ListRunner的泛型添加out协变
正如Nishant Jalan指出,需要修改ListRunner的参数类型,添加out关键字实现协变:
class ListRunner(private val runners: List<Runner<out Runnable>>)
步骤2:为Runner接口的方法参数添加@UnsafeVariance注解
正如Sweeper所说:
向其中传入任何内容都是不安全的。Kotlin类型系统会通过提示run方法接受Nothing类型来告知这一点。
因此需要为Runner接口的run方法参数添加@UnsafeVariance注解:
interface Runner<in T> where T : Runnable { fun run(runnable: @UnsafeVariance T) }
注意:@UnsafeVariance仅用于抑制编译器的类型安全报错,本身存在潜在的类型不安全风险。但如果业务中已有前置验证逻辑,能确保Runnable实例被传入正确的runner处理,则可以安全使用此方案。
内容的提问来源于stack exchange,提问作者Thiago Cordeiro
相关产品推荐
相关产品推荐

