• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Swift5.3语言参考(六)声明

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

热烈欢迎,请直接点击!!!

进入博主App Store主页,下载使用各个作品!!!

注:博主将坚持每月上线一个新app!!!

一个声明引入了一个新的名称或构建到你的程序。例如,您使用声明来引入函数和方法,引入变量和常量,以及定义枚举,结构,类和协议类型。您还可以使用声明来扩展现有命名类型的行为,并将符号导入到其他地方声明的程序中。

在Swift中,大多数声明也是定义,因为它们是在声明它们的同时实现或初始化的。也就是说,由于协议不实现其成员,因此大多数协议成员仅是声明。为方便起见,因为在Swift中区别并不重要,术语声明包括声明和定义。

 1 GRAMMAR OF A DECLARATION
 2 
 3 declaration → import-declaration
 4 
 5 declaration → constant-declaration
 6 
 7 declaration → variable-declaration
 8 
 9 declaration → typealias-declaration
10 
11 declaration → function-declaration
12 
13 declaration → enum-declaration
14 
15 declaration → struct-declaration
16 
17 declaration → class-declaration
18 
19 declaration → protocol-declaration
20 
21 declaration → initializer-declaration
22 
23 declaration → deinitializer-declaration
24 
25 declaration → extension-declaration
26 
27 declaration → subscript-declaration
28 
29 declaration → operator-declaration
30 
31 declaration → precedence-group-declaration
32 
33 declarations → declaration declarations opt

顶级代码

Swift源文件中的顶级代码由零个或多个语句,声明和表达式组成。默认情况下,属于同一模块的每个源文件中的代码都可以访问在源文件顶层声明的变量,常量和其他命名声明。您可以通过使用访问级别修饰符标记声明来覆盖此默认行为,如访问控制级别中所述。

1 GRAMMAR OF A TOP-LEVEL DECLARATION
2 
3 top-level-declaration → statements opt

代码块

甲码块是由各种声明和控制结构,以组语句一起使用。它具有以下形式:

1 {
2     statements
3 }

代码块中的语句包括声明,表达式和其他类型的语句,并按照它们在源代码中的出现顺序执行。

1 GRAMMAR OF A CODE BLOCK
2 
3 code-block → { statements opt }

引用声明

一个引用声明,您可以访问声明当前文件之外的符号。基本表单导入整个模块; 它由import关键字后跟模块名称组成:

import module

提供更多详细信息限制导入的符号 - 您可以在模块或子模块中指定特定子模块或特定声明。使用此详细表单时,只有导入的符号(而不是声明它的模块)在当前作用域中可用。

1 import import kind module.symbol name
2 import module.submodule
1 GRAMMAR OF AN IMPORT DECLARATION
2 
3 import-declaration → attributes opt import import-kind opt import-path
4 
5 import-kind → typealias | struct | class | enum | protocol | let | var | func
6 
7 import-path → import-path-identifier | import-path-identifier . import-path
8 
9 import-path-identifier → identifier | operator

常数声明

一个常数声明引入了一个名为常量的值到你的程序。使用let关键字声明常量声明,并具有以下形式:

let constant name: type = expression

常量声明定义常量名称和初始化表达式值之间的不可变绑定; 设置常量值后,不能更改。也就是说,如果使用类对象初始化常量,则对象本身可以更改,但常量名称与其引用的对象之间的绑定不能。

当在全局范围内声明常量时,必须使用值初始化它。当在函数或方法的上下文中发生常量声明时,可以稍后对其进行初始化,只要保证在第一次读取其值之前设置值即可。当在类或结构声明的上下文中发生常量声明时,它被视为常量属性。常量声明不是计算属性,因此没有getter或setter。

如果常量声明的常量名称是元组模式,则元组中每个项的名称将绑定到初始化表达式中的相应值。

let (firstNumber, secondNumber) = (10, 42)

在此示例中,firstNumber是值的命名常量10,并且secondNumber是值的命名常量42。这两个常量现在可以独立使用:

1 print("The first number is \(firstNumber).")
2 // Prints "The first number is 10."
3 print("The second number is \(secondNumber).")
4 // Prints "The second number is 42."

当可以推断常量名称的类型时,类型注释(: 类型)在常量声明中是可选的,如类型推断中所述

要声明常量类型属性,请使用static声明修饰符标记声明。类型属性在类型属性中讨论。

有关常量的更多信息以及有关何时使用它们的指导,请参阅常量和变量以及存储的属性。

1 GRAMMAR OF A CONSTANT DECLARATION
2 
3 constant-declaration → attributes opt declaration-modifiers opt let pattern-initializer-list
4 
5 pattern-initializer-list → pattern-initializer | pattern-initializer , pattern-initializer-list
6 
7 pattern-initializer → pattern initializer opt
8 
9 initializer → = expression

变量声明

一个变量声明引入了一个名为变量值到你的程序,并使用声明var的关键字。

变量声明有几种形式,用于声明不同类型的命名可变值,包括存储和计算变量和属性,存储变量和属性观察器以及静态变量属性。要使用的适当形式取决于声明变量的范围以及要声明的变量类型。

注意

您还可以在协议声明的上下文中声明属性,如协议属性声明中所述。

您可以通过使用override声明修饰符标记子类的属性声明来覆盖子类中的属性,如覆盖中所述。

存储变量和存储变量属性

以下表单声明存储变量或存储变量属性:

var variable name: type = expression

您可以在全局范围,函数的本地范围或类或结构声明的上下文中定义此形式的变量声明。当在全局范围或函数的局部范围声明此表单的变量声明时,它被称为存储变量。当它在类或结构声明的上下文中声明时,它被称为存储变量属性。

初始化表达式不能出现在协议声明中,但在所有其他上下文中,初始化表达式是可选的。也就是说,如果不存在初始化表达式,则变量声明必须包含显式类型注释(: 类型)。

与常量声明一样,如果变量名是元组模式,则元组中每个项的名称将绑定到初始化表达式中的相应值。

顾名思义,存储变量或存储变量属性的值存储在内存中。

计算变量和计算属性

以下表单声明计算变量或计算属性:

1 var variable name: type {
2     get {
3         statements
4     }
5     set(setter name) {
6         statements
7     }
8 }

您可以在全局范围,函数的本地范围或类,结构,枚举或扩展声明的上下文中定义此形式的变量声明。当在全局范围或函数的局部范围声明此形式的变量声明时,它被称为计算变量。当它在类,结构或扩展声明的上下文中声明时,它被称为计算属性。

getter用于读取值,setter用于写入值。setter子句是可选的,当只需要一个getter时,你可以省略这两个子句,直接返回所请求的值,如Read-Only Computed Properties中所述。但是,如果提供setter子句,则还必须提供getter子句。

该二传手名称和圆括号是可选的。如果提供setter名称,则将其用作setter参数的名称。如果未提供setter名称,则seter的默认参数名称为newValue,如Shorthand Setter Declaration中所述。

与存储的命名值和存储的变量属性不同,计算的命名值或计算属性的值不存储在内存中。

有关更多信息以及查看计算属性的示例,请参阅计算属性。

存储变量观察器和属性观察器

您还可以使用willSetdidSet观察器声明存储的变量或属性。使用观察器声明的存储变量或属性具有以下形式:

1 var variable name: type = expression {
2     willSet(setter name) {
3         statements
4     }
5     didSet(setter name) {
6         statements
7     }
8 }

您可以在全局范围,函数的本地范围或类或结构声明的上下文中定义此形式的变量声明。当在全局范围或函数的局部范围声明此表单的变量声明时,观察器称为存储变量观察器。当在类或结构声明的上下文中声明它时,观察器被称为属性观察器。

您可以将属性观察器添加到任何存储的属性。您还可以通过覆盖子类中的属性将属性观察器添加到任何继承的属性(无论是存储还是计算),如覆盖属性观察器中所述。

初始化表达式在类或结构声明的上下文中是可选的,但在其他地方需要。该类型的注释是可选的,当类型可以从初始化推断表达。

willSetdidSet观察器提供了一种方式来观察(并适当地作出响应)时被设定的变量或属性的值。首次初始化变量或属性时,不会调用观察器。相反,只有在初始化上下文之外设置值时才会调用它们。

一个willSet观察器被称为设置变量或属性的值之前。新值willSet作为常量传递给观察器,因此在willSet子句的实现中不能更改它。在didSet新的值设置观测后立即调用。与willSet观察器相反,变量或属性的旧值将传递给didSet观察器,以防您仍需要访问它。也就是说,如果在其自己的didSetobserver子句中为变量或属性赋值,则分配的新值将替换刚刚设置并传递给willSet观察器的值。

和子句中的setter名称和括号是可选的。如果提供setter名称,它们将用作和观察器的参数名称。如果不提供setter名称,则观察器的默认参数名称为观察器的默认参数名称。willSetdidSetwillSetdidSetwillSetnewValuedidSetoldValue

didSet当您提供willSet子句时,该子句是可选的。同样,willSet当您提供didSet子句时,该子句是可选的。

有关更多信息以及查看如何使用属性观察器的示例,请参阅Property Observers。

变量属性

要声明类型变量属性,请使用static声明修饰符标记声明。类可以使用class声明修饰符标记类型计算属性,而不是允许子类覆盖超类的实现。类型属性在类型属性中讨论。

注意

在类声明中,static关键字与使用classfinal声明修饰符标记声明具有相同的效果。

 1 GRAMMAR OF A VARIABLE DECLARATION
 2 
 3 variable-declaration → variable-declaration-head pattern-initializer-list
 4 
 5 variable-declaration → variable-declaration-head variable-name type-annotation code-block
 6 
 7 variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-block
 8 
 9 variable-declaration → variable-declaration-head variable-name type-annotation getter-setter-keyword-block
10 
11 variable-declaration → variable-declaration-head variable-name initializer willSet-didSet-block
12 
13 variable-declaration → variable-declaration-head variable-name type-annotation initializer opt willSet-didSet-block
14 
15 variable-declaration-head → attributes opt declaration-modifiers opt var
16 
17 variable-name → identifier
18 
19 getter-setter-block → code-block
20 
21 getter-setter-block → { getter-clause setter-clause opt }
22 
23 getter-setter-block → { setter-clause getter-clause }
24 
25 getter-clause → attributes opt mutation-modifier opt get code-block
26 
27 setter-clause → attributes opt mutation-modifier opt set setter-name opt code-block
28 
29 setter-name → ( identifier )
30 
31 getter-setter-keyword-block → { getter-keyword-clause setter-keyword-clause opt }
32 
33 getter-setter-keyword-block → { setter-keyword-clause getter-keyword-clause }
34 
35 getter-keyword-clause → attributes opt mutation-modifier opt get
36 
37 setter-keyword-clause → attributes opt mutation-modifier opt set
38 
39 willSet-didSet-block → { willSet-clause didSet-clause opt }
40 
41 willSet-didSet-block → { didSet-clause willSet-clause opt }
42 
43 willSet-clause → attributes opt willSet setter-name opt code-block
44 
45 didSet-clause → attributes opt didSet setter-name opt code-block

类型别名声明

一个类型别名声明介绍了现有类型的命名别名到你的程序。类型别名声明使用typealias关键字声明,并具有以下形式:

typealias name = existing type

一个类型别名声明后,别名名称可以代替的现有类型无处不在你的程序。在现有类型可以是命名型或复合型。类型别名不会创建新类型; 它们只是允许名称引用现有类型。

类型别名声明可以使用泛型参数为现有泛型类型指定名称。类型别名可以为现有类型的部分或全部通用参数提供具体类型。例如:

1 typealias StringDictionary<Value> = Dictionary<String, Value>
2 
3 // The following dictionaries have the same type.
4 var dictionary1: StringDictionary<Int> = [:]
5 var dictionary2: Dictionary<String, Int> = [:]

当使用泛型参数声明类型别名时,对这些参数的约束必须与现有类型的泛型参数的约束完全匹配。例如:

typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>

由于类型别名和现有类型可以互换使用,因此类型别名不能引入其他通用约束。

类型别名可以通过省略声明中的所有泛型参数来转发现有类型的泛型参数。例如,Diccionario此处声明的类型别名具有相同的通用参数和约束Dictionary

typealias Diccionario = Dictionary

在协议声明中,类型别名可以为经常使用的类型提供更简单,更方便的名称。例如:

1 protocol Sequence {
2     associatedtype Iterator: IteratorProtocol
3     typealias Element = Iterator.Element
4 }
5 
6 func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
7     // ...
8 }

如果没有此类别别名,则该sum函数必须引用关联的类型T.Iterator.Element而不是T.Element

另请参阅协议关联类型声明。

1 GRAMMAR OF A TYPE ALIAS DECLARATION
2 
3 typealias-declaration → attributes opt access-level-modifier opt typealias typealias-name generic-parameter-clause opt typealias-assignment
4 
5 typealias-name → identifier
6 
7 typealias-assignment → = type

函数声明

一个函数声明引入了一个函数或方法到你的程序。在类,结构,枚举或协议的上下文中声明的函数称为方法。函数声明使用func关键字声明,并具有以下形式:

1 func function name(parameters) -> return type {
2     statements
3 }

如果函数的返回类型为Void,则返回类型可以省略,如下所示:

1 func function name(parameters) {
2     statements
3 }

必须包含每个参数的类型 - 无法推断。如果inout在参数类型前面写入,则可以在函数范围内修改参数。输入输出参数将在下面的输入输出参数中详细讨论。

函数可以使用元组类型作为函数的返回类型返回多个值。

函数定义可以出现在另一个函数声明中。这种函数称为嵌套函数。

如果嵌套函数捕获保证永不转义的值(例如输入输出参数)或作为非转义函数参数传递,则嵌套函数是非转义的。否则,嵌套函数是一个转义函数。

有关嵌套函数的讨论,请参阅嵌套函数。

参数名称

函数参数是以逗号分隔的列表,其中每个参数都具有多种形式之一。函数调用中参数的顺序必须与函数声明中的参数顺序相匹配。参数列表中最简单的条目具有以下形式:

parameter name: parameter type

参数具有在函数体中使用的名称,以及在调用函数或方法时使用的参数标签。默认情况下,参数名称也用作参数标签。例如:

1 func f(x: Int, y: Int) -> Int { return x + y }
2 f(x: 1, y: 2) // both x and y are labeled

您可以使用以下格式之一覆盖参数标签的默认行为:

1 argument label parameter name: parameter type
2 _ parameter name: parameter type

参数名称前面的名称为参数提供显式参数标签,该标签可以与参数名称不同。相应的参数必须在函数或方法调用中使用给定的参数标签。

_参数名称前面的下划线()会抑制参数标签。相应的参数在函数或方法调用中必须没有标签。

1 func repeatGreeting(_ greeting: String, count n: Int) { /* Greet n times */ }
2 repeatGreeting("Hello, world!", count: 2) //  count is labeled, greeting is not

输入输出参数

输入输出参数传递如下:

  1. 调用该函数时,将复制参数的值。
  2. 在函数体中,修改了副本。
  3. 函数返回时,副本的值将分配给原始参数。

此行为称为copy-in copy-out或按值调用结果。例如,当计算属性或具有观察器的属性作为输入输出参数传递时,其getter作为函数调用的一部分被调用,其setter作为函数返回的一部分被调用。

作为优化,当参数是存储在存储器中的物理地址处的值时,在函数体内部和外部使用相同的存储器位置。优化的行为称为引用调用 ; 它满足了拷入式拷贝模型的所有要求,同时消除了复制的开销。使用copy-in copy-out给出的模型编写代码,而不依赖于逐个引用的优化,以便在有或没有优化的情况下它的行为正确。

在函数内,不要访问作为输入输出参数传递的值,即使原始值在当前范围内可用。访问原始版本是同时访问该值,这违反了Swift的内存独占性保证。出于同样的原因,您无法将相同的值传递给多个输入输出参数。

有关内存安全性和内存独占性的更多信息,请参阅内存安全性。

捕获输入输出参数的闭包或嵌套函数必须是非溢出的。如果您需要捕获in-out参数而不进行变更或观察其他代码所做的更改,请使用捕获列表以不可变的方式显式捕获参数。

1 func someFunction(a: inout Int) -> () -> Int {
2     return { [a] in return a + 1 }
3 }

如果需要捕获并改变输入输出参数,请使用显式本地副本,例如在多线程代码中确保在函数返回之前完成所有变异。

1 func multithreadedFunction(queue: DispatchQueue, x: inout Int) {
2     // Make a local copy and manually copy it back.
3     var localX = x
4     defer { x = localX }
5 
6     // Operate on localX asynchronously, then wait before returning.
7     queue.async { someMutatingOperation(&localX) }
8     queue.sync {}
9 }

有关输入输出参数的更多讨论和示例,请参阅输入输出参数。

特殊参数

可以忽略参数,获取可变数量的值,并使用以下形式提供默认值:

1 _ : parameter type
2 parameter name: parameter type...
3 parameter name: parameter type = default argument value

下划线(_)参数被明确忽略,无法在函数体内访问。

具有基本类型名称后面紧跟三个点(...)的参数被理解为可变参数。函数最多只能有一个可变参数。可变参数被视为包含基本类型名称元素的数组。例如,可变参数Int...被视为[Int]。有关使用可变参数的示例,请参阅可变参数。

具有等号(=)的参数和其类型之后的表达式被理解为具有给定表达式的默认值。调用函数时会计算给定的表达式。如果在调用函数时省略该参数,则使用默认值。

1 func f(x: Int = 42) -> Int { return x }
2 f()       // Valid, uses default value
3 f(x: 7)   // Valid, uses the value provided
4 f(7)      // Invalid, missing argument label

特殊方法

枚举或修改的结构上的方法self必须使用mutating声明修饰符进行标记。

必须使用override声明修饰符标记覆盖超类方法的方法。在没有override修饰符的情况下覆盖方法或override在不覆盖超类方法的方法上使用修饰符是编译时错误。

与类型而不是类型实例关联的方法必须使用static枚举和结构的声明修饰符标记,或使用类的staticclass声明修饰符标记。用class声明修饰符标记的类类型方法可以被子类实现覆盖; 标记为的类类型方法static无法重写。

投掷功能和方法

必须使用throws关键字标记可以抛出错误的函数和方法。这些函数和方法称为抛出函数和抛出方法。它们具有以下形式:

1 func function name(parameters) throws -> return type {
2     statements
3 }

对throw函数或方法的调用必须包装在一个trytry!表达式中(即在一个trytry!运算符的范围内)。

throws关键字是一个函数的类型的一部分,和nonthrowing函数是投掷功能的亚型。因此,您可以在与抛出函数相同的位置使用非抛出函数。

您不能仅基于函数是否可以引发错误来重载函数。也就是说,您可以根据函数参数是否可以引发错误来重载函数。

投掷方法不能覆盖非投掷方法,投掷方法不能满足非投掷方法的协议要求。也就是说,非投掷方法可以覆盖投掷方法,非投掷方法可以满足投掷方法的协议要求。

重新定义函数和方法

可以使用rethrows关键字声明函数或方法,以指示仅当其中一个函数参数引发错误时才会抛出错误。这些函数和方法称为rethrowing函数和rethrowing方法。重新抛出函数和方法必须至少有一个抛出函数参数。

1 func someFunction(callback: () throws -> Void) rethrows {
2     try callback()
3 }

重新抛出函数或方法throw只能在catch子句中包含语句。这允许您在docatch块内调用throw函数并catch通过抛出不同的错误来处理子句中的错误。此外,该catch子句必须只处理其中一个重新抛出函数的抛出参数引发的错误。例如,以下内容无效,因为该catch子句将处理引发的错误alwaysThrows()

 1 func alwaysThrows() throws {
 2     throw SomeError.error
 3 }
 4 func someFunction(callback: () throws -> Void) rethrows {
 5     do {
 6         try callback()
 7         try alwaysThrows()  // Invalid, alwaysThrows() isn't a throwing parameter
 8     } catch {
 9         throw AnotherError.error
10     }
11 }

投掷方法不能覆盖重新抛出方法,投掷方法不能满足重新抛出方法的协议要求。也就是说,重新抛出方法可以覆盖投掷方法,并且重新抛出方法可以满足投掷方法的协议要求。

非返回的功能

Swift定义了一个Never类型,表示函数或方法不返回其调用者。具有Never返回类型的函数和方法称为非返回。非回归函数和方法要么导致不可恢复的错误,要么开始无限期地继续工作。这意味着永远不会执行在调用之后立即运行的代码。抛出和重新抛出函数可以将程序控制转移到适当的catch块,即使它们是非回退的。

可以调用非返回函数或方法来结束elseguard语句的子句,如Guard Statement中所讨论的。

您可以覆盖非返回方法,但新方法必须保留其返回类型和非返回行为。

 1 GRAMMAR OF A FUNCTION DECLARATION
 2 
 3 function-declaration → function-head function-name generic-parameter-clause opt function-signature generic-where-clause opt function-body opt
 4 
 5 function-head → attributes opt declaration-modifiers opt func
 6 
 7 function-name → identifier | operator
 8 
 9 function-signature → parameter-clause throwsopt function-result opt
10 
11 function-signature → parameter-clause rethrows function-result opt
12 
13 function-result → -> attributes opt type
14 
15 function-body → code-block
16 
17 parameter-clause → ( ) | ( parameter-list )
18 
19 parameter-list → parameter | parameter , parameter-list
20 
21 parameter → external-parameter-name opt local-parameter-name type-annotation default-argument-clause opt
22 
23 parameter → external-parameter-name opt local-parameter-name type-annotation
24 
25 parameter → external-parameter-name opt local-parameter-name type-annotation ...
26 
27 external-parameter-name → identifier
28 
29 local-parameter-name → identifier
30 
31 default-argument-clause → = expression

枚举声明

一个枚举声明引入了一个名为枚举类型到你的程序。

枚举声明有两种基本形式,并使用enum关键字声明。使用任一形式声明的枚举体包含零个或多个值 - 称为枚举的情况 - 以及任意数量的声明,包括计算属性,实例方法,类型方法,初始值设定项,类型别名,甚至其他枚举,结构和类声明。枚举声明不能包含deinitializer或协议声明。

枚举类型可以采用任意数量的协议,但不能从类,结构或其他枚举继承。

与类和结构不同,枚举类型没有隐式提供的默认初始值设定项; 必须明确声明所有初始值设定项。初始化程序可以委托给枚举中的其他初始化程序,但只有在初始化程序将其中一个枚举情况分配给初始化程序后,初始化过程才会完成self

与结构类似,但与类不同,枚举是值类型; 枚举的实例在分配给变量或常量时复制,或者作为参数传递给函数调用时复制。有关值类型的信息,请参阅结构和枚举是值类型。

您可以使用扩展声明扩展枚举类型的行为,如扩展声明中所述。

任何类型的枚举个案

以下表单声明了一个枚举类型,其中包含任何类型的枚举个案:

1 enum enumeration name: adopted protocols {
2     case enumeration case 1
3     case enumeration case 2(associated value types)
4 }

以这种形式声明的枚举有时被称为其他编程语言中的歧视联合。

在此表单中,每个案例块由case关键字后跟一个或多个枚举案例组成,以逗号分隔。每个案例的名称必须是唯一的。每种情况也可以指定它存储给定类型的值。这些类型在关联的值类型元组中指定,紧跟在案例名称后面。

存储关联值的枚举情况可用作创建具有指定关联值的枚举实例的函数。就像函数一样,您可以获得对枚举案例的引用,并在稍后的代码中应用它。

1 enum Number {
2     case integer(Int)
3     case real(Double)
4 }
5 let f = Number.integer
6 // f is a function of type (Int) -> Number
7 
8 // Apply f to create an array of Number instances with integer values
9 let evenInts: [Number] = [0, 2, 4, 6].map(f)

有关更多信息以及查看具有关联值类型的案例示例,请参阅关联值。

具有间接的枚举

枚举可以具有递归结构,也就是说,它们可以具有关联值的案例,这些值是枚举类型本身的实例。但是,枚举类型的实例具有值语义,这意味着它们在内存中具有固定的布局。为了支持递归,编译器必须插入一个间接层。

要为特定枚举情况启用间接寻址,请使用indirect声明修饰符对其进行标记。间接案例必须具有关联值。

1 enum Tree<T> {
2     case empty
3     indirect case node(value: T, left: Tree, right: Tree)
4 }

要为具有关联值的枚举的所有情况启用间接,请使用indirect修饰符标记整个枚举- 当枚举包含许多需要使用indirect修饰符标记的情况时,这很方便。

使用indirect修饰符标记的枚举可以包含具有关联值的案例和不具有关联值的案例的混合。也就是说,它不能包含任何也用indirect修饰符标记的情况。

有关原始价值案件的查点

以下表单声明一个枚举类型,其中包含相同基本类型的枚举个案:

1 enum enumeration name: raw-value type, adopted protocols {
2     case enumeration case 1 = raw value 1
3     case enumeration case 2 = raw value 2
4 }

在此表单中,每个案例块由case关键字组成,后跟一个或多个枚举案例,以逗号分隔。与第一种形式的情况不同,每种情况都有一个基本值,称为原始值,具有相同的基本类型。这些值的类型在raw-value类型中指定,并且必须表示整数,浮点数,字符串或单个字符。特别是,原始值类型必须符合Equatable协议和以下协议之一:ExpressibleByIntegerLiteral对于整数文字,ExpressibleByFloatLiteral对于浮点文字,ExpressibleByStringLiteral对于包含任意数量字符的字符串文字,和/ ExpressibleByUnicodeScalarLiteralExpressibleByExtendedGraphemeClusterLiteral对于仅包含单个字符的字符串文字。每个案例都必须具有唯一名称并分配唯一的原始值。

如果原始值的类型被指定为Int和你不分配一个值,以明确的情况下,它们被隐式分配的值012,等等。每个未分配的类型的情况都Int被隐式分配一个原始值,该值从前一个案例的原始值自动递增。

1 enum ExampleEnum: Int {
2     case a, b, c = 5, d
3 }

在上面的例子中,原始值ExampleEnum.aIS 0和的值ExampleEnum.b1。并且因为ExampleEnum.c显式设置5了值,所以值ExampleEnum.d会自动递增,5因此6

如果将原始值类型指定为String并且您没有显式为案例分配值,则会为每个未分配的案例隐式分配一个字符串,该字符串与该案例的名称具有相同的文本。

1 enum GamePlayMode: String {
2     case cooperative, individual, competitive
3 }

在上面的例子中,原始值GamePlayMode.cooperative"cooperative",原始值GamePlayMode.individual"individual",。和原始值GamePlayMode.competitive"competitive"

具有原始值类型的枚举隐式地符合RawRepresentableSwift标准库中定义的协议。因此,他们有一个rawValue属性和一个带签名的可用初始化程序。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Swift动画基础发布时间:2022-07-18
下一篇:
深度学习的下一个大热门——Swift发布时间:2022-07-18
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap