假设:
val sets = listOf(setOf(1, 2, 3), setOf(2, 3, 4), setOf(3, 4, 5))
为什么在Kotlin 1.2中这是非法的?
val unionOfSets = sets.reduce(Set<Int>::union) // == setOf(1, 2, 3, 4, 5)
这不应该吗?
val unionOfSets = sets.reduce { acc, set -> acc.union(set) }
来自https://kotlinlang.org/docs/reference/lambdas.html:
带有和不带有接收器的功能类型的非文字值可以互换,因此接收器可以代表第一个参数,反之亦然。例如,可以在期望A.(B)-> C的地方传递或分配类型(A,B)-> C的值,反之亦然
答案 0 :(得分:3)
Kotlin似乎没有在接收器上成功进行类型推断,这可能是由于所有模板所致(Kotlin对类型没有任何保证)。
但是您可以通过将引用传递给invoke可调用对象来解决:
fun main(args: Array<String>) {
val sets = listOf(setOf(1,2,3), setOf(4,5,6), setOf(7,8,9))
val unionOfSets = sets.reduce(Set<Int>::union::invoke)
println(unionOfSets)
}
更新:这是sets.reduce(Set :: union)不起作用的原因
科特琳使用智能投射来解析接收者(请参阅第https://github.com/JetBrains/kotlin/blob/143c3ccb95f93299233ade88c24b2fa2b9b29abf/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt行第553页)
但是,只有在文档(https://kotlinlang.org/docs/reference/typecasts.html#smart-casts)中提到的类型可以保证的情况下,智能转换才能起作用:
请注意,当编译器无法保证变量不能在检查和用法之间更改时,智能强制转换将不起作用。
编译器尝试(通过智能强制转换)找到正确的接收者,但无法做到这一点,因为编译器无法保证acc变量不能更改。这是由于嵌套的泛型:您有一个List<Set<Int>>
,它将在运行时为List<*>
。
这就是为什么我们可以改用invoke的原因。调用是在构建时生成的一种运算符方法,将是安全类型(无需智能强制转换)。