kotlin 如何从内部函数返回高阶函数的结果

cxfofazt  于 2022-12-23  发布在  Kotlin
关注(0)|答案(2)|浏览(125)

我有一个需要返回值的“高阶”函数,在这个“高阶”函数内部有一个“内部”函数,它实际上是“高阶”函数返回值的生成器。
用一个例子来说明我的意思会更简单:

lifecycle.coroutineScope.launch {
        val result = doWork() 
        Log.d("Tag", "some result: ${result.someString}")
    }

private val service = SomeService()

suspend fun doWork(): DoWorkResult {

    fun onSomeString(someString: String): DoWorkResult {

        //some execution

        val returnResultForDoWork = DoWorkResult(someString)

        //How to return 'returnResultForDoWork' from fun doWork
        return returnResultForDoWork
    }

    service.getString { someString ->
        onSomeString(someString)
    }

}

class SomeService() {
    suspend fun getString(
        onResult: (String) -> Unit
    ) {
        delay(1000)
        onResult("work is done")
    }
}

data class DoWorkResult(val someString: String)

流程执行:
1.调用service.getString
1.当从service.getString返回someString时调用onSomeString(someString)
1.在onSomeString中分析/处理someString并从doWork返回(如何?)DoWorkResult(someString)
我的问题是如何将onSomeString函数的结果作为doWork函数的结果返回?

z0qdvdin

z0qdvdin1#

挂起函数不需要像那样的高阶回调。实际上,它是一个反模式,因为它恢复了协程解决的“回调地狱”。一个适当版本的函数应该看起来像这样:

class SomeService() {
    suspend fun getString(): String {
        delay(1000)
        return "work is done"
    }
}

然后调用函数变为:

suspend fun doWork(): DoWorkResult {
    val serviceReturnValue = getString()

    //some execution

    val returnResultForDoWork = DoWorkResult(serviceReturnValue)
    return returnResultForDoWork
}

但是让我们假设您的服务函数不是一个suspend函数,而是与回调异步的,并且您无法控制源代码使其成为suspend函数。

class SomeService() {
    fun getString(
        onResult: (String) -> Unit
    ) {
        val handler = Handler(Looper.myLooper())
        thread {
            Thread.sleep(1000) //simulate some work
            handler.post { onResult("work is done") }
        }
    }
}

然后,为了能够在suspend函数中返回回调函数的内部值,您需要将异步函数转换为一个suspend函数。这可以通过suspendCoroutinesuspendCancellableCoroutine来完成。您可以在本网站或在线查找许多示例,但这里有一个快速示例。您可以将其编写为扩展函数,以像异步函数的重载版本一样工作。

suspend fun SomeService.getString(): String = suspendCoroutine { continuation ->
    getString { continuation.resume(it) }
}

现在,您可以调用该函数的适当挂起版本,就像在上面的第二个代码块中一样。

zu0ti5jz

zu0ti5jz2#

老实说,我不太确定我是否真的明白你想做什么,但...
这是您要找的吗?

private val service = SomeService()
    data class DoWorkResult(val someString: String)

    suspend fun doWork(): DoWorkResult {
        fun onSomeString(someString: String): DoWorkResult {
            //some execution

            val returnResultForDoWork = DoWorkResult(someString)

            //How to return 'returnResultForDoWork' from fun doWork
            return returnResultForDoWork
        }

        return service.getString { someString ->
            onSomeString(someString)
        }
    }

    class SomeService {
        suspend fun getString(onResult: (String) -> DoWorkResult): DoWorkResult {
            delay(1000)
            val myStringFromNetworkOrSomething = "work is done"
            return onResult(myStringFromNetworkOrSomething)
        }
    }

相关问题