在Kotlin中将vargs值传递给具有多个参数的另一个函数?

时间:2019-03-20 07:47:05

标签: kotlin

我在Kotin(1.3)中声明了两个扩展函数:

fun SomeClass.fooBuilder(vararg x: String, fn: ((String) -> Unit)? = null): Result.Builder = TODO()
fun SomeClass.foo(vararg x: String, fn: ((String) -> Unit)? = null): Result = fooBuilder(*x, fn).build()

我想做的是从fooBuilder调用foo,然后简单地对build()返回的结果调用fooBuilder

不幸的是,由于对fooBuilder(*x, fn).build()的调用因以下原因而失败,因此上面的代码无法编译:

Error:(28, 143) Kotlin: Type mismatch: inferred type is ((String) -> Unit)? but String was expected

即编译器似乎认为我想传递其他字符串(x)参数,但实际上我想传递的是函数。

如何解决此问题,并保留此示例中指定fn时用于省略括号的选项:

SomeClass().foo("x") { str -> println("Hello $str") }

3 个答案:

答案 0 :(得分:2)

vararg之后的任何参数都必须作为命名参数传递。试试吧:

fun SomeClass.fooBuilder(vararg x: String, fn: ((String) -> Unit)? = null): Result.Builder = TODO()
fun SomeClass.foo(vararg x: String, fn: ((String) -> Unit)? = null): Result = fooBuilder(*x, fn = fn).build() // here I used named param

// it should work now:
SomeClass().foo("x") { str -> println("Hello $str") }

答案 1 :(得分:2)

您有两个选择:

1)vararg应该是最后一个参数(但是这样您将无法使用简化的lambda调用)

2)使用命名参数:

fun SomeClass.fooBuilder(vararg x: String, fn: ((String) -> Unit)? = null): Result.Builder = TODO()
fun SomeClass.foo(vararg x: String, fn: ((String) -> Unit)? = null): Result = fooBuilder(x = *x, fn = fn).build()

您遇到的错误非常合逻辑-传递vararg argumnets完成后,编译器如何知道?

答案 2 :(得分:0)

这是另一种选择-它不如使用命名参数清晰,简短或有效,但出于完整性考虑,我将其包括在内。

就像在呼叫者面前一样,将fn传递到括号之外。我认为您无法直接执行此操作,但是可以将呼叫包装到fn,如下所示:

fun SomeClass.foo(vararg x: String, fn: ((String) -> Unit)? = null): Result
    = fooBuilder(*x){ fn?.invoke(it) }.build()