gpt4 book ai didi

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

转载 作者:IT王子 更新时间:2023-10-29 05:14:20 24 4
gpt4 key购买 nike

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

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

extension String {
static let test = "Test"
static var test2 = "Test2"
}

最佳答案

扩展不能包含存储的实例属性。为什么?因为添加实例属性将更改该类型的实例的大小。如果一个模块添加了扩展名,使得Int现在长2个字,会发生什么情况?例如,当它从另一个仍为1个字大小的模块中获取Int时,应该怎么办?

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

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

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

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

struct S<T> {

static var foo: Int {
return 5
}

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

就像 foo是针对 S的个别特化(例如 S<Int>.fooS<Float>.foo)而不是 S本身调用一样(实际上, S目前还不是一种类型,它要求 T满足); bar可能相同。例如,它将被称为 S<Int>.bar而不是 S.bar

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

因此,能够在泛型类型的不同专长上调用相同的静态属性初始化程序,则有可能为每种类型创建不同的属性值(考虑 static let baz = T.self的简单情况)。因此,我们需要为每个存储空间单独存储。

但是,尽管如此,编译器/运行时无法做到这一点并没有真正的理由,它可能会在该语言的 future 版本中实现。尽管有一个反对的说法,那就是在某些情况下它可能会产生困惑的行为。

例如,考虑:
import Foundation

struct S<T> {
static let date = Date()
}

如果运行时在每次对 date进行新的特化处理时隐式生成了 S<T>的新存储,则 S<Float>.date将不等于 S<Int>.date;这可能会造成混淆和/或不期望。

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

这主要是从上一点开始的。协议(protocol)扩展中的 static存储属性将为该协议(protocol)的每种符合类型都需要单独存储(但同样;没有理由,编译器/运行时不能这样做)。

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

例如,如果我们有:
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 {}

我们无法访问协议(protocol)类型本身上的 foo,也不能说 P.foo。我们只能说 S.fooS1.foo。这很重要,因为 foo的getter可以调用 self上的静态协议(protocol)要求;但是,如果 selfP.self(即协议(protocol)类型本身),则无法实现,例如 protocols don't conform to themselves

对于 static存储的属性(例如 bar),将同样如此(可能)。

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

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

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

关于swift - 扩展名可能不包含存储的属性,但是为什么允许使用静态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45467329/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com