You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Kotlin允许返回泛型为预期返回值子类型的对象?

问题分析与解决方案

首先,你的代码编译失败的核心原因是Kotlin泛型默认是不变的:即使B继承自A,Baz<B>和Baz<A>之间也不存在任何继承或兼容关系,所以无法直接将Baz<B>作为Baz<A>返回。

为什么编译器不允许自动推断?

假设允许这种隐式转换,考虑如果Baz包含可写的属性(比如var value: T),那么后续可能出现这样的操作:

val bazA: Baz<A> = doBar() // 假设允许转换
bazA.value = C() // C是A的另一个子类

此时bazA实际指向的是Baz<B>实例,却被赋值了C类型的对象,这会导致类型安全问题。为了避免这种情况,Kotlin默认禁止泛型类型的协变转换。

无需手动转换的解决方案

因为你的Baz类中value是只读的val,没有修改T类型的操作,适合将Baz定义为协变泛型:在泛型参数前添加out关键字,声明T是一个协变类型参数。

修改后的代码如下:

open class A
class B: A()

// 添加out关键字使Baz协变
class Baz<out T>(val value: T)

fun doFoo(): Baz<A> {
  return doBar() // 现在可以正常编译
}

fun doBar(): Baz<B> {
  return Baz(B())
}

这样修改后,Baz<B>会被视为Baz<A>的子类型,编译器允许隐式转换,同时完全保留类型安全性——因为协变泛型只允许对外暴露T类型的输出(比如只读属性、返回T的方法),不允许接收T类型的输入(比如var属性、参数为T的方法),从根本上避免了上述的类型安全问题。

你之前尝试将A改为接口无效,是因为问题的根源不在A的类型(类或接口),而在于Baz的泛型不变性,修改泛型的协变属性就能解决问题。

内容的提问来源于stack exchange,提问作者user2084865

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 11:08:10