Kotlin-推断两个泛型参数之一的类型



我正在尝试创建一个具有两种泛型类型的函数:一种是具体化的,另一种是从其使用上下文派生的(因为它是一个扩展函数(:

inline fun <reified E, A> Either<Throwable, A>.bypassLeft(transformation: Throwable.() -> A): Either<Throwable, A> =
when (this) {
is Either.Left -> when (value) {
is E -> value.transformation().right()
else -> this
}
else -> this
}

这个想法是调用只提到具体类型的函数,比如:

a.bypassLeft<NoResultException> { "" }

其中";a";是类型为"或者<可抛出,字符串>

但是编译器不允许我放弃它,并要求我指定两种泛型类型,而不是从调用函数的对象派生第二种类型。这似乎是一件很合理的事情,但也许我错了。。。

这有可能实现吗?如果是,我做错了什么?

从Kotlin v1.7.0开始,使用下划线运算符就可以实现这一点。

下划线运算符_可以用于类型参数。当显式指定其他类型时,使用它可以自动推断参数的类型:

interface Foo<T>
fun <T, F : Foo<T>> bar() {}
fun baz() {
bar<_, Foo<String>>() // T = String is inferred
}

在你的例子中,它可能是这样的:

a.bypassLeft<NoResultException, _> { "" }

当前函数不可能赋予单个类型参数,而让另一个参数推断。如果键入lambda参数,则可以通过将实现更改为不使用接收器类型来实现所需的内容。

我在那里添加了一个额外的impl,它显示了类型args如何也可以部分应用于类或其他周围的作用域。

import arrow.core.Either
import arrow.core.right
inline fun <reified E : Throwable, A> Either<Throwable, A>.bypassLeft(
transformation: (E) -> A //changed to regular arg not receiver
): Either<Throwable, A> =
when (this) {
is Either.Left -> when (val v = value) { //name locally for smart cast
is E -> transformation(v).right()
else -> this
}
else -> this
}
class Catch<A>(val f: () -> A) { //alternative impl with partial type app
inline fun <reified E : Throwable> recover(
recover: (E) -> A
): Either<Throwable, A> =
Either.catch(f).fold(
{
if (it is E) Either.Right(recover(it))
else Either.Left(it)
},
{
Either.Right(it)
}
)
}
suspend fun main() {
val x: Either<Throwable, Int> = Either.Left(StackOverflowError())
val recovered = x.bypassLeft { 
s: StackOverflowError -> //here infers E
0 // here infers A
}
println(recovered) // Either.Right(0)
val notRecovered: Either<Throwable, Int> =
Catch {
throw NumberFormatException()
1
}.recover<StackOverflowError> { 0 }
println(notRecovered) // Either.Left(java.lang.NumberFormatException)
}

相关内容

  • 没有找到相关文章

最新更新