修改挂起函数返回的对象

问题描述

我最近开始使用 Kotlin,现在正在用一些基本的东西进行测试。想象一下,我有一个用于访问数据库的类,让它看起来像这样:

@ThreadLocal object DataService {

    private var dao: DataAccessObject? = null

    private val context = dispatchers.Default

    fun injectDao(dao: DataAccessObject) {
        Coroutinescope(context).async {
            DataService.dao = dao
        }
    }

    suspend fun get(dataObjectType: TypeOfDataObject,id: String): DataObject? = withContext(context) {
        dao?.get(dataObjectType = dataObjectType,id = id)
    }

}

它的设计方式是无论何时何地我们调用它的线程 - 代码都将在后台运行。为了实现这一点,每当我们注入 dao 依赖项时,它都会被注入到 DataService 对象的后台线程副本中。基本上它工作得很好,并且一切都是在后台触发的。但是当我们例如使用 get 函数然后尝试修改返回的对象时 - 我们有一个可变性异常。所以这段代码不起作用:

suspend  fun test() {
    var object = get(TypeOfDataObject.someObject,id = "F702BCAF-DD63-4196-AA7B-E214248CAEB7")
    object.id = "whatever"
}

那么处理这种情况的最佳方法是什么?想象一下,我只想从 db 获取一个元素,更改一些值并将其写回,然后传递给 update 函数。我怎样才能做到这一点?

Kotlin's Immutability 是否意味着如果这个对象是在后台线程中创建的,它也只能在后台线程中更新?

解决方法

Kotlin 的不变性是否意味着如果这个对象是在后台线程中创建的,它也只能在后台线程中更新?

总而言之,是的。如果你想要可变状态,简单的答案就是在你创建它的线程中改变它。

withContext(context) {
//whatever
}

从传递给 withContext 的 lambda 返回的任何内容都将在返回时冻结。

现在,我觉得我没有在做我的工作,因为我没有指出你可能不应该首先改变数据对象。但是,您并不是在寻求该建议,因此我们将不理会这个话题。

我会做这样的事情:

suspend fun get(dataObjectType: TypeOfDataObject,id: String,doStuff:(DataObject?)->DataObject?): DataObject? = withContext(context) {
    doStuff(dao?.get(dataObjectType = dataObjectType,id = id))
}

然后这样称呼它:

suspend  fun test() {
    var object = get(TypeOfDataObject.someObject,id = "F702BCAF-DD63-4196-AA7B-E214248CAEB7") { newObject ->
        newObject.id = "whatever"
    }
}
,

我找到了适合我的解决方案。我会在下面留下一些笔记,以供将来可能遇到此问题的时间旅行者使用。

基本上,我使我试图完成的任务过于复杂。在这种特殊情况下,使 aggregate(mpg ~ am,data = mtcars,mean) > aggregate(mpg ~ am,mean) am mpg 1 0 17.14737 2 1 24.39231 函数按我预期工作的最简单和最合适的方法就是不使用它们。

我更喜欢反应式编程风格,因此对于 Kotlin 世界来说,使用简单的闭包或 lambda 对我来说没有什么坏处。所以看起来很简单:

suspend

感谢 Kevin,他解释了这些基础知识,帮助我找到了一种简单而合适的方法。

附言如果有任何时间旅行者会阅读本文,请发表评论,@ThreadLocal object DataService { private var dao: DataAccessObject? = null private val scope = GlobalScope fun injectDao(dao: DataAccessObject) { scope.async { DataService.dao = dao } } fun get(dataObjectType: KNTypeOfDataObject,onComplete: (KNDataObject?) -> Unit) { scope.async { dao?.get(dataObjectType = dataObjectType,id = id,onComplete = onComplete) } } } 函数在哪些情况下真正适合我使用反应式编程风格?

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...