我想要一个applyif
像这样工作:
builder.applyif(<condition expression>) {
builder.set...
}
等于:
builder.apply {
if (<condition expression>) {
builder.set...
}
}
有可能吗?
答案 0 :(得分:7)
是的,当然。您几乎可以编写任何程序, 但是不要重新发明轮子。请看答案底部,以查看没有自己的扩展功能的标准Kotlin方法,这些扩展功能可能已经满足您的需求(尽管并不完全applyIf
)。
现在,让我们看看如何实现applyIf
:
inline fun <T> T.applyIf(predicate: T.() -> Boolean, block: T.() -> Unit): T = apply {
if (predicate(this))
block(this)
}
如果要使用lambda实现扩展功能,请不要忘记inline
。
以下是上述示例。
// sample class
class ADemo {
fun isTrue() = true
}
// sample usage using method references
ADemo().applyIf(ADemo::isTrue, ::println)
// or if you prefer or require it, here without
ADemo().applyIf( { isTrue() } ) {
println(this)
}
如果只是想提供布尔值,则可以使用以下扩展功能:
inline fun <T> T.applyIf(condition : Boolean, block : T.() -> Unit) : T = apply {
if(condition) block(this)
}
并调用:
val someCondition = true
ADemo().applyIf(someCondition) {
println(this)
}
现在是一种可能的 科特林标准方式 ,人们可能会对此更加熟悉:
ADemo().takeIf(ADemo::isTrue)
?.apply(::println)
// or
ADemo().takeIf { it.isTrue() }
?.apply { println(this) }
如果他们确实记得(直到我看到Marko Topolniks评论时我才真正记得),他们应该立即知道发生了什么。
但是,如果在调用ADemo()
之后需要给定值(即takeIf
),则此方法可能对您不起作用,因为以下方法会将变量设置为null
,然后:
val x = ADemo().takeIf { false }
?.apply { println(this) /* never called */ }
// now x = null
以下内容将变量设置为ADemo
-instance:
val x = ADemo().applyIf(false) { println(this) /* also not called */ }
// now x contains the ADemo()-instance
然后束缚构建器调用可能并不那么好。您仍然可以通过将takeIf
与apply
或also
(或with
,let
,run
,取决于您是否要退货还是要使用it
或this
):
val x = builder.apply {
takeIf { false }
?.apply(::println) // not called
takeIf { true }
?.apply(::println) // called
}
// x contains the builder
但是话又说回来,我们已经到了您已经在问题中的位置。使用applyIf
-使用,同样看起来更好:
val x = builder.applyIf(false, ::println) // not called
.applyIf(true) {
println(this) // called
}
// x contains the builder
答案 1 :(得分:1)
当然可以,您只需要一个扩展函数即可在builder
上调用它,并且需要它带有一个Boolean
参数和一个lambda来执行。
如果您查看apply
函数本身的源代码,它将对大多数实现有所帮助:
public inline fun <T> T.apply(block: T.() -> Unit): T {
block()
return this
}
基于此,applyIf
可以很简单:
inline fun <T> T.applyIf(condition: Boolean, block: T.() -> Unit): T {
return if (condition) this.apply(block) else this
}
用法如下:
builder.applyIf(x > 200) {
setSomething()
}