我在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") }
答案 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()