Kotlin中的条件副作用和可选类型
我正在努力在Kotlin中执行一个简单的副作用:
fun handle(request: Request) { repository.findByUID(request.userId)?.let { if (someCondition) return service.run(...) } }
正如你所看到的那样,当知识库返回一个非空值并且满足someCondition时,应该执行副作用 。
有没有Kotlin这样做的方式,而不是使用如果{} – 返回结构?
在Java 8中,可以通过以下方式来实现:
optional .filter(...) .ifPresent(...)
更新: 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(...) }
Kotlin的可空类型与Java的可选 类型非常相似(与Guava的可选 类型非常相似)。
Kotlin 1.1可以使用takeIf
,“就像filter
一个单一的值”( takeIf()和also() – Kotlin 1.1中的新功能 – Kotlin编程语言 ):
repository.findByUID(request.userId).takeIf { !someCondition }?.let { service.run(...) }
在Kotlin 1.0中没有定义map
, flatMap
, filter
等可为空类型,但可以轻松定义自己的函数。 例如:
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(...) }
我会去没有额外的库,也没有扩展功能这个结构:
?.let { if (someCondition) null else it }
在原始问题的代码样本上添加这个构造之后,它将如下所示:
fun handle(request: Request) { repository.findByUID(request.userId) ?.let { if (someCondition) null else it } ?.let { service.run { /* ... */ } } }
或者至少它看起来findByUid
,在定义了Request
, repository
, findByUid
等之后,在我的代码库中编译并具有相同的类型:-)