Kotlin中的条件副作用和可选类型

时间:2016-12-28 09:18:28

标签: kotlin side-effects

我试图在Kotlin中执行一个简单的副作用:

   foreach($products as $product){
            $this->addCacheTags('RecordName_' . $product->getUid());
        }

如您所见,当存储库返回非空值并且 someCondition 满足时,应执行副作用。

有没有Kotlin方式这样做而不是使用 if {} - return 构造?

在Java 8中,它可以通过以下方式实现:

fun handle(request: Request) {
    repository.findByUID(request.userId)?.let {
        if (someCondition) return

        service.run(...)
    }
}

3 个答案:

答案 0 :(得分:5)

Kotlin的nullable types与Java的Optional非常相似(与Guava的Optional非常相似)。

在Kotlin 1.1中,您可以使用takeIffilter就像一个值”(takeIf() and also() - What's New in Kotlin 1.1 - Kotlin Programming Language):

repository.findByUID(request.userId).takeIf { !someCondition }?.let { service.run(...) }

Kotlin 1.0没有为可空类型定义mapflatMapfilter / takeIf等,但您可以轻松定义自己的函数。 e.g:

inline fun <T> filter(value: T?, predicate: (T) -> Boolean): T? {
    return if (value != null && predicate(value)) value else null
}

使用示例:

filter(repository.findByUID(request.userId)) { !someCondition }?.let { service.run(...) }

答案 1 :(得分:4)

<强>更新 Kotlin 1.1有一个名为takeIf的方法:

/**
 * Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null

你可以这样使用它:

repository.findByUID(request.userId)?.takeIf { someCondition }?.let { service -> }

Kotlin在stdlib中没有包含这样的方法。

但是,您可以定义它:

inline fun <K : Any> K.ifPresent(condition: K.() -> Boolean): K? = if (condition()) this else null

使用此方法,您的示例可以重写为:

fun handle(request: Request) {
    repository.findByUID(request.userId)?.ifPresent { someCondition }?.let {
        service.run(...)
    }
}

另一种选择可能是使用内置的扩展名列表(但是使用列表会产生开销):

listOf(repository.findByUID(userId)).filter { someCondition }.forEach { service.run(...) }

答案 2 :(得分:1)

使用此结构我不会使用额外的库或扩展函数:

?.let { if (someCondition) null else it }

在原始问题的代码示例中使用此构造后,它看起来像:

fun handle(request: Request) {
    repository.findByUID(request.userId)
            ?.let { if (someCondition) null else it }
            ?.let {
                service.run {
                    /* ... */
                }
            }
}

或者至少它看起来没问题,在定义RequestrepositoryfindByUid等后,在我的代码库中编译和使用相同的类型: - )