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

在Kotlin中实现右偏Either类型时的协变类型问题

解决方法

错误的核心原因是:L被声明为out协变类型,但在flatMap的参数f的返回类型Either<L, R2>中,L处于逆变位置——函数类型(R) -> Either<L, R2>对于L是逆变的,而协变类型参数不允许出现在逆变位置。

以下是两种仅通过类型调整解决问题的方案,无需外部函数或when语句:

方案一:将f的返回类型声明为Either<out L, R2>

通过在f的返回类型中给L添加out修饰,明确允许返回L的子类类型的Either,避免L出现在逆变位置:

sealed class Either<out L, out R> {
    abstract fun isLeft(): Boolean
    abstract fun isRight(): Boolean

    // 修改flatMap的参数f的返回类型为Either<out L, R2>
    abstract fun <R2> flatMap(f: (R) -> Either<out L, R2>): Either<L, R2>

    fun <R2> map(f: (R) -> R2): Either<L, R2> = flatMap { Right(f(it)) }
}

data class Left<L>(val l: L): Either<L, Nothing>() {
    override fun isLeft(): Boolean = true
    override fun isRight(): Boolean = false

    override fun <R2> flatMap(f: (Nothing) -> Either<out L, R2>): Either<L, R2> = this
}

data class Right<R>(val r: R): Either<Nothing, R>() {
    override fun isLeft(): Boolean = false
    override fun isRight(): Boolean = true

    override fun <R2> flatMap(f: (R) -> Either<out Nothing, R2>): Either<Nothing, R2> = f(r)
}

方案二:引入新的逆变类型参数L2

通过声明一个新的类型参数L2并限制它为L的子类,让f返回Either<L2, R2>,而flatMap的返回类型保持Either<L, R2>(利用L的协变性,Either<L2, R2>可安全转换为Either<L, R2>):

sealed class Either<out L, out R> {
    abstract fun isLeft(): Boolean
    abstract fun isRight(): Boolean

    // 新增L2类型参数,限制为L的子类
    abstract fun <L2 : L, R2> flatMap(f: (R) -> Either<L2, R2>): Either<L, R2>

    fun <R2> map(f: (R) -> R2): Either<L, R2> = flatMap { Right(f(it)) }
}

data class Left<L>(val l: L): Either<L, Nothing>() {
    override fun isLeft(): Boolean = true
    override fun isRight(): Boolean = false

    override fun <L2 : L, R2> flatMap(f: (Nothing) -> Either<L2, R2>): Either<L, R2> = this
}

data class Right<R>(val r: R): Either<Nothing, R>() {
    override fun isLeft(): Boolean = false
    override fun isRight(): Boolean = true

    override fun <L2 : Nothing, R2> flatMap(f: (R) -> Either<L2, R2>): Either<Nothing, R2> = f(r)
}

两种方案都能保留Either的协变性,同时让flatMap的类型签名符合Kotlin的泛型规则,且不需要依赖外部函数或when语句实现逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 15:44:52