代码之家  ›  专栏  ›  技术社区  ›  HelloCW

为什么作者可以通过更新将新对象重新分配给val?

  •  0
  • HelloCW  · 技术社区  · 3 年前

    代码A来自官方示例代码 here .

    这个 private val _uiState val 在我看来,val只能分配一个对象一次。

    看来 _uiState.update { it.copy(loading = true) } 显示 _uiState 由重新指定给新对象 update .

    我不明白为什么作者可以通过 使现代化 ,你能告诉我吗?

    代码A

    data class InterestsUiState(
        val topics: List<InterestSection> = emptyList(),
        val people: List<String> = emptyList(),
        val publications: List<String> = emptyList(),
        val loading: Boolean = false,
    )
    
    class InterestsViewModel(
        private val interestsRepository: InterestsRepository
    ) : ViewModel() {
    
        // UI state exposed to the UI
        private val _uiState = MutableStateFlow(InterestsUiState(loading = true))
        val uiState: StateFlow<InterestsUiState> = _uiState.asStateFlow()
    
    
        private fun refreshAll() {
            _uiState.update { it.copy(loading = true) }
             ...
        }
    
        ...
    }   
    
    data class InterestsUiState(
        val topics: List<InterestSection> = emptyList(),
        val people: List<String> = emptyList(),
        val publications: List<String> = emptyList(),
        val loading: Boolean = false,
    )  
    
    /**
     * Updates the [MutableStateFlow.value] atomically using the specified [function] of its value.
     *
     * [function] may be evaluated multiple times, if [value] is being concurrently updated.
     */
    public inline fun <T> MutableStateFlow<T>.update(function: (T) -> T) {
        while (true) {
            val prevValue = value
            val nextValue = function(prevValue)
            if (compareAndSet(prevValue, nextValue)) {
                return
            }
        }
    }
    

    添加的内容

    赵:谢谢!

    但所有成员 data class InterestsUiState(...val loading: Boolean = false) 是val类型,并且在创建的对象时不能更改任何成员变量 InterestsUiState .

    所以我还是不明白为什么 _uiState公司 可以在作者启动时更改 _uiState。更新{it.copy(加载=true)} .

    还有更多

    _uiState。更新{it.copy(加载=true)} 等于 _uiState.value = _uiState.value.copy(loading = true) 正当

    1 回复  |  直到 3 年前
        1
  •  3
  •   Chaoz    3 年前

    这个 val 关键字仅指变量持有的对象,而不是所述对象内的数据。例如:

    class MyClass(var value: Int)
    

    以下代码为 允许:

    val obj = MyClass(5)
    obj = MyClass(7) // compile error
    

    因为 增值税 关键字是指变量本身被重新分配给不同的对象。然而,该代码, 允许:

    val obj = MyClass(5)
    obj.value = 7
    

    在这里,obj仍然是相同的对象,只有所述对象的属性改变了值。在您提供的代码中,update函数修改存储在 _uiState 对象,但它不会将其交换为新对象。这一点很重要,因为:

    var obj = MyClass(5)
    val copy = obj
    obj = MyClass(7)
    println(copy.value) // prints 5
    println(obj.value)  // prints 7
    

    重新分配变量时,旧对象保留,引用该对象的任何其他变量都不会更新。就你而言, _uiState.value 是修改的,而不是变量本身。希望这能把事情弄清楚!

    编辑:

    it.copy() 是创建新对象的表达式。然而,该代码是在该行中执行的 _uiState.update { it.copy(loading = true) } ,在 refreshAll() 作用由于它是lambda表达式中的最后一条语句(也是唯一一条,但无关紧要),因此它是所述lambda的返回值。这里我们必须看一下update函数的声明。
    λ存储在 function 变量(类型 (T)->T ). 这意味着,无论何时 function() 调用时,执行lambda中的代码,然后由 函数() 呼叫该值分配给 val nextValue 变量和非to _uiState公司 它本身这个 compareAndSet 函数修改 _uiState。价值 并且不会改变对象 _uiState公司 变量引用。
    顺便说一句,返回的对象是 它复制() 属于类型T,而不是类型 MutableStateFlow<T> ,您的 _uiState公司 变量保持不变。T是 _uiState。价值 .