swift - 在 Swift 中,为什么分配给静态变量也会调用它的 getter

标签 swift variables static lazy-evaluation

我知道在 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 )。

这个访问器:

  1. 获取指向编译器生成的全局标志的指针,该标志确定静态变量是否已初始化。

  2. 调用 swift_once使用这个指针,以及一个初始化静态变量的函数(这是你给它的初始化表达式,即 = Hat())。在 Apple 平台上,swift_once 只是 forwards onto dispatch_once_f .

  3. 返回指向静态变量存储的指针,调用者随后可以自由读取和修改该存储 - 因为存储具有静态生命周期。

所以它或多或少相当于 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/

相关文章:

ios - 从 Web 服务获取数组到 pickerview

haskell - 在haskell中,有没有一种方法可以防止变量在递归内部发生变化?

string - SSIS:从字符串变量中过滤多个 GUID 作为数据流 OLE 源中的参数

c - 静态分配和有限范围之间的关系

swift - 属性更改时的动画 View SwiftUI

iphone - 联系后尝试隐藏节点

环球银行金融电信协会2 : multiline MKPointAnnotation

php - "Notice: Undefined variable"、 "Notice: Undefined index"、 "Warning: Undefined array key"和 "Notice: Undefined offset"使用 PHP

c - 如何添加静态断言来检查变量是否是静态的?

c# - 关于c#的点(.)运算符