基于可变值的 Kotlin 和惯用的编写方式,'如果不是 null,否则......'
Posted
技术标签:
【中文标题】基于可变值的 Kotlin 和惯用的编写方式,\'如果不是 null,否则......\'【英文标题】:Kotlin and idiomatic way to write, 'if not null, else...' based around mutable value基于可变值的 Kotlin 和惯用的编写方式,'如果不是 null,否则......' 【发布时间】:2018-02-03 06:03:42 【问题描述】:假设我们有这样的代码:
class QuickExample
fun function(argument: SomeOtherClass)
if (argument.mutableProperty != null )
doSomething(argument.mutableProperty)
else
doOtherThing()
fun doSomething(argument: Object)
fun doOtherThing()
class SomeOtherClass
var mutableProperty: Object? = null
与在 Java 中不同的是,在 Java 中,您可能会独自担心在运行时取消引用 null,这不会编译 - 非常正确。当然,mutableProperty
在“if”中可能不再为空。
我的问题是处理这个问题的最佳方法是什么?
一些选项是显而易见的。在不使用任何新的 Kotlin 语言功能的情况下,最简单的方法显然是将值复制到方法范围内,该值随后不会更改。
有这个:
fun function(argument: SomeOtherClass)
argument.mutableProperty?.let
doSomething(it)
return
doOtherThing()
这有一个明显的缺点,即您需要提前返回或避免执行后续代码 - 在某些小型上下文中可以,但有异味。
那么就有这种可能:
fun function(argument: SomeOtherClass)
argument.mutableProperty.let
when
it != null ->
doSomething(it)
else ->
doOtherThing()
虽然它的目的更清晰,但可以说它比 Java 风格的处理方式更加笨拙和冗长。
我是否遗漏了什么,是否有一个首选的成语来实现这一点?
【问题讨论】:
IMO 我真的认为简单的with(argument.mutableProperty) if (this != null) a(this) else b()
就足够简洁了(或与let
相当)。通常这应该不是什么大问题,而且仍然很短。跨度>
我觉得不错,谢谢!我建议您将其添加为答案 - 至少,这是实现它的另一种方式。
【参考方案1】:
我认为没有真正“短”的方法来实现它,但是您可以简单地在with
或let
中使用条件:
with(mutableVar) if (this != null) doSomething(this) else doOtherThing()
mutableVar.let if (it != null) doSomething(it) else doOtherThing()
事实上,“捕获”一个可变值是let
的主要用例之一。
这相当于您的when
声明。
总是有你描述的选项,将它分配给一个变量:
val immutable = mutableVar
if (immutable != null)
doSomething(immutable)
else
doOtherThing()
这始终是一个很好的后备方案,例如事情变得太冗长了。
可能没有真正的很好方法来实现这一点,因为只允许将 last lambda 参数放在()
之外,因此指定两个不会真正适合所有其他标准函数的语法。
如果您不介意,可以写一个(或者如果您将传递方法引用):
inline fun <T : Any, R> T?.ifNotNullOrElse(ifNotNullPath: (T) -> R, elsePath: () -> R)
= let if(it == null) elsePath() else ifNotNullPath(it)
...
val a: Int? = null
a.ifNotNullOrElse( println("not null") , println("null") )
请注意,我个人不会这样做,因为这些自定义构造都不是很悦耳的阅读。 IMO:坚持使用let
/run
,必要时回退到if
-else
。
【讨论】:
【参考方案2】:更新:
正如 franta 在 cmets 上提到的,如果方法 doSomething()
返回 null,则将执行 elvis 运算符右侧的代码,这可能不是大多数人想要的情况。但同时,在这种情况下,doSomething()
方法很可能只会做某事而不会返回任何内容。
还有一个替代方案:正如 protossor 在 cmets 上提到的那样,可以使用 also
而不是 let
,因为 also
返回 this
对象而不是函数块的结果。
mutableProperty?.also doSomething(it) ?: doOtherThing()
原答案:
我会将let
与Elvis operator 一起使用。
mutableProperty?.let doSomething(it) ?: doOtherThing()
来自文档:
如果 ?: 左边的表达式不为空,elvis 运算符 返回它,否则将表达式返回到右边。笔记 仅当左侧表达式时才计算右侧表达式 边为空。
右侧表达式后面的代码块:
mutableProperty?.let
doSomething(it)
?: run
doOtherThing()
doOtherThing()
【讨论】:
这样做的缺点似乎是限制了 RHS 上的单个方法调用,而不是代码块。我在这方面错过了什么技巧吗? @RobPridham 我想你可以在技术上使用run
并在那里使用 lambda,但这是一个延伸
是的。正如@1blustone 所提到的,可以使用run
或let
。或者你可以只写一个函数块并通过调用.invoke()
或在关闭的lambda 后面加上()
来调用它,但是这个函数不会被内联。
我不明白为什么这个答案有这么多的赞成票。您提出了一些建议,并且在下一节中您将证明您的建议是错误的。再读一遍文档 -> 如果mutableProperty
不为空,它会跳转到doSomething(it)
,如果此方法返回null
,则elvis 运算符执行doOtherThing()
。
天哪。真是一团糟。【参考方案3】:
添加自定义内联函数如下:
inline fun <T> T?.whenNull(block: T?.() -> Unit): T?
if (this == null) block()
return this@whenNull
inline fun <T> T?.whenNonNull(block: T.() -> Unit): T?
this?.block()
return this@whenNonNull
那么你可以这样写代码:
var nullableVariable :Any? = null
nullableVariable.whenNonNull
doSomething(nullableVariable)
.whenNull
doOtherThing()
【讨论】:
【参考方案4】:我通常是这样写的:
takeIfsomecondition?.alsoput somecondition is met code?:runput your else code here
注意 takeIf 后面的问号是必须的。您也可以使用或应用关键字。
【讨论】:
【参考方案5】:你也可以这样做:
class If<T>(val any: T?, private val i: (T) -> Unit)
infix fun Else(e: () -> Unit)
if (any == null) e()
else i(any)
然后你可以像这样使用它:
If(nullableString)
//Use string
Else
【讨论】:
【参考方案6】:怎么样:
argument.mutableProperty
?.let doSomething(it)
?: doOtherThing()
【讨论】:
这可能在某些情况下有效,但如果例如doSomething() 返回一个值。在这种情况下,它也会调用 doOtherThing(),如果 doSomething() 返回 null【参考方案7】:我通常只是这样做:
when(val it=argument.mutableProperty)
null -> doOtherThing()
else -> doSomething(it)
【讨论】:
【参考方案8】:感谢@zyc zyc,现在我使用此代码
inline fun <T> T?.ifNull(block: () -> Unit): T?
if (this == null) block()
return this@ifNull
inline fun <T> T?.ifNonNull(block: (T) -> Unit): T?
this?.let(block)
return this@ifNonNull
// use
xxxx.ifNull
// todo
.ifNonNull
// todo
【讨论】:
以上是关于基于可变值的 Kotlin 和惯用的编写方式,'如果不是 null,否则......'的主要内容,如果未能解决你的问题,请参考以下文章
Kotlin集合操作 ⑤ ( Map 集合 | 获取 Map 值 | Map 遍历 | 可变 Map 集合 )