首页 > 解决方案 > 在第二次迭代调用中到底发生了什么?

问题描述

我在 Kotlin 中有以下代码:

fun iterate(first: String, second: String, iter: Int, func: (String, String) -> String) {
    for(i in 0..iter)
        println(func(first, second))
}

fun concatenation(one: String, two: String): String {
    return "$one $two";
}

fun main(args: Array<String>) {
    iterate("Me", "You", 5, ::concatenation)
    iterate("Another", "One", 6) {a, b -> a + b}
}

谁能解释第二次调用 iterate 函数时大括号中发生了什么?我要覆盖它吗?另外,我尝试在函数声明中交换func和参数。iter这样我就不能再在第二次调用中使用大括号并插入代码,因为我不知道在哪里放置 iter 参数。

标签: functionkotlin

解决方案


您的func参数的类型是一个函数 - 它的类型是(String, String) -> String这意味着它需要两个String参数(在括号中)并返回一个String(在箭头之后)。

这就是所有函数类型的样子,(x) -> y. 不带参数且不返回值的函数类型具有类型(因为在 Kotlin 中() -> Unit每个函数都返回某些Unit内容,因此是“无意义值”类型)。

因此,对于您的func参数,您可以传入任何具有该类型的函数 - 接受两个字符串,返回一个字符串。您的concatenation函数与之匹配,因此您可以将其传入 - 您正在使用函数引用,::concatenation这是传递该函数的一种方式 - 它是对它的引用。

在您的第二次iterate调用中,您正在创建一个要传入的函数对象,而不是引用一个在类上声明为实际方法的函数对象。您正在使用一个接受两个参数的 lambdaab, 并调用+它们(并隐式返回该值作为结果)。

现在你不是它们在String这里(如果你愿意,你可以显式声明它们的类型),但类型系统基本上是检查这是否可以应用于两个String变量,并且+on 的结果也将是String. 所以一切正常,它可以在你的iterate函数中使用。


就像@IR42 在评论中所说,您使用的是尾随 lambda - 基本上当函数调用中的最后一个参数是 lambda 时,您可以将其移到外面(如果 lambda是那里唯一的东西)。

但这仅在它是最后一个参数时才有效 - 否则它不会确定您移出哪个参数!- 这就是为什么您不能更改顺序并保留尾随 lambda 的原因。您可以切换顺序,但调用必须是这样的:

iterate("Me", "You", ::concatenation, 5)
iterate("Another", "One", {a, b -> a + b}, 6)

推荐阅读