我尝试重用Swift的一段旧代码,但是得到一个错误“不能在不可变值上使用mutating getter:'self'是不可变错误'。Xcode想在func之前添加'mutating',并提供了通过' fix '来完成。因此,错误在那里消失了,但仍然保留在'Text'语句中。
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
2条答案
按热度按时间zyfwsgd61#
因为当你在struct内部调用
x
时,并不清楚contentView
本身是否是可变的,一个值类型只有在被定义为var
时才是可变的。因此,如果在结构体内部的构建器函数中使用它之前,先用一个不可变的值 Package 它,那会很有帮助。
像这样:
💡* * 注意**:
Lazy
属性的值将在第一次调用时关联,这会使对象发生变化。因此,它们被视为mutating
kfgdxczn2#
getter无法变异
这主要是Swift在getter中实施的一种设计,其原理是:
getter不应该改变对象,因为开发者可能不希望这样,他们应该只在你使用 setter 或调用一个 mutating 函数时才希望改变,getter两者都不是。
下面的示例按预期工作:
当我们打印时,我们得到
a.isOn
的值,a和b是相同的。然而在下面的例子中,getter会有一个副作用,它甚至不会编译,但让我们假设它编译了,看看会发生什么。
当我们打印时,我们 * 得到 *
a.isOn
的值,但是这次a,B不再相同。a.x
现在是5,因为写入时复制已经发生,而b.x
仍然是3。Swift的架构不允许“getter改变对象”。
例外情况
Swift体系结构对此规则有两个例外:
lazy
@State
或其他属性 PackageLazy正在变异:
即使
print(x)
在 * 获得 *x
的值时会改变x
,这也没关系,因为它是一个惰性属性。您可能想知道
lazy var x = 5
和var x = 5
之间有什么不同,答案是后者在结构体初始化时设置了x
的值...SwiftUI -特殊情况
因为
body
变量是一个计算属性,所以你不能改变/设置变量,但是有一种方法可以解决这个问题。使用
@State
属性 Package 器标记变量。下面的代码将无法编译:
但是下面的代码可以,仅仅因为它有
@State
有关详细信息,请参见here