我知道在 Swift 中,静态变量是隐式惰性的:https://stackoverflow.com/a/34667272/1672161
但我不清楚为什么会这样:
protocol HatType {}
class Hat: HatType {
init() { print("real hat") }
}
class MockHat: HatType {
init() { print("mock hat") }
}
struct HatInjector {
static var hat: HatType = Hat()
}
HatInjector.hat = MockHat()
// Output:
// real hat
// mock hat
我看到的是,对静态变量的赋值在某种意义上也是在调用 getter。这对我来说不直观。这里发生了什么?为什么不只发生赋值?
最佳答案
这是因为静态和全局存储变量目前(这所有都可能发生变化)编译器只给了一个访问器——unsafeMutableAddressor
,它得到一个指向变量的存储(可以看到 by examining the SIL or IR emitted )。
这个访问器:
获取指向编译器生成的全局标志的指针,该标志确定静态变量是否已初始化。
调用
swift_once
使用这个指针,以及一个初始化静态变量的函数(这是你给它的初始化表达式,即= Hat()
)。在 Apple 平台上,swift_once
只是 forwards ontodispatch_once_f
.返回指向静态变量存储的指针,调用者随后可以自由读取和修改该存储 - 因为存储具有静态生命周期。
所以它或多或少相当于 Objective-C 线程安全的惰性初始化模式:
+(Hat*) hat {
static Hat* sharedHat = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
sharedHat = [[Hat alloc] init];
});
return sharedHat;
}
主要区别在于 Swift 返回一个指向 sharedHat
存储的指针(一个指向引用的指针),而不是 sharedHat
本身(只是对实例的引用)。
因为这是静态和全局存储变量的唯一也是唯一访问器,为了执行赋值,Swift 需要调用它以获得指向存储的指针。因此,如果它还没有被初始化——访问者需要先将它初始化为默认值(因为它不知道调用者要用它做什么),然后调用者然后设置它到另一个值。
这种行为确实有些不直观,已经filed as a bug .正如 Jordan Rose 在报告的评论中所说:
This is currently by design, but it might be worth changing the design.
所以这种行为很可能会在未来的语言版本中改变。
关于swift - 在 Swift 中,为什么分配给静态变量也会调用它的 getter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43374222/