我正在try 在Kotlin中实现偏向正确的任一类型,并且我在平面映射声明中(而不是在实现中)遇到了协方差问题:

Type parameter L is declared as 'out' but occurs in 'in' position in type

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

    abstract fun <R2> flatMap(f: (R) -> Either<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<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<Nothing, R2>): Either<Nothing, R2> = f(r)
}

可以用打字来解决吗?我宁愿不陷入when个条款的外部功能

推荐答案

问题是Kotlin不知道如何实现抽象的flatMap方法.并不是每个现有实现都要判断它们是否是类型安全的,这本身可能是非常困难的.

例如,您可以像这样实现Either,作为附加实现.

class A {
    fun somethingSpecific() {}
}
class B

class SomethingElse: Either<A, Int>() {
    override fun isLeft() = true

    override fun isRight() = true

    override fun <R2> flatMap(f: (Int) -> Either<A, R2>): Either<A, R2> {
        val x = f(1)
        when (x) {
            is Left -> x.l.somethingSpecific()
            else -> {}
        }
        return Left(A())
    }

}

你做到了:

val x: Either<Any, Int> = SomethingElse()
val y = x.flatMap { Left(B()) }

你最终会拨打BsomethingSpecific.

无论如何,抽象方法方法都是不可能的.

改为使用通用扩展来实现flatMap:

fun <L, R, R2> Either<L, R>.flatMap(f: (R) -> Either<L, R2>): Either<L, R2> =
    when (this) {
        is Left -> this
        is Right -> f(this.r)
    }

请注意,在这里不能对SomethingElse使用相同的技巧.不能使用SomethingElse.flatMap的实现将第三个手臂添加到when,因为LR不受约束.

is SomethingElse -> {
    val x = f(1) // oops, f doesn't take an Int
    when (x) {
        is Left -> x.l.somethingSpecific() // oops, x.l is not A
        else -> {}
    }
    Left(A()) // oops, this should return Either<L, R2>, not Either<A, Nothing>
}

如果do将他们限制在AInt,你将无法在Either<Any, Int>上呼叫flatMap.

Kotlin相关问答推荐

Kotlin中的增广赋值语句中的难以理解的错误

我可以更改方法中泛型类的类型参数边界吗?

有没有什么方法或算法可以在没有存储的情况下生成唯一的随机数?

Kotlin 如何使用其 get 函数在内部检索映射值

Kotlin 函数中接收者和参数的类型相同

如何在 Compose 中创建可重用的修饰符?

如何使用 Kotlin KClass 属性 simpleName 生成空值

如何禁用智能投射突出显示 Kotlin?

在粘贴时将 java 转换为 kotlin

零安全的好处

Kotlin惰性默认属性

Android EditText 协程go 抖操作符,如 RxJava

在 suspendCoroutine 块中调用挂起函数的适当方法是什么?

如何从协程范围返回值

Kotlin扩展函数与成员函数?

Android studio 4.0 新更新版本说 Kotlin 与这个新版本不兼容

Kotlin内联属性的用例是什么?

Kotlin Flow 收集后无法执行代码

Android studio,构建kotlin时出现奇怪错误:生成错误代码

Kotlin Realm:如果类包含自定义构造函数,则必须声明一个不带参数的公共构造函数