如何实施Kotlin的应用程序?

时间:2018-07-31 06:43:47

标签: kotlin

我想要一个applyif像这样工作:

builder.applyif(<condition expression>) {
    builder.set...
}

等于:

builder.apply {
    if (<condition expression>) {
        builder.set...
    }
}

有可能吗?

2 个答案:

答案 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

然后束缚构建器调用可能并不那么好。您仍然可以通过将takeIfapplyalso(或withletrun,取决于您是否要退货还是要使用itthis):

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()
}