为什么声明为val的MutableStateFlow可通过update方法修改存储的值
问题解答
1. 为什么val修饰的_uiState可以调用update方法修改内容
Kotlin中val的核心约束是变量的引用不可变,而非变量指向的对象内部状态不可变。你可以把val理解为只读的变量指针,一旦初始化完成,就不能再让这个指针指向其他对象,但指针指向的对象本身的内部属性是允许修改的。
举个简单的例子:
val numList = mutableListOf(1, 2, 3) numList.add(4) // 合法,修改的是List对象内部的内容,没有改变numList的指向 numList = mutableListOf(5,6) // 非法,尝试给val变量重新赋值,改变指针指向
回到你的代码,_uiState被val修饰,只是限制你不能再给_uiState分配新的MutableStateFlow实例,但是MutableStateFlow内部持有的value属性是可变的,调用update方法修改的是MutableStateFlow内部的value,没有改变_uiState本身的引用,完全符合val的语法约束。
2. 全val的InterestsUiState为什么可以被修改
InterestsUiState作为全val的data class,本身实例一旦创建确实无法修改任何成员属性,你看到的“值变化”本质是对象替换,而非修改原对象:
- 调用
it.copy(loading = true)时,会基于旧的InterestsUiState实例,生成一个全新的InterestsUiState实例,旧的实例不会有任何变化 update方法做的事,就是把MutableStateFlow内部持有的旧的InterestsUiState实例,替换为新生成的copy实例
所以变化的是MutableStateFlow里存储的对象,不是原InterestsUiState实例本身,完全符合data class的不可变特性。
3. update写法和直接修改value是否等价
单线程场景下,两者的执行效果完全一致,但是多线程并发更新场景下有本质区别:
- 你写的
_uiState.value = _uiState.value.copy(loading = true)是非原子操作,如果多个线程同时执行这段代码,会出现竞态条件,部分更新会被覆盖丢失 update方法内部是基于CAS实现的原子操作,源码里通过循环+compareAndSet保证并发场景下所有更新都能生效,不会丢失
如果你的代码不存在多线程同时更新_uiState的场景,两种写法没有差异。
内容的提问来源于stack exchange,提问作者HelloCW
相关产品推荐
相关产品推荐

