【问题标题】:Kotlin and RxJava - Why is my Single.zip() not compiling?Kotlin 和 RxJava - 为什么我的 Single.zip() 没有编译?
【发布时间】:2017-03-06 21:33:11
【问题描述】:

我有点疯了。我正在尝试创建一个 Observable<BigDecimal> 扩展函数(针对 RxJava 2.x)来发出平均排放量,但我在使用 Single.zip() 函数时遇到了编译错误。有人知道我做错了什么吗?我也试图对我所有的类型都明确表示,但这没有用......

import io.reactivex.Observable
import io.reactivex.Single
import java.math.BigDecimal


fun Observable<BigDecimal>.sum() = reduce { total, next -> total + next }

//compile error
fun Observable<BigDecimal>.average() = publish().autoConnect(2).let {
    Single.zip(it.sum().toSingle(), it.count()) {
        sum, count -> sum / BigDecimal.valueOf(count)
    }
}

【问题讨论】:

  • 询问错误时,发布错误。
  • 本来打算做的但是忘记了,以后会更新以供其他人参考。
  • 错误是什么??
  • 在上方添加屏幕剪辑并弹出错误消息。

标签: rx-java kotlin


【解决方案1】:

类型推断大多不适用于 rxJava2。这实际上不是类型推断问题。 Kotlin 通常会生成将 SAM 替换为 kotlin 函数类型的扩展方法,但由于某种原因,此技术不适用于被覆盖的方法。

更多详情在这里https://youtrack.jetbrains.com/issue/KT-13609

作为一种选择,您可以尝试为 lambda 参数指定类型

fun Observable<BigDecimal>.average() = publish().autoConnect(2).let {
    Single.zip(it.sum().toSingle(), it.count(), BiFunction {
        sum: BigDecimal, count: Long ->
        sum / BigDecimal.valueOf(count)
    })
}

【讨论】:

  • 谢谢,回答 Stepan,因为它可以最大化推理。
  • 如果我在 zip 中有三个或更多单曲怎么办,BiFunction 似乎不起作用,因为它只需要两个
  • @IzzoObella,在这种情况下,您需要使用 Function3 而不是 BiFunction
  • 没关系,我通过使用 RxKotlin 得到了一个解决方案,它有一个扩展功能
  • 不错。写出包括这样的泛型在内的整个 BiFunction 声明看起来要干净得多。 BiFunction>{ a, b -> Pair(a,b)})
【解决方案2】:

类型推断由于某种原因失败了,必须以某种方式在此上下文中推断出多种类型的组合。

您可以使用更传统(不幸的是更冗长)的语法显式指定类型,如下所示:

fun Observable<BigDecimal>.average() = publish().autoConnect(2).let {
    Single.zip(it.sum().toSingle(), it.count(), BiFunction<BigDecimal, Long, BigDecimal> {
        sum, count ->
        sum / BigDecimal.valueOf(count)
    })
}

更新:

我刚刚在处理类似问题时发现,这里的实际问题是 Kotlin 无法推断您尝试调用哪个 Single.zip 重载。来自official documentation

如果 Java 类有多个采用函数式接口的方法, 您可以使用适配器功能选择您需要调用的那个 将 lambda 转换为特定的 SAM 类型。那些适配器功能 编译器也会在需要的时候生成。

所以事实证明,使用更明确的 SAM 构造函数本身就解决了这个问题,并为您提供类型推断(基本上,我之前的回答是使用比实际需要的更长的语法):

fun Observable<BigDecimal>.average(): Single<BigDecimal> = publish().autoConnect(2).let {
    Single.zip(it.sum().toSingle(), it.count(), BiFunction {
        sum, count ->
        sum / BigDecimal.valueOf(count)
    })
}

【讨论】:

  • Ew... 好的,我明天运行它,如果它有效,我会跟进。如果这不能被推断,那是不幸的。
  • 嘿,我刚刚用更好的解决方案更新了我的答案。
【解决方案3】:

如果类型推断是问题,您可以做的一件事是使用RxKotlin

implementation "io.reactivex.rxjava2:rxkotlin:$rxKotlinVersion"

RxKotlin 专门提供 SAM helpers 来帮助缓解类型推断问题。

在这种情况下,

Singles.zip(..., ...)

将能够正常工作而没有任何歧义。注意我使用的是Singles 而不是Single

【讨论】:

  • 如果我不知道单身人士的数量(将他们放在列表中),是否可以使用Singles.zip(..., ...)
  • @Micer 我想我需要更多的上下文,这听起来像是有必要提出自己的问题
  • 我有 N 个 url,我需要进行 N 个网络调用并合并结果。我创建了单曲并将它们放入列表中。我不能使用Singles.zip(..., ...),因为它接受确切数量的单个对象。我终于通过使用来自 RxJava2 库的&lt;T, R&gt; Single&lt;R&gt; zip(final Iterable&lt;? extends SingleSource&lt;? extends T&gt;&gt; sources, Function&lt;? super Object[], ? extends R&gt; zipper) 解决了它。不管怎么说,还是要谢谢你。 ;-)
猜你喜欢
  • 1970-01-01
  • 2016-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 2022-11-27
  • 1970-01-01
相关资源
最近更新 更多