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

为何Kotlin密封类JsonValue的构造参数要使用out T?

为什么Kotlin中JsonValue密封类要用out T而不是in T?

先纠正一个关键误区:协变(out)和逆变(in)的规则是针对类的对外成员接口(比如成员函数、属性的读写),而不是构造器参数。构造器是创建实例时的初始化逻辑,不属于类对外暴露的可调用接口,所以它接收T类型参数这件事,和协变的规则不冲突。

先看代码里的核心需求

在main函数中,我们把JsonValue<String>、JsonValue<Number>这些不同泛型参数的子类实例,赋值给了JsonValue<Any?>类型的变量pi。这种泛型类型的向上转型,正是out T带来的协变能力:当类声明为out T时,JsonValue<String>会被视为JsonValue<Any?>的子类型(因为String是Any?的子类型),这样赋值才合法。

如果换成in T(逆变),情况会完全相反:JsonValue<Any?>会成为JsonValue<String>的子类型,这时候你根本不能把JsonValue<String>赋值给JsonValue<Any?>的变量,这就是为什么替换后编译失败的原因。

再拆解out T的真实含义

out T的本质是标记这个类是T类型的生产者:它对外暴露的接口只会输出T(比如返回T、提供只读的T类型属性),不会输入T(比如没有接收T作为参数的成员函数、没有可写的T类型属性)。

回到你的代码:

  • val value: T是只读属性,对外提供的是一个返回T类型值的getter,属于“输出T”,完全符合out T的要求。
  • 构造器接收T参数只是初始化这个只读属性,不是类对外的可调用接口,所以不受out规则的限制——协变管的是类创建后能做什么,不是创建时需要什么。

为什么不能用in T

in T标记类是T类型的消费者:它对外暴露的接口只会输入T(比如接收T作为参数的成员函数),不会输出T。如果给JsonValue用in T,意味着这个类应该是接收T类型数据来处理,而不是对外提供T类型数据,这和代码里JsonValue存储并对外提供value的定位完全不符,同时也破坏了main函数中需要的向上转型能力。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 19:05:24