【问题标题】:Return first non-null value after transformation in Kotlin在 Kotlin 中转换后返回第一个非空值
【发布时间】:2021-01-14 13:12:58
【问题描述】:

我想在 Kotlin 中转换元素列表后返回第一个非 null 值,所以是这样的:

suspend fun myFunction(): Any {
    val firstNonNullId = this.mapNotNull{ it.id }
        ?.first{ transform(id) != null }

    return transform(firstNonNullID)
}

编写此函数的更好、更惯用的方法是什么?我想尽可能少地调用transform(it),并且所讨论的转换也是suspend函数。

编辑:transform()suspend 函数时,asSequence() 解决方案会出错,因为它必须从协程主体中调用。即使整个 myFunction() 是一个挂起函数,也会发生这种情况。转换为挂起函数时应该怎么解决?

【问题讨论】:

  • 如果转换是挂起函数,您只能在协程中执行此操作。你上面的代码不也是这样吗?您是否需要转换集合中的每个项目,即使除了第一个元素之外您没有存储转换后的元素?
  • 如果变换是挂起函数,整体功能也是挂起函数,那就可以了。然而,虽然整体函数是一个挂起函数,并且转换是从一个序列中调用的,但它不再是原始协程体的一部分。
  • 我的另一个问题呢?我认为序列解决方案会在第一个元素之后跳过所有元素的转换,即使它确实有效。与您上面的代码相同。但是你说“第一个非值转换之后”。
  • 我不需要转换集合中的每个项目,这就是我使用first 而不是例如调用filterNotNull 的原因。

标签: list kotlin


【解决方案1】:

从 Kotlin 1.5 开始,您可以使用 firstNotNullOf 函数或其 ...OrNull 变体:

// returns the first non-null result of transform
this.firstNotNullOf { transform(it.id) }  

firstNotNullOf如果没有找到转换的非空结果,则抛出异常,firstNotNullOfOrNull在这种情况下返回null。

这两个函数都是内联的,因此当它们自己从挂起函数调用时,应该可以在它们的 lambda 参数中调用挂起函数。

【讨论】:

  • 谢谢!最后:D
【解决方案2】:

我建议使用 Kotlin sequences:

this.asSequence()
    .mapNotNull { it.id }
    .mapNotNull { transform(it) }
    .first()

由于序列求值是惰性的,所以你的transform函数只会在调用.first()的过程中被调用,在得到第一个非空结果后不会被调用。

【讨论】:

  • 试过这个解决方案,但在这种情况下,转换是一个挂起函数,所以它给出了一个错误 - 请参阅编辑!
  • 如果您使用asFlow 而不是asSequence,它应该可以工作。 Flow 可以被认为是具有暂停功能的序列版本。
猜你喜欢
  • 2017-09-02
  • 2019-12-07
  • 1970-01-01
  • 2017-05-15
  • 2014-01-08
  • 2021-03-07
  • 1970-01-01
  • 1970-01-01
  • 2018-05-20
相关资源
最近更新 更多