空或空Lambda作为默认值

25
哪个解决方案更好?使用可空lambda还是将空lambda作为默认参数传递?Kotlin是否会优化空的lambda,或者创建一个什么也不做的新实例?
``` class Test1(val action: () -> Unit = {}) ```
不幸的是,我不理解生成的字节码。 让我们来分析一下。
``` val test11 = Test1() ```
反编译后给我们:
``` private static final Test1 test11 = new Test1((Function0)null, 1, (DefaultConstructorMarker)null); ```
最后,由于传递了lambda,类似这样:
``` var1 = (Function0)null.INSTANCE; ```
编辑: 隐藏的问题是:Kotlin如何处理空lambda作为默认值?

哪种解决方案更好取决于你想要实现或优化什么? - miensol
1
我不想要不必要的、空的实例。我知道最简单的解决方案是使用可为空的lambda,但这意味着丑陋的构造action?.invoke() - Paweł Byszewski
@PawełByszewski,你对class Test1(val action: () -> Unit = {})有什么疑虑? - ruX
你询问了两个主观答案之间的意见。因此,答案就在你的问题中:如果你喜欢处理null值,那么使用null;如果你希望在值缺失时具有空行为,则使用empty。同样的问题也可以问到“我应该有一个null列表还是空列表?”答案仍然是“取决于你”。 - Jayson Minard
两种解决方案对我来说都有些不可取。为什么不分别设计两个类型:一个带有行动,一个没有?你可能需要使用继承和/或委托来重用一些代码。你甚至可以将“action”变成抽象函数,而不是一个属性。我猜测你的代码会更加清晰。 - mfulton26
你可能是正确的,但我认为在某些情况下这种方法是合理的。例如DSL或例如遵循框架中已知模式的对话窗口构建器。无论如何,“Kotlin如何工作”的问题仍在等待回答。 - Paweł Byszewski
2个回答

16

将空的Lambda表达式作为lambda参数的默认值而不是null,更符合惯用语。

IntelliJ IDEA中使用的反编译器并不总是能够很好地处理Kotlin字节码,因此在这种情况下输出的结果并不反映实际发生的情况。实际上,将空lambda编译为实现相应FunctionN接口且具有空体的单例嵌套类,并使用该单例实例作为默认值。

关于Kotlin如何实现默认参数,请参见我的演讲幻灯片了解更多信息。


4
如何检查Lambda表达式是否为空? - Sunstrike
@Sunstrike 没有办法做到那样的事情。你为什么认为你需要那个? - yole
1
打开了一个问题 https://dev59.com/YKTja4cB1Zd3GeqPC4NC 并且可能已经得到了解决方案。 - Sunstrike
Kotlin新手在这里。在我完成lambda后,将空lambda(分配给保存lambda内容的变量)“只是为了释放资源”是否愚蠢? - Sevastyan Savanyuk
1
“将空的 lambda 传递过去是更符合惯用语的” - 我不同意。因为在 Kotlin 中,空值是一流公民并且是缺失值的明显指示,所以我会将 null 作为默认参数传递。它还有一个好处,就是可以轻松地进行检查和处理,并且您不希望 lambda 执行有用的操作 - 特别是对于带有返回值的 lambda。 - Mathias Henze
我不同意你的观点,Yole。我还要补充一下@MathiasHenze所指出的,空的lambda表达式会消耗内存和处理时间。而且这并不仅仅是一个参数的问题。一个项目由成千上万个“仅仅是一个参数”组成。 - Natan Lotério

13

看一下暴露的函数的最后一个参数:

internal fun showDialog(title: String, message: String? = null, okButtonAction: () -> Unit, koButtonAction:() -> Unit = {}) { //do things..... }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接