访问结构上的惰性 属性 会改变结构
Accessing a lazy property on a struct mutates the struct
我在结构中有一个惰性 属性,每次访问它时,它都会改变结构。
var numbers = [1,2,3]
struct MyStruct {
lazy var items = numbers
}
class MyClass {
var myStructPropery: MyStruct = MyStruct() {
didSet {
print(myStructPropery)
}
}
}
var myClass = MyClass()
myClass.myStructPropery.items
myClass.myStructPropery.items
myClass.myStructPropery.items
结果:
每次都会调用Print(didSet)
理想的行为应该是第一次突变(因为这是惰性变量的行为方式)。这是 Swift 中的错误还是我做错了什么?
我开始使用以下设置进行调试 -
var numbers = [1,2,3]
struct MyStruct {
lazy var items = numbers
}
class MyClass {
var myStructPropery: MyStruct = MyStruct() {
didSet {
// Changed this to make sure we are not invoking getter here
print("myStructPropery setter called")
}
}
}
let myClass = MyClass()
myClass.myStructPropery.items
myClass.myStructPropery.items
myClass.myStructPropery.items
我可以使用 Swift 5.4
在 Xcode 12.5
上重现该问题。
尝试 1:将 var numbers
变成 let numbers
- 不起作用。
let numbers = [1,2,3]
尝试 2:在不使用额外变量的情况下直接分配值 - 不起作用。
struct MyStruct {
lazy var items = [1,2,3]
}
尝试 3:使用完整的 getter 语法分配内联值 - 不起作用。
struct MyStruct {
lazy var items: [Int] = {
return [1,2,3]
}()
}
在这一点上,我们没有选择可以尝试。尽管我们可以清楚地看到 return [1,2,3]
在最后一次尝试中恰好执行了一次,但 MyClass.myStructPropery.modify
在访问 items
.
时被重复调用
也许 Swift Forums 是讨论这个问题的更好地方。
你看到的是观察到的 属性 items
已经通知它的观察者它已经被访问了,因为它被访问了,并且惰性变量根据定义是变异的,因为它会稍后设置。因此 didSet
被调用来处理这个问题。
惰性变量实际上只设置了一次,即使它发出信号表明它已经发生变异,并且 属性 myStructPropery
仅在首次设置变量时发生一次变异,但之后是同一个实例.
我们可以通过以下方式验证这一点,首先更改惰性 var 声明,使其更像我们通常声明此类变量的方式
lazy var items: [Int] = { numbers }()
然后添加打印语句
lazy var items: [Int] = {
print("inside lazy")
return numbers
}()
如果我们现在运行测试代码
var myClass = MyClass()
myClass.myStructProperty.items
myClass.myStructProperty.items
myClass.myStructProperty.items
我们看到“inside lazy”只打印一次。为了验证 属性 myStructProperty
没有改变,我们可以使结构符合 Equatable
并在 didSet
中执行简单检查
didSet {
if oldValue != myStructProperty {
print(myStructProperty)
}
}
现在 运行在测试中我们看到 didSet
中的打印从未执行,因此 myStructProperty 从未更改。
我不知道这种行为是否是一个错误,但我个人觉得 属性 观察者在访问惰性 属性 后停止观察它可能会很复杂var 一旦设置就不会被定义为变异。
我在结构中有一个惰性 属性,每次访问它时,它都会改变结构。
var numbers = [1,2,3]
struct MyStruct {
lazy var items = numbers
}
class MyClass {
var myStructPropery: MyStruct = MyStruct() {
didSet {
print(myStructPropery)
}
}
}
var myClass = MyClass()
myClass.myStructPropery.items
myClass.myStructPropery.items
myClass.myStructPropery.items
结果:
每次都会调用Print(didSet)
理想的行为应该是第一次突变(因为这是惰性变量的行为方式)。这是 Swift 中的错误还是我做错了什么?
我开始使用以下设置进行调试 -
var numbers = [1,2,3]
struct MyStruct {
lazy var items = numbers
}
class MyClass {
var myStructPropery: MyStruct = MyStruct() {
didSet {
// Changed this to make sure we are not invoking getter here
print("myStructPropery setter called")
}
}
}
let myClass = MyClass()
myClass.myStructPropery.items
myClass.myStructPropery.items
myClass.myStructPropery.items
我可以使用 Swift 5.4
在 Xcode 12.5
上重现该问题。
尝试 1:将 var numbers
变成 let numbers
- 不起作用。
let numbers = [1,2,3]
尝试 2:在不使用额外变量的情况下直接分配值 - 不起作用。
struct MyStruct {
lazy var items = [1,2,3]
}
尝试 3:使用完整的 getter 语法分配内联值 - 不起作用。
struct MyStruct {
lazy var items: [Int] = {
return [1,2,3]
}()
}
在这一点上,我们没有选择可以尝试。尽管我们可以清楚地看到 return [1,2,3]
在最后一次尝试中恰好执行了一次,但 MyClass.myStructPropery.modify
在访问 items
.
也许 Swift Forums 是讨论这个问题的更好地方。
你看到的是观察到的 属性 items
已经通知它的观察者它已经被访问了,因为它被访问了,并且惰性变量根据定义是变异的,因为它会稍后设置。因此 didSet
被调用来处理这个问题。
惰性变量实际上只设置了一次,即使它发出信号表明它已经发生变异,并且 属性 myStructPropery
仅在首次设置变量时发生一次变异,但之后是同一个实例.
我们可以通过以下方式验证这一点,首先更改惰性 var 声明,使其更像我们通常声明此类变量的方式
lazy var items: [Int] = { numbers }()
然后添加打印语句
lazy var items: [Int] = {
print("inside lazy")
return numbers
}()
如果我们现在运行测试代码
var myClass = MyClass()
myClass.myStructProperty.items
myClass.myStructProperty.items
myClass.myStructProperty.items
我们看到“inside lazy”只打印一次。为了验证 属性 myStructProperty
没有改变,我们可以使结构符合 Equatable
并在 didSet
didSet {
if oldValue != myStructProperty {
print(myStructProperty)
}
}
现在 运行在测试中我们看到 didSet
中的打印从未执行,因此 myStructProperty 从未更改。
我不知道这种行为是否是一个错误,但我个人觉得 属性 观察者在访问惰性 属性 后停止观察它可能会很复杂var 一旦设置就不会被定义为变异。