在 Kotlin 1.5 中收集流时结果嵌套两次(kotlin.Result 无法转换为 `Type`)
Result nested twice when collecting a Flow in Kotlin 1.5 (kotlin.Result cannot be cast to `Type`)
最近我将我的项目更新为 Kotlin 1.5 并注意到将 Flow
与 Result
组合时出现一些奇怪的意外行为。考虑以下示例:
// Kotlin 1.5.0
// Coroutines (kotlinx-coroutines-core) 1.5.0
class Foo
interface FooListener {
fun onSuccess(foo: Foo)
fun onFailure(error: Throwable?)
}
suspend fun collectData(listener: FooListener) {
flow { emit(Result.success(Foo())) }
.collect { result -> // for reference
when {
result.isSuccess -> listener.onSuccess(result.getOrThrow())
result.isFailure -> listener.onFailure(result.exceptionOrNull())
}
}
}
fun main() {
runBlocking {
collectData(object : FooListener {
override fun onSuccess(foo: Foo) {
println(foo)
}
override fun onFailure(error: Throwable?) {
println(error)
}
})
}
}
以上编译但在运行时失败:
Exception in thread "main" java.lang.ClassCastException: kotlin.Result cannot be cast to Foo
经过一些调试后,我注意到收集的值 (result
) 似乎是 Result<Result<Foo>>
类型,而不是预期的 Result<Foo>
:
suspend fun collectData(listener: FooListener) {
flow { emit(Result.success(Foo())) }
.collect { result ->
println(result) // Output: Success(Success(Foo@...))
when {
result.isSuccess -> listener.onSuccess(result.getOrThrow())
result.isFailure -> listener.onFailure(result.exceptionOrNull())
}
}
}
当我放弃在 collectData
中使用外部提供的侦听器或回调函数的想法时,问题就消失了,例如,使用全局定义的东西:
class Foo
interface FooListener {
fun onSuccess(foo: Foo)
fun onFailure(error: Throwable?)
}
val listener = object : FooListener {
override fun onSuccess(foo: Foo) {
println(foo)
}
override fun onFailure(error: Throwable?) {
println(error)
}
}
suspend fun collectData() {
flow { emit(Result.success(Foo())) }
.collect { result ->
println(result) // Output: Success(Foo@...)
when {
result.isSuccess -> listener.onSuccess(result.getOrThrow())
result.isFailure -> listener.onFailure(result.exceptionOrNull())
}
}
}
fun main() {
runBlocking {
collectData()
}
}
以上运行没有任何错误。
在我看来,这似乎是语言中的一个错误,但我已经关注这个问题很长时间了,我不是 100% 确定,在将它提交到 Kotlin YouTrack 之前我可以征求第二意见.
我已经看到了 Why does Kotlin crash passing generic Result parameter? and JVM / IR: ClassCastException with Result object when it is used by a generic method in a suspend call 但是这个错误不仅看起来是相反的,而且应该也会在最新版本中修复。
我有同样的问题我将 kotlin 版本从 1.5.10
降级到 1.4.32
并且代码 运行 正确。
这在 https://youtrack.jetbrains.com/issue/KT-46915 中进行了跟踪,看起来修复将与 Kotlin 1.5.30
一起发布
最近我将我的项目更新为 Kotlin 1.5 并注意到将 Flow
与 Result
组合时出现一些奇怪的意外行为。考虑以下示例:
// Kotlin 1.5.0
// Coroutines (kotlinx-coroutines-core) 1.5.0
class Foo
interface FooListener {
fun onSuccess(foo: Foo)
fun onFailure(error: Throwable?)
}
suspend fun collectData(listener: FooListener) {
flow { emit(Result.success(Foo())) }
.collect { result -> // for reference
when {
result.isSuccess -> listener.onSuccess(result.getOrThrow())
result.isFailure -> listener.onFailure(result.exceptionOrNull())
}
}
}
fun main() {
runBlocking {
collectData(object : FooListener {
override fun onSuccess(foo: Foo) {
println(foo)
}
override fun onFailure(error: Throwable?) {
println(error)
}
})
}
}
以上编译但在运行时失败:
Exception in thread "main" java.lang.ClassCastException: kotlin.Result cannot be cast to Foo
经过一些调试后,我注意到收集的值 (result
) 似乎是 Result<Result<Foo>>
类型,而不是预期的 Result<Foo>
:
suspend fun collectData(listener: FooListener) {
flow { emit(Result.success(Foo())) }
.collect { result ->
println(result) // Output: Success(Success(Foo@...))
when {
result.isSuccess -> listener.onSuccess(result.getOrThrow())
result.isFailure -> listener.onFailure(result.exceptionOrNull())
}
}
}
当我放弃在 collectData
中使用外部提供的侦听器或回调函数的想法时,问题就消失了,例如,使用全局定义的东西:
class Foo
interface FooListener {
fun onSuccess(foo: Foo)
fun onFailure(error: Throwable?)
}
val listener = object : FooListener {
override fun onSuccess(foo: Foo) {
println(foo)
}
override fun onFailure(error: Throwable?) {
println(error)
}
}
suspend fun collectData() {
flow { emit(Result.success(Foo())) }
.collect { result ->
println(result) // Output: Success(Foo@...)
when {
result.isSuccess -> listener.onSuccess(result.getOrThrow())
result.isFailure -> listener.onFailure(result.exceptionOrNull())
}
}
}
fun main() {
runBlocking {
collectData()
}
}
以上运行没有任何错误。
在我看来,这似乎是语言中的一个错误,但我已经关注这个问题很长时间了,我不是 100% 确定,在将它提交到 Kotlin YouTrack 之前我可以征求第二意见.
我已经看到了 Why does Kotlin crash passing generic Result parameter? and JVM / IR: ClassCastException with Result object when it is used by a generic method in a suspend call 但是这个错误不仅看起来是相反的,而且应该也会在最新版本中修复。
我有同样的问题我将 kotlin 版本从 1.5.10
降级到 1.4.32
并且代码 运行 正确。
这在 https://youtrack.jetbrains.com/issue/KT-46915 中进行了跟踪,看起来修复将与 Kotlin 1.5.30
一起发布