Swift常量:结构或枚举

cvxl0en2  于 2022-10-31  发布在  Swift
关注(0)|答案(5)|浏览(160)

我不确定哪一个更适合定义常量。一个结构体还是一个枚举。一个结构体在每次使用时是否会被复制?当我想到一个带有static let常量的结构体时,在我看来,它总是被复制是没有意义的。但是如果它不会被复制,那么我取什么也没有关系了。
选择结构体或枚举有什么好处?
Francescu says use structs.
雷·温德利希说使用枚举,但我缺乏理由。

ltskdhd1

ltskdhd11#

结构和枚举都可以使用。

struct PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}

enum PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}

工作并定义一个静态属性PhysicalConstants.speedOfLight

Re:每次使用结构体时是否都要复制它?

structenum都是值类型,因此也适用于枚举。但这在这里是 * 不相关的 *,因为你根本不需要创建一个值:静态属性(也称为 type 属性)是型别本身的属性,而不是该型别之执行严修的属性。

Re:选择结构体或枚举有什么好处?

如链接文章中所述:
使用不区分大小写的枚举的优点是,它不会意外地被示例化,并且可以作为纯命名空间工作。
所以对于一个结构,

let foo = PhysicalConstants()

会建立PhysicalConstants型别的(无用的)值,但对于不区分大小写的枚举型别,它无法编译:

let foo = PhysicalConstants()
// error: 'PhysicalConstants' cannot be constructed because it has no accessible initializers
pod7payv

pod7payv2#

这里有一个简短的答案:你的常量需要是唯一的吗?那么使用一个枚举,它会强制执行这个。
想要使用几个不同的常量来包含相同的值(通常对清晰度很有用)?那么就使用一个结构体,它允许这样做。

w7t8yxp5

w7t8yxp53#

两者之间的一个区别是,结构体可以被示例化,而枚举不能。因此,在大多数情况下,你只需要使用常量,最好使用枚举来避免混淆。
例如:

struct Constants {
    static let someValue = "someValue"
}

let _ = Constants()

上述代码仍然有效。
如果我们使用枚举:

enum Constants {
    static let someValue = "someValue"
}

let _ = Constants() // error

以上代码无效,避免混淆。

oo7oh9g9

oo7oh9g94#

使用Xcode 7.3.1和Swift 2.2
虽然我同意Martin R的观点,Ray Wenderlich风格指南也指出枚举在几乎所有用例中都更好,因为它是一个纯命名空间,但有一个地方使用struct胜过enums

Switch陈述式

让我们从结构体版本开始:

struct StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

使用一个结构体,它将匹配并输出Matched StaticVars.someString
现在让我们考虑无大小写的枚举版本(通过只将关键字struct更改为enum):

enum StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}

你会注意到在switch语句的case StaticVars.someString:行上出现了一个编译时错误,错误代码是Enum case 'someString' not found in type 'String'
有一个伪解决方法,将静态属性转换为返回类型的闭包。
因此,您可以将其更改为:

enum StaticVars {
    static let someString = { return "someString" }
}

switch "someString" {
case StaticVars.someString(): print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}
  • 请注意,case语句中需要使用括号,因为它现在是一个函数。*

缺点是,现在我们已经把它变成了一个函数,每次调用它时,它都会被执行。所以,如果它只是一个简单的原语类型,比如StringInt,这还不算太糟。它本质上是一个计算属性。如果它是一个需要计算的常量,而你只想计算一次,考虑将其计算到不同的属性中并在闭包中返回已经计算的值。
你也可以用一个私有的初始化器来覆盖默认的初始化器,然后你会得到和无大小写枚举一样的编译时错误。

struct StaticVars {
    static let someString = "someString"
    private init() {}
}

但是这样的话,你会想把struct的声明放在它自己的文件中,因为如果你把它声明在同一个文件中,比如说,一个View Controller类,该类的文件仍然可能意外地示例化一个无用的StaticVars示例,但是在类的文件之外,它会按预期工作。

qni6mghb

qni6mghb5#

Combine框架中,Apple选择了命名空间的枚举。

enum Publishers

用作发布服务器的类型的命名空间。

enum Subscribers

用作订阅服务器的类型的命名空间。

enum Subscriptions

与订阅相关的符号的命名空间。

相关问题