Kotlin 函数引用是否有一个简单的空安全运算符?

las*_*ase 4 kotlin

我想在可空对象上传递函数引用。以 Android 为例,假设我想Activity#onBackPressed从作为该活动的子级的片段中使用。

如果我想调用这个函数,我可以很容易地做到

activity?.onBackPressed()
Run Code Online (Sandbox Code Playgroud)

但是,假设我想将其作为参考传递:

val onBackPressedRef = activity::onBackPressed
Run Code Online (Sandbox Code Playgroud)

这给出了熟悉的空安全错误Only safe or non null asserted calls are allowed...


我可以通过以下方式消除错误,但使用!!显然并不理想:

val onBackPressedRef = activity!!::onBackPressed
Run Code Online (Sandbox Code Playgroud)

尝试activity?::onBackPressed是我的第一直觉,但这也打破了几个错误,解释器似乎很困惑。

val onBackPressedRef = activity?.let { it::onBackPressed } 
Run Code Online (Sandbox Code Playgroud)

最后一个变体有效,但它比仅使用?::. 我检查了我能找到的所有文档,但我觉得我错过了一些东西。有任何想法吗?

The*_*tor 6

你是对的,?::Kotlin 中没有运算符。
您有几种选择:

1.letrun

因此,您必须使用辅助函数。代替let(),您还可以使用run(),使表达式更短一点:

val onBackPressedRef = activity?.let { it::onBackPressed }
val onBackPressedRef = activity?.run { ::onBackPressed }
Run Code Online (Sandbox Code Playgroud)

但请记住,无论哪种方式,调用也会更加冗长:

onBackPressedRef?.invoke(args)
Run Code Online (Sandbox Code Playgroud)

因此,您应该问问自己,这是否真的是您想要的,或者是否也可以接受无操作函数调用。

2. 关闭

您可以使用闭包——但这会改变语义:

val onBackPressedRef = { activity?.onBackPressed() }
Run Code Online (Sandbox Code Playgroud)

在这里,onBackPressedRef不再可以为空,因此您可以使用()运算符调用它,如果为空activity,它将无效。

3. 辅助功能

如果您经常遇到带有可为空对象的函数引用,您可以编写自己的小抽象:

// Return type: () -> Unit
fun <T> funcRef(obj: T?, function: T.() -> Unit) = { obj?.function() }
Run Code Online (Sandbox Code Playgroud)

这为非空函数变量交换了不同的语法:

 // activity can be null
 val onBackPressedRef = funcRef(activity, Activity::onBackPressed)

 // Callable directly
 onBackPressedRef()
Run Code Online (Sandbox Code Playgroud)