我试图写一个Kotlin函数,它返回一个带参数的lambda。我尝试使用以下代码执行此操作:
fun <T> makeFunc() : (T.() -> Unit) {
return { t: T ->
print("Foo")
}
}
注意:在实际程序中,函数更复杂并使用t
。
Kotlin拒绝将此视为无效,并提供“预期无参数”。错误t: T
。
但是,首先将此lambda分配给变量不会被拒绝并且正常工作:
fun <T> makeFunc() : (T.() -> Unit) {
val x = { t: T ->
print("Foo")
}
return x
}
这两个片段看起来完全相同,为什么会这样呢?在将return
语句解释为lambda以外的其他语句之后是花括号吗?
此外,IntelliJ告诉我变量的值可以内联,但这似乎会导致错误。
答案 0 :(得分:5)
在Kotlin中设计函数类型和lambda表达式时有一个奇怪的时刻。
事实上,可以在这两个陈述中描述这种行为:
功能类型的命名值可以在普通功能类型(如(A, B) -> C
)和相应类型的功能之间互换,第一个参数变为接收器A.(B) -> C
。这些类型为assignable from each other。
因此,当您声明一个键入为(T) -> Unit
的变量时,您可以传递它或在预期T.() -> Unit
的地方使用它,反之亦然。
然而,Lambda表达式不能以这种自由的方式使用。
当一个带接收器T.() -> Unit
的函数被预期时,你不能在该位置放置一个参数为T
的lambda,lambda应该与签名完全匹配,接收器和第一个参数不能是相互转换:
函数文字参数或函数表达式的形状必须与相应参数的扩展名完全匹配。您不能传递扩展函数文字或扩展函数表达式,其中函数是预期的,反之亦然。如果您真的想这样做,请更改形状,将文字指定给变量或使用
as
运算符。
此规则使lambda更易于阅读:它们始终与预期类型匹配。例如,带接收器的lambda和带有隐式it
的lambda之间没有任何歧义。
比较
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诊断错误。请report it作为Kotlin问题跟踪器的错误。
答案 1 :(得分:1)
您正在接收方model.add(Dense(4672, activation='softmax'))
上定义函数类型() -> Unit
,该函数确实没有参数,请参阅T
。这个错误很有意义。由于您定义了以"()"
作为接收方的函数类型,因此您可以T
引用T
:
this