在 Kotlin 中,如何在不计算两次的情况下测试和使用一个值?

In Kotlin, how can I test and use a value without computing it twice?

提问人:Tim Baverstock 提问时间:5/26/2022 最后编辑:Tim Baverstock 更新时间:5/26/2022 访问量:150

问:

每隔一段时间,我就会发现自己想要为某种过滤操作计算一个值,但当它已经消失在条件检查中时,我又想使用该值。

例如:

val found = list.firstOrNull { slowConversion(it).isWanted() }
if (found != null) {
   something(found, slowConversion(found))
}

when {
   other_conditions -> other_actions
   list.any { it.contains(regex1) } -> something(list.firstOrNull { it.contains(regex1) } ?: "!!??")
}

对于 slowConversion(),我可以使用映射到成对的序列,尽管术语 first 和 second 有点混淆......

val pair = list.asSequence().map { it to slowConversion(it) }.firstOrNull { it.second.isWanted() }
if ( pair != null ) {
  something(pair.first, pair.second)
}

或者如果我只想要转换,

val converted = list.firstNotNullOfOrNull { slowConversion(it).takeIf { it.isWanted() } }

但是,为了避免重复,我能想到的最好的办法是将动作部分移动到条件部分!when

fun case(s: List<String>, r: Regex) {
   val match = s.firstOrNull { it.contains(r) }?.also { something(it) }
   return match != null
}

when {
  other_conditions -> other_actions
  case(list, regex1) -> true
}

在这一点上,似乎我应该将一堆函数调用与 ||

other_things || case(list, regex1) || case(list, regex2) || catchAll(list)

对于其中任何一个,有更好或更简洁的东西吗?

Kotlin 字典 过滤器 延迟评估 短路

评论

0赞 gidds 5/26/2022
作为记录,在更简单的情况下,避免重复值/表达式/调用(或使用临时变量)的惯用方法是使用 Kotlin 的作用域函数,通常与 safe-call () 或 elvis () 运算符结合使用。但是这个问题有更棘手的情况,我认为任何通常的模式都不会有太大帮助。?.?:
0赞 Tim Baverstock 5/27/2022
@gidds哈,谢谢 - 我经常使用,但更关注是否有办法合并 和 喜欢令人敬畏的名字.?.also{}mapfirstOrNullfirstNotNullofOrNull

答:

1赞 Arpit Shukla 5/26/2022 #1

你可以这样编写你的第一个示例:

for(element in list) {
    val result = slowConversion(element)
    if(result.isWanted()) {
        something(element, result)
        break
    }
}

这可能看起来不是很像Kotlin,但我认为它非常简单易懂。

对于第二个示例,可以使用以下函数:find

when {
    other_conditions -> other_actions
    else -> list.find { it.contains(regex1) }?.let(::something)
}

如果你有多个正则表达式,只需遍历它们,

val regexes = listOf(regex1, regex2, ...)
for(regex in regexes) {
    val element = list.find { it.contains(regex1) } ?: continue
    something(element)
    break
}

评论

0赞 Tim Baverstock 7/7/2022
谢谢。我想我对漂亮的语法太过炯炯有神。也许 Kotlin 还有创造更多神奇语法的余地,但“不,目前没有很神奇的方式”对我来说已经足够了。干杯。:)