假设我们有这段代码:
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中不同的是,您可以单独担心在运行时空取消引用,这不会编译 - 非常正确。当然,{if}中的mutableProperty
可能不再为null。
我的问题是处理这个问题的最佳方法是什么?
有一些选择是显而易见的。在不使用任何新的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风格的方式更加笨拙和冗长。
我错过了什么,是否有一个首选的习惯用来实现这个目标?
答案 0 :(得分:31)
<强>更新强>
正如franta在评论中提到的,如果方法doSomething()
返回null,那么将执行elvis运算符右侧的代码,这可能不是大多数情况下的理想情况。但与此同时,在这种情况下,doSomething()
方法很可能只会执行某些操作而不返回任何内容。
另一种选择:正如protossor在评论中提到的那样,可以使用also
而不是let
,因为also
会返回this
个对象,而不是mutableProperty?.also { doSomething(it) } ?: doOtherThing()
功能块。
let
原始回答:
我会将mutableProperty?.let { doSomething(it) } ?: doOtherThing()
与Elvis operator一起使用。
mutableProperty?.let {
doSomething(it)
} ?: run {
doOtherThing()
doOtherThing()
}
来自doc:
如果?:左边的表达式不为null,则为elvis运算符 返回它,否则返回右边的表达式。注意 只有左手才能评估右侧表达式 方是空的。
对于右侧表达式后面的代码块:
NSString *result = [webView stringByEvaluatingJavaScriptFromString:@"document.body.offsetHeight;"];
NSInteger height = [result integerValue];
答案 1 :(得分:12)
我不相信有一个真正的&#34;短&#34;实现它的方法,但您可以在with
或let
:
with(mutableVar) { if (this != null) doSomething(this) else doOtherThing() }
mutableVar.let { if (it != null) doSomething(it) else doOtherThing() }
事实上,&#34;捕获&#34;可变值是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") })
答案 2 :(得分:1)
添加自定义内联函数,如下所示:
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()
}
答案 3 :(得分:1)
关于:
argument.mutableProperty
?.let { doSomething(it) }
?: doOtherThing()
答案 4 :(得分:0)
我通常这样写:
takeIf{somecondition}?.also{put somecondition is met code}?:run{put your else code here}
在takeIf为必填项后注意问号。您还可以使用或应用关键字。
答案 5 :(得分:0)
您还可以执行以下操作:
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 :(得分:0)
我通常只是这样做:
when(val it=argument.mutableProperty) {
null -> doOtherThing()
else -> doSomething(it)
}