英文:
How iterate until the condition is met using kotlin and functional programming?
问题
这段代码的目的是使用 API 获取航班信息,然后一直获取,直到返回的响应不再是 "Canceled" 为止。您尝试使用函数式编程风格来实现这一目标。以下是您可以尝试的方法:
import kotlinx.coroutines.*
// 定义一个挂起函数,用于获取航班信息
suspend fun fetchFlightInfo(): String {
println("Started fetching Flight info.")
val response = client.get<String>(FLIGHT_ENDPOINT)
println("Finished fetching Flight info.")
return response
}
// 定义一个挂起函数,用于检查响应是否被取消
suspend fun isCanceled(flightResponse: String): Boolean {
val (_, _, _, status, _) = flightResponse.split(',')
return status == "Canceled"
}
// 使用协程来执行循环,直到条件满足
suspend fun repeatUntilNotCanceled(): String {
var response: String
do {
response = fetchFlightInfo()
} while (isCanceled(response))
return response
}
// 使用协程范围来执行异步任务
val flightResponse = coroutineScope {
async { repeatUntilNotCanceled() }
}
// 等待异步任务完成
val result = flightResponse.await()
在上面的代码中,我们首先定义了两个挂起函数,一个用于获取航班信息,另一个用于检查响应是否已取消。然后,我们使用 repeatUntilNotCanceled
函数执行循环,不断获取航班信息,直到响应不再是 "Canceled"。最后,我们在协程范围内使用 async
来执行异步任务,并等待异步任务完成,从而获得最终的响应。
这样,您可以使用函数式编程风格来实现获取非取消响应的逻辑。
英文:
I'm using an API that returns a text like this:
BW3511,HGP,ITP,Canceled,32
.
I have to continue fetching until I get a response that is not "Canceled".
this code fetches the data:
val flightResponse = async {
println("Started fetching Flight info.")
client.get<String>(FLIGHT_ENDPOINT).also {
println("Finished fetching Flight info.")
}
}
the client.get can only be called within The coroutineScope body, also the flightResponse type is Deferred<String>
.
check if it is canceled:
fun isCanceled(
flightResponse: String
) : Boolean {
val (_, _, _, status, _) = flightResponse.split(",")
return status == "Canceled"
}
how can I repeat client.get<String>(FLIGHT_ENDPOINT)
until my condition is met using Functional Programming style?
I tried using takeIf
but I have to get at least one result and it cannot be a nullable type.
答案1
得分: 1
以下是您要翻译的内容:
如@Jorn所述,这似乎是对函数式风格的过度使用。可以通过一个简单的循环来实现,这样可能对读者更清晰:
fun getNextNotCancelled() {
while (true) {
val response = client.get<String>(FLIGHT_ENDPOINT)
if (!isCanceled(response)) return response
}
}
如果您的实际情况更复杂,因此您有多个过滤器等等,或者由于任何其他原因您确实需要以声明方式执行此操作,那么您需要创建一种无限生成器。对于经典的同步代码,这意味着序列,而对于异步代码,这意味着流。
使用序列的示例:
generateSequence { client.get<String>(FLIGHT_ENDPOINT) }
.first { !isCanceled(it) }
流:
flow {
while (true) {
emit(client.get<String>(FLIGHT_ENDPOINT))
}
}.first { !isCanceled(it) }
正如您所说,您使用协程,我假设您想选择后者。正如您所看到的,它与我们最初的基于循环的方法非常相似,只是更复杂。当然,我们可以创建类似的generateFlow()
实用程序函数,然后它会更短。
英文:
As said in the comment by @Jorn, this looks like an overuse of functional style. It can be implemented by a simple loop and this way it will be probably more clear to the reader:
fun getNextNotCancelled() {
while (true) {
val response = client.get<String>(FLIGHT_ENDPOINT)
if (!isCanceled(response)) return response
}
}
If your real case is more complex, so you have several filters, etc. or for any other reason you really need to do this declaratively, then you need to create some kind of an infinite generator. For classic synchronous code that means sequence and for asynchronous - flow.
Example using a sequence:
generateSequence { client.get<String>(FLIGHT_ENDPOINT) }
.first { !isCanceled(it) }
Flow:
flow {
while (true) {
emit(client.get<String>(FLIGHT_ENDPOINT))
}
}.first { !isCanceled(it) }
As you said you use coroutines, I assume you would like to go for the latter. And as you can see, it is pretty similar to our initial loop-based approach, only more complicated. Of course, we can create a similar generateFlow()
utility function and then it would be shorter.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论