?: 在 Kotlin 中做啥? (猫王操作员)

     2023-02-23     114

关键词:

【中文标题】?: 在 Kotlin 中做啥? (猫王操作员)【英文标题】:What does ?: do in Kotlin? (Elvis Operator)?: 在 Kotlin 中做什么? (猫王操作员) 【发布时间】:2018-06-23 12:00:54 【问题描述】:

我不知道?: 在这种情况下做了什么

val list = mutableList ?: mutableListOf() 

为什么可以修改成这个

val list = if (mutableList != null) mutableList else mutableListOf()

【问题讨论】:

如果不为空则返回左侧,否则返回右侧。第一个表达式是第二个表达式的简写。 kotlinlang.org/docs/reference/null-safety.html#elvis-operator 【参考方案1】:

TL;DR:如果结果对象引用 [第一个操作数] 不是 null,则返回它。否则返回第二个操作数(可能是null)的值。另外,如果返回null,操作符可以抛出异常。


Elvis 运算符 是许多编程语言的一部分,例如Kotlin 还有 Groovy 或 C#。 我发现Wikipedia 的定义非常准确:

在某些计算机编程语言中,Elvis 运算符?: 是一个二元运算符,如果该操作数是true,则返回其第一个操作数,否则计算和返回它的第二个操作数。它是一种三元条件运算符的变体? :,在这些语言(以及许多其他语言)中都可以找到:Elvis 运算符是 省略了第二个操作数的三元运算符 .

对于 Kotlin 来说尤其如此:

一些计算机编程语言对该运算符有不同的语义。 不是第一个操作数必须产生一个布尔值,它必须产生一个对象引用。如果结果对象引用不是null,则返回它。否则返回第二个操作数的值(可能是null)。如果第二个操作数为 null,则操作符也可以抛出异常。

一个例子:

x ?: y // yields `x` if `x` is not null, `y` otherwise.
x ?: throw SomeException() // yields `x` if `x` is not null, throws SomeException otherwise

【讨论】:

【参考方案2】:

Elvis Operator 由一个问号后跟一个冒号表示:?:,它可以与以下语法一起使用:

first operand ?: second operand

它使您可以编写简洁的代码,并且可以这样工作:

如果first operand 不为空,则返回。如果为空,则返回second operand。这可用于保证表达式不会返回 null 值,因为如果提供的值为 null,您将提供一个不可为 null 的值。


例如(在 Kotlin 中):

fun retrieveString(): String     //Notice that this type isn't nullable
    val nullableVariable: String? = getPotentialNull() //This variable may be null
    
    return nullableVariable ?: "Secondary Not-Null String"

这种情况下,如果getPotentialNull的计算值不为null,则由retrieveString返回;如果为null,则返回第二个表达式"Secondary Not-Null String"

另请注意,如果左侧为 null,则评估右侧表达式。

在 Kotlin 中,您可以使用任何表达式作为 second operand,例如 throw Exception 表达式

return nullVariable ?: throw IllegalResponseException("My inner function returned null! Oh no!")

Elvis Operator 这个名字来源于美国著名歌手Elvis Presley。他的发型像一个问号

资料来源:Wojda、I. Moskala、M. 使用 Kotlin 进行 Android 开发。 2017. Packt 出版

【讨论】:

【参考方案3】:

这被称为Elvis operator,它确实......正是您在问题中所描述的。如果它的左侧是 null 值,则它返回右侧,有点作为后备。否则它只返回左侧的值。

a ?: b 只是if (a != null) a else b 的简写。

更多类型的例子:

val x: String? = "foo"
val y: String = x ?: "bar"      // "foo", because x was non-null    

val a: String? = null
val b: String = a ?: "bar"      // "bar", because a was null

【讨论】:

如果你来自java,它更像是:a != null ? a : b【参考方案4】:

我们来看看defintion:

当我们有一个可为空的引用 r 时,我们可以说“如果 r 不为空,使用 它,否则使用一些非空值 x":

?: (Elvis) 运算符避免冗长,使您的代码非常简洁。

例如,许多集合扩展函数返回 null 作为后备。

listOf(1, 2, 3).firstOrNull  it == 4  ?: throw IllegalStateException("Ups")

?: 为您提供了一种优雅地处理后备情况的方法,即使您有多层后备。如果是这样,您可以简单地链接乘法 Elvis 运算符,如下所示:

val l = listOf(1, 2, 3)

val x = l.firstOrNull  it == 4  ?: l.firstOrNull  it == 5  ?: throw IllegalStateException("Ups")

如果你用 if else 来表达同样的意思,那将是更多难以阅读的代码。

【讨论】:

【参考方案5】:

简单地说,你有两只手。你想知道,你的左手现在还在工作吗?如果左手不工作,returnempty 否则busy

Java 示例:

private int a;
if(a != null)
    println("a is not null, Value is: "+a)

else
    println("a is null")

Kotlin 示例:

val a : Int = 5
val l : Int = if (a != null) a.length else "a is null"

【讨论】:

【参考方案6】:

Kotlin 中的 elvis 运算符用于 null 安全性。

x = a ?: b

在上面的代码中,如果 a 不是 nullb 如果 anullx 将被分配 a 的值。

不使用 elvis 运算符的等效 kotlin 代码如下:

x = if(a == null) b else a

【讨论】:

【参考方案7】:

基本上,如果 Elvis 的左侧由于某种原因返回 null,则改为返回右侧。

val number: Int? = null
println(number ?: "Number is null")

所以,如果数字不为空,它将打印数字,否则将打印“数字为空”。

【讨论】:

【参考方案8】:

不过是一点点补充

X = A ?: B

如果AB 的计算结果都为nullX 仍将是null

因此,如果您希望 X 始终为 non-null,请确保 B 始终为 non-null,或者如果 B 是函数或表达式,则始终计算为 non-null

【讨论】:

【参考方案9】:

考虑下面的例子,

var myStr:String? = null

//trying to find out length of myStr, but it could be null, so a null check can be put as,

val len = if (myStr != null)
    myStr.length

else
    -1

使用elvis操作符,上面的代码可以写成一行

val len = myStr?.length ?: -1     // will return -1 if myStr is null else will return length

【讨论】:

【参考方案10】:

除了已经满足的内容之外,还有一种对我来说并不明显但很常见的好模式,例如您正在编写一个长函数,但如果某些内容为 null,则继续没有意义,您唯一能做的就是从该函数返回。通常你会写

something = expression
if (something == null) 
       return

有了猫王,它变得更短更优雅:

something = expression ?: return

【讨论】:

:: 在 PostgreSQL 中做啥? [复制]

】::在PostgreSQL中做啥?[复制]【英文标题】:Whatdoes::doinPostgreSQL?[duplicate]::在PostgreSQL中做什么?[复制]【发布时间】:2013-03-1009:12:04【问题描述】:我在网上看到过很多涉及postgres代码的地方::。例如:SELECT\'apple,cherryapple,avocado\'::... 查看详情

是啥! (感叹号)在 FreeMarker 中做啥?

】是啥!(感叹号)在FreeMarker中做啥?【英文标题】:Whatdoesthe!(exclamationpoint)inFreeMarkerdo?是什么!(感叹号)在FreeMarker中做什么?【发布时间】:2020-05-0322:54:02【问题描述】:我一直在Magnoliacodeexamples的FreeMarker代码末尾看到感... 查看详情

|=(管道等号)符号在python中做啥?

】|=(管道等号)符号在python中做啥?【英文标题】:Whatdoes|=(pipeequal)signdoinpython?|=(管道等号)符号在python中做什么?【发布时间】:2017-03-0808:10:34【问题描述】:我在一个项目中看到一段代码,其中写了以下内容:move=Move.crea... 查看详情

<!-- 在Javascript中做啥?

】<!--在Javascript中做啥?【英文标题】:whatdoes<!--inJavascriptdo?<!--在Javascript中做什么?【发布时间】:2011-08-2109:56:31【问题描述】:在谷歌中搜索符号太难了,所以我在这里问。&lt;!--对我来说看起来像是一条评论,但它... 查看详情

3D 在这个 HTML 中做啥?

】3D在这个HTML中做啥?【英文标题】:What\'sa3DdoinginthisHTML?3D在这个HTML中做什么?【发布时间】:2011-04-3006:52:30【问题描述】:我正在尝试通过查看其代码来复制我进入我的gmail的邮件。我在多个源查看器中看到了很多这种情况... 查看详情

compute() 在 dask 中做啥?

】compute()在dask中做啥?【英文标题】:whatdoescompute()doindask?compute()在dask中做什么?【发布时间】:2019-11-0514:01:13【问题描述】:我是dask的新手,不明白compute()方法在dask中究竟做了什么?它是一种打印它调用的对象的方法吗?我... 查看详情

“|”是啥意思(单管道)在 JavaScript 中做啥?

】“|”是啥意思(单管道)在JavaScript中做啥?【英文标题】:Whatdoesthe"|"(singlepipe)doinJavaScript?“|”是什么意思(单管道)在JavaScript中做什么?【发布时间】:2011-09-0521:37:33【问题描述】:console.log(0.5|0);//0console.log(-1|0);/... 查看详情

您可以在 CoreBluetooth 后台委托调用中做啥?

】您可以在CoreBluetooth后台委托调用中做啥?【英文标题】:WhatcanyoudoinCoreBluetoothbackgrounddelegatecalls?您可以在CoreBluetooth后台委托调用中做什么?【发布时间】:2013-01-0910:56:40【问题描述】:我在我的项目中使用CoreBluetooth。我已经... 查看详情

>> 在 Java 中做啥?

】>>在Java中做啥?【英文标题】:Whatdoes>>doinJava?>>在Java中做什么?【发布时间】:2011-04-2416:24:07【问题描述】:好的,我尝试查找&gt;&gt;或shift的含义,但正如本网站所解释的那样,这让我无法理解:http://www.... 查看详情

++ 运算符在 Python 中做啥? [复制]

】++运算符在Python中做啥?[复制]【英文标题】:Whatis++operatordoinginPython?[duplicate]++运算符在Python中做什么?[复制]【发布时间】:2013-11-0301:56:42【问题描述】:Python不支持C风格的++a增量,但令我惊讶的是,它并没有抱怨导致我暂... 查看详情

??!??! 是啥意思?运算符在 C 中做啥?

】??!??!是啥意思?运算符在C中做啥?【英文标题】:Whatdoesthe??!??!operatordoinC???!??!是什么意思?运算符在C中做什么?【发布时间】:2011-12-1102:56:28【问题描述】:我看到一行C看起来像这样:!ErrorHasOccured()??!??!HandleError();它编译正... 查看详情

“?”是啥意思?和“:”在布尔语句中做啥? [复制]

】“?”是啥意思?和“:”在布尔语句中做啥?[复制]【英文标题】:Whatdoes"?"and":"doinbooleanstatements?[duplicate]“?”是什么意思?和“:”在布尔语句中做什么?[复制]【发布时间】:2013-05-3009:47:19【问题描述】... 查看详情

">"在Css中做啥[重复]

】">"在Css中做啥[重复]【英文标题】:Whatis">"doinginCss[duplicate]">"在Css中做什么[重复]【发布时间】:2014-06-0414:32:28【问题描述】:我有一个关于css的问题,在一些引导文件中我看到">":.nav-tabs.nav-jus... 查看详情

我应该在 CMakeLists.txt w.r.t 中做啥?构建类型?

】我应该在CMakeLists.txtw.r.t中做啥?构建类型?【英文标题】:WhatshouldIdoinCMakeLists.txtw.r.t.thebuildtype?我应该在CMakeLists.txtw.r.t中做什么?构建类型?【发布时间】:2020-04-1912:03:54【问题描述】:我是一些使用CMake构建的库的作者。... 查看详情

/s ^ $ 在正则表达式中做啥? [关闭]

】/s^$在正则表达式中做啥?[关闭]【英文标题】:whatdo/s^$doinRegex?[closed]/s^$在正则表达式中做什么?[关闭]【发布时间】:2013-12-2402:01:32【问题描述】:所以我今天刚刚学习了正则表达式,我们没有接触到这些符号/s^$我问的原因... 查看详情

如果发生内部提交,我可以在 Oracle 中做啥以保留保存点?

】如果发生内部提交,我可以在Oracle中做啥以保留保存点?【英文标题】:WhatcanidoinOracleinordertopreservethesavepointifinternalcommitoccurs?如果发生内部提交,我可以在Oracle中做什么以保留保存点?【发布时间】:2012-11-0615:17:43【问题描... 查看详情

watchOS 3 - 我应该在 userNotificationCenter:willPresentNotification:withCompletionHandler: 中做啥来实际显示通知?

】watchOS3-我应该在userNotificationCenter:willPresentNotification:withCompletionHandler:中做啥来实际显示通知?【英文标题】:watchOS3-WhatamIsupposedtodoinuserNotificationCenter:willPresentNotification:withCompletionHandler:toactuallyshowthenot 查看详情

celery.utils.log.ProcessAwareLoggerobject 在 logging.Logger.manager.loggerDict 中做啥

】celery.utils.log.ProcessAwareLoggerobject在logging.Logger.manager.loggerDict中做啥【英文标题】:Whatiscelery.utils.log.ProcessAwareLoggerobjectdoinginlogging.Logger.manager.loggerDictcelery.utils.log.ProcessAwareLoggerobject在loggi 查看详情