简体   繁体   English

在reduce()中使用扩展函数引用

[英]Using extension function reference inside reduce()

Suppose: 假设:

val sets = listOf(setOf(1, 2, 3), setOf(2, 3, 4), setOf(3, 4, 5))

Why is this illegal in Kotlin 1.2? 为什么这在Kotlin 1.2中是非法的?

val unionOfSets = sets.reduce(Set<Int>::union)  // == setOf(1, 2, 3, 4, 5)

Shouldn't it be equivalent to this? 它不应该等同于此吗?

val unionOfSets = sets.reduce { acc, set -> acc.union(set) }

From https://kotlinlang.org/docs/reference/lambdas.html : 来自https://kotlinlang.org/docs/reference/lambdas.html

Non-literal values of function types with and without receiver are interchangeable, so that the receiver can stand in for the first parameter, and vice versa. 具有和不具有接收器的功能类型的非文字值是可互换的,因此接收器可以代表第一个参数,反之亦然。 For instance, a value of type (A, B) -> C can be passed or assigned where a A.(B) -> C is expected and the other way around 例如,类型(A,B) - > C的值可以传递或分配,其中A.(B) - > C是预期的,反之亦然

It appears that Kotlin doesn't do type inference successfully on the receiver, maybe because of all the templates (Kotlin doesn't have any guarantee on types). 似乎Kotlin没有在接收器上成功进行类型推断,可能是因为所有模板(Kotlin对类型没有任何保证)。

But you can work around it by passing a reference to the invoke callable instead : 但是你可以通过传递对调用callable的引用来解决它:

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)
}

Update : Here is the reason why sets.reduce(Set::union) doesn't work 更新 :这就是sets.reduce(Set :: union)不起作用的原因

Kotlin use a smart cast to resolve receivers (cf. https://github.com/JetBrains/kotlin/blob/143c3ccb95f93299233ade88c24b2fa2b9b29abf/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt at line 553) Kotlin使用智能演员来解析接收器(参见https://github.com/JetBrains/kotlin/blob/143c3ccb95f93299233ade88c24b2fa2b9abf/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt 553)

But smart cast can work only if the type is guaranteed as mentionned in the documentation ( https://kotlinlang.org/docs/reference/typecasts.html#smart-casts ) : 但是智能强制转换只有在文档中提到的类型得到保证时才能工作( https://kotlinlang.org/docs/reference/typecasts.html#smart-casts ):

Note that smart casts do not work when the compiler cannot guarantee that the variable cannot change between the check and the usage. 请注意,当编译器无法保证变量在检查和使用之间无法更改时,智能强制转换不起作用。

The compiler tries to find the right receiver (through a smart cast), but cannot do it because the compiler cannot guarantee the acc variable cannot change. 编译器试图找到合适的接收器(通过智能转换),但不能这样做,因为编译器不能保证acc变量不能改变。 This is due to the nested generic: you have a List<Set<Int>> which will be List<*> at runtime. 这是由于嵌套泛型:你有一个List<Set<Int>> ,它在运行时将是List<*>

And that's why we can use invoke instead. 这就是我们可以使用invoke的原因。 Invoke is an operator method generated at build time and will be type safe (no smart cast needed). Invoke是在构建时生成的运算符方法,并且类型安全(不需要智能强制转换)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM