Hel*_*oCW 7 lambda function-call higher-order-functions kotlin android-jetpack-compose
代码 A 来自Roman Y 回答的问题。
代码A调用with时可以正常工作background(appState)() {...}
,为什么不能去掉括号()?
但是代码 B 在调用 with 时失败了background(appState) {...}
,为什么?
而且更多的代码C在调用 with 时可以很好地工作 val aa=background(appState) aa{...}
,为什么呢?
代码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) }
}
Run Code Online (Sandbox Code Playgroud)
代码B
@Composable
fun NiaApp(
windowSizeClass: WindowSizeClass,
appState: NiaAppState = rememberNiaAppState(windowSizeClass)
) {
NiaTheme {
background(appState){
Scaffold(
...
) { padding ->
}
}
}
}
...
Run Code Online (Sandbox Code Playgroud)
代码C
@Composable
fun NiaApp(
windowSizeClass: WindowSizeClass,
appState: NiaAppState = rememberNiaAppState(windowSizeClass)
) {
val aa=background(appState)
NiaTheme {
aa{
Scaffold(
...
) { padding ->
}
}
}
}
...
Run Code Online (Sandbox Code Playgroud)
这与其说是一个Kotlin
function
问题Compose
,不如说是一个问题,因此我们将Jetpack Compose
在这里省略所有相关的代码,只留下Kotlin
相关的上下文以保持所有内容的焦点。
首先让我们key points
用一个字符来定义和标记它们。
Key point A
。Lambda 调用:lambda.invoke
等于()
Key point B
。基于文档\n\n传递尾随 lambda:
\n根据 Kotlin 约定,如果函数的最后一个参数是函数,则可以将作为相应参数传递的 lambda 表达式放在括号之外:
\n...
\n如果 lambda 是该调用中的唯一参数,则可以完全省略括号
\n\xe2\x80\xa6
\n
我们将使后台函数看起来像这样,没有@Composable
注释和NiaAppState
参数,没有参数,但我们将保持函数调用相同,这样我们就可以步入正轨。为了更清晰的描述,我还命名了返回的 lambda 参数。
fun background() : (anotherLambda: () -> Unit) -> Unit { ... }\n
Run Code Online (Sandbox Code Playgroud)\n\n\n代码A在使用background(appState)()\n{...}调用时可以很好地工作,为什么我不能删除括号()?
\n但是代码 B 在使用 background(appState) {...} 调用时失败,为什么?
\n
让我们分解您的问题CodeA
,CodeB
同时回答您上面的两个问题。但请记住,我们使用的是我们自己的 background
函数,而不是 compose 函数。
\n\n1:
\n首先从一个简单的调用开始,这里我们只是调用后台函数,并忽略\n它返回的值,这里没有什么异常
\n
background()\n
Run Code Online (Sandbox Code Playgroud)\n\n\n2:
\n在这里,我们在调用后台函数的同时,也立即INVOKING\n返回的lambda( )
\nKey point A
,\n我们会在这里得到一个编译错误\' No value pass forparameter anotherLambda \'\n因为当我们INVOKE它时,它要求我们传递一个参数给它,它是一种类型() -> Unit
background()() // <-- compile error: No value passed for parameter anotherLambda\n
Run Code Online (Sandbox Code Playgroud)\n\n\n3:代码A在使用background(appState)() {...}调用时可以很好地工作
\n这里,当我们指定 lambda block\n{ ... } 时,编译错误消失了,因为
\n\n
\n- 我们立即调用返回的 lambda(
\nKey point A
)- 我们为它提供了一个 lambda 参数,并且由于代码遵循
\nKey point B
它,因此只需调用参数 lambda\'s block { ... }
background()() {\n ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n\n4:但是代码 B 在使用 background(appState) {...} 调用时失败,为什么?为什么我不能删除括号 ()?
\n在这里,我们会得到另一种错误,“ Too much arguments for public funbackground() ... ”。
\n因为我们没有调用返回的 lambda,所以我们只是调用 background() 函数本身,并且它没有任何 lambda 参数或根本没有任何参数,请检查我们上面所做的后台函数签名和
\nKey point B
。并且您的实际后台函数只有一个参数(appState:NiaAppState),并且它不是 lambda 类型参数,请再次检查
\nKey point B
。
background() { // big chunk of compile error here: Too many arguments for public fun background() ...\n ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n\n5:
\n这是不带
\nKey point B
. 我们立即调用返回的 lambda (Key point A
)并在其中 传递 lambda 参数。
background () ( {\n ...\n} )\n
Run Code Online (Sandbox Code Playgroud)\nbackground()
使用 lambda 的invoke()
\而不是括号进行等效调用()
:
// #2\nbackground().invoke() // <-- compile error: No value passed for parameter anotherLambda\n\n// #3\nbackground().invoke {\n ...\n}\n\n// #4\nbackground(invoke { // big chunk of compile error here: Too many arguments for public fun background() ... and Unresolved reference invoke\n ...\n} )\n\n// #5\nbackground().invoke ( {\n ...\n} )\n
Run Code Online (Sandbox Code Playgroud)\n\n\n而且更多的代码C在使用val\naa=background(appState) aa{...}调用时可以很好地工作,为什么呢?
\n
最后让我们分解一下CodeC
:
\n\n1:
\n这里我们调用后台函数,因为我们有一个类型推断的赋值操作,
\naa
现在是从background()\nin Vocation 返回的 lambda 值
val aa = background()\n\n// your actual background function equivalent\nval aa = background(appState)\n
Run Code Online (Sandbox Code Playgroud)\n\n\n2:
\n指定类型的赋值声明。
\n
// aa assignment declaration with type specified\nval aa : (() -> Unit) -> Unit = background()\n\n// your actual background function equivalent\nval aa : @Composable (@Composable () -> Unit) -> Unit = background(appState)\n
Run Code Online (Sandbox Code Playgroud)\n\n\n3:
\n具有指定类型和 aa 的 lambda 参数的定义名称的赋值声明。
\n
// aa assignment declaration with type specified and named parameter\nval aa : (aaLambdaParam : () -> Unit) -> Unit = background()\n\n// your actual background function equivalent\nval aa : @Composable (aaLambdaParam: @Composable () -> Unit) -> Unit = background(appState)\n
Run Code Online (Sandbox Code Playgroud)\n\n\n4:
\n\n
aa
是返回的 lambda,它接受类型的参数() -> Unit
,因为Key point B
,我们可以省略括号并直接调用传递 lambda 参数的块 {...}
aa {\n ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n\n5:
\n但是如果我们这样调用它,我们会得到一个错误,“没有为参数传递值...”,因为
\naa
现在是一个需要类型为参数的函数() -> Unit
,请参阅Key point A
。
aa() // <-- No value passed for parameter \'p1\' (#2) or \'No value passed for parameter \'aaLambdaParam\' (#3)\n
Run Code Online (Sandbox Code Playgroud)\n\n\n6:
\n这是不带
\nKey point B
. 我们调用 lambda (Key point A
) 并在其中传递一个 lambda 参数。
aa ( {\n ...\n} )\n
Run Code Online (Sandbox Code Playgroud)\naa
使用 lambda 的invoke()
\而不是括号进行等效调用()
:
// #4, Key point B\naa.invoke {\n ...\n}\n\n// #5\naa.invoke() // <-- No value passed for parameter \'p1\' or \'aaLambdaParam\'\n\n// #6, not Key point B\naa.invoke( {\n ...\n} )\n
Run Code Online (Sandbox Code Playgroud)\n我建议重新访问Kotlin 的高阶函数和 Lambda。
\n 归档时间: |
|
查看次数: |
926 次 |
最近记录: |