Kotlin 如何为特定泛型类型提供条件方法?
可以用带泛型约束的扩展函数,为特定类型提供方法,同时保留原响应体类型。Kotlin 不支持根据泛型参数条件启用类成员方法,因此这不是 Ok 上的条件成员方法。
保留 ResponseEntity 的具体类型
fun <B> ResponseResult.Ok<ResponseEntity<B>>.toResponseEntity(): ResponseEntity<B> = value
这个扩展函数的接收者限定为 Ok<ResponseEntity<B>>。静态类型为 ResponseResult.Ok<ResponseEntity<String>> 的值可以调用它,返回值类型也会是 ResponseEntity<String>。由于 String 等类型都是 Any 的子类,它们也适用。
如果希望扩展函数接受 T 为任意 ResponseEntity 子类型的情况,可以这样写:
fun <T : ResponseEntity<*>> ResponseResult.Ok<T>.toResponseEntity(): T = value
这个版本返回 T,因此会保留实际传入的响应类型。
为什么不能直接返回 ResponseEntity
ResponseEntity<String> 不能直接作为 ResponseEntity<Any> 返回。Kotlin 泛型默认不协变,因此 ResponseEntity 的类型参数不能安全地从 String 扩大为 Any。即使响应体类型是 Any 的子类,也不会改变这一点。
如果调用方只需要读取响应,可以将返回类型设为星投影:
fun <B> ResponseResult.Ok<ResponseEntity<B>>.toResponseEntity(): ResponseEntity<*> = value
如果调用方需要 ResponseEntity<Any>,就要明确转换方式,例如复制原响应的状态码、headers 和 body,再构造一个新响应。具体写法取决于使用的 Spring API 版本,以及 body 是否允许为 null。直接把现有对象强制转换为 ResponseEntity<Any> 会绕过泛型类型检查,不适合作为常规方案。
与密封类型分支的配合
在 when 分支中,编译器能否确认 Ok 的参数是 ResponseEntity<B>,取决于 result 的静态类型。如果它的类型只是 ResponseResult<*>,分支中的 Ok 通常也只能按星投影处理,编译器无法推断它的值一定是 ResponseEntity。这时需要在类型设计或调用处提供足够的类型信息,或者显式检查并处理运行时类型。
备注:内容仅供参考。
