代码A来自罗马人Y回答的question。
代码A在调用background(appState)() {...}
时可以很好地工作,为什么我不能去掉括号()?
但是代码B在调用background(appState) {...}
时失败了,为什么?
当用val aa=background(appState) aa{...}
调用时,更多的代码C可以很好地工作,为什么?
代码A
@Composable
fun NiaApp(
windowSizeClass: WindowSizeClass,
appState: NiaAppState = rememberNiaAppState(windowSizeClass)
) {
NiaTheme {
background(appState)() {
Scaffold(
...
) { padding ->
}
}
}
}
@Composable
fun background(appState: NiaAppState): @Composable (@Composable () -> Unit) -> Unit =
when (appState.currentDestination?.route) {
ForYouDestination.route -> { content ->
NiaGradientBackground(content = content) }
else -> { content -> NiaBackground(content = content) }
}
代码B
@Composable
fun NiaApp(
windowSizeClass: WindowSizeClass,
appState: NiaAppState = rememberNiaAppState(windowSizeClass)
) {
NiaTheme {
background(appState){
Scaffold(
...
) { padding ->
}
}
}
}
...
代码C
@Composable
fun NiaApp(
windowSizeClass: WindowSizeClass,
appState: NiaAppState = rememberNiaAppState(windowSizeClass)
) {
val aa=background(appState)
NiaTheme {
aa{
Scaffold(
...
) { padding ->
}
}
}
}
...
2条答案
按热度按时间izkcnapc1#
这更像是一个
Kotlin
function
问题,而不是一个Compose
问题,因此我们将在这里省略所有与Jetpack Compose
相关的代码,只留下与Kotlin
相关的上下文,以使所有内容都集中在焦点上。让我们首先定义
key points
并使用字符标记它们。Key point A
. λ调用:λ.invoke
等于()
Key point B
。基于文档传递尾随lambda:
根据Kotlin约定,如果函数的最后一个参数是函数,那么作为相应参数传递的lambda表达式可以放在括号之外:
...
如果lambda是该调用中的唯一参数,则可以完全省略括号
...
我们将使后台函数看起来像这样,没有
@Composable
注解和NiaAppState
参数,只留下NO参数,但我们将保持函数调用相同,以便我们继续前进。为了更清楚起见,我还命名了返回的lambda参数。代码A在调用background(appState)(){...}时可以很好地工作,为什么我不能去掉括号()呢?
但是代码B在使用background(appState){...}调用时失败,为什么?
让我们同时分解你的
CodeA
和CodeB
来回答你上面的两个问题。但是记住,我们使用的是**我们自己的****background
**函数,而不是compose函数。一句话:
首先从一个简单的调用开始,这里我们只是调用后台函数,忽略它返回的值,这里没有什么异常
二:
在这里,我们调用后台函数,但同时也INVOKING返回的lambda(
Key point A
)立即,我们将在这里得到一个编译错误“No value passed for parameter anotherLambda”,因为当我们INVOKE它时,它要求我们向它传递一个类型为() -> Unit
的参数3:代码A在后台调用(appState)(){...}时可以正常工作
这里,当我们指定lambda块{...}时,编译错误消失了,因为
Key point A
)Key point B
,所以只需调用参数lambda的block {...}4:但是代码B在后台调用(appState){...}时失败,为什么?为什么我不能删除括号()?
在这里,我们将得到另一种错误,'Too many arguments for public fun background()...'。
因为我们没有调用返回的lambda,我们只是调用了background()函数本身,它没有任何lambda参数或任何参数,请检查我们上面所做的后台函数签名和
Key point B
。实际的后台函数只有一个参数(appState:NiaAppState),而且它不是lambda类型参数,再次检查
Key point B
。五:
这是没有**
Key point B
的版本(检查#3)。我们立即调用返回的lambda(Key point A
)并在它内部**传递一个lambda参数。使用lambda的
invoke()
而不是括号()
的等效background()
调用:而更多的代码C在调用瓦尔aa=background(appState)aa{...}时可以很好地工作,为什么呢?
最后,让我们分解一下
CodeC
:一句话:
这里我们调用了background函数,因为我们有一个带有推断类型的赋值操作,
aa
现在是background()调用返回的lambda值二:
具有指定类型的赋值声明。
第三章:
具有指定类型和aa的lambda参数的已定义名称的赋值声明。
第四章:
aa
是返回的lambda,它接受() -> Unit
类型的参数,由于Key point B
,我们可以省略括号并直接调用传递lambda参数的块{...}五:
但是如果我们这样调用它,我们会得到一个错误,'No value passed for parameter...',因为
aa
现在是一个需要() -> Unit
类型参数的函数,请参见Key point A
。六:
这是没有**
Key point B
的版本(检查#4)**。我们调用lambda(Key point A
)并在其中传递lambda参数。使用lambda的
invoke()
而不是括号()
的等效aa
调用:我建议再来这里。
m0rkklqb2#
这是一个高阶函数的问题,这个例子会比较容易理解
innerLambda将返回一个数字,因此当我们调用函数getResult时
第二个括号是
invoke
函数,因此这两条线是一样的,当我们到达这里时,我们必须传入
innerLambda
,因此它看起来像此时ide会提示您
Lambda argument should be moved out of parentheses
,如下所示版本A结果
而对于C版本则比较简单,用一个变量来curried一个函数是函数编程中常见的,调用curried函数,所以当我们弄清楚A版本的时候,我们可以查出来下面的代码
步骤与上一个示例相同,将lambda移出
当lambda是最后一个参数时,我们可以删除不必要括号
这两行是一样,请记住,在Kotlin中,当lambda是最后一个参数时,我们可以删除不必要括号,再次,最终我们得到了
添加与上述答案相关的一些示例
运算符fun是常用,如
+
是unaryPlus
,这些都是Kotlin语法的糖,所以在Kotlin中3.unaryPlus(5)
等于3 + 5
,这就是为什么invoke
可以用()
代替