Swift常量:Struct或Enum

我不确定哪个更好定义常量。 结构或枚举。 每次我使用它或不是会复制一个结构体? 当我想到一个带有static let常量的结构时,在我看来,它总是会被复制,这是毫无意义的。 但是,如果它不会被复制,那么我拿什么都没有关系?

结构或枚举的select有什么优点?

Francisco说使用Struct的。

雷Wunderlich说使用Enum的。 但我缺乏理由。

结构和枚举都起作用。 作为一个例子,两者

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

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

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

Re:每当我使用它时,结构都会被复制?

structenum都是值types,所以也适用于枚举。 但是这里没有什么关系 ,因为根本不需要创build一个值:静态属性(也称为types属性)是types本身的属性,而不是该types的一个实例。

Re:结构或枚举的select有什么优点?

正如链接文章中提到的 :

使用无枚举枚举的优点是它不会意外地被实例化,并且作为一个纯名称空间来工作。

所以对于一个结构,

 let foo = PhysicalConstants() 

创build一个(无用的) PhysicalConstantstypes的值,但对于无例外枚举,则无法编译:

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

使用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") } 

使用一个结构体,这将匹配和打印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") } 

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

通过将静态属性转换为一个返回types的闭包来实现伪解决方法。

所以你可以这样改变它:

 enum StaticVars { static let someString = { return "someString" } } switch "someString" { case StaticVars.someString(): print("Matched StaticVars.someString") default: print("Didn't match StaticVars.someString") } 

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

缺点是现在我们已经把它变成了一个函数,每次调用它都会被执行。 所以,如果它只是一个简单的基本types如StringInt ,这并不是那么糟糕。 它本质上是一个计算的属性。 如果它是一个需要计算的常量,并且只需要计算一次,则可以考虑将其计算为不同的属性,并返回已经计算的闭包中的值。

你也可以使用私有的默认初始化方法来覆盖默认的初始化方法,然后你会得到和无情的枚举类似的编译时错误。

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

但是,有了这个,你会想把结构的声明放在它自己的文件中,因为如果你把它声明在同一个文件中,例如一个View Controller类,那么这个类的文件仍然能够意外地实例化一个无用的StaticVars实例,但在类的文件之外它将按预期工作。 但这是你的电话。