扩展名可能不包含存储的属性,但是为什么允许使用静态

扩展不能包含存储的属性,但是为什么可以在扩展内定义静态存储的属性呢?

我也没有找到任何文档提及扩展中允许使用静态属性。

extension String {

static let test = "Test"

static var test2 = "Test2"

}

回答:

扩展不能包含存储的 实例 属性。为什么?因为添加实例属性会更改该类型的实例的大小。如果一个模块添加了一个扩展名,使得an

Int现在为2个字,会发生什么情况?例如,当它Int从另一个仍为1个字大小的模块中获取一个时,应该怎么办?

扩展中允许使用 静态

存储属性的原因仅仅是因为它们具有静态生存期。它们独立于要扩展的给定类型的任何实例而存在。实际上,它们只不过是全局存储的变量,只是命名空间为一种类型。因此,可以自由添加它们,而不会影响在不了解它们的情况下已经编译的代码。

但是,值得注意的是,当前在定义静态存储属性方面存在三个限制。

1.您不能static在通用类型上定义存储的属性

对于通用占位符的每个单独的专业化,这将需要单独的属性存储。例如,使用:

struct S<T> {

static var foo: Int {

return 5

}

static let bar = "" // error: Static stored properties not supported in generic types

}

就像fooSS<Int>.fooS<Float>.foo不是

S自身进行专门化所要求的一样(实际上;S目前甚至还不是一种类型,它都需要T满足)。bar(可能)是相同的。这将被称为,例如S<Int>.bar,没有S.bar

这是一个重要的细节,因为调用静态成员的元类型将作为隐式self参数传递给接收者。这可以在静态属性初始化程序表达式中访问;因此允许他们调用其他静态方法。

因此,能够在泛型类型的 不同 专长上调用相同的静态属性初始化程序,就有可能为每个类型创建不同的属性值(考虑的简单情况static let baz =

T.self)。因此,我们需要为它们中的每一个单独存储。

综上所述,没有真正的理由使编译器/运行时无法做到这一点,并且很可能在该语言的未来版本中做到这一点。尽管有一个反对的说法,那就是在某些情况下它可能会产生混乱的行为。

例如,考虑:

import Foundation

struct S<T> {

static let date = Date()

}

如果运行时隐式地产生新的存储date每次它获取上的一个新的专业化的访问S<T>,那么S<Float>.date就不会相等S<Int>.date;

这可能会造成混淆和/或不期望。

2.您不能static在协议扩展中定义存储的属性

这主要是从上一点开始的。一个static在协议扩展存储的属性将需要对每个符合类型的协议单独的存储(但同样的,没有任何理由的编译器/运行时无法做到这一点)。

这对于协议是必要的,因为static协议扩展中的成员 不是 协议类型本身的成员。它们是符合协议的具体类型的成员。

例如,如果我们有:

protocol P {}

extension P {

static var foo: Int {

return 5

}

static let bar = "" // error: Static stored properties not supported in generic types

// (not really a great diagnostic)

}

struct S : P {}

struct S1 : P {}

我们foo不能说协议类型本身P.foo。我们只能说S.fooS1.foo。这很重要,因为foo吸气剂可以调用静态协议要求self;

但是,这是不可能selfP.self(即协议类型 本身),因为协议不符合自身。

对于static存储的属性(例如),也可能会发生同样的情况bar

3.您不能定义class存储的属性

我不认为类主体中的此类声明会存在任何问题(它等同于classstatic存储属性支持的计算属性)。

但是,在扩展中可能 出现问题,因为扩展无法将新成员添加到Swift类vtable中(尽管可以将它们添加到Obj-C对应对象中)。因此,在大多数情况下,它们不会动态分配给(实际上是final,因此static)。尽管如此,但扩展名当前允许使用class计算 属性,因此出于一致性考虑,可以允许使用 计算 属性。

以上是 扩展名可能不包含存储的属性,但是为什么允许使用静态 的全部内容, 来源链接: utcz.com/qa/412657.html

回到顶部