不能对不可变值使用变异 getter:'self' 是不可变错误

Posted

技术标签:

【中文标题】不能对不可变值使用变异 getter:\'self\' 是不可变错误【英文标题】:Cannot use mutating getter on immutable value: 'self' is immutable error不能对不可变值使用变异 getter:'self' 是不可变错误 【发布时间】:2019-12-10 11:29:45 【问题描述】:

我正在尝试重用一段较旧的 Swift 代码,但出现错误“不能在不可变值上使用 mutating getter:'self' is immutable error”。 Xcode 想在 func 之前添加“变异”,并提出通过“修复”来实现。所以错误消失了,但仍然存在于“文本”语句中。

import SwiftUI

struct ContentView: View 

     typealias PointTuple = (day: Double, mW: Double)
    let points: [PointTuple] = [(0.0, 31.98), (1.0, 31.89), (2.0, 31.77), (4.0, 31.58), (6.0, 31.46)]

    lazy var meanDays = points.reduce(0)  $0 + $1.0  / Double(points.count)
    lazy var meanMW   = points.reduce(0)  $0 + $1.1  / Double(points.count)

    lazy var a = points.reduce(0)  $0 + ($1.day - meanDays) * ($1.mW - meanMW) 
    lazy var b = points.reduce(0)  $0 + pow($1.day - meanDays, 2) 

    lazy var m = a / b
    lazy var c = meanMW - m * meanDays        
    lazy var x : Double = bG(day: 3.0)
    lazy var y : Double = bG(day: 5.0)
    lazy var z : Double = bG(day: 7.0)

    mutating func bG(day: Double) -> Double 
        return m * day + c
    

    var body: some View 
        VStack 
            Text("\(x)")
            Text("\(y)")
            Text("\(z)")
        
    


#if DEBUG
struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    

#endif

【问题讨论】:

我发现这个问题的解决方法是使用计算属性而不是惰性变量。我不明白为什么我不能使用惰性变量,但我也不明白建议的解决方案 @charel-f 我写了一个新答案。请看一下 谢谢,您的新答案非常简洁易懂 【参考方案1】:

因为当您在结构内部调用x 时,不清楚contentView 本身是否可变。一个值类型只有在被定义为var时才变得可变。

因此,如果在结构内部的构建器函数中使用它之前使用不可变值包装它会有所帮助。

像这样:

func xValue() -> Double 
    var mutatableSelf = self
    return mutatableSelf.x


var body: some View 
    VStack 
        Text("\(xValue())")
    


?注意:延迟属性的值将在第一次调用时关联,这会改变对象。所以他们被认为是mutating

【讨论】:

【参考方案2】:

这与SwiftUI 无关。这是关于 Swift 使用它的 getter 执行的设计。原理是:

getter 不应该改变对象。因为开发人员可能没有预料到这一点。当您使用 setter 或调用 mutating 函数时,他们应该只期待更改。吸气剂都不是。

以下示例按预期工作:

struct Device 
    var isOn = true


let x = Device()
let y = Device()

y.isOn // Doing such will not cause the object to mutate.

然而在下面的例子中,getter 会产生副作用。 Swift 架构就是不允许这样做。

struct Device2 

    var x = 3
    var isOn: Bool 
        x = 5
        return true
    


let a = Device2()
let b = Device2()

a.isOn // Doing such will mutate the object. a.x will be '5'. While `b.x` will be '3'. Swift doesn't want to allow this.

【讨论】:

这帮助我意识到惰性属性在第一次调用时会改变对象,因此将始终被视为mutating。这很不幸,但至少现在说得通。

以上是关于不能对不可变值使用变异 getter:'self' 是不可变错误的主要内容,如果未能解决你的问题,请参考以下文章

不能对不可变值使用变异成员:“父”是“让”常量? [关闭]

从子视图中更改视图中的数组“不能在不可变值上使用变异成员:'self' 是不可变的”

Swift 2在协议扩展中使用变异函数时出错“无法在不可变值上使用变异成员:'self'是不可变的

如何使swiftui结构可变

发送到不可变对象的变异方法

SDK 8.3 不可变值...只有名为“附加”的变异成员