我试图编写一个允许我这样做的高阶函数:
blah1 { em ->
// do some stuff here
}
以及:
blah2 { em ->
// do some stuff here
listOf("1","2","3")
}
在第一个例子中,我没有返回任何内容,在第二个例子中,我返回一个字符串列表。
这适用于第一个:
inline fun blah1(f: (em: EM) -> Unit): Result {
f(em)
return Result()
}
对于第二个,我需要一个不同的返回类型:
inline fun blah2(f: (em: EM) -> Any?): Result {
val res = f(em)
when (res) {
is List<*> -> res.forEach { item ->
// do something with item
}
}
return Result()
}
是否可以合并blah1
和blah2
,以便我这样做:
blah { em ->
}
val res = f(em)
res将是Unit类型,当我这样做时:
blah { em ->
listOf("1","2","3")
}
val res = f(em)
res的类型为List?
我试过这样做:
inline fun blah(
noinline f1: (em: EM) -> Unit = f1fun,
noinline f2: (em: EM) -> Any? = f2fun
): Result {
f1(em)
f2(em)?.let { res ->
when (res) {
is List<*> -> res.forEach { item ->
// do something with item
}
}
}
return Result()
}
val f1fun: (em: EntityManager) -> Unit = { Unit }
val f2fun: (em: EntityManager) -> Any? = { null }
...但现在我是否
blah { em ->
// code here
}
或
blah { em ->
// code here
listOf("1", "2")
}
总是执行 f2
&#39; lambda。
有没有办法让blah { with or without statement }
允许你收集该值为Any?
如果一个语句确实在lambda中并且没有语句存在时,将其视为{{ {1}} lambda?
此:
Unit
在某些情况下无法编译:
inline fun blah2(f: (em: EM) -> Any?): Result {
尽管这很好用:
blah2 {
k = k + 1
}
这很好用:
blah2 {
}
更新:在此期间记录了错误:https://youtrack.jetbrains.com/issue/KT-20215
答案 0 :(得分:3)
这适用于Kotlin:
inline fun blah2(f: (em: EM) -> Any?): Result {
val res = f(EM())
when (res) {
is List<*> -> res.forEach {
// do something with item
println("Item: " + it)
}
is Unit -> {
// do something else
}
}
return Result()
}
fun tryit() {
var res = blah2 { }
res = blah2 { arrayListOf<String>("A","b","c") }
}
但是如果你试图从Java代码中调用你的Kotlin blah2
,你可能会遇到问题。此链接(Unit closures required to return Kotlin.Unit)描述了将函数从Java返回到Kotlin方法的函数的问题。我没有跟着看它是否已经解决了。
修改强> 这些也应该有效:
var k: Int = 0
res = blah2 { k++ }
//res = blah2 { k = k + 1 } // does not compile
//res = blah2 { k = k + 1; return@blah2 } // does not compile
res = blah2 { k = k + 1; return@blah2 k }
但这两条注释的行不起作用。 OP已就此编写了一份错误报告(我同意这是一个错误)。但是,请记住,如果它确实有效,那么行为将与Java所期望的行为不同。在Java中,k = k + 1
是一个表达式,但在Kotlin中却不是。因此,此表达式的返回类型不是Int
。如果有效,则返回类型为Nothing
(请参阅Return and Jumps)。如果SO要从Java移植到Kotlin,他们需要注意&#34;赋值作为表达式&#34;。 Here is an interesting discussion on this matter.
<强>更新强> 以下是不一致的另一个例子:
class TestLambdaReturnType {
var k = 1;
var a: () -> Any = {} //explicitly typed (accepts: () -> Unit )
val b = { k=2 } //compiler implicitly types b: () -> Unit
val c = {} //compiler implicitly types c: () -> Unit
val d: () -> Any = {k=2} //compiler error (??: lambda returns Unit, Unit is derived from Any)
val e: () -> Unit = { k=2 } //no compiler error
val f: () -> Any = e // no compiler error: ?? inconsistent
fun blah2(v: () -> Any): Any = v()
companion object{
@JvmStatic
fun main(args: Array<String>) {
val tn = TestLambdaReturnType()
tn.a = tn.b
tn.blah2(tn.a) //ni compiler error, no surprise
tn.blah2(tn.b) //no compiler error, no surprise
tn.blah2(tn.c) //no compiler error, no surprise
tn.blah2 { tn.k=2 } //error: why "f" different than "v"?
}
}
}
lambda必须具有返回类型。在这些示例中,返回类型是Unit。但基于这些示例,似乎有两种类型Unit
,一种源自Any
,另一种源自who-knows-what
。
答案 1 :(得分:3)
k = k + 1
是一个赋值,它不是Kotlin中的表达式,因此不会评估为Unit或任何其他类型。
为什么在没有类型的作业时会考虑到 编译器正在寻找表达式?
考虑以下简短程序:
fun main(args: Array<String>) {
val result = num { a ->
var b = a * 5
// ...put whatever code you want here
// ...and here
b++ // <- the last line matters
}
}
fun num(f: (i: Int) -> Int): Int {
return f(5)
}
该lambda体内的最后一行,这是重要的行,它必须是一个表达式(在这种情况下为Int
),因为它是这个lambda返回的内容。
那么,最后一行可以b = b + 1
吗?不,因为它不是表达式,因此不能这样返回。
即使您使用Any
或Unit
作为返回类型也不会改变b = b + 1
不属于这些类型的事实。
我必须做的就是这样做:blah2 {k = k + 1; 单位},否则我的lambda不起作用
是的,因为Unit是有效的表达式,blah2 { k = k + 1; Unit }
与
blah2 {
k = k + 1
Unit // again, last line matters
}