当试图返回内联lambda时,Kotlin“预计没有参数”
我试图写一个Kotlin函数返回一个lambda采取参数。 我试图使用下面的代码来做到这一点:
fun makeFunc() : (T.() -> Unit) { return { t: T -> print("Foo") } }
注意:在实际的程序中,function比较复杂,使用t
。
Kotlin认为这是无效的,在t: T
给出了’Expected no parameters’错误。
但是,首先将这个lambda赋值给一个variables不会被拒绝,并且工作正常:
fun makeFunc() : (T.() -> Unit) { val x = { t: T -> print("Foo") } return x }
这两个片段似乎是相同的,为什么这是这种情况? return
语句之后的花括号是否被解释为lambda之外的东西?
此外,IntelliJ告诉我,variables的值可以内联,而这似乎导致错误。
在Kotlin的函数types和lambdaexpression式的设计中有一个好奇的时刻。
其实这种行为可以用这两种说法来描述:
-
(A, B) -> C
的函数types的命名值在第一个参数变成接收器A.(B) -> C
可以互换。 这些types可以相互分配 。所以,当你声明一个types为
(T) -> Unit
的variables时,你可以传递它,或者在T.() -> Unit
是预期的地方使用它,反之亦然。 -
但是,Lambdaexpression式不能以这种自由的方式使用。
当一个带有接收者
T.() -> Unit
的函数被期望的时候,你不能把一个带有参数T
的lambda放在那个位置,lambda应该和签名完全匹配,接收者和第一个参数不能相互转换:函数文字参数或函数expression式的形状必须与相应参数的扩展名完全匹配。 你不能传递一个扩展函数字面量或扩展函数expression式的地方,反之亦然。 如果你真的想这样做,改变形状,分配文字到一个variables或使用
as
运算符。(来自上面链接的文件 )
这个规则使得lambda更容易阅读:它们总是匹配预期的types。 例如,在一个带有接收器的lambdaexpression式和一个带有隐式lambdaexpression式的lambda之间没有任何歧义,
it
只是未被使用。
比较:
fun foo(bar: (A) -> B) = Unit fun baz(qux: A.() -> B) = Unit val f: (A) -> B = { TODO() } val g: A.() -> B = { TODO() } foo(f) // OK foo(g) // OK baz(f) // OK baz(g) // OK // But: foo { a: A -> println(a); TODO() } // OK foo { println(this@foo); TODO() } // Error baz { println(this@baz); TODO() } // OK baz { a: A -> println(a); TODO() } // Error
基本上,这是错误的IDE诊断。 请将其报告为Kotlin问题跟踪程序的错误。
你正在接收器T
上定义一个函数type () -> Unit
,实际上这个函数没有参数,参见"()"
。 错误是有道理的。 既然你定义了T
作为接收者的函数types,你可以参考T
:
fun makeFunc(): (T.() -> Unit) { return { print(this) } }