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

In Swift, why does assigning to a static variable also invoke its getter

我知道在 Swift 中,静态变量是隐式惰性的:

但我不清楚为什么会这样:

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。这对我来说不直观。这里发生了什么?为什么不只发生赋值?

中相同的解决方案

尝试延迟加载:

struct HatInjector {
    private static var _hat: HatType?
    static var hat: HatType {
        get { return _hat ?? Hat() }
        set(value) { _hat = value }
    }
}

或者:

struct HatInjector {
    private static var _hat: HatType?
    static var hat: HatType {
        get {
            if _hat == nil {
                _hat = Hat()
            }
            return _hat!
        }
        set(value) { _hat = value }
    }
}

原因: 代码中的静态变量不是可选的。因此在使用它时 swift 必须确保它不是 nil(swift 是保存!)。因此编译器要求你设置一个初始值。您不能定义:

static var prop1: MyProtocol

这将导致编译器错误。如果你定义

static var prop1: MyProtocol?

它将有效,因为它是

的快捷方式
static var prop1: MyProtocol? = nil

这是因为静态和全局存储变量目前(这是所有可能会发生变化)编译器只给了一个访问器——unsafeMutableAddressor,它得到一个指向变量存储的指针(可见by examining the SIL or IR emitted)。

这个存取器:

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

  2. 调用 swift_once with this pointer, along with a function that initialises the static variable (this is the initialiser expression you give it, i.e = Hat()). On Apple platforms, swift_once simply forwards onto dispatch_once_f.

  3. Returns 一个指向静态变量存储的指针,调用者可以自由读取和修改——因为存储具有静态生命周期。

所以它或多或少相当于 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需要调用它才能获得指向存储的指针。因此,如果它还没有初始化——访问者需要先将它初始化为默认值(因为它不知道调用者要用它做什么),然后再调用者 then 将其设置为另一个值。

这种行为确实有些不直观,一直filed as a bug。正如 Jordan Rose 在报告的评论中所说:

This is currently by design, but it might be worth changing the design.

所以这种行为很可能会在语言的未来版本中改变。