Swift常量:Struct或Enum

Pai*_*xsn 68 enums struct constants swift

我不确定哪两个更好地定义常量.结构或枚举.每次使用它时都会复制一个结构?当我想到一个带有static let常量的结构时,在我看来,它一直都会被复制是没有意义的.但如果它不会被复制,那么我采取什么并不重要?

结构或枚举的选择有什么优势?

Francisco说使用Struct的.

Ray Wunderlich说使用Enum的.但我缺乏理由.

Mar*_*n R 102

结构和枚举都有效.作为一个例子,两者

struct PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}
Run Code Online (Sandbox Code Playgroud)

enum PhysicalConstants {
    static let speedOfLight = 299_792_458
    // ...
}
Run Code Online (Sandbox Code Playgroud)

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

Re:每次使用它时都会复制一个结构体?

这两个structenum是值类型,以便将适用于枚举为好.但这无关,因为您根本不必创建值:静态属性(也称为类型属性)是类型本身的属性,而不是该类型的实例.

Re:结构或枚举的选择有哪些优点?

链接文章中所述:

使用无大小写枚举的优点是它不会被意外地实例化并且作为纯命名空间工作.

所以对于一个结构,

let foo = PhysicalConstants()
Run Code Online (Sandbox Code Playgroud)

创建一个(无用的)类型的值PhysicalConstants,但是对于无大小写的枚举,它无法编译:

let foo = PhysicalConstants()
// error: 'PhysicalConstants' cannot be constructed because it has no accessible initializers
Run Code Online (Sandbox Code Playgroud)

  • 次要添加:如果我们将`private init(){}`添加到`Struct`示例中,它还将具有无法在运行中意外实例化的"优势".(当然,这个"优势"可以被一些开发者用户通过在`Struct`的扩展中包含一个初始化器来规避:但是_if_我们出于某种原因更喜欢以"纯命名空间"的方式使用`Struct`,私有初始化程序可能是一个很好的"不使用 - 实例 - 保护",而不是"枚举". (6认同)

jgl*_*sse 14

这是一个简短的回答:你的常数需要是独一无二的吗?然后使用枚举,强制执行此操作.

想要使用几个不同的常量来包含相同的值(通常用于清晰度)?然后使用一个允许这个的结构.

  • 我认为他不会使用个别情况,因为那时他总是需要编写 `StaticVars.pi.rawValue` (3认同)

Sil*_*ntK 10

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

例如:

struct Constants {
    static let someValue = "someValue"
}

let _ = Constants()
Run Code Online (Sandbox Code Playgroud)

上面的代码仍然有效。

如果我们使用枚举:

enum Constants {
    static let someValue = "someValue"
}

let _ = Constants() // error
Run Code Online (Sandbox Code Playgroud)

上面的代码将是无效的,因此避免混淆。

  • 据我了解,如果将其所有 init 方法显式设为私有,则无法实例化结构 (2认同)

Rya*_*yan 7

Combine框架中,Apple 选择优先使用枚举作为命名空间。

enum Publishers
Run Code Online (Sandbox Code Playgroud)

作为发布者的类型的命名空间。

enum Subscribers
Run Code Online (Sandbox Code Playgroud)

用作订阅者的类型的命名空间。

enum Subscriptions
Run Code Online (Sandbox Code Playgroud)

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


Tim*_*qua 5

使用Xcode 7.3.1和Swift 2.2

尽管我同意Martin R的观点,但Ray Wenderlich样式指南指出,由于枚举是纯名称空间,因此在几乎所有用例中枚举都更好,这是一个很好的观点,但在某个地方使用struct王牌即可enums

切换语句

让我们从struct版本开始:

struct StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}
Run Code Online (Sandbox Code Playgroud)

使用一个结构,它将匹配并打印出来Matched StaticVars.someString

现在,让我们考虑无大小写的枚举版本(只需将关键字更改structenum):

enum StaticVars {
    static let someString = "someString"
}

switch "someString" {
case StaticVars.someString: print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}
Run Code Online (Sandbox Code Playgroud)

您会注意到,在该case StaticVars.someString:行的switch语句中遇到了编译时错误。错误是Enum case 'someString' not found in type 'String'

通过将static属性转换为返回类型的闭包,可以找到一种伪解决方法。

因此,您可以像这样更改它:

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

switch "someString" {
case StaticVars.someString(): print("Matched StaticVars.someString")
default: print("Didn't match StaticVars.someString")
}
Run Code Online (Sandbox Code Playgroud)

注意case语句中需要括号,因为它现在是一个函数。

不利的一面是,既然我们已经使其成为一个函数,则每次调用它都会执行一次。因此,如果它只是一个简单的原始类型(例如String或)Int,那么还算不错。它本质上是一个计算属性。如果它是一个需要计算的常数,而您只想计算一次,请考虑将其计算为其他属性,然后在闭包中返回该已计算的值。

您还可以使用专用的初始化器覆盖默认的初始化器,然后获得与无case枚举相同的编译时错误优度。

struct StaticVars {
    static let someString = "someString"
    private init() {}
}
Run Code Online (Sandbox Code Playgroud)

但是与此相关的是,您希望将结构的声明放入其自己的文件中,因为如果将其声明为与View Controller类的文件相同,则该类的文件仍然能够意外地实例化一个无用的文件。的实例StaticVars,但在类文件的外部,它将按预期工作。但这是你的电话。

  • 显然,此问题已得到解决。“无外壳枚举版本”将按预期在Xcode 8 beta 6中编译并运行。 (2认同)
  • 就在!我真的很喜欢使用无大小写枚举来获得“无实例化”的好处。我也很高兴我以 Xcode 版本信息开始我的帖子,否则可能会出现“在我的机器上运行”问题。 (2认同)