From a5911a9e43becc79d44ed7a01989af6487ab0fb1 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 13:33:11 +0800 Subject: [PATCH 01/24] modify pattern code style --- source/chapter3/07_Patterns.md | 168 +++++++++++++++------------------ 1 file changed, 75 insertions(+), 93 deletions(-) diff --git a/source/chapter3/07_Patterns.md b/source/chapter3/07_Patterns.md index ae6263ac..31dc2f01 100644 --- a/source/chapter3/07_Patterns.md +++ b/source/chapter3/07_Patterns.md @@ -1,6 +1,6 @@ > 翻译:honghaoz -> 校对:numbbbbb +> 校对:numbbbbb、stanzhai # 模式(Patterns) ----------------- @@ -11,7 +11,7 @@ - [标识符模式(Identifier Pattern)](#identifier_pattern) - [值绑定模式(Value-Binding Pattern)](#value-binding_pattern) - [元组模式(Tuple Pattern)](#tuple_pattern) -- [枚举案例模式(Enumeration Case Pattern)](#enumeration_case_pattern) +- [枚举用例模式(Enumeration Case Pattern)](#enumeration_case_pattern) - [类型转换模式(Type-Casting Patterns)](#type-casting_patterns) - [表达式模式(Expression Pattern)](#expression_pattern) @@ -21,49 +21,40 @@ 你可以为通配符模式(wildcard pattern),标识符模式(identifier pattern)和元组模式(tuple pattern)指定类型注释,用来限制这种模式只匹配某种类型的值。 -> 模式的语法: -> -> pattern → wildcard-patterntype-annotationopt -> -> pattern → identifier-patterntype-annotationopt -> -> pattern → value-binding-pattern -> -> pattern → tuple-patterntype-annotationopt -> -> pattern → enum-case-pattern -> -> pattern → type-casting-pattern -> -> pattern → expression-pattern +> 模式(Patterns) 语法 +> *模式* → [*通配符模式*](..\chapter3\07_Patterns.html#wildcard_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotation) _可选_ +> *模式* → [*标识符模式*](..\chapter3\07_Patterns.html#identifier_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotati(Value Binding)on) _可选_ +> *模式* → [*值绑定模式*](..\chapter3\07_Patterns.html#value_binding_pattern) +> *模式* → [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) [*类型注解*](..\chapter3\03_Types.html#type_annotation) _可选_ +> *模式* → [*enum-case-pattern*](..\chapter3\07_Patterns.html#enum_case_pattern) +> *模式* → [*type-casting-pattern*](..\chapter3\07_Patterns.html#type_casting_pattern) +> *模式* → [*表达式模式*](..\chapter3\07_Patterns.html#expression_pattern) ## 通配符模式(Wildcard Pattern) 通配符模式匹配并忽略任何值,包含一个下划线(_)。当你不关心被匹配的值时,可以使用此模式。例如,下面这段代码进行了`1...3`的循环,并忽略了每次循环的值: - for _ in 1...3 { - // Do something three times. - } + for _ in 1...3 { + // Do something three times. + } -> 通配符模式的语法: -> -> wildcard-pattern → _ +> 通配符模式语法 +> *通配符模式* → **_** ## 标识符模式(Identifier Pattern) 标识符模式匹配任何值,并将匹配的值和一个变量或常量绑定起来。例如,在下面的常量申明中,`someValue`是一个标识符模式,匹配了类型是`Int`的`42`。 - let someValue = 42 + let someValue = 42 当匹配成功时,`42`被绑定(赋值)给常量`someValue`。 当一个变量或常量申明的左边是标识符模式时,此时,标识符模式是隐式的值绑定模式(value-binding pattern)。 -> 标识符模式的语法: -> -> identifier-pattern → identifier +> 标识符模式语法 +> *标识符模式* → [*标识符*](LexicalStructure.html#identifier) ## 值绑定模式(Value-Binding Pattern) @@ -72,19 +63,18 @@ 标识符模式包含在值绑定模式中,绑定新的变量或常量到匹配的值。例如,你可以分解一个元组的元素,并把每个元素绑定到相应的标识符模式中。 - let point = (3, 2) - switch point { - // Bind x and y to the elements of point. - case let (x, y): - println("The point is at (\(x), \(y)).") - } - // prints "The point is at (3, 2).” + let point = (3, 2) + switch point { + // Bind x and y to the elements of point. + case let (x, y): + println("The point is at (\(x), \(y)).") + } + // prints "The point is at (3, 2).” 在上面这个例子中,`let`将元组模式`(x, y)`分配到各个标识符模式。因为这种行为,`switch`语句中`case let (x, y):`和`case (let x, let y):`匹配的值是一样的。 -> 值绑定模式的语法: -> -> value-binding-pattern → var pattern | let pattern +> 值绑定(Value Binding)模式语法 +> *值绑定模式* → **var** [*模式*](..\chapter3\07_Patterns.html#pattern) | **let** [*模式*](..\chapter3\07_Patterns.html#pattern) ## 元组模式(Tuple Pattern) @@ -95,44 +85,40 @@ 当元组模式被用在`for-in`语句或者变量或常量申明时,它可以包含通配符模式,标识符模式或者其他包含这两种模式的模式。例如,下面这段代码是不正确的,因为`(x, 0)`中的元素`0`是一个表达式模式: - let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] - // This code isn't valid. - for (x, 0) in points { - /* ... */ - } + let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] + // This code isn't valid. + for (x, 0) in points { + /* ... */ + } 对于只包含一个元素的元组,括号是不起作用的。模式匹配那个单个元素的类型。例如,下面是等效的: - let a = 2 // a: Int = 2 - let (a) = 2 // a: Int = 2 - let (a): Int = 2 // a: Int = 2 + let a = 2 // a: Int = 2 + let (a) = 2 // a: Int = 2 + let (a): Int = 2 // a: Int = 2 -> 元组模式的语法: -> -> tuple-pattern → (tuple-pattern-element-list opt) -> -> tuple-pattern-element-list → tuple-pattern-element | tuple-pattern-element, tuple-pattern-element-list -> -> tuple-pattern-element → pattern +> 元组模式语法 +> *元组模式* → **(** [*元组模式元素列表*](..\chapter3\07_Patterns.html#tuple_pattern_element_list) _可选_ **)** +> *元组模式元素列表* → [*元组模式元素*](..\chapter3\07_Patterns.html#tuple_pattern_element) | [*元组模式元素*](..\chapter3\07_Patterns.html#tuple_pattern_element) **,** [*元组模式元素列表*](..\chapter3\07_Patterns.html#tuple_pattern_element_list) +> *元组模式元素* → [*模式*](..\chapter3\07_Patterns.html#pattern) -## 枚举案例模式(Enumeration Case Pattern) +## 枚举用例模式(Enumeration Case Pattern) -枚举案例模式匹配现有的枚举类型的某种案例。枚举案例模式仅在`switch`语句中的`case`标签中出现。 +枚举用例模式匹配现有的枚举类型的某种用例。枚举用例模式仅在`switch`语句中的`case`标签中出现。 -如果你准备匹配的枚举案例有任何关联的值,则相应的枚举案例模式必须指定一个包含每个关联值元素的元组模式。关于使用`switch`语句来匹配包含关联值枚举案例的例子,请参阅`Associated Values`. +如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。关于使用`switch`语句来匹配包含关联值枚举用例的例子,请参阅`Associated Values`. -> 枚举案例模式的语法: -> -> enum-case-pattern → type-identifier opt . enum-case-name tuple-pattern opt +> 枚举用例模式语法 +> *enum-case-pattern* → [*类型标识*](..\chapter3\03_Types.html#type_identifier) _可选_ **.** [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*元组模式*](..\chapter3\07_Patterns.html#tuple_pattern) _可选_ ## 类型转换模式(Type-Casting Patterns) 有两种类型转换模式,`is`模式和`as`模式。这两种模式均只出现在`switch`语句中的`case`标签中。`is`模式和`as`模式有以下形式: - is type - pattern as type + is type + pattern as type `is`模式匹配一个值,如果这个值的类型在运行时(runtime)和`is`模式右边的指定类型(或者那个类型的子类)是一致的。`is`模式和`is`操作符一样,他们都进行类型转换,但是抛弃了返回的类型。 @@ -140,13 +126,10 @@ 关于使用`switch`语句来匹配`is`模式和`as`模式值的例子,请参阅`Type Casting for Any and AnyObject`。 -> 类型转换模式的语法: -> -> type-casting-pattern → is-pattern as-pattern -> -> is-pattern → istype -> -> as-pattern → patternastype +> 类型转换模式语法 +> *type-casting-pattern* → [*is模式*](..\chapter3\07_Patterns.html#is_pattern) | [*as模式*](..\chapter3\07_Patterns.html#as_pattern) +> *is模式* → **is** [*类型*](..\chapter3\03_Types.html#type) +> *as模式* → [*模式*](..\chapter3\07_Patterns.html#pattern) **as** [*类型*](..\chapter3\03_Types.html#type) ## 表达式模式(Expression Pattern) @@ -155,34 +138,33 @@ 由表达式模式所代表的表达式用Swift标准库中的`~=`操作符与输入表达式的值进行比较。如果`~=`操作符返回`true`,则匹配成功。默认情况下,`~=`操作符使用`==`操作符来比较两个相同类型的值。它也可以匹配一个整数值与一个`Range`对象中的整数范围,正如下面这个例子所示: - let point = (1, 2) - switch point { - case (0, 0): - println("(0, 0) is at the origin.") - case (-2...2, -2...2): - println("(\(point.0), \(point.1)) is near the origin.") - default: - println("The point is at (\(point.0), \(point.1)).") - } - // prints "(1, 2) is near the origin.” + let point = (1, 2) + switch point { + case (0, 0): + println("(0, 0) is at the origin.") + case (-2...2, -2...2): + println("(\(point.0), \(point.1)) is near the origin.") + default: + println("The point is at (\(point.0), \(point.1)).") + } + // prints "(1, 2) is near the origin.” 你可以重载`~=`操作符来提供自定义的表达式行为。例如,你可以重写上面的例子,以实现用字符串表达的点来比较`point`表达式。 - // Overload the ~= operator to match a string with an integer - func ~=(pattern: String, value: Int) -> Bool { - return pattern == "\(value)" - } - switch point { - case ("0", "0"): - println("(0, 0) is at the origin.") - case ("-2...2", "-2...2"): - println("(\(point.0), \(point.1)) is near the origin.") - default: - println("The point is at (\(point.0), \(point.1)).") - } - // prints "(1, 2) is near the origin.” + // Overload the ~= operator to match a string with an integer + func ~=(pattern: String, value: Int) -> Bool { + return pattern == "\(value)" + } + switch point { + case ("0", "0"): + println("(0, 0) is at the origin.") + case ("-2...2", "-2...2"): + println("(\(point.0), \(point.1)) is near the origin.") + default: + println("The point is at (\(point.0), \(point.1)).") + } + // prints "(1, 2) is near the origin.” -> 表达式模式的语法: -> -> expression-pattern → expression +> 表达式模式语法 +> *表达式模式* → [*表达式*](..\chapter3\04_Expressions.html#expression) From 5d96ced584a6cc2711941b14f51e219f66ccfec8 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 13:36:50 +0800 Subject: [PATCH 02/24] a trivial change --- source/chapter3/07_Patterns.md | 2 +- source/chapter3/09_Summary_of_the_Grammar.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/chapter3/07_Patterns.md b/source/chapter3/07_Patterns.md index 31dc2f01..4fe4f9d4 100644 --- a/source/chapter3/07_Patterns.md +++ b/source/chapter3/07_Patterns.md @@ -1,6 +1,6 @@ > 翻译:honghaoz -> 校对:numbbbbb、stanzhai +> 校对:numbbbbb, stanzhai # 模式(Patterns) ----------------- diff --git a/source/chapter3/09_Summary_of_the_Grammar.md b/source/chapter3/09_Summary_of_the_Grammar.md index 87d5c488..958eff6a 100644 --- a/source/chapter3/09_Summary_of_the_Grammar.md +++ b/source/chapter3/09_Summary_of_the_Grammar.md @@ -1,4 +1,4 @@ -> 翻译:StanZhai +> 翻译:stanzhai > 校对:xielingwang From 1f351fad779bf7d79c001636463c405f6402d43c Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 13:47:00 +0800 Subject: [PATCH 03/24] correct attributes grammar --- source/chapter3/06_Attributes.md | 22 ++++++++++---------- source/chapter3/09_Summary_of_the_Grammar.md | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/source/chapter3/06_Attributes.md b/source/chapter3/06_Attributes.md index bf661f30..7ff947d0 100644 --- a/source/chapter3/06_Attributes.md +++ b/source/chapter3/06_Attributes.md @@ -114,14 +114,14 @@ Interface Builder特性是Interface Builder用来与Xcode同步的声明特性 该特性用于修饰函数或方法的类型,表明该函数或方法不会返回到它的调用者中去。你也可以用它标记函数或方法的声明,表示函数或方法的相应类型,`T`,是`@noreturn T`。 -> 特性的语法 -> attribute -> @ [attribute-name]() [attribute-argument-clause]()opt -> attribute-name -> [identifier]() -> attribute-argument-clause -> ( [balanced-tokens]()opt ) -> attributes -> [attribute]() [attributes]()opt -> balanced-tokens -> [balanced-token]() [balanced-tokens]()opt -> balanced-token -> ( [balanced-tokens]()opt ) -> balanced-token -> [ [balanced-tokens]()opt ] -> balanced-token -> { [balanced-tokens]()opt } -> balanced-token -> 任意标识符,关键字,字面量,或运算符 -> balanced-token -> 任意标点符号,除了(, ), [, ], {, 或 } +> 特性语法 +> *特色* → **@** [*特性名*](..\chapter3\06_Attributes.html#attribute_name) [*特性参数子句*](..\chapter3\06_Attributes.html#attribute_argument_clause) _可选_ +> *特性名* → [*标识符*](LexicalStructure.html#identifier) +> *特性参数子句* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)** +> *特性(Attributes)列表* → [*特色*](..\chapter3\06_Attributes.html#attribute) [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ +> *平衡令牌列表* → [*平衡令牌*](..\chapter3\06_Attributes.html#balanced_token) [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ +> *平衡令牌* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)** +> *平衡令牌* → **[** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **]** +> *平衡令牌* → **{** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **}** +> *平衡令牌* → **任意标识符, 关键字, 字面量或运算符** +> *平衡令牌* → **任意标点除了(, ), [, ], {, 或 }** diff --git a/source/chapter3/09_Summary_of_the_Grammar.md b/source/chapter3/09_Summary_of_the_Grammar.md index 958eff6a..37a2f41a 100644 --- a/source/chapter3/09_Summary_of_the_Grammar.md +++ b/source/chapter3/09_Summary_of_the_Grammar.md @@ -417,8 +417,8 @@ _________________ > *平衡令牌* → **(** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **)** > *平衡令牌* → **[** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **]** > *平衡令牌* → **{** [*平衡令牌列表*](..\chapter3\06_Attributes.html#balanced_tokens) _可选_ **}** -> *平衡令牌* → 任意标识符, 关键字, 字面量或运算符 -> *平衡令牌* → 任意除了(-, )=, [-, ]-, {- 或 }- +> *平衡令牌* → **任意标识符, 关键字, 字面量或运算符** +> *平衡令牌* → **任意标点除了(, ), [, ], {, 或 }** ## 表达式 From 8519bfad0a05972fa2be7c12502e1742e2bd4638 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 14:18:51 +0800 Subject: [PATCH 04/24] correct declarations grammar --- source/chapter3/05_Declarations.md | 379 ++++++++++++----------------- 1 file changed, 161 insertions(+), 218 deletions(-) diff --git a/source/chapter3/05_Declarations.md b/source/chapter3/05_Declarations.md index e928c346..a79c5d76 100644 --- a/source/chapter3/05_Declarations.md +++ b/source/chapter3/05_Declarations.md @@ -1,6 +1,6 @@ > 翻译:marsprince -> 校对:numbbbbb +> 校对:numbbbbb, stanzhai # 声明 ----------------- @@ -31,41 +31,24 @@ 在swift中,大多数声明在某种意义上讲也是执行或同事声明它们的初始化定义。这意味着,因为协议和他们的成员不匹配, 大多数协议成员需要单独的声明。为了方便起见,也因为这些区别在swift里不是很重要,声明语句同时包含了声明和定义。 ->GRAMMAR OF A DECLARATION - ->declaration → import-declaration­ - ->declaration → constant-declaration­ - ->declaration → variable-declaration­ - ->declaration → typealias-declaration­ - ->declaration → function-declaration­ - ->declaration → enum-declaration­ - ->declaration → struct-declaration­ - ->declaration → class-declaration­ - ->declaration → protocol-declaration­ - -> declaration → initializer-declaration­ - ->declaration → deinitializer-declaration­ - -> declaration → extension-declaration­ - -> declaration → subscript-declaration­ - ->declaration → operator-declaration­ - ->declarations → declaration­declarations­opt­ - ->declaration-specifiers → declaration-specifier­declaration-specifiers­opt­ - ->declaration-specifier → class­ | mutating ­| nonmutating­ | override­ | static­ | unowned | +> 声明语法 +> *声明* → [*导入声明*](..\chapter3\05_Declarations.html#import_declaration) +> *声明* → [*常量声明*](..\chapter3\05_Declarations.html#constant_declaration) +> *声明* → [*变量声明*](..\chapter3\05_Declarations.html#variable_declaration) +> *声明* → [*类型别名声明*](..\chapter3\05_Declarations.html#typealias_declaration) +> *声明* → [*函数声明*](..\chapter3\05_Declarations.html#function_declaration) +> *声明* → [*枚举声明*](..\chapter3\05_Declarations.html#enum_declaration) +> *声明* → [*结构体声明*](..\chapter3\05_Declarations.html#struct_declaration) +> *声明* → [*类声明*](..\chapter3\05_Declarations.html#class_declaration) +> *声明* → [*协议声明*](..\chapter3\05_Declarations.html#protocol_declaration) +> *声明* → [*构造器声明*](..\chapter3\05_Declarations.html#initializer_declaration) +> *声明* → [*析构器声明*](..\chapter3\05_Declarations.html#deinitializer_declaration) +> *声明* → [*扩展声明*](..\chapter3\05_Declarations.html#extension_declaration) +> *声明* → [*附属脚本声明*](..\chapter3\05_Declarations.html#subscript_declaration) +> *声明* → [*运算符声明*](..\chapter3\05_Declarations.html#operator_declaration) +> *声明(Declarations)列表* → [*声明*](..\chapter3\05_Declarations.html#declaration) [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_ +> *声明描述符(Specifiers)列表* → [*声明描述符(Specifier)*](..\chapter3\05_Declarations.html#declaration_specifier) [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ +> *声明描述符(Specifier)* → **class** | **mutating** | **nonmutating** | **override** | **static** | **unowned** | **unowned(safe)** | **unowned(unsafe)** | **weak** ##模块范围 @@ -73,9 +56,8 @@ 模块范围定义了对模块中其他源文件可见的代码。(注:待改进)在swift的源文件中,最高级别的代码由零个或多个语句, 声明和表达组成。变量,常量和其他的声明语句在一个源文件的最顶级被声明,使得他们对同一模块中的每个源文件都是可见的。 ->GRAMMAR OF A TOP-LEVEL DECLARATION - ->top-level-declaration → statements ­opt +> 顶级(Top Level) 声明语法 +> *顶级声明* → [*多条语句(Statements)*](..\chapter3\10_Statements.html#statements) _可选_ ##代码块 @@ -88,9 +70,8 @@ 代码块中的语句包括声明,表达式和各种其他类型的语句,它们按照在源码中的出现顺序被依次执行。 ->GRAMMAR OF A CODE BLOCK - ->code-block → ­statements ­opt­ +> 代码块语法 +> *代码块* → **{** [*多条语句(Statements)*](..\chapter3\10_Statements.html#statements) _可选_ **}** ##引入声明 @@ -106,12 +87,11 @@ import import kind module.symbol name import module.submodule ->GRAMMAR OF AN IMPORT DECLARATION - ->import-declaration → attributes ­opt ­import­ import-kind­ opt import-path­ ->import-kind → typealias­ | struct­ | class­ | enum­ | protocol­ | var­ | func­ ->import-path → import-path-identifier­ import-path-identifier­.­import-path­ ->import-path-identifier → identifier­ operator +> 导入(Import)声明语法 +> *导入声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **import** [*导入类型*](..\chapter3\05_Declarations.html#import_kind) _可选_ [*导入路径*](..\chapter3\05_Declarations.html#import_path) +> *导入类型* → **typealias** | **struct** | **class** | **enum** | **protocol** | **var** | **func** +> *导入路径* → [*导入路径标识符*](..\chapter3\05_Declarations.html#import_path_identifier) | [*导入路径标识符*](..\chapter3\05_Declarations.html#import_path_identifier) **.** [*导入路径*](..\chapter3\05_Declarations.html#import_path) +> *导入路径标识符* → [*标识符*](LexicalStructure.html#identifier) | [*运算符*](LexicalStructure.html#operator) ##常量声明 @@ -131,10 +111,10 @@ 在上例中,firstNumber是一个值为10的常量,secnodeName是一个值为42的常量。所有常量都可以独立的使用: - 1 println("The first number is \(firstNumber).") - 2 // prints "The first number is 10." - 3 println("The second number is \(secondNumber).") - 4 // prints "The second number is 42." + println("The first number is \(firstNumber).") + // prints "The first number is 10." + println("The second number is \(secondNumber).") + // prints "The second number is 42." 类型注释(:type)在常量声明中是一个可选项,它可以用来描述在类型接口(type inference)中找到的类型。 @@ -143,12 +123,11 @@ 如果还想获得更多关于常量的信息或者想在使用中获得帮助,请查看常量和变量(constants and variables), 存储属性(stored properties)等节。 ->GRAMMAR OF A CONSTANT DECLARATION - ->constant-declaration → attributes­ opt ­declaration-specifiers­ opt ­let­pattern-initializer-list­ ->pattern-initializer-list → pattern-initializer­ | pattern-initializer­ , pattern-initializer-list­ ->pattern-initializer → pattern ­initializer ­opt­ ->initializer → =­expression +> 常数声明语法 +> *常量声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **let** [*模式构造器列表*](..\chapter3\05_Declarations.html#pattern_initializer_list) +> *模式构造器列表* → [*模式构造器*](..\chapter3\05_Declarations.html#pattern_initializer) | [*模式构造器*](..\chapter3\05_Declarations.html#pattern_initializer) **,** [*模式构造器列表*](..\chapter3\05_Declarations.html#pattern_initializer_list) +> *模式构造器* → [*模式*](..\chapter3\07_Patterns.html#pattern) [*构造器*](..\chapter3\05_Declarations.html#initializer) _可选_ +> *构造器* → **=** [*表达式*](..\chapter3\04_Expressions.html#expression) ##变量声明 @@ -246,47 +225,27 @@ willset监视器初始名为newvalue,didset监视器初始名为oldvalue。 class关键字用来声明类的计算型属性。static关键字用来声明类的静态变量属性。类和静态变量在类型属性(type properties)中有详细讨论。 ->GRAMMAR OF A VARIABLE DECLARATION - ->variable-declaration → variable-declaration-head­pattern-initializer-list­ - ->variable-declaration → variable-declaration-head ­variable-name ­type-annotation ­code-block­ - ->variable-declaration → variable-declaration-head ­variable-name ­type-annotation ­getter-setter-block­ - ->variable-declaration → variable-declaration-head ­variable-name­ type-annotation ­getter-setter-keyword-block­ - - > variable-declaration → variable-declaration-head­ variable-name ­type-annotation­initializer­ opt ­willSet-didSet-block­ - ->variable-declaration-head → attributes ­opt­ declaration-specifiers ­opt ­var -­ ->variable-name → identifier­ - ->getter-setter-block → {­getter-clause ­setter-clause­ opt­}­ - ->getter-setter-block → {­setter-clause ­getter-clause­}­ - ->getter-clause → attributes ­opt­get­code-block­ - ->setter-clause → attributes ­opt ­set­ setter-name­ opt­ code-block­ - ->setter-name → (­identifier­)­ - ->getter-setter-keyword-block → {­getter-keyword-clause ­setter-keyword-clause­ opt­} -­ ->getter-setter-keyword-block → {­setter-keyword-clause ­getter-keyword-clause­} - ->getter-keyword-clause → attributes­ opt­ get­ - ->setter-keyword-clause → attributes ­opt­ set­ - ->willSet-didSet-block → {­willSet-clause ­didSet-clause ­opt­}­ - ->willSet-didSet-block → {­didSet-clause ­willSet-clause­}­ - ->willSet-clause → attributes ­opt ­willSet ­setter-name­ opt ­code-block­ - ->didSet-clause → attributes ­opt ­didSet ­setter-name ­opt­ code-block­ +> 变量声明语法 +> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*模式构造器列表*](..\chapter3\05_Declarations.html#pattern_initializer_list) +> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*代码块*](..\chapter3\05_Declarations.html#code_block) +> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*getter-setter块*](..\chapter3\05_Declarations.html#getter_setter_block) +> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*getter-setter关键字(Keyword)块*](..\chapter3\05_Declarations.html#getter_setter_keyword_block) +> *变量声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*构造器*](..\chapter3\05_Declarations.html#initializer) _可选_ [*willSet-didSet代码块*](..\chapter3\05_Declarations.html#willSet_didSet_block) +> *变量声明头(Head)* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **var** +> *变量名称* → [*标识符*](LexicalStructure.html#identifier) +> *getter-setter块* → **{** [*getter子句*](..\chapter3\05_Declarations.html#getter_clause) [*setter子句*](..\chapter3\05_Declarations.html#setter_clause) _可选_ **}** +> *getter-setter块* → **{** [*setter子句*](..\chapter3\05_Declarations.html#setter_clause) [*getter子句*](..\chapter3\05_Declarations.html#getter_clause) **}** +> *getter子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **get** [*代码块*](..\chapter3\05_Declarations.html#code_block) +> *setter子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **set** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block) +> *setter名称* → **(** [*标识符*](LexicalStructure.html#identifier) **)** +> *getter-setter关键字(Keyword)块* → **{** [*getter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#getter_keyword_clause) [*setter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#setter_keyword_clause) _可选_ **}** +> *getter-setter关键字(Keyword)块* → **{** [*setter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#setter_keyword_clause) [*getter关键字(Keyword)子句*](..\chapter3\05_Declarations.html#getter_keyword_clause) **}** +> *getter关键字(Keyword)子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **get** +> *setter关键字(Keyword)子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **set** +> *willSet-didSet代码块* → **{** [*willSet子句*](..\chapter3\05_Declarations.html#willSet_clause) [*didSet子句*](..\chapter3\05_Declarations.html#didSet_clause) _可选_ **}** +> *willSet-didSet代码块* → **{** [*didSet子句*](..\chapter3\05_Declarations.html#didSet_clause) [*willSet子句*](..\chapter3\05_Declarations.html#willSet_clause) **}** +> *willSet子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **willSet** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block) +> *didSet子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **didSet** [*setter名称*](..\chapter3\05_Declarations.html#setter_name) _可选_ [*代码块*](..\chapter3\05_Declarations.html#code_block) ##类型的别名声明 @@ -301,12 +260,11 @@ class关键字用来声明类的计算型属性。static关键字用来声明类 查看更多Protocol Associated Type Declaration. ->GRAMMAR OF A TYPE ALIAS DECLARATION - -> typealias-declaration → typealias-head­ typealias-assignment -> typealias-head → typealias­ typealias-name -> typealias-name → identifier -> typealias-assignment → =type +> 类型别名声明语法 +> *类型别名声明* → [*类型别名头(Head)*](..\chapter3\05_Declarations.html#typealias_head) [*类型别名赋值*](..\chapter3\05_Declarations.html#typealias_assignment) +> *类型别名头(Head)* → **typealias** [*类型别名名称*](..\chapter3\05_Declarations.html#typealias_name) +> *类型别名名称* → [*标识符*](LexicalStructure.html#identifier) +> *类型别名赋值* → **=** [*类型*](..\chapter3\03_Types.html#type) ##函数声明 @@ -420,23 +378,22 @@ f()和f(x:7)都是只有一个变量x的函数的有效调用,但是f(7)是非 多级柯里化应用如下 ->GRAMMAR OF A FUNCTION DECLARATION - ->function-declaration → function-head­ function-name­ generic-parameter-clause ­opt­function-signature­ function-body­ -> function-head → attributes ­opt ­declaration-specifiers ­opt ­func­ -> function-name → identifier­ operator­ ->function-signature → parameter-clauses ­function-result ­opt­ -> function-result → ->­attributes ­opt ­type­ -> function-body → code-block­ -> parameter-clauses → parameter-clause ­parameter-clauses ­opt­ -> parameter-clause → (­)­ (­parameter-list­...­opt­)­ -> parameter-list → parameter­ parameter­,­parameter-list­ -> parameter → inout ­opt ­let ­opt­#­opt­parameter-name local-parameter-name ­opt­ type-annotation ­default-argument-clause ­opt­ -> parameter → inout­opt­var­#­opt­parameter-name­local-parameter-name ­opt­ type-annotation­default-argument-clause ­opt­ -> parameter → attributes ­opt ­type­ -> parameter-name → identifier­ _­ -> local-parameter-name → identifier­ _­ -> default-argument-clause → =­expression­: +> 函数声明语法 +> *函数声明* → [*函数头*](..\chapter3\05_Declarations.html#function_head) [*函数名*](..\chapter3\05_Declarations.html#function_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*函数签名(Signature)*](..\chapter3\05_Declarations.html#function_signature) [*函数体*](..\chapter3\05_Declarations.html#function_body) +> *函数头* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*声明描述符(Specifiers)列表*](..\chapter3\05_Declarations.html#declaration_specifiers) _可选_ **func** +> *函数名* → [*标识符*](LexicalStructure.html#identifier) | [*运算符*](LexicalStructure.html#operator) +> *函数签名(Signature)* → [*parameter-clauses*](..\chapter3\05_Declarations.html#parameter_clauses) [*函数结果*](..\chapter3\05_Declarations.html#function_result) _可选_ +> *函数结果* → **->** [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type) +> *函数体* → [*代码块*](..\chapter3\05_Declarations.html#code_block) +> *parameter-clauses* → [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause) [*parameter-clauses*](..\chapter3\05_Declarations.html#parameter_clauses) _可选_ +> *参数子句* → **(** **)** | **(** [*参数列表*](..\chapter3\05_Declarations.html#parameter_list) **...** _可选_ **)** +> *参数列表* → [*参数*](..\chapter3\05_Declarations.html#parameter) | [*参数*](..\chapter3\05_Declarations.html#parameter) **,** [*参数列表*](..\chapter3\05_Declarations.html#parameter_list) +> *参数* → **inout** _可选_ **let** _可选_ **#** _可选_ [*参数名*](..\chapter3\05_Declarations.html#parameter_name) [*本地参数名*](..\chapter3\05_Declarations.html#local_parameter_name) _可选_ [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*默认参数子句*](..\chapter3\05_Declarations.html#default_argument_clause) _可选_ +> *参数* → **inout** _可选_ **var** **#** _可选_ [*参数名*](..\chapter3\05_Declarations.html#parameter_name) [*本地参数名*](..\chapter3\05_Declarations.html#local_parameter_name) _可选_ [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*默认参数子句*](..\chapter3\05_Declarations.html#default_argument_clause) _可选_ +> *参数* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type) +> *参数名* → [*标识符*](LexicalStructure.html#identifier) | **_** +> *本地参数名* → [*标识符*](LexicalStructure.html#identifier) | **_** +> *默认参数子句* → **=** [*表达式*](..\chapter3\04_Expressions.html#expression) ##枚举声明 @@ -505,24 +462,23 @@ ExampleEnum.D的值会自动增长为6. 枚举类型是模式匹配(pattern-matched)的,和其相反的是switch语句case块中枚举事件匹配,在枚举事件类型(Enumeration Case Pattern)中有描述。 ->GRAMMAR OF AN ENUMERATION DECLARATION - -> enum-declaration → attributes­opt­union-style-enum­ attributes­opt­raw-value-style-enum­ -> union-style-enum → enum-name­generic-parameter-clause­opt­{­union-style-enum-members­opt­}­ - union-style-enum-members → union-style-enum-member­union-style-enum-members­opt­ - union-style-enum-member → declaration­ union-style-enum-case-clause­ - union-style-enum-case-clause → attributes­opt­case­union-style-enum-case-list­ - union-style-enum-case-list → union-style-enum-case­ union-style-enum-case­,­union-style-enum-case-list­ - union-style-enum-case → enum-case-name­tuple-type­opt­ - enum-name → identifier­ - enum-case-name → identifier­ - raw-value-style-enum → enum-name­generic-parameter-clause­opt­:­type-identifier­{­raw-value-style-enum-members­opt­}­ - raw-value-style-enum-members → raw-value-style-enum-member­raw-value-style-enum-members­opt­ - raw-value-style-enum-member → declaration­ raw-value-style-enum-case-clause­ - raw-value-style-enum-case-clause → attributes­opt­case­raw-value-style-enum-case-list­ - raw-value-style-enum-case-list → raw-value-style-enum-case­ raw-value-style-enum-case­,­raw-value-style-enum-case-list­ - raw-value-style-enum-case → enum-case-name­raw-value-assignment­opt­ - raw-value-assignment → =­literal­ +> 枚举声明语法 +> *枚举声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*联合式枚举*](..\chapter3\05_Declarations.html#union_style_enum) | [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*原始值式枚举*](..\chapter3\05_Declarations.html#raw_value_style_enum) +> *联合式枚举* → [*枚举名*](..\chapter3\05_Declarations.html#enum_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ **{** [*union-style-enum-members*](..\chapter3\05_Declarations.html#union_style_enum_members) _可选_ **}** +> *union-style-enum-members* → [*union-style-enum-member*](..\chapter3\05_Declarations.html#union_style_enum_member) [*union-style-enum-members*](..\chapter3\05_Declarations.html#union_style_enum_members) _可选_ +> *union-style-enum-member* → [*声明*](..\chapter3\05_Declarations.html#declaration) | [*联合式(Union Style)的枚举case子句*](..\chapter3\05_Declarations.html#union_style_enum_case_clause) +> *联合式(Union Style)的枚举case子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **case** [*联合式(Union Style)的枚举case列表*](..\chapter3\05_Declarations.html#union_style_enum_case_list) +> *联合式(Union Style)的枚举case列表* → [*联合式(Union Style)的case*](..\chapter3\05_Declarations.html#union_style_enum_case) | [*联合式(Union Style)的case*](..\chapter3\05_Declarations.html#union_style_enum_case) **,** [*联合式(Union Style)的枚举case列表*](..\chapter3\05_Declarations.html#union_style_enum_case_list) +> *联合式(Union Style)的case* → [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*元组类型*](..\chapter3\03_Types.html#tuple_type) _可选_ +> *枚举名* → [*标识符*](LexicalStructure.html#identifier) +> *枚举的case名* → [*标识符*](LexicalStructure.html#identifier) +> *原始值式枚举* → [*枚举名*](..\chapter3\05_Declarations.html#enum_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ **:** [*类型标识*](..\chapter3\03_Types.html#type_identifier) **{** [*原始值式枚举成员列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_members) _可选_ **}** +> *原始值式枚举成员列表* → [*原始值式枚举成员*](..\chapter3\05_Declarations.html#raw_value_style_enum_member) [*原始值式枚举成员列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_members) _可选_ +> *原始值式枚举成员* → [*声明*](..\chapter3\05_Declarations.html#declaration) | [*原始值式枚举case子句*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_clause) +> *原始值式枚举case子句* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **case** [*原始值式枚举case列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_list) +> *原始值式枚举case列表* → [*原始值式枚举case*](..\chapter3\05_Declarations.html#raw_value_style_enum_case) | [*原始值式枚举case*](..\chapter3\05_Declarations.html#raw_value_style_enum_case) **,** [*原始值式枚举case列表*](..\chapter3\05_Declarations.html#raw_value_style_enum_case_list) +> *原始值式枚举case* → [*枚举的case名*](..\chapter3\05_Declarations.html#enum_case_name) [*原始值赋值*](..\chapter3\05_Declarations.html#raw_value_assignment) _可选_ +> *原始值赋值* → **=** [*字面量*](LexicalStructure.html#literal) ##结构体声明 @@ -556,11 +512,10 @@ ExampleEnum.D的值会自动增长为6. 你可以使用扩展声明来扩展结构体类型的行为,参见扩展声明(Extension Declaration). ->GRAMMAR OF A STRUCTURE DECLARATION - -> struct-declaration → attributes­opt­struct­struct-name­generic-parameter-clause­opt­type-inheritance-clause­opt­struct-body­ -> struct-name → identifier­ -> struct-body → {­declarations­opt­} +> 结构体声明语法 +> *结构体声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **struct** [*结构体名称*](..\chapter3\05_Declarations.html#struct_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*结构体主体*](..\chapter3\05_Declarations.html#struct_body) +> *结构体名称* → [*标识符*](LexicalStructure.html#identifier) +> *结构体主体* → **{** [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_ **}** ##类声明 @@ -599,11 +554,10 @@ ExampleEnum.D的值会自动增长为6. 你可以使用扩展声明来扩展类的行为,参见扩展声明(Extension Declaration). - > GRAMMAR OF A CLASS DECLARATION - - > class-declaration → attributes­opt­class­class-name­generic-parameter-clause­opt­type-inheritance-clause­opt­class-body­ - > class-name → identifier­ - > class-body → {­declarations­opt­} +> 类声明语法 +> *类声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **class** [*类名*](..\chapter3\05_Declarations.html#class_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*类主体*](..\chapter3\05_Declarations.html#class_body) +> *类名* → [*标识符*](LexicalStructure.html#identifier) +> *类主体* → **{** [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_ **}** ##协议声明(translated by 小一) @@ -638,25 +592,23 @@ protocol protocol name: inherited protocols { 你可以使用协议来声明一个类的代理的方法或者应该实现的结构,就像[委托(代理)模式](../chapter2/21_Protocols.html#delegation)描述的那样。 ->协议声明的语法 -protocol-declaration → attributes­opt­protocol­protocol-name­type-inheritance-clause­opt­protocol-body­ -protocol-name → identifier­ -protocol-body → {­protocol-member-declarations­opt­}­ -protocol-member-declaration → protocol-property-declaration­ -protocol-member-declaration → protocol-method-declaration­ -protocol-member-declaration → protocol-initializer-declaration­ -protocol-member-declaration → protocol-subscript-declaration­ -protocol-member-declaration → protocol-associated-type-declaration­ -protocol-member-declarations → protocol-member-declaration­protocol-member-declarations­opt­ +> 协议(Protocol)声明语法 +> *协议声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **protocol** [*协议名*](..\chapter3\05_Declarations.html#protocol_name) [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*协议主体*](..\chapter3\05_Declarations.html#protocol_body) +> *协议名* → [*标识符*](LexicalStructure.html#identifier) +> *协议主体* → **{** [*协议成员声明(Declarations)列表*](..\chapter3\05_Declarations.html#protocol_member_declarations) _可选_ **}** +> *协议成员声明* → [*协议属性声明*](..\chapter3\05_Declarations.html#protocol_property_declaration) +> *协议成员声明* → [*协议方法声明*](..\chapter3\05_Declarations.html#protocol_method_declaration) +> *协议成员声明* → [*协议构造器声明*](..\chapter3\05_Declarations.html#protocol_initializer_declaration) +> *协议成员声明* → [*协议附属脚本声明*](..\chapter3\05_Declarations.html#protocol_subscript_declaration) +> *协议成员声明* → [*协议关联类型声明*](..\chapter3\05_Declarations.html#protocol_associated_type_declaration) +> *协议成员声明(Declarations)列表* → [*协议成员声明*](..\chapter3\05_Declarations.html#protocol_member_declaration) [*协议成员声明(Declarations)列表*](..\chapter3\05_Declarations.html#protocol_member_declarations) _可选_ ###协议属性声明 协议声明了一致性类型必须在协议声明的主体里通过引入一个协议属性声明来实现一个属性。协议属性声明有一种特殊的类型声明形式: -```javascript -var property name: type { get set } -``` + var property name: type { get set } 同其它协议成员声明一样,这些属性声明仅仅针对符合该协议的类型声明了`getter`和`setter`要求。结果就是你不需要在协议里它被声明的地方实现`getter`和`setter`。 @@ -664,8 +616,8 @@ var property name: type { get set } 更多参见[变量声明](../chapter3/05_Declarations.html#variable_declaration) ->协议属性声明语法 -protocol-property-declaration → variable-declaration-head­variable-name­type-annotation­getter-setter-keyword-block­ +> 协议属性声明语法 +> *协议属性声明* → [*变量声明头(Head)*](..\chapter3\05_Declarations.html#variable_declaration_head) [*变量名*](..\chapter3\05_Declarations.html#variable_name) [*类型注解*](..\chapter3\03_Types.html#type_annotation) [*getter-setter关键字(Keyword)块*](..\chapter3\05_Declarations.html#getter_setter_keyword_block) ###协议方法声明 @@ -679,9 +631,8 @@ protocol-property-declaration → variable-declaration-head­variable-name­type 更多请参阅函数声明。 ->GRAMMAR OF A PROTOCOL METHOD DECLARATION - ->protocol-method-declaration → function-head­function-name­generic-parameter-clause­opt­function-signature­ +> 协议方法声明语法 +> *协议方法声明* → [*函数头*](..\chapter3\05_Declarations.html#function_head) [*函数名*](..\chapter3\05_Declarations.html#function_name) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*函数签名(Signature)*](..\chapter3\05_Declarations.html#function_signature) ###协议构造器声明 @@ -690,16 +641,15 @@ protocol-property-declaration → variable-declaration-head­variable-name­type 更多请参阅构造器声明。 ->GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION - ->protocol-initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­ +> 协议构造器声明语法 +> *协议构造器声明* → [*构造器头(Head)*](..\chapter3\05_Declarations.html#initializer_head) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause) ###协议附属脚本声明 协议声明了一致性类型必须在协议声明的主体里通过引入一个协议附属脚本声明来实现一个附属脚本。协议属性声明 对附属脚本声明有一个特殊的形式: ->subscript (parameters) -> return type { get set } + subscript (parameters) -> return type { get set } 附属脚本声明只为和协议一致的类型声明了必需的最小数量的的getter和setter。如果附属脚本申明包含get和set关键字, 一致的类型也必须有一个getter和setter语句。如果附属脚本声明值包含get关键字,一致的类型必须至少包含一个 @@ -707,9 +657,8 @@ getter语句,可以选择是否包含setter语句。 更多参阅附属脚本声明。 ->GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION - ->protocol-subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ +> 协议附属脚本声明语法 +> *协议附属脚本声明* → [*附属脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*附属脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](..\chapter3\05_Declarations.html#getter_setter_keyword_block) ###协议相关类型声明 @@ -717,9 +666,8 @@ getter语句,可以选择是否包含setter语句。 语句中的类型参数很相似,但是它们在声明的协议中包含self关键字。在这些语句中,self指代和协议一致的可能的类型。 获得更多信息和例子,查看相关类型或类型别名声明。 ->GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION - ->protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­opt­ +> 协议关联类型声明语法 +> *协议关联类型声明* → [*类型别名头(Head)*](..\chapter3\05_Declarations.html#typealias_head) [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*类型别名赋值*](..\chapter3\05_Declarations.html#typealias_assignment) _可选_ ##构造器声明 @@ -759,11 +707,10 @@ overrride关键字。 查看更多关于不同声明方法的构造器的例子,参阅构造过程一节。 ->GRAMMAR OF AN INITIALIZER DECLARATION - ->initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­initializer-body­ ->initializer-head → attributes­opt­convenience­opt­init­ ->initializer-body → code-block­ +> 构造器声明语法 +> *构造器声明* → [*构造器头(Head)*](..\chapter3\05_Declarations.html#initializer_head) [*泛型参数子句*](GenericParametersAndArguments.html#generic_parameter_clause) _可选_ [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause) [*构造器主体*](..\chapter3\05_Declarations.html#initializer_body) +> *构造器头(Head)* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **convenience** _可选_ **init** +> *构造器主体* → [*代码块*](..\chapter3\05_Declarations.html#code_block) ##析构声明 @@ -781,12 +728,10 @@ overrride关键字。 析构器不会被直接调用。 -查看例子和如何在类的声明中使用析构器,参见析构过程一节 -。 +查看例子和如何在类的声明中使用析构器,参见析构过程一节。 ->GRAMMAR OF A DEINITIALIZER DECLARATION - ->deinitializer-declaration → attributes­opt­deinit­code-block +> 析构器声明语法 +> *析构器声明* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **deinit** [*代码块*](..\chapter3\05_Declarations.html#code_block) ##扩展声明 @@ -809,23 +754,23 @@ type-inheritance-clause是一个只包含协议列表的扩展声明。 扩展声明可以包含构造器声明,这意味着,如果你扩展的类型在其他模块中定义,构造器声明必须委托另一个在 那个模块里声明的构造器来恰当的初始化。 ->GRAMMAR OF AN EXTENSION DECLARATION - ->extension-declaration → extension­type-identifier­type-inheritance-clause­opt­extension-body­ ->extension-body → {­declarations­opt­}­ +> 扩展(Extension)声明语法 +> *扩展声明* → **extension** [*类型标识*](..\chapter3\03_Types.html#type_identifier) [*类型继承子句*](..\chapter3\03_Types.html#type_inheritance_clause) _可选_ [*extension-body*](..\chapter3\05_Declarations.html#extension_body) +> *extension-body* → **{** [*声明(Declarations)列表*](..\chapter3\05_Declarations.html#declarations) _可选_ **}** ##附属脚本声明(translated by 林) 附属脚本用于向特定类型添加附属脚本支持,通常为访问集合,列表和序列的元素时提供语法便利。附属脚本声明使用关键字`subscript`,声明形式如下: -> subscript (`parameter`) -> (return type){ - get{ - `statements` - } - set(`setter name`){ - `statements` - } -} +> subscript (`parameter`) -> (return type){ + get{ + `statements` + } + set(`setter name`){ + `statements` + } +} + 附属脚本声明只能在类,结构体,枚举,扩展和协议声明的上下文进行声明。 _变量(parameters)_指定一个或多个用于在相关类型的附属脚本中访问元素的索引(例如,表达式`object[i]`中的`i`)。尽管用于元素访问的索引可以是任意类型的,但是每个变量必须包含一个用于指定每种索引类型的类型标注。_返回类型(return type)_指定被访问的元素的类型。 @@ -840,13 +785,12 @@ setter的名字和封闭的括号是可选的。如果使用了setter名称, 更多关于附属脚本和附属脚本声明的例子,请参考[Subscripts](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Subscripts.html#//apple_ref/doc/uid/TP40014097-CH16-XID_393)。 ->GRAMMAR OF A SUBSCRIPT DECLARATION - ->subscript-declaration → subscript-head­subscript-result­code-block­ ->subscript-declaration → subscript-head­subscript-result­getter-setter-block­ ->subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ ->subscript-head → attributes­opt­subscript­parameter-clause­ ->subscript-result → ->­attributes­opt­type­ +> 附属脚本声明语法 +> *附属脚本声明* → [*附属脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*附属脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*代码块*](..\chapter3\05_Declarations.html#code_block) +> *附属脚本声明* → [*附属脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*附属脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*getter-setter块*](..\chapter3\05_Declarations.html#getter_setter_block) +> *附属脚本声明* → [*附属脚本头(Head)*](..\chapter3\05_Declarations.html#subscript_head) [*附属脚本结果(Result)*](..\chapter3\05_Declarations.html#subscript_result) [*getter-setter关键字(Keyword)块*](..\chapter3\05_Declarations.html#getter_setter_keyword_block) +> *附属脚本头(Head)* → [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ **subscript** [*参数子句*](..\chapter3\05_Declarations.html#parameter_clause) +> *附属脚本结果(Result)* → **->** [*特性(Attributes)列表*](..\chapter3\06_Attributes.html#attributes) _可选_ [*类型*](..\chapter3\03_Types.html#type) ##运算符声明(translated by 林) @@ -889,14 +833,13 @@ _中缀_运算符是二元运算符,它可以被置于两个操作数之间, 声明了一个新的运算符以后,需要声明一个跟这个运算符同名的函数来实现这个运算符。如何实现一个新的运算符,请参考[Custom Operators](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_48)。 ->GRAMMAR OF AN OPERATOR DECLARATION -> ->operator-declaration → prefix-operator-declaration­ postfix-operator-declaration­ >infix-operator-declaration­ ->prefix-operator-declaration → operator ­prefix­ operator­{­}­ ->postfix-operator-declaration → operator ­postfix­ operator­{­}­ ->infix-operator-declaration → operator­infix­operator­{­infix-operator-attributes­opt­}­ ->infix-operator-attributes → precedence-clause­opt­associativity-clause­opt­ ->precedence-clause → precedence­precedence-level­ ->precedence-level → Digit 0 through 255 ->associativity-clause → associativity­associativity­ ->associativity → left­ right­ none +> 运算符声明语法 +> *运算符声明* → [*前置运算符声明*](..\chapter3\05_Declarations.html#prefix_operator_declaration) | [*后置运算符声明*](..\chapter3\05_Declarations.html#postfix_operator_declaration) | [*中置运算符声明*](..\chapter3\05_Declarations.html#infix_operator_declaration) +> *前置运算符声明* → **运算符** **prefix** [*运算符*](LexicalStructure.html#operator) **{** **}** +> *后置运算符声明* → **运算符** **postfix** [*运算符*](LexicalStructure.html#operator) **{** **}** +> *中置运算符声明* → **运算符** **infix** [*运算符*](LexicalStructure.html#operator) **{** [*中置运算符属性*](..\chapter3\05_Declarations.html#infix_operator_attributes) _可选_ **}** +> *中置运算符属性* → [*优先级子句*](..\chapter3\05_Declarations.html#precedence_clause) _可选_ [*结和性子句*](..\chapter3\05_Declarations.html#associativity_clause) _可选_ +> *优先级子句* → **precedence** [*优先级水平*](..\chapter3\05_Declarations.html#precedence_level) +> *优先级水平* → 数值 0 到 255 +> *结和性子句* → **associativity** [*结和性*](..\chapter3\05_Declarations.html#associativity) +> *结和性* → **left** | **right** | **none** \ No newline at end of file From 3495061b0ad066e2ebedbdbf11867d3aa4f34e61 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 15:20:48 +0800 Subject: [PATCH 05/24] modify [a swift tour] code style --- source/chapter1/01_swift.md | 3 +- source/chapter1/02_a_swift_tour.md | 740 ++++++++++++++--------------- 2 files changed, 362 insertions(+), 381 deletions(-) diff --git a/source/chapter1/01_swift.md b/source/chapter1/01_swift.md index 52d04681..aeea0dbd 100644 --- a/source/chapter1/01_swift.md +++ b/source/chapter1/01_swift.md @@ -1,5 +1,4 @@ -> 翻译:numbbbbb - +> 翻译:numbbbbb > 校对:yeahdongcn # 关于 Swift diff --git a/source/chapter1/02_a_swift_tour.md b/source/chapter1/02_a_swift_tour.md index ad40f81e..32fc84c1 100644 --- a/source/chapter1/02_a_swift_tour.md +++ b/source/chapter1/02_a_swift_tour.md @@ -1,5 +1,5 @@ -> 翻译:numbbbbb -> 校对:shinyzhu +> 翻译:numbbbbb +> 校对:shinyzhu, stanzhai # Swift 初见 @@ -7,26 +7,25 @@ 本页内容包括: -- [简单值(Simple Values)](#simple_values) -- [控制流(Control Flow)](#control_flow) -- [函数和闭包(Functions and Closures)](#functions_and_closures) -- [对象和类(Objects and Classes)](#objects_and_classes) -- [枚举和结构体(Enumerations and Structures)](#enumerations_and_structures) -- [接口和扩展(Protocols and Extensions)](#protocols_and_extensions) -- [泛型(Generics)](#generics) +- [简单值(Simple Values)](#simple_values) +- [控制流(Control Flow)](#control_flow) +- [函数和闭包(Functions and Closures)](#functions_and_closures) +- [对象和类(Objects and Classes)](#objects_and_classes) +- [枚举和结构体(Enumerations and Structures)](#enumerations_and_structures) +- [接口和扩展(Protocols and Extensions)](#protocols_and_extensions) +- [泛型(Generics)](#generics) 通常来说,编程语言教程中的第一个程序应该在屏幕上打印“Hello, world”。在 Swift 中,可以用一行代码实现: ```swift - println("Hello, world") +println("Hello, world") ``` 如果你写过 C 或者 Objective-C 代码,那你应该很熟悉这种形式——在 Swift 中,这行代码就是一个完整的程序。你不需要为了输入输出或者字符串处理导入一个单独的库。全局作用域中的代码会被自动当做程序的入口点,所以你也不需要`main`函数。你同样不需要在每个语句结尾写上分号。 这个教程会通过一系列编程例子来让你对 Swift 有初步了解,如果你有什么不理解的地方也不用担心——任何本章介绍的内容都会在后面的章节中详细讲解。 -> 注意: - +> 注意: > 为了获得最好的体验,在 Xcode 当中使用代码预览功能。代码预览功能可以让你编辑代码并实时看到运行结果。 @@ -35,9 +34,9 @@ 使用`let`来声明常量,使用`var`来声明变量。一个常量的值在编译时并不需要获取,但是你只能为它赋值一次。也就是说你可以用常量来表示这样一个值:你只需要决定一次,但是需要使用很多次。 ```swift - var myVariable = 42 - myVariable = 50 - let myConstant = 42 +var myVariable = 42 +myVariable = 50 +let myConstant = 42 ``` 常量或者变量的类型必须和你赋给它们的值一样。然而,声明时类型是可选的,声明的同时赋值的话,编译器会自动推断类型。在上面的例子中,编译器推断出`myVariable`是一个整数(integer)因为它的初始值是整数。 @@ -45,65 +44,62 @@ 如果初始值没有提供足够的信息(或者没有初始值),那你需要在变量后面声明类型,用冒号分割。 ```swift - let implicitInteger = 70 - let implicitDouble = 70.0 - let explicitDouble: Double = 70 +let implicitInteger = 70 +let implicitDouble = 70.0 +let explicitDouble: Double = 70 ``` -> 练习: -> +> 练习: > 创建一个常量,显式指定类型为`Float`并指定初始值为4。 值永远不会被隐式转换为其他类型。如果你需要把一个值转换成其他类型,请显式转换。 ```swift - let label = "The width is" - let width = 94 - let widthLabel = label + String(width) +let label = "The width is" +let width = 94 +let widthLabel = label + String(width) ``` -> 练习: -> +> 练习: > 删除最后一行中的`String`,错误提示是什么? 有一种更简单的把值转换成字符串的方法:把值写到括号中,并且在括号之前写一个反斜杠。例如: ```swift - let apples = 3 - let oranges = 5 - let appleSummary = "I have \(apples) apples." - let fruitSummary = "I have \(apples + oranges) pieces of fruit." +let apples = 3 +let oranges = 5 +let appleSummary = "I have \(apples) apples." +let fruitSummary = "I have \(apples + oranges) pieces of fruit." ``` -> 练习: -> +> 练习: > 使用`\()`来把一个浮点计算转换成字符串,并加上某人的名字,和他打个招呼。 使用方括号`[]`来创建数组和字典,并使用下标或者键(key)来访问元素。 ```swift - var shoppingList = ["catfish", "water", "tulips", "blue paint"] - shoppingList[1] = "bottle of water" +var shoppingList = ["catfish", "water", "tulips", "blue paint"] +shoppingList[1] = "bottle of water" ``` ```swift - var occupations = [ - "Malcolm": "Captain", - "Kaylee": "Mechanic", - ] - occupations["Jayne"] = "Public Relations" +var occupations = [ + "Malcolm": "Captain", + "Kaylee": "Mechanic", +] +occupations["Jayne"] = "Public Relations" ``` 要创建一个空数组或者字典,使用初始化语法。 ```swift - let emptyArray = String[]() - let emptyDictionary = Dictionary() +let emptyArray = String[]() +let emptyDictionary = Dictionary() ``` 如果类型信息可以被推断出来,你可以用`[]`和`[:]`来创建空数组和空字典——就像你声明变量或者给函数传参数的时候一样。 ```swift - shoppingList = [] // 去逛街并买点东西 +shoppingList = [] // 去逛街并买点东西 ``` @@ -112,16 +108,16 @@ 使用`if`和`switch`来进行条件操作,使用`for-in`、`for`、`while`和`do-while`来进行循环。包裹条件和循环变量括号可以省略,但是语句体的大括号是必须的。 ```swift - let individualScores = [75, 43, 103, 87, 12] - var teamScore = 0 - for score in individualScores { - if score > 50 { - teamScore += 3 - } else { - teamScore += 1 - } +let individualScores = [75, 43, 103, 87, 12] +var teamScore = 0 +for score in individualScores { + if score > 50 { + teamScore += 3 + } else { + teamScore += 1 } - teamScore +} +teamScore ``` 在`if`语句中,条件必须是一个布尔表达式——这意味着像`if score { ... }`这样的代码将报错,而不会隐形地与 0 做对比。 @@ -129,18 +125,17 @@ 你可以一起使用`if`和`let`来处理值缺失的情况。有些变量的值是可选的。一个可选的值可能是一个具体的值或者是`nil`,表示值缺失。在类型后面加一个问号来标记这个变量的值是可选的。 ```swift - var optionalString: String? = "Hello" - optionalString == nil +var optionalString: String? = "Hello" +optionalString == nil - var optionalName: String? = "John Appleseed" - var greeting = "Hello!" - if let name = optionalName { - greeting = "Hello, \(name)" - } +var optionalName: String? = "John Appleseed" +var greeting = "Hello!" +if let name = optionalName { + greeting = "Hello, \(name)" +} ``` -> 练习: -> +> 练习: > 把`optionalName`改成`nil`,greeting会是什么?添加一个`else`语句,当`optionalName`是`nil`时给greeting赋一个不同的值。 如果变量的可选值是`nil`,条件会判断为`false`,大括号中的代码会被跳过。如果不是`nil`,会将值赋给`let`后面的常量,这样代码块中就可以使用这个值了。 @@ -148,21 +143,20 @@ `switch`支持任意类型的数据以及各种比较操作——不仅仅是整数以及测试相等。 ```swift - let vegetable = "red pepper" - switch vegetable { - case "celery": - let vegetableComment = "Add some raisins and make ants on a log." - case "cucumber", "watercress": - let vegetableComment = "That would make a good tea sandwich." - case let x where x.hasSuffix("pepper"): - let vegetableComment = "Is it a spicy \(x)?" - default: - let vegetableComment = "Everything tastes good in soup." - } +let vegetable = "red pepper" +switch vegetable { +case "celery": + let vegetableComment = "Add some raisins and make ants on a log." +case "cucumber", "watercress": + let vegetableComment = "That would make a good tea sandwich." +case let x where x.hasSuffix("pepper"): + let vegetableComment = "Is it a spicy \(x)?" +default: + let vegetableComment = "Everything tastes good in soup." +} ``` -> 练习: -> +> 练习: > 删除`default`语句,看看会有什么错误? 运行`switch`中匹配到的子句之后,程序会退出`switch`语句,并不会继续向下运行,所以不需要在每个子句结尾写`break`。 @@ -170,56 +164,55 @@ 你可以使用`for-in`来遍历字典,需要两个变量来表示每个键值对。 ```swift - let interestingNumbers = [ - "Prime": [2, 3, 5, 7, 11, 13], - "Fibonacci": [1, 1, 2, 3, 5, 8], - "Square": [1, 4, 9, 16, 25], - ] - var largest = 0 - for (kind, numbers) in interestingNumbers { - for number in numbers { - if number > largest { - largest = number - } +let interestingNumbers = [ + "Prime": [2, 3, 5, 7, 11, 13], + "Fibonacci": [1, 1, 2, 3, 5, 8], + "Square": [1, 4, 9, 16, 25], +] +var largest = 0 +for (kind, numbers) in interestingNumbers { + for number in numbers { + if number > largest { + largest = number } } - largest +} +largest ``` -> 练习: -> +> 练习: > 添加另一个变量来记录哪种类型的数字是最大的。 使用`while`来重复运行一段代码直到不满足条件。循环条件可以在开头也可以在结尾。 ```swift - var n = 2 - while n < 100 { - n = n * 2 - } - n +var n = 2 +while n < 100 { + n = n * 2 +} +n - var m = 2 - do { - m = m * 2 - } while m < 100 - m +var m = 2 +do { + m = m * 2 +} while m < 100 +m ``` 你可以在循环中使用`..`来表示范围,也可以使用传统的写法,两者是等价的: ```swift - var firstForLoop = 0 - for i in 0..3 { - firstForLoop += i - } - firstForLoop +var firstForLoop = 0 +for i in 0..3 { + firstForLoop += i +} +firstForLoop - var secondForLoop = 0 - for var i = 0; i < 3; ++i { - secondForLoop += 1 - } - secondForLoop +var secondForLoop = 0 +for var i = 0; i < 3; ++i { + secondForLoop += 1 +} +secondForLoop ``` 使用`..`创建的范围不包含上界,如果想包含的话需要使用`...`。 @@ -230,112 +223,109 @@ 使用`func`来声明一个函数,使用名字和参数来调用函数。使用`->`来指定函数返回值。 ```swift - func greet(name: String, day: String) -> String { - return "Hello \(name), today is \(day)." - } - greet("Bob", "Tuesday") +func greet(name: String, day: String) -> String { + return "Hello \(name), today is \(day)." +} +greet("Bob", "Tuesday") ``` -> 练习: -> +> 练习: > 删除`day`参数,添加一个参数来表示今天吃了什么午饭。 使用一个元组来返回多个值。 ```swift - func getGasPrices() -> (Double, Double, Double) { - return (3.59, 3.69, 3.79) - } - getGasPrices() +func getGasPrices() -> (Double, Double, Double) { + return (3.59, 3.69, 3.79) +} +getGasPrices() ``` 函数可以带有可变个数的参数,这些参数在函数内表现为数组的形式: ```swift - func sumOf(numbers: Int...) -> Int { - var sum = 0 - for number in numbers { - sum += number - } - return sum +func sumOf(numbers: Int...) -> Int { + var sum = 0 + for number in numbers { + sum += number } - sumOf() - sumOf(42, 597, 12) + return sum +} +sumOf() +sumOf(42, 597, 12) ``` -> 练习: -> +> 练习: > 写一个计算参数平均值的函数。 函数可以嵌套。被嵌套的函数可以访问外侧函数的变量,你可以使用嵌套函数来重构一个太长或者太复杂的函数。 ```swift - func returnFifteen() -> Int { - var y = 10 - func add() { - y += 5 - } - add() - return y +func returnFifteen() -> Int { + var y = 10 + func add() { + y += 5 } - returnFifteen() + add() + return y +} +returnFifteen() ``` 函数是第一等类型,这意味着函数可以作为另一个函数的返回值。 ```swift - func makeIncrementer() -> (Int -> Int) { - func addOne(number: Int) -> Int { - return 1 + number - } - return addOne +func makeIncrementer() -> (Int -> Int) { + func addOne(number: Int) -> Int { + return 1 + number } - var increment = makeIncrementer() - increment(7) + return addOne +} +var increment = makeIncrementer() +increment(7) ``` 函数也可以当做参数传入另一个函数。 ```swift - func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool { - for item in list { - if condition(item) { - return true - } +func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool { + for item in list { + if condition(item) { + return true } - return false } - func lessThanTen(number: Int) -> Bool { - return number < 10 - } - var numbers = [20, 19, 7, 12] - hasAnyMatches(numbers, lessThanTen) + return false +} +func lessThanTen(number: Int) -> Bool { + return number < 10 +} +var numbers = [20, 19, 7, 12] +hasAnyMatches(numbers, lessThanTen) ``` 函数实际上是一种特殊的闭包,你可以使用`{}`来创建一个匿名闭包。使用`in`将参数和返回值类型声明与闭包函数体进行分离。 ```swift - numbers.map({ - (number: Int) -> Int in - let result = 3 * number - return result - }) +numbers.map({ + (number: Int) -> Int in + let result = 3 * number + return result +}) ``` -> 练习: -> +> 练习: > 重写闭包,对所有奇数返回 0. 有很多种创建闭包的方法。如果一个闭包的类型已知,比如作为一个回调函数,你可以忽略参数的类型和返回值。单个语句闭包会把它语句的值当做结果返回。 ```swift - numbers.map({ number in 3 * number }) +numbers.map({ number in 3 * number }) ``` 你可以通过参数位置而不是参数名字来引用参数——这个方法在非常短的闭包中非常有用。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。 ```swift - sort([1, 5, 3, 12, 2]) { $0 > $1 } +sort([1, 5, 3, 12, 2]) { $0 > $1 } ``` @@ -344,41 +334,40 @@ 使用`class`和类名来创建一个类。类中属性的声明和常量、变量声明一样,唯一的区别就是它们的上下文是类。同样,方法和函数声明也一样。 ```swift - class Shape { - var numberOfSides = 0 - func simpleDescription() -> String { - return "A shape with \(numberOfSides) sides." - } +class Shape { + var numberOfSides = 0 + func simpleDescription() -> String { + return "A shape with \(numberOfSides) sides." } +} ``` -> 练习: -> +> 练习: > 使用`let`添加一个常量属性,再添加一个接收一个参数的方法。 要创建一个类的实例,在类名后面加上括号。使用点语法来访问实例的属性和方法。 ```swift - var shape = Shape() - shape.numberOfSides = 7 - var shapeDescription = shape.simpleDescription() +var shape = Shape() +shape.numberOfSides = 7 +var shapeDescription = shape.simpleDescription() ``` 这个版本的`Shape`类缺少了一些重要的东西:一个构造函数来初始化类实例。使用`init`来创建一个构造器。 ```swift - class NamedShape { - var numberOfSides: Int = 0 - var name: String +class NamedShape { + var numberOfSides: Int = 0 + var name: String - init(name: String) { - self.name = name - } - - func simpleDescription() -> String { - return "A shape with \(numberOfSides) sides." - } + init(name: String) { + self.name = name } + + func simpleDescription() -> String { + return "A shape with \(numberOfSides) sides." + } +} ``` 注意`self`被用来区别实例变量。当你创建实例的时候,像传入函数参数一样给类传入构造器的参数。每个属性都需要赋值——无论是通过声明(就像`numberOfSides`)还是通过构造器(就像`name`)。 @@ -390,61 +379,60 @@ 子类如果要重写父类的方法的话,需要用`override`标记——如果没有添加`override`就重写父类方法的话编译器会报错。编译器同样会检测`override`标记的方法是否确实在父类中。 ```swift - class Square: NamedShape { - var sideLength: Double +class Square: NamedShape { + var sideLength: Double - init(sideLength: Double, name: String) { - self.sideLength = sideLength - super.init(name: name) - numberOfSides = 4 - } - - func area() -> Double { - return sideLength * sideLength - } - - override func simpleDescription() -> String { - return "A square with sides of length \(sideLength)." - } + init(sideLength: Double, name: String) { + self.sideLength = sideLength + super.init(name: name) + numberOfSides = 4 } - let test = Square(sideLength: 5.2, name: "my test square") - test.area() - test.simpleDescription() + + func area() -> Double { + return sideLength * sideLength + } + + override func simpleDescription() -> String { + return "A square with sides of length \(sideLength)." + } +} +let test = Square(sideLength: 5.2, name: "my test square") +test.area() +test.simpleDescription() ``` -> 练习: -> +> 练习: > 创建`NamedShape`的另一个子类`Circle`,构造器接收两个参数,一个是半径一个是名称,实现`area`和`describe`方法。 属性可以有 getter 和 setter 。 ```swift - class EquilateralTriangle: NamedShape { - var sideLength: Double = 0.0 +class EquilateralTriangle: NamedShape { + var sideLength: Double = 0.0 - init(sideLength: Double, name: String) { - self.sideLength = sideLength - super.init(name: name) - numberOfSides = 3 - } - - var perimeter: Double { - get { - return 3.0 * sideLength - } - set { - sideLength = newValue / 3.0 - } - } - - override func simpleDescription() -> String { - return "An equilateral triagle with sides of length \(sideLength)." - } + init(sideLength: Double, name: String) { + self.sideLength = sideLength + super.init(name: name) + numberOfSides = 3 } - var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle") - triangle.perimeter - triangle.perimeter = 9.9 - triangle.sideLength + + var perimeter: Double { + get { + return 3.0 * sideLength + } + set { + sideLength = newValue / 3.0 + } + } + + override func simpleDescription() -> String { + return "An equilateral triagle with sides of length \(sideLength)." + } +} +var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle") +triangle.perimeter +triangle.perimeter = 9.9 +triangle.sideLength ``` 在`perimeter`的 setter 中,新值的名字是`newValue`。你可以在`set`之后显式的设置一个名字。 @@ -460,47 +448,47 @@ 比如,下面的类确保三角形的边长总是和正方形的边长相同。 ```swift - class TriangleAndSquare { - var triangle: EquilateralTriangle { - willSet { - square.sideLength = newValue.sideLength - } - } - var square: Square { - willSet { - triangle.sideLength = newValue.sideLength - } - } - init(size: Double, name: String) { - square = Square(sideLength: size, name: name) - triangle = EquilateralTriangle(sideLength: size, name: name) - } +class TriangleAndSquare { + var triangle: EquilateralTriangle { + willSet { + square.sideLength = newValue.sideLength } - var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape") - triangleAndSquare.square.sideLength - triangleAndSquare.triangle.sideLength - triangleAndSquare.square = Square(sideLength: 50, name: "larger square") - triangleAndSquare.triangle.sideLength + } + var square: Square { + willSet { + triangle.sideLength = newValue.sideLength + } + } + init(size: Double, name: String) { + square = Square(sideLength: size, name: name) + triangle = EquilateralTriangle(sideLength: size, name: name) + } +} +var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape") +triangleAndSquare.square.sideLength +triangleAndSquare.triangle.sideLength +triangleAndSquare.square = Square(sideLength: 50, name: "larger square") +triangleAndSquare.triangle.sideLength ``` 类中的方法和一般的函数有一个重要的区别,函数的参数名只在函数内部使用,但是方法的参数名需要在调用的时候显式说明(除了第一个参数)。默认情况下,方法的参数名和它在方法内部的名字一样,不过你也可以定义第二个名字,这个名字被用在方法内部。 ```swift - class Counter { - var count: Int = 0 - func incrementBy(amount: Int, numberOfTimes times: Int) { - count += amount * times - } +class Counter { + var count: Int = 0 + func incrementBy(amount: Int, numberOfTimes times: Int) { + count += amount * times } - var counter = Counter() - counter.incrementBy(2, numberOfTimes: 7) +} +var counter = Counter() +counter.incrementBy(2, numberOfTimes: 7) ``` 处理变量的可选值时,你可以在操作(比如方法、属性和子脚本)之前加`?`。如果`?`之前的值是`nil`,`?`后面的东西都会被忽略,并且整个表达式返回`nil`。否则,`?`之后的东西都会被运行。在这两种情况下,整个表达式的值也是一个可选值。 ```swift - let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") - let sideLength = optionalSquare?.sideLength +let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") +let sideLength = optionalSquare?.sideLength ``` @@ -509,31 +497,30 @@ 使用`enum`来创建一个枚举。就像类和其他所有命名类型一样,枚举可以包含方法。 ```swift - enum Rank: Int { - case Ace = 1 - case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten - case Jack, Queen, King - func simpleDescription() -> String { - switch self { - case .Ace: - return "ace" - case .Jack: - return "jack" - case .Queen: - return "queen" - case .King: - return "king" - default: - return String(self.toRaw()) - } +enum Rank: Int { + case Ace = 1 + case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten + case Jack, Queen, King + func simpleDescription() -> String { + switch self { + case .Ace: + return "ace" + case .Jack: + return "jack" + case .Queen: + return "queen" + case .King: + return "king" + default: + return String(self.toRaw()) } } - let ace = Rank.Ace - let aceRawValue = ace.toRaw() +} +let ace = Rank.Ace +let aceRawValue = ace.toRaw() ``` -> 练习: -> +> 练习: > 写一个函数,通过比较它们的原始值来比较两个`Rank`值。 在上面的例子中,枚举原始值的类型是`Int`,所以你只需要设置第一个原始值。剩下的原始值会按照顺序赋值。你也可以使用字符串或者浮点数作为枚举的原始值。 @@ -541,36 +528,35 @@ 使用`toRaw`和`fromRaw`函数来在原始值和枚举值之间进行转换。 ```swift - if let convertedRank = Rank.fromRaw(3) { - let threeDescription = convertedRank.simpleDescription() - } +if let convertedRank = Rank.fromRaw(3) { + let threeDescription = convertedRank.simpleDescription() +} ``` 枚举的成员值是实际值,并不是原始值的另一种表达方法。实际上,如果原始值没有意义,你不需要设置。 ```swift - enum Suit { - case Spades, Hearts, Diamonds, Clubs - func simpleDescription() -> String { - switch self { - case .Spades: - return "spades" - case .Hearts: - return "hearts" - case .Diamonds: - return "diamonds" - case .Clubs: - return "clubs" - } +enum Suit { + case Spades, Hearts, Diamonds, Clubs + func simpleDescription() -> String { + switch self { + case .Spades: + return "spades" + case .Hearts: + return "hearts" + case .Diamonds: + return "diamonds" + case .Clubs: + return "clubs" } - } - let hearts = Suit.Hearts - let heartsDescription = hearts.simpleDescription() + +} +let hearts = Suit.Hearts +let heartsDescription = hearts.simpleDescription() ``` -> 练习: -> +> 练习: > 给`Suit`添加一个`color`方法,对`spades`和`clubs`返回“black”,对`hearts`和`diamonds`返回“red”。 注意,有两种方式可以引用`Hearts`成员:给`hearts`常量赋值时,枚举成员`Suit.Hearts`需要用全名来引用,因为常量没有显式指定类型。在`switch`里,枚举成员使用缩写`.Hearts`来引用,因为`self`的值已经知道是一个`suit`。已知变量类型的情况下你可以使用缩写。 @@ -579,20 +565,19 @@ 结构体是传值,类是传引用。 ```swift - struct Card { - var rank: Rank - var suit: Suit - func simpleDescription() -> String { - return "The \(rank.simpleDescription()) of \ - (suit.simpleDescription())" - } +struct Card { + var rank: Rank + var suit: Suit + func simpleDescription() -> String { + return "The \(rank.simpleDescription()) of \ + (suit.simpleDescription())" } - let threeOfSpades = Card(rank: .Three, suit: .Spades) - let threeOfSpadesDescription = threeOfSpades.simpleDescription() +} +let threeOfSpades = Card(rank: .Three, suit: .Spades) +let threeOfSpadesDescription = threeOfSpades.simpleDescription() ``` -> 练习: -> +> 练习: > 给`Card`添加一个方法,创建一副完整的扑克牌并把每张牌的 rank 和 suit 对应起来。 一个枚举成员的实例可以有实例值。相同枚举成员的实例可以有不同的值。创建实例的时候传入值即可。实例值和原始值是不同的:枚举成员的原始值对于所有实例都是相同的,而且你是在定义枚举的时候设置原始值。 @@ -600,24 +585,23 @@ 例如,考虑从服务器获取日出和日落的时间。服务器会返回正常结果或者错误信息。 ```swift - enum ServerResponse { - case Result(String, String) - case Error(String) - } +enum ServerResponse { + case Result(String, String) + case Error(String) +} - let success = ServerResponse.Result("6:00 am", "8:09 pm") - let failure = ServerResponse.Error("Out of cheese.") +let success = ServerResponse.Result("6:00 am", "8:09 pm") +let failure = ServerResponse.Error("Out of cheese.") - switch success { - case let .Result(sunrise, sunset): - let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)." - case let .Error(error): - let serverResponse = "Failure... \(error)" - } +switch success { +case let .Result(sunrise, sunset): + let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)." +case let .Error(error): + let serverResponse = "Failure... \(error)" +} ``` -> 练习: -> +> 练习: > 给`ServerResponse`和`switch`添加第三种情况。 注意如何从`ServerResponse`中提取日升和日落时间。 @@ -628,39 +612,38 @@ 使用`protocol`来声明一个接口。 ```swift - protocol ExampleProtocol { - var simpleDescription: String { get } - mutating func adjust() - } +protocol ExampleProtocol { + var simpleDescription: String { get } + mutating func adjust() +} ``` 类、枚举和结构体都可以实现接口。 ```swift - class SimpleClass: ExampleProtocol { - var simpleDescription: String = "A very simple class." - var anotherProperty: Int = 69105 - func adjust() { - simpleDescription += " Now 100% adjusted." - } +class SimpleClass: ExampleProtocol { + var simpleDescription: String = "A very simple class." + var anotherProperty: Int = 69105 + func adjust() { + simpleDescription += " Now 100% adjusted." } - var a = SimpleClass() - a.adjust() - let aDescription = a.simpleDescription +} +var a = SimpleClass() +a.adjust() +let aDescription = a.simpleDescription - struct SimpleStructure: ExampleProtocol { - var simpleDescription: String = "A simple structure" - mutating func adjust() { - simpleDescription += " (adjusted)" - } +struct SimpleStructure: ExampleProtocol { + var simpleDescription: String = "A simple structure" + mutating func adjust() { + simpleDescription += " (adjusted)" } - var b = SimpleStructure() - b.adjust() - let bDescription = b.simpleDescription +} +var b = SimpleStructure() +b.adjust() +let bDescription = b.simpleDescription ``` -> 练习: -> +> 练习: > 写一个实现这个接口的枚举。 注意声明`SimpleStructure`时候`mutating`关键字用来标记一个会修改结构体的方法。`SimpleClass`的声明不需要标记任何方法因为类中的方法经常会修改类。 @@ -668,15 +651,15 @@ 使用`extension`来为现有的类型添加功能,比如添加一个计算属性的方法。你可以使用扩展来给任意类型添加协议,甚至是你从外部库或者框架中导入的类型。 ```swift - extension Int: ExampleProtocol { - var simpleDescription: String { - return "The number \(self)" - } - mutating func adjust() { - self += 42 - } +extension Int: ExampleProtocol { + var simpleDescription: String { + return "The number \(self)" } - 7.simpleDescription + mutating func adjust() { + self += 42 + } +} +7.simpleDescription ``` > 练习: @@ -686,9 +669,9 @@ 你可以像使用其他命名类型一样使用接口名——例如,创建一个有不同类型但是都实现一个接口的对象集合。当你处理类型是接口的值时,接口外定义的方法不可用。 ```swift - let protocolValue: ExampleProtocol = a - protocolValue.simpleDescription - // protocolValue.anotherProperty // Uncomment to see the error +let protocolValue: ExampleProtocol = a +protocolValue.simpleDescription +// protocolValue.anotherProperty // Uncomment to see the error ``` 即使`protocolValue`变量运行时的类型是`simpleClass`,编译器会把它的类型当做`ExampleProtocol`。这表示你不能调用类在它实现的接口之外实现的方法或者属性。 @@ -699,46 +682,45 @@ 在尖括号里写一个名字来创建一个泛型函数或者类型。 ```swift - func repeat(item: ItemType, times: Int) -> ItemType[] { - var result = ItemType[]() - for i in 0..times { - result += item - } - return result +func repeat(item: ItemType, times: Int) -> ItemType[] { + var result = ItemType[]() + for i in 0..times { + result += item } - repeat("knock", 4) + return result +} +repeat("knock", 4) ``` 你也可以创建泛型类、枚举和结构体。 ```swift - // Reimplement the Swift standard library's optional type - enum OptionalValue { - case None - case Some(T) - } - var possibleInteger: OptionalValue = .None - possibleInteger = .Some(100) +// Reimplement the Swift standard library's optional type +enum OptionalValue { + case None + case Some(T) +} +var possibleInteger: OptionalValue = .None +possibleInteger = .Some(100) ``` 在类型名后面使用`where`来指定一个需求列表——例如,要限定实现一个协议的类型,需要限定两个类型要相同,或者限定一个类必须有一个特定的父类。 ```swift - func anyCommonElements (lhs: T, rhs: U) -> Bool { - for lhsItem in lhs { - for rhsItem in rhs { - if lhsItem == rhsItem { - return true - } +func anyCommonElements (lhs: T, rhs: U) -> Bool { + for lhsItem in lhs { + for rhsItem in rhs { + if lhsItem == rhsItem { + return true } } - return false } - anyCommonElements([1, 2, 3], [3]) + return false +} +anyCommonElements([1, 2, 3], [3]) ``` -> 练习: -> +> 练习: > 修改`anyCommonElements`函数来创建一个函数,返回一个数组,内容是两个序列的共有元素。 简单起见,你可以忽略`where`,只在冒号后面写接口或者类名。` `和``是等价的。 From 24bc899b1d89e7c0f6dadf6e8764dd1078668ab6 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 16:11:17 +0800 Subject: [PATCH 06/24] fix 2.1 the basics --- source/chapter2/01_The_Basics.md | 428 ++++++++++++++++++------------- 1 file changed, 255 insertions(+), 173 deletions(-) diff --git a/source/chapter2/01_The_Basics.md b/source/chapter2/01_The_Basics.md index 6e5b0a98..f2c628c4 100644 --- a/source/chapter2/01_The_Basics.md +++ b/source/chapter2/01_The_Basics.md @@ -1,6 +1,5 @@ -> 翻译:numbbbbb, lyuka, JaySurplus - -> 校对:lslxdx +> 翻译:numbbbbb, lyuka, JaySurplus +> 校对:lslxdx # 基础部分 ----------------- @@ -42,9 +41,10 @@ Swift 是一个类型安全的语言,可选就是一个很好的例子。Swift 常量和变量必须在使用前声明,用`let`来声明常量,用`var`来声明变量。下面的例子展示了如何用常量和变量来记录用户尝试登录的次数: - let maximumNumberOfLoginAttempts = 10 - var currentLoginAttempt = 0 - +```swift +let maximumNumberOfLoginAttempts = 10 +var currentLoginAttempt = 0 +``` 这两行代码可以被理解为: @@ -54,10 +54,11 @@ Swift 是一个类型安全的语言,可选就是一个很好的例子。Swift 你可以在一行中声明多个常量或者多个变量,用逗号隔开: - var x = 0.0, y = 0.0, z = 0.0 +```swift +var x = 0.0, y = 0.0, z = 0.0 +``` ->注意: -> +>注意: 如果你的代码中有不需要改变的值,请使用`let`关键字将它声明为常量。只将需要改变的值声明为变量。 ### 类型标注 @@ -66,7 +67,9 @@ Swift 是一个类型安全的语言,可选就是一个很好的例子。Swift 这个例子给`welcomeMessage`变量添加了类型标注,表示这个变量可以存储`String`类型的值: - var welcomeMessage: String +```swift +var welcomeMessage: String +``` 声明中的冒号代表着“是...类型”,所以这行代码可以被理解为: @@ -76,63 +79,74 @@ Swift 是一个类型安全的语言,可选就是一个很好的例子。Swift `welcomeMessage`变量现在可以被设置成任意字符串: - welcomeMessage = "Hello" +```swift +welcomeMessage = "Hello" +``` -> 注意: -> +> 注意: 一般来说你很少需要写类型标注。如果你在声明常量或者变量的时候赋了一个初始值,Swift可以推断出这个常量或者变量的类型,请参考[类型安全和类型推断](#type_safety_and_type_inference)。在上面的例子中,没有给`welcomeMessage`赋初始值,所以变量`welcomeMessage`的类型是通过一个类型标注指定的,而不是通过初始值推断的。 ### 常量和变量的命名 你可以用任何你喜欢的字符作为常量和变量名,包括 Unicode 字符: - let π = 3.14159 - let 你好 = "你好世界" - let 🐶🐮 = "dogcow" +```swift +let π = 3.14159 +let 你好 = "你好世界" +let 🐶🐮 = "dogcow" +``` 常量与变量名不能包含数学符号,箭头,保留的(或者非法的)Unicode 码位,连线与制表符。也不能以数字开头,但是可以在常量与变量名的其他地方包含数字。 一旦你将常量或者变量声明为确定的类型,你就不能使用相同的名字再次进行声明,或者改变其存储的值的类型。同时,你也不能将常量与变量进行互转。 -> 注意: -> +> 注意: 如果你需要使用与Swift保留关键字相同的名称作为常量或者变量名,你可以使用反引号(`)将关键字包围的方式将其作为名字使用。无论如何,你应当避免使用关键字作为常量或变量名,除非你别无选择。 你可以更改现有的变量值为其他同类型的值,在下面的例子中,`friendlyWelcome`的值从`"Hello!"`改为了`"Bonjour!"`: - var friendlyWelcome = "Hello!" - friendlyWelcome = "Bonjour!" - // friendlyWelcome 现在是 "Bonjour!" +```swift +var friendlyWelcome = "Hello!" +friendlyWelcome = "Bonjour!" +// friendlyWelcome 现在是 "Bonjour!" +``` 与变量不同,常量的值一旦被确定就不能更改了。尝试这样做会导致编译时报错: - let languageName = "Swift" - languageName = "Swift++" - // 这会报编译时错误 - languageName 不可改变 +```swift +let languageName = "Swift" +languageName = "Swift++" +// 这会报编译时错误 - languageName 不可改变 +``` ### 输出常量和变量 你可以用`println`函数来输出当前常量或变量的值: - println(friendlyWelcome) - // 输出 "Bonjour!" +```swift +println(friendlyWelcome) +// 输出 "Bonjour!" +``` `println`是一个用来输出的全局函数,输出的内容会在最后换行。如果你用 Xcode,`println`将会输出内容到“console”面板上。(另一种函数叫`print`,唯一区别是在输出内容最后不会换行。) `println`函数输出传入的`String`值: - println("This is a string") - // 输出 "This is a string" +```swift +println("This is a string") +// 输出 "This is a string" +``` 与 Cocoa 里的`NSLog`函数类似的是,`println`函数可以输出更复杂的信息。这些信息可以包含当前常量和变量的值。 Swift 用_字符串插值(string interpolation)_的方式把常量名或者变量名当做占位符加入到长字符串中,Swift 会用当前常量或变量的值替换这些占位符。将常量或变量名放入圆括号中,并在开括号前使用反斜杠将其转义: - println("The current value of friendlyWelcome is \(friendlyWelcome)") - // 输出 "The current value of friendlyWelcome is Bonjour! +```swift +println("The current value of friendlyWelcome is \(friendlyWelcome)") +// 输出 "The current value of friendlyWelcome is Bonjour! +``` -> 注意: -> +> 注意: 字符串插值所有可用的选项,请参考[字符串插值](03_Strings_and_Characters.html#string_interpolation)。 @@ -141,18 +155,24 @@ Swift 用_字符串插值(string interpolation)_的方式把常量名或者 Swift 中的注释与C 语言的注释非常相似。单行注释以双正斜杠(`//`)作为起始标记: - // 这是一个注释 +```swift +// 这是一个注释 +``` 你也可以进行多行注释,其起始标记为单个正斜杠后跟随一个星号(`/*`),终止标记为一个星号后跟随单个正斜杠(`*/`): - /* 这是一个, - 多行注释 */ +```swift +/* 这是一个, +多行注释 */ +``` 与 C 语言多行注释不同,Swift 的多行注释可以嵌套在其它的多行注释之中。你可以先生成一个多行注释块,然后在这个注释块之中再嵌套成第二个多行注释。终止注释时先插入第二个注释块的终止标记,然后再插入第一个注释块的终止标记: - /* 这是第一个多行注释的开头 - /* 这是第二个被嵌套的多行注释 */ - 这是第一个多行注释的结尾 */ +```swift +/* 这是第一个多行注释的开头 +/* 这是第二个被嵌套的多行注释 */ +这是第一个多行注释的结尾 */ +``` 通过运用嵌套多行注释,你可以快速方便的注释掉一大段代码,即使这段代码之中已经含有了多行注释块。 @@ -160,8 +180,10 @@ Swift 中的注释与C 语言的注释非常相似。单行注释以双正斜杠 ## 分号 与其他大部分编程语言不同,Swift 并不强制要求你在每条语句的结尾处使用分号(`;`),当然,你也可以按照你自己的习惯添加分号。有一种情况下必须要用分号,即你打算在同一行内写多条独立的语句: - let cat = "🐱"; println(cat) - // 输出 "🐱" +```swift +let cat = "🐱"; println(cat) +// 输出 "🐱" +``` ## 整数 @@ -174,8 +196,10 @@ Swift 提供了8,16,32和64位的有符号和无符号整数类型。这些 你可以访问不同整数类型的`min`和`max`属性来获取对应类型的最大值和最小值: - let minValue = UInt8.min // minValue 为 0,是 UInt8 类型的最小值 - let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型的最大值 +```swift +let minValue = UInt8.min // minValue 为 0,是 UInt8 类型的最小值 +let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型的最大值 +``` ### Int @@ -193,8 +217,7 @@ Swift 也提供了一个特殊的无符号类型`UInt`,长度与当前平台 * 在32位平台上,`UInt`和`UInt32`长度相同。 * 在64位平台上,`UInt`和`UInt64`长度相同。 -> 注意: -> +> 注意: 尽量不要使用`UInt`,除非你真的需要存储一个和当前平台原生字长相同的无符号整数。除了这种情况,最好使用`Int`,即使你要存储的值已知是非负的。统一使用`Int`可以提高代码的可复用性,避免不同类型数字之间的转换,并且匹配数字的类型推测,请参考[类型安全和类型推测](#type_safety_and_type_inference)。 @@ -207,8 +230,7 @@ Swift 也提供了一个特殊的无符号类型`UInt`,长度与当前平台 * `Double`表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。 * `Float`表示32位浮点数。精度要求不高的话可以使用此类型。 -> 注意: -> +> 注意: `Double`精确度很高,至少有15位数字,而`Float`最少只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围。 @@ -226,20 +248,26 @@ Swift 是一个_类型安全(type safe)_的语言。类型安全的语言可 例如,如果你给一个新常量赋值`42`并且没有标明类型,Swift 可以推测出常量类型是`Int`,因为你给它赋的初始值看起来像一个整数: - let meaningOfLife = 42 - // meaningOfLife 会被推测为 Int 类型 +```swift +let meaningOfLife = 42 +// meaningOfLife 会被推测为 Int 类型 +``` 同理,如果你没有给浮点字面量标明类型,Swift 会推测你想要的是`Double`: - let pi = 3.14159 - // pi 会被推测为 Double 类型 +```swift +let pi = 3.14159 +// pi 会被推测为 Double 类型 +``` 当推测浮点数的类型时,Swift 总是会选择`Double`而不是`Float`。 如果表达式中同时出现了整数和浮点数,会被推测为`Double`类型: - let anotherPi = 3 + 0.14159 - // anotherPi 会被推测为 Double 类型 +```swift +let anotherPi = 3 + 0.14159 +// anotherPi 会被推测为 Double 类型 +``` 原始值`3`没有显式声明类型,而表达式中出现了一个浮点字面量,所以表达式会被推测为`Double`类型。 @@ -255,10 +283,12 @@ Swift 是一个_类型安全(type safe)_的语言。类型安全的语言可 下面的所有整数字面量的十进制值都是`17`: - let decimalInteger = 17 - let binaryInteger = 0b10001 // 二进制的17 - let octalInteger = 0o21 // 八进制的17 - let hexadecimalInteger = 0x11 // 十六进制的17 +```swift +let decimalInteger = 17 +let binaryInteger = 0b10001 // 二进制的17 +let octalInteger = 0o21 // 八进制的17 +let hexadecimalInteger = 0x11 // 十六进制的17 +``` 浮点字面量可以是十进制(没有前缀)或者是十六进制(前缀是`0x`)。小数点两边必须有至少一个十进制数字(或者是十六进制的数字)。浮点字面量还有一个可选的_指数(exponent)_,在十进制浮点数中通过大写或者小写的`e`来指定,在十六进制浮点数中通过大写或者小写的`p`来指定。 @@ -272,15 +302,19 @@ Swift 是一个_类型安全(type safe)_的语言。类型安全的语言可 下面的这些浮点字面量都等于十进制的`12.1875`: - let decimalDouble = 12.1875 - let exponentDouble = 1.21875e1 - let hexadecimalDouble = 0xC.3p0 +```swift +let decimalDouble = 12.1875 +let exponentDouble = 1.21875e1 +let hexadecimalDouble = 0xC.3p0 +``` 数值类字面量可以包括额外的格式来增强可读性。整数和浮点数都可以添加额外的零并且包含下划线,并不会影响字面量: - let paddedDouble = 000123.456 - let oneMillion = 1_000_000 - let justOverOneMillion = 1_000_000.000_000_1 +```swift +let paddedDouble = 000123.456 +let oneMillion = 1_000_000 +let justOverOneMillion = 1_000_000.000_000_1 +``` ## 数值型类型转换 @@ -292,18 +326,22 @@ Swift 是一个_类型安全(type safe)_的语言。类型安全的语言可 不同整数类型的变量和常量可以存储不同范围的数字。`Int8`类型的常量或者变量可以存储的数字范围是`-128`~`127`,而`UInt8`类型的常量或者变量能存储的数字范围是`0`~`255`。如果数字超出了常量或者变量可存储的范围,编译的时候会报错: - let cannotBeNegative: UInt8 = -1 - // UInt8 类型不能存储负数,所以会报错 - let tooBig: Int8 = Int8.max + 1 - // Int8 类型不能存储超过最大值的数,所以会报错 +```swift +let cannotBeNegative: UInt8 = -1 +// UInt8 类型不能存储负数,所以会报错 +let tooBig: Int8 = Int8.max + 1 +// Int8 类型不能存储超过最大值的数,所以会报错 +``` 由于每种整数类型都可以存储不同范围的值,所以你必须根据不同情况选择性使用数值型类型转换。这种选择性使用的方式,可以预防隐式转换的错误并让你的代码中的类型转换意图变得清晰。 要将一种数字类型转换成另一种,你要用当前值来初始化一个期望类型的新数字,这个数字的类型就是你的目标类型。在下面的例子中,常量`twoThousand`是`UInt16`类型,然而常量`one`是`UInt8`类型。它们不能直接相加,因为它们类型不同。所以要调用`UInt16(one)`来创建一个新的`UInt16`数字并用`one`的值来初始化,然后使用这个新数字来计算: - let twoThousand: UInt16 = 2_000 - let one: UInt8 = 1 - let twoThousandAndOne = twoThousand + UInt16(one) +```swift +let twoThousand: UInt16 = 2_000 +let one: UInt8 = 1 +let twoThousandAndOne = twoThousand + UInt16(one) +``` 现在两个数字的类型都是`UInt16`,可以进行相加。目标常量`twoThousandAndOne`的类型被推测为`UInt16`,因为它是两个`UInt16`值的和。 @@ -313,22 +351,25 @@ Swift 是一个_类型安全(type safe)_的语言。类型安全的语言可 整数和浮点数的转换必须显式指定类型: - let three = 3 - let pointOneFourOneFiveNine = 0.14159 - let pi = Double(three) + pointOneFourOneFiveNine - // pi 等于 3.14159,所以被推测为 Double 类型 +```swift +let three = 3 +let pointOneFourOneFiveNine = 0.14159 +let pi = Double(three) + pointOneFourOneFiveNine +// pi 等于 3.14159,所以被推测为 Double 类型 +``` 这个例子中,常量`three`的值被用来创建一个`Double`类型的值,所以加号两边的数类型相同。如果不进行转换,两者无法相加。 浮点数到整数的反向转换同样行,整数类型可以用`Double`或者`Float`类型来初始化: - let integerPi = Int(pi) - // integerPi 等于 3,所以被推测为 Int 类型 +```swift +let integerPi = Int(pi) +// integerPi 等于 3,所以被推测为 Int 类型 +``` 当用这种方式来初始化一个新的整数值时,浮点值会被截断。也就是说`4.75`会变成`4`,`-3.9`会变成`-3`。 -> 注意: -> +> 注意: 结合数字类常量和变量不同于结合数字类字面量。字面量`3`可以直接和字面量`0.14159`相加,因为数字字面量本身没有明确的类型。它们的类型只在编译器需要求值的时候被推测。 @@ -338,12 +379,16 @@ _类型别名(type aliases)_就是给现有类型定义另一个名字。你 当你想要给现有类型起一个更有意义的名字时,类型别名非常有用。假设你正在处理特定长度的外部资源的数据: - typealias AudioSample = UInt16 +```swift +typealias AudioSample = UInt16 +``` 定义了一个类型别名之后,你可以在任何使用原始名的地方使用别名: - var maxAmplitudeFound = AudioSample.min - // maxAmplitudeFound 现在是 0 +```swift +var maxAmplitudeFound = AudioSample.min +// maxAmplitudeFound 现在是 0 +``` 本例中,`AudioSample`被定义为`UInt16`的一个别名。因为它是别名,`AudioSample.min`实际上是`UInt16.min`,所以会给`maxAmplitudeFound`赋一个初值`0`。 @@ -352,35 +397,43 @@ _类型别名(type aliases)_就是给现有类型定义另一个名字。你 Swift 有一个基本的_布尔(Boolean)_类型,叫做`Bool`。布尔值指_逻辑上的(logical)_,因为它们只能是真或者假。Swift 有两个布尔常量,`true`和`false`: - let orangesAreOrange = true - let turnipsAreDelicious = false +```swift +let orangesAreOrange = true +let turnipsAreDelicious = false +``` `orangesAreOrange`和`turnipsAreDelicious`的类型会被推测为`Bool`,因为它们的初值是布尔字面量。就像之前提到的`Int`和`Double`一样,如果你创建变量的时候给它们赋值`true`或者`false`,那你不需要将常量或者变量声明为`Bool`类型。初始化常量或者变量的时候如果所赋的值类型已知,就可以触发类型推测,这让 Swift 代码更加简洁并且可读性更高。 当你编写条件语句比如`if`语句的时候,布尔值非常有用: - if turnipsAreDelicious { - println("Mmm, tasty turnips!") - } else { - println("Eww, turnips are horrible.") - } - // 输出 "Eww, turnips are horrible." +```swift +if turnipsAreDelicious { + println("Mmm, tasty turnips!") +} else { + println("Eww, turnips are horrible.") +} +// 输出 "Eww, turnips are horrible." +``` 条件语句,例如`if`,请参考[控制流](05_Control_Flow.html)。 如果你在需要使用`Bool`类型的地方使用了非布尔值,Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误: - let i = 1 - if i { - // 这个例子不会通过编译,会报错 - } +```swift +let i = 1 +if i { + // 这个例子不会通过编译,会报错 +} +``` 然而,下面的例子是合法的: - let i = 1 - if i == 1 { - // 这个例子会编译成功 - } +```swift +let i = 1 +if i == 1 { + // 这个例子会编译成功 +} +``` `i == 1`的比较结果是`Bool`类型,所以第二个例子可以通过类型检查。类似`i == 1`这样的比较,请参考[基本操作符](05_Control_Flow.html)。 @@ -393,8 +446,10 @@ _元组(tuples)_把多个值组合成一个复合值。元组内的值可以 下面这个例子中,`(404, "Not Found")`是一个描述 _HTTP 状态码(HTTP status code)_的元组。HTTP 状态码是当你请求网页的时候 web 服务器返回的一个特殊值。如果你请求的网页不存在就会返回一个`404 Not Found`状态码。 - let http404Error = (404, "Not Found") - // http404Error 的类型是 (Int, String),值是 (404, "Not Found") +```swift +let http404Error = (404, "Not Found") +// http404Error 的类型是 (Int, String),值是 (404, "Not Found") +``` `(404, "Not Found")`元组把一个`Int`值和一个`String`值组合起来表示 HTTP 状态码的两个部分:一个数字和一个人类可读的描述。这个元组可以被描述为“一个类型为`(Int, String)`的元组”。 @@ -402,40 +457,49 @@ _元组(tuples)_把多个值组合成一个复合值。元组内的值可以 你可以将一个元组的内容_分解(decompose)_成单独的常量和变量,然后你就可以正常使用它们了: - let (statusCode, statusMessage) = http404Error - println("The status code is \(statusCode)") - // 输出 "The status code is 404" - println("The status message is \(statusMessage)") - // 输出 "The status message is Not Found" +```swift +let (statusCode, statusMessage) = http404Error +println("The status code is \(statusCode)") +// 输出 "The status code is 404" +println("The status message is \(statusMessage)") +// 输出 "The status message is Not Found" +``` 如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线(`_`)标记: - let (justTheStatusCode, _) = http404Error - println("The status code is \(justTheStatusCode)") - // 输出 "The status code is 404" +```swift +let (justTheStatusCode, _) = http404Error +println("The status code is \(justTheStatusCode)") +// 输出 "The status code is 404" +``` 此外,你还可以通过下标来访问元组中的单个元素,下标从零开始: - println("The status code is \(http404Error.0)") - // 输出 "The status code is 404" - println("The status message is \(http404Error.1)") - // 输出 "The status message is Not Found" +```swift +println("The status code is \(http404Error.0)") +// 输出 "The status code is 404" +println("The status message is \(http404Error.1)") +// 输出 "The status message is Not Found" +``` 你可以在定义元组的时候给单个元素命名: - let http200Status = (statusCode: 200, description: "OK") +```swift +let http200Status = (statusCode: 200, description: "OK") +``` 给元组中的元素命名后,你可以通过名字来获取这些元素的值: - println("The status code is \(http200Status.statusCode)") - // 输出 "The status code is 200" - println("The status message is \(http200Status.description)") - // 输出 "The status message is OK" +```swift +println("The status code is \(http200Status.statusCode)") +// 输出 "The status code is 200" +println("The status message is \(http200Status.description)") +// 输出 "The status message is OK" +``` 作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个`(Int, String)`元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考[函数参数与返回值](06_Functions.html#Function_Parameters_and_Return_Values)。 -> 注意: -> +> 注意: 元组在临时组织值的时候很有用,但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用,请使用类或者结构体而不是元组。请参考[类和结构体](09_Classes_and_Structures.html)。 @@ -449,17 +513,18 @@ _元组(tuples)_把多个值组合成一个复合值。元组内的值可以 * _没有_值 -> 注意: -> +> 注意: C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回`nil`,`nil`表示“缺少一个合法的对象”。然而,这只对对象起作用——对于结构体,基本的 C 类型或者枚举类型不起作用。对于这些类型,Objective-C 方法一般会返回一个特殊值(比如`NSNotFound`)来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而,Swift 的可选可以让你暗示_任意类型_的值缺失,并不需要一个特殊值。 来看一个例子。Swift 的`String`类型有一个叫做`toInt`的方法,作用是将一个`String`值转换成一个`Int`值。然而,并不是所有的字符串都可以转换成一个整数。字符串`"123"`可以被转换成数字`123`,但是字符串`"hello, world"`不行。 下面的例子使用`toInt`方法来尝试将一个`String`转换成`Int`: - let possibleNumber = "123" - let convertedNumber = possibleNumber.toInt() - // convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int" +```swift +let possibleNumber = "123" +let convertedNumber = possibleNumber.toInt() +// convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int" +``` 因为`toInt`方法可能会失败,所以它返回一个_可选的(optional)_`Int`,而不是一个`Int`。一个可选的`Int`被写作`Int?`而不是`Int`。问号暗示包含的值是可选,也就是说可能包含`Int`值也可能不包含值。(不能包含其他任何值比如`Bool`值或者`String`值。只能是`Int`或者什么都没有。) @@ -469,17 +534,18 @@ C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C 当你确定可选_确实_包含值之后,你可以在可选的名字后面加一个感叹号(`!`)来获取值。这个惊叹号表示“我知道这个可选有值,请使用它。”这被称为可选值的_强制解析(forced unwrapping)_: - if convertedNumber { - println("\(possibleNumber) has an integer value of \(convertedNumber!)") - } else { - println("\(possibleNumber) could not be converted to an integer") - } - // 输出 "123 has an integer value of 123" +```swift +if convertedNumber { + println("\(possibleNumber) has an integer value of \(convertedNumber!)") +} else { + println("\(possibleNumber) could not be converted to an integer") +} +// 输出 "123 has an integer value of 123" +``` 更多关于`if`语句的内容,请参考[控制流](05_Control_Flow.html)。 -> 注意: -> +> 注意: 使用`!`来获取一个不存在的可选值会导致运行时错误。使用`!`来强制解析值之前,一定要确定可选包含一个非`nil`的值。 @@ -489,18 +555,22 @@ C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C 像下面这样在`if`语句中写一个可选绑定: - if let constantName = someOptional { - statements - } +```swift +if let constantName = someOptional { + statements +} +``` 你可以像上面这样使用可选绑定来重写`possibleNumber`这个例子: - if let actualNumber = possibleNumber.toInt() { - println("\(possibleNumber) has an integer value of \(actualNumber)") - } else { - println("\(possibleNumber) could not be converted to an integer") - } - // 输出 "123 has an integer value of 123" +```swift +if let actualNumber = possibleNumber.toInt() { + println("\(possibleNumber) has an integer value of \(actualNumber)") +} else { + println("\(possibleNumber) could not be converted to an integer") +} +// 输出 "123 has an integer value of 123" +``` 这段代码可以被理解为: @@ -514,22 +584,24 @@ C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C 你可以给可选变量赋值为`nil`来表示它没有值: - var serverResponseCode: Int? = 404 - // serverResponseCode 包含一个可选的 Int 值 404 - serverResponseCode = nil - // serverResponseCode 现在不包含值 +```swift +var serverResponseCode: Int? = 404 +// serverResponseCode 包含一个可选的 Int 值 404 +serverResponseCode = nil +// serverResponseCode 现在不包含值 +``` -> 注意: -> +> 注意: `nil`不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况,请把它们声明成对应的可选类型。 如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为`nil`: - var surveyAnswer: String? - // surveyAnswer 被自动设置为 nil +```swift +var surveyAnswer: String? +// surveyAnswer 被自动设置为 nil +``` -> 注意: -> +> 注意: Swift 的`nil`和 Objective-C 中的`nil`并不一样。在 Objective-C 中,`nil`是一个指向不存在对象的指针。在 Swift 中,`nil`不是指针——它是一个确定的值,用来表示值缺失。_任何_类型的可选都可以被设置为`nil`,不只是对象类型。 ### 隐式解析可选 @@ -544,36 +616,42 @@ Swift 的`nil`和 Objective-C 中的`nil`并不一样。在 Objective-C 中,`n 一个隐式解析可选其实就是一个普通的可选,但是可以被当做非可选来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选`String`和隐式解析可选`String`之间的区别: - let possibleString: String? = "An optional string." - println(possibleString!) // 需要惊叹号来获取值 - // 输出 "An optional string." +```swift +let possibleString: String? = "An optional string." +println(possibleString!) // 需要惊叹号来获取值 +// 输出 "An optional string." +``` - let assumedString: String! = "An implicitly unwrapped optional string." - println(assumedString) // 不需要感叹号 - // 输出 "An implicitly unwrapped optional string." +```swift +let assumedString: String! = "An implicitly unwrapped optional string." +println(assumedString) // 不需要感叹号 +// 输出 "An implicitly unwrapped optional string." +``` 你可以把隐式解析可选当做一个可以自动解析的可选。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。 -> 注意: -> +> 注意: 如果你在隐式解析可选没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选后面加一个惊叹号一样。 你仍然可以把隐式解析可选当做普通可选来判断它是否包含值: - if assumedString { - println(assumedString) - } - // 输出 "An implicitly unwrapped optional string." +```swift +if assumedString { + println(assumedString) +} +// 输出 "An implicitly unwrapped optional string." +``` 你也可以在可选绑定中使用隐式解析可选来检查并解析它的值: - if let definiteString = assumedString { - println(definiteString) - } - // 输出 "An implicitly unwrapped optional string." +```swift +if let definiteString = assumedString { + println(definiteString) +} +// 输出 "An implicitly unwrapped optional string." +``` -> 注意: -> +> 注意: 如果一个变量之后可能变成`nil`的话请不要使用隐式解析可选。如果你需要在变量的生命周期中判断是否是`nil`的话,请使用普通可选类型。 @@ -589,15 +667,19 @@ Swift 的`nil`和 Objective-C 中的`nil`并不一样。在 Objective-C 中,`n 你可以使用全局`assert`函数来写一个断言。向`assert`函数传入一个结果为`true`或者`false`的表达式以及一条信息,当表达式为`false`的时候这条信息会被显示: - let age = -3 - assert(age >= 0, "A person's age cannot be less than zero") - // 因为 age < 0,所以断言会触发 +```swift +let age = -3 +assert(age >= 0, "A person's age cannot be less than zero") +// 因为 age < 0,所以断言会触发 +``` 在这个例子中,只有`age >= 0`为`true`的时候代码运行才会继续,也就是说,当`age`的值非负的时候。如果`age`的值是负数,就像代码中那样,`age >= 0`为`false`,断言被触发,结束应用。 断言信息不能使用字符串插值。断言信息可以省略,就像这样: - assert(age >= 0) +```swift +assert(age >= 0) +``` ### 何时使用断言 @@ -609,6 +691,6 @@ Swift 的`nil`和 Objective-C 中的`nil`并不一样。在 Objective-C 中,`n 请参考[附属脚本](12_Subscripts.html)和[函数](06_Functions.html)。 -> 注意: -> +> 注意: 断言可能导致你的应用终止运行,所以你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布之前,有时候非法条件可能出现,这时使用断言可以快速发现问题。 + From 19112e1cd2b3d185d7066cebc8582de3e9c8dbb6 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 16:18:40 +0800 Subject: [PATCH 07/24] fix 2.2 basic operators --- source/chapter2/02_Basic_Operators.md | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/source/chapter2/02_Basic_Operators.md b/source/chapter2/02_Basic_Operators.md index 63a99d96..bef7e11a 100644 --- a/source/chapter2/02_Basic_Operators.md +++ b/source/chapter2/02_Basic_Operators.md @@ -1,6 +1,5 @@ -> 翻译:xielingwang - -> 校对:Evilcome +> 翻译:xielingwang +> 校对:Evilcome # 基本运算符 ----------------- @@ -49,7 +48,7 @@ a = b 如果赋值的右边是一个多元组,它的元素可以马上被分解多个变量或变量: -``` +```swiflt let (x, y) = (1, 2) // 现在 x 等于 1, y 等于 2 ``` @@ -105,8 +104,7 @@ let dogCow = dog + cow 求余运算(`a % b`)是计算`b`的多少倍刚刚好可以容入`a`,返回多出来的那部分(余数)。 ->注意: -> +>注意: 求余运算(`%`)在其他语言也叫取模运算。然而严格说来,我们看该运算符对负数的操作结果,"求余"比"取模"更合适些。 我们来谈谈取余是怎么回事,计算`9 % 4`,你先计算出`4`的多少倍会刚好可以容入`9`中: @@ -230,8 +228,7 @@ a += 2 // a 现在是 3 表达式`a += 2`是`a = a + 2`的简写,一个加赋运算就把加法和赋值两件事完成了。 ->注意: -> +>注意: 复合赋值运算没有返回值,`let b = a += 2`这类代码是错误。这不同于上面提到的自增和自减运算符。 在[表达式](../chapter3/04_Expressions.html)章节里有复合运算符的完整列表。 @@ -248,8 +245,7 @@ a += 2 // a 现在是 3 - 大于等于(`a >= b`) - 小于等于(`a <= b`) -> 注意: -> +> 注意: Swift 也提供恒等`===`和不恒等`!==`这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在[类与结构](09_Classes_and_Structures.html)。 每个比较运算都返回了一个标识表达式是否成立的布尔值: @@ -286,10 +282,9 @@ if name == "world" { ```swift if question: { - answer1 -} -else { - answer2 + answer1 +} else { + answer2 } ``` @@ -332,7 +327,7 @@ Swift 提供了两个方便表达一个区间的值的运算符。 ```swift for index in 1...5 { - println("\(index) * 5 = \(index * 5)") + println("\(index) * 5 = \(index * 5)") } // 1 * 5 = 5 // 2 * 5 = 10 From a168d948221251879d60e2e9e982409485cddfe2 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 16:27:01 +0800 Subject: [PATCH 08/24] fix 2.3 Strings_and_Characters --- source/chapter2/03_Strings_and_Characters.md | 81 +++++++++----------- 1 file changed, 35 insertions(+), 46 deletions(-) diff --git a/source/chapter2/03_Strings_and_Characters.md b/source/chapter2/03_Strings_and_Characters.md index 0e3e5bdc..5e8f4178 100644 --- a/source/chapter2/03_Strings_and_Characters.md +++ b/source/chapter2/03_Strings_and_Characters.md @@ -1,6 +1,5 @@ -> 翻译:wh1100717 - -> 校对:Hawstein +> 翻译:wh1100717 +> 校对:Hawstein # 字符串和字符(Strings and Characters) ----------------- @@ -31,11 +30,9 @@ Swift 的`String`和`Character`类型提供了一个快速的,兼容 Unicode Swift 可以在常量、变量、字面量和表达式中进行字符串插值操作,可以轻松创建用于展示、存储和打印的自定义字符串。 -> 注意: -> +> 注意: Swift 的`String`类型与 Foundation `NSString`类进行了无缝桥接。如果您利用 Cocoa 或 Cocoa Touch 中的 Foundation 框架进行工作。所有`NSString` API 都可以调用您创建的任意`String`类型的值。除此之外,还可以使用本章介绍的`String`特性。您也可以在任意要求传入`NSString`实例作为参数的 API 中使用`String`类型的值作为替代。 -> ->更多关于在 Foundation 和 Cocoa 中使用`String`的信息请查看 [Using Swift with Cocoa and Objective-C](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216)。 +>更多关于在 Foundation 和 Cocoa 中使用`String`的信息请查看 [Using Swift with Cocoa and Objective-C](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/index.html#//apple_ref/doc/uid/TP40014216)。 ## 字符串字面量(String Literals) @@ -45,12 +42,11 @@ Swift 的`String`类型与 Foundation `NSString`类进行了无缝桥接。如 字符串字面量可以用于为常量和变量提供初始值。 -``` +```swift let someString = "Some string literal value" ``` -> 注意: -> +> 注意: `someString`变量通过字符串字面量进行初始化,Swift 因此推断该变量为`String`类型。 字符串字面量可以包含以下特殊字符: @@ -64,12 +60,12 @@ let someString = "Some string literal value" `wiseWords`常量包含了两个转移特殊字符 (双括号); `dollarSign`、`blackHeart`和`sparklingHeart`常量演示了三种不同格式的 Unicode 标量: -``` +```swift let wiseWords = "\"我是要成为海贼王的男人\" - 路飞" // "我是要成为海贼王的男人" - 路飞 -let dollarSign = "\x24" // $, Unicode 标量 U+0024 -let blackHeart = "\u2665" // ♥, Unicode 标量 U+2665 -let sparklingHeart = "\U0001F496" // 💖, Unicode 标量 U+1F496 +let dollarSign = "\x24" // $, Unicode 标量 U+0024 +let blackHeart = "\u2665" // ♥, Unicode 标量 U+2665 +let sparklingHeart = "\U0001F496" // 💖, Unicode 标量 U+1F496 ``` @@ -78,7 +74,7 @@ let sparklingHeart = "\U0001F496" // 💖, Unicode 标量 U+1F496 为了构造一个很长的字符串,可以创建一个空字符串作为初始值。 可以将空的字符串字面量赋值给变量,也可以初始化一个新的`String`实例: -``` +```swift var emptyString = "" // 空字符串字面量 var anotherEmptyString = String() // 初始化 String 实例 // 两个字符串均为空并等价。 @@ -86,7 +82,7 @@ var anotherEmptyString = String() // 初始化 String 实例 您可以通过检查其`Boolean`类型的`isEmpty`属性来判断该字符串是否为空: -``` +```swift if emptyString.isEmpty { println("什么都没有") } @@ -98,7 +94,7 @@ if emptyString.isEmpty { 您可以通过将一个特定字符串分配给一个变量来对其进行修改,或者分配给一个常量来保证其不会被修改: -``` +```swift var variableString = "Horse" variableString += " and carriage" // variableString 现在为 "Horse and carriage" @@ -107,8 +103,7 @@ constantString += " and another Highlander" // 这会报告一个编译错误 (compile-time error) - 常量不可以被修改。 ``` -> 注意: -> +> 注意: 在 Objective-C 和 Cocoa 中,您通过选择两个不同的类(`NSString`和`NSMutableString`)来指定该字符串是否可以被修改,Swift 中的字符串是否可以修改仅通过定义的是变量还是常量来决定,实现了多种类型可变性操作的统一。 @@ -119,8 +114,7 @@ Swift 的`String`类型是值类型。 任何情况下,都会对已有字符串值创建新副本,并对该新副本进行传递或赋值操作。 值类型在 [结构体和枚举是值类型](09_Classes_and_Structures.html#structures_and_enumerations_are_value_types) 中进行了说明。 -> 注意: -> +> 注意: 与 Cocoa 中的`NSString`不同,当您在 Cocoa 中创建了一个`NSString`实例,并将其传递给一个函数/方法,或者赋值给一个变量,您传递或赋值的是该`NSString`实例的一个引用,除非您特别要求进行值拷贝,否则字符串不会生成新的副本来进行赋值操作。 Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字符串的值。 @@ -136,7 +130,7 @@ Swift 的`String`类型表示特定序列的`Character`(字符) 类型值的 每一个字符值代表一个 Unicode 字符。 您可利用`for-in`循环来遍历字符串中的每一个字符: -``` +```swift for character in "Dog!🐶" { println(character) } @@ -151,7 +145,7 @@ for-in 循环在 [For Loops](05_Control_Flow.html#for_loops) 中进行了详细 另外,通过标明一个`Character`类型注解并通过字符字面量进行赋值,可以建立一个独立的字符常量或变量: -``` +```swift let yenSign: Character = "¥" ``` @@ -160,24 +154,22 @@ let yenSign: Character = "¥" 通过调用全局`countElements`函数,并将字符串作为参数进行传递,可以获取该字符串的字符数量。 -``` +```swift let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪" println("unusualMenagerie has \(countElements(unusualMenagerie)) characters") // 打印输出:"unusualMenagerie has 40 characters" ``` -> 注意: -> +> 注意: 不同的 Unicode 字符以及相同 Unicode 字符的不同表示方式可能需要不同数量的内存空间来存储。所以 Swift 中的字符在一个字符串中并不一定占用相同的内存空间。因此字符串的长度不得不通过迭代字符串中每一个字符的长度来进行计算。如果您正在处理一个长字符串,需要注意`countElements`函数必须遍历字符串中的字符以精准计算字符串的长度。 -> -> 另外需要注意的是通过`countElements`返回的字符数量并不总是与包含相同字符的`NSString`的`length`属性相同。`NSString`的`length`属性是基于利用 UTF-16 表示的十六位代码单元数字,而不是基于 Unicode 字符。为了解决这个问题,`NSString`的`length`属性在被 Swift 的`String`访问时会成为`utf16count`。 +> 另外需要注意的是通过`countElements`返回的字符数量并不总是与包含相同字符的`NSString`的`length`属性相同。`NSString`的`length`属性是基于利用 UTF-16 表示的十六位代码单元数字,而不是基于 Unicode 字符。为了解决这个问题,`NSString`的`length`属性在被 Swift 的`String`访问时会成为`utf16count`。 ## 连接字符串和字符 (Concatenating Strings and Characters) 字符串和字符的值可以通过加法运算符(`+`)相加在一起并创建一个新的字符串值: -``` +```swift let string1 = "hello" let string2 = " there" let character1: Character = "!" @@ -191,7 +183,7 @@ let characterPlusCharacter = character1 + character2 // 等于 "!?" 您也可以通过加法赋值运算符 (`+=`) 将一个字符串或者字符添加到一个已经存在字符串变量上: -``` +```swift var instruction = "look over" instruction += string2 // instruction 现在等于 "look over there" @@ -201,8 +193,7 @@ welcome += character1 // welcome 现在等于 "good morning!" ``` -> 注意: -> +> 注意: 您不能将一个字符串或者字符添加到一个已经存在的字符变量上,因为字符变量只能包含一个字符。 @@ -211,7 +202,7 @@ welcome += character1 字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。 您插入的字符串字面量的每一项都被包裹在以反斜线为前缀的圆括号中: -``` +```swift let multiplier = 3 let message = "\(multiplier) 乘以 2.5 是 \(Double(multiplier) * 2.5)" // message 是 "3 乘以 2.5 是 7.5" @@ -224,8 +215,7 @@ let message = "\(multiplier) 乘以 2.5 是 \(Double(multiplier) * 2.5)" 该表达式计算`Double(multiplier) * 2.5`的值并将结果 (7.5) 插入到字符串中。 在这个例子中,表达式写为`\(Double(multiplier) * 2.5)`并包含在字符串字面量中。 -> 注意: -> +> 注意: 插值字符串中写在括号中的表达式不能包含非转义双引号 (`"`) 和反斜杠 (`\`),并且不能包含回车或换行符。 @@ -238,7 +228,7 @@ Swift 提供了三种方式来比较字符串的值:字符串相等、前缀 如果两个字符串以同一顺序包含完全相同的字符,则认为两者字符串相等: -``` +```swift let quotation = "我们是一样一样滴." let sameQuotation = "我们是一样一样滴." if quotation == sameQuotation { @@ -256,7 +246,7 @@ if quotation == sameQuotation { 下面的例子以一个字符串数组表示莎士比亚话剧《罗密欧与朱丽叶》中前两场的场景位置: -``` +```swift let romeoAndJuliet = [ "Act 1 Scene 1: Verona, A public place", "Act 1 Scene 2: Capulet's mansion", @@ -274,7 +264,7 @@ let romeoAndJuliet = [ 您可以利用`hasPrefix`方法来计算话剧中第一幕的场景数: -``` +```swift var act1SceneCount = 0 for scene in romeoAndJuliet { if scene.hasPrefix("Act 1 ") { @@ -287,7 +277,7 @@ println("There are \(act1SceneCount) scenes in Act 1") 相似地,您可以用`hasSuffix`方法来计算发生在不同地方的场景数: -``` +```swift var mansionCount = 0 var cellCount = 0 for scene in romeoAndJuliet { @@ -306,7 +296,7 @@ println("\(mansionCount) mansion scenes; \(cellCount) cell scenes") 您可以通过字符串的`uppercaseString`和`lowercaseString`属性来访问大写/小写版本的字符串。 -``` +```swift let normal = "Could you help me, please?" let shouty = normal.uppercaseString // shouty 值为 "COULD YOU HELP ME, PLEASE?" @@ -346,7 +336,7 @@ Swift 提供了几种不同的方式来访问字符串的 Unicode 表示。 下面由`D``o``g``!`和`🐶`(`DOG FACE`,Unicode 标量为`U+1F436`)组成的字符串中的每一个字符代表着一种不同的表示: -``` +```swift let dogString = "Dog!🐶" ``` @@ -356,7 +346,7 @@ let dogString = "Dog!🐶" 您可以通过遍历字符串的`utf8`属性来访问它的`UTF-8`表示。 其为`UTF8View`类型的属性,`UTF8View`是无符号8位 (`UInt8`) 值的集合,每一个`UInt8`值都是一个字符的 UTF-8 表示: -``` +```swift for codeUnit in dogString.utf8 { print("\(codeUnit) ") } @@ -373,7 +363,7 @@ print("\n") 您可以通过遍历字符串的`utf16`属性来访问它的`UTF-16`表示。 其为`UTF16View`类型的属性,`UTF16View`是无符号16位 (`UInt16`) 值的集合,每一个`UInt16`都是一个字符的 UTF-16 表示: -``` +```swift for codeUnit in dogString.utf16 { print("\(codeUnit) ") } @@ -395,7 +385,7 @@ print("\n") 每一个`UnicodeScalar`拥有一个值属性,可以返回对应的21位数值,用`UInt32`来表示。 -``` +```swift for scalar in dogString.unicodeScalars { print("\(scalar.value) ") } @@ -409,7 +399,7 @@ print("\n") 作为查询字符值属性的一种替代方法,每个`UnicodeScalar`值也可以用来构建一个新的字符串值,比如在字符串插值中使用: -``` +```swift for scalar in dogString.unicodeScalars { println("\(scalar) ") } @@ -419,4 +409,3 @@ for scalar in dogString.unicodeScalars { // ! // 🐶 ``` - From 57b4b6475ace4c6d01e4fd0deddb147296e4b9f5 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 16:34:13 +0800 Subject: [PATCH 09/24] fix 2.4 Collection_Types --- source/chapter2/04_Collection_Types.md | 353 +++++++++++++++---------- 1 file changed, 211 insertions(+), 142 deletions(-) diff --git a/source/chapter2/04_Collection_Types.md b/source/chapter2/04_Collection_Types.md index 76ab248d..59f1c24e 100644 --- a/source/chapter2/04_Collection_Types.md +++ b/source/chapter2/04_Collection_Types.md @@ -1,6 +1,5 @@ -> 翻译:zqp - -> 校对:shinyzhu +> 翻译:zqp +> 校对:shinyzhu # 集合类型 (Collection Types) ----------------- @@ -15,8 +14,7 @@ Swift 语言提供经典的数组和字典两种集合类型来存储集合数 Swift 语言里的数组和字典中存储的数据值类型必须明确。 这意味着我们不能把不正确的数据类型插入其中。 同时这也说明我们完全可以对获取出的值类型非常自信。 Swift 对显式类型集合的使用确保了我们的代码对工作所需要的类型非常清楚,也让我们在开发中可以早早地找到任何的类型不匹配错误。 -> 注意: -> +> 注意: Swift 的数组结构在被声明成常量和变量或者被传入函数与方法中时会相对于其他类型展现出不同的特性。 获取更多信息请参见[集合的可变性](#mutability_of_collections)与[集合在赋值和复制中的行为](09_Classes_and_Structures.html#assignment_and_copy_behavior_for_collection_types)章节。 @@ -39,20 +37,23 @@ Swift 数组对存储数据有具体要求。 不同于 Objective-C 的`NSArray` 下面这个例子创建了一个叫做`shoppingList`并且存储字符串的数组: - var shoppingList: String[] = ["Eggs", "Milk"] - // shoppingList 已经被构造并且拥有两个初始项。 +```swift +var shoppingList: String[] = ["Eggs", "Milk"] +// shoppingList 已经被构造并且拥有两个初始项。 +``` `shoppingList`变量被声明为“字符串值类型的数组“,记作`String[]`。 因为这个数组被规定只有`String`一种数据结构,所以只有`String`类型可以在其中被存取。 在这里,`shoppinglist`数组由两个`String`值(`"Eggs"` 和`"Milk"`)构造,并且由字面语句定义。 -> 注意: -> -> `Shoppinglist`数组被声明为变量(`var`关键字创建)而不是常量(`let`创建)是因为以后可能会有更多的数据项被插入其中。 +> 注意: +> `Shoppinglist`数组被声明为变量(`var`关键字创建)而不是常量(`let`创建)是因为以后可能会有更多的数据项被插入其中。 在这个例子中,字面语句仅仅包含两个`String`值。匹配了该数组的变量声明(只能包含`String`的数组),所以这个字面语句的分配过程就是允许用两个初始项来构造`shoppinglist`。 由于 Swift 的类型推断机制,当我们用字面语句构造只拥有相同类型值数组的时候,我们不必把数组的类型定义清楚。 `shoppinglist`的构造也可以这样写: - var shoppingList = ["Eggs", "Milk"] +```swift +var shoppingList = ["Eggs", "Milk"] +``` 因为所有字面语句中的值都是相同的类型,Swift 可以推断出`String[]`是`shoppinglist`中变量的正确类型。 @@ -62,105 +63,132 @@ Swift 数组对存储数据有具体要求。 不同于 Objective-C 的`NSArray` 我们可以通过数组的方法和属性来访问和修改数组,或者下标语法。 还可以使用数组的只读属性`count`来获取数组中的数据项数量。 - println("The shopping list contains \(shoppingList.count) items.") - // 输出"The shopping list contains 2 items."(这个数组有2个项) +```swift +println("The shopping list contains \(shoppingList.count) items.") +// 输出"The shopping list contains 2 items."(这个数组有2个项) +``` 使用布尔项`isEmpty`来作为检查`count`属性的值是否为 0 的捷径。 - if shoppingList.isEmpty { - println("The shopping list is empty.") - } else { - println("The shopping list is not empty.") - } - // 打印 "The shopping list is not empty."(shoppinglist不是空的) +```swift +if shoppingList.isEmpty { + println("The shopping list is empty.") +} else { + println("The shopping list is not empty.") +} +// 打印 "The shopping list is not empty."(shoppinglist不是空的) +``` 也可以使用`append`方法在数组后面添加新的数据项: - shoppingList.append("Flour") - // shoppingList 现在有3个数据项,有人在摊煎饼 +```swift +shoppingList.append("Flour") +// shoppingList 现在有3个数据项,有人在摊煎饼 +``` 除此之外,使用加法赋值运算符(`+=`)也可以直接在数组后面添加数据项: - shoppingList += "Baking Powder" - // shoppingList 现在有四项了 +```swift +shoppingList += "Baking Powder" +// shoppingList 现在有四项了 +``` 我们也可以使用加法赋值运算符(`+=`)直接添加拥有相同类型数据的数组。 - shoppingList += ["Chocolate Spread", "Cheese", "Butter"] - // shoppingList 现在有7项了 +```swift +shoppingList += ["Chocolate Spread", "Cheese", "Butter"] +// shoppingList 现在有7项了 +``` 可以直接使用下标语法来获取数组中的数据项,把我们需要的数据项的索引值放在直接放在数组名称的方括号中: - var firstItem = shoppingList[0] - // 第一项是 "Eggs" +```swift +var firstItem = shoppingList[0] +// 第一项是 "Eggs" +``` 注意第一项在数组中的索引值是`0`而不是`1`。 Swift 中的数组索引总是从零开始。 我们也可以用下标来改变某个已有索引值对应的数据值: - shoppingList[0] = "Six eggs" - // 其中的第一项现在是 "Six eggs" 而不是 "Eggs" +```swift +shoppingList[0] = "Six eggs" +// 其中的第一项现在是 "Six eggs" 而不是 "Eggs" +``` 还可以利用下标来一次改变一系列数据值,即使新数据和原有数据的数量是不一样的。下面的例子把`"Chocolate Spread"`,`"Cheese"`,和`"Butter"`替换为`"Bananas"`和 `"Apples"`: - shoppingList[4...6] = ["Bananas", "Apples"] - // shoppingList 现在有六项 +```swift +shoppingList[4...6] = ["Bananas", "Apples"] +// shoppingList 现在有六项 +``` -> 注意: -> ->我们不能使用下标语法在数组尾部添加新项。如果我们试着用这种方法对索引越界的数据进行检索或者设置新值的操作,我们会引发一个运行期错误。我们可以使用索引值和数组的`count`属性进行比较来在使用某个索引之前先检验是否有效。除了当`count`等于 0 时(说明这是个空数组),最大索引值一直是`count - 1`,因为数组都是零起索引。 +> 注意: +>我们不能使用下标语法在数组尾部添加新项。如果我们试着用这种方法对索引越界的数据进行检索或者设置新值的操作,我们会引发一个运行期错误。我们可以使用索引值和数组的`count`属性进行比较来在使用某个索引之前先检验是否有效。除了当`count`等于 0 时(说明这是个空数组),最大索引值一直是`count - 1`,因为数组都是零起索引。 调用数组的`insert(atIndex:)`方法来在某个具体索引值之前添加数据项: - shoppingList.insert("Maple Syrup", atIndex: 0) - // shoppingList 现在有7项 - // "Maple Syrup" 现在是这个列表中的第一项 +```swift +shoppingList.insert("Maple Syrup", atIndex: 0) +// shoppingList 现在有7项 +// "Maple Syrup" 现在是这个列表中的第一项 +``` 这次`insert`函数调用把值为`"Maple Syrup"`的新数据项插入列表的最开始位置,并且使用`0`作为索引值。 类似的我们可以使用`removeAtIndex`方法来移除数组中的某一项。这个方法把数组在特定索引值中存储的数据项移除并且返回这个被移除的数据项(我们不需要的时候就可以无视它): - let mapleSyrup = shoppingList.removeAtIndex(0) - //索引值为0的数据项被移除 - // shoppingList 现在只有6项,而且不包括Maple Syrup - // mapleSyrup常量的值等于被移除数据项的值 "Maple Syrup" +```swift +let mapleSyrup = shoppingList.removeAtIndex(0) +// 索引值为0的数据项被移除 +// shoppingList 现在只有6项,而且不包括Maple Syrup +// mapleSyrup常量的值等于被移除数据项的值 "Maple Syrup" +``` 数据项被移除后数组中的空出项会被自动填补,所以现在索引值为`0`的数据项的值再次等于`"Six eggs"`: - firstItem = shoppingList[0] - // firstItem 现在等于 "Six eggs" +```swift +firstItem = shoppingList[0] +// firstItem 现在等于 "Six eggs" +``` 如果我们只想把数组中的最后一项移除,可以使用`removeLast`方法而不是`removeAtIndex`方法来避免我们需要获取数组的`count`属性。就像后者一样,前者也会返回被移除的数据项: - let apples = shoppingList.removeLast() - // 数组的最后一项被移除了 - // shoppingList现在只有5项,不包括cheese - // apples 常量的值现在等于"Apples" 字符串 +```swift +let apples = shoppingList.removeLast() +// 数组的最后一项被移除了 +// shoppingList现在只有5项,不包括cheese +// apples 常量的值现在等于"Apples" 字符串 +``` ### 数组的遍历 我们可以使用`for-in`循环来遍历所有数组中的数据项: - for item in shoppingList { - println(item) - } - // Six eggs - // Milk - // Flour - // Baking Powder - // Bananas +```swift +for item in shoppingList { + println(item) +} +// Six eggs +// Milk +// Flour +// Baking Powder +// Bananas +``` 如果我们同时需要每个数据项的值和索引值,可以使用全局`enumerate`函数来进行数组遍历。`enumerate`返回一个由每一个数据项索引值和数据值组成的键值对组。我们可以把这个键值对组分解成临时常量或者变量来进行遍历: - for (index, value) in enumerate(shoppingList) { - println("Item \(index + 1): \(value)") - } - // Item 1: Six eggs - // Item 2: Milk - // Item 3: Flour - // Item 4: Baking Powder - // Item 5: Bananas +```swift +for (index, value) in enumerate(shoppingList) { + println("Item \(index + 1): \(value)") +} +// Item 1: Six eggs +// Item 2: Milk +// Item 3: Flour +// Item 4: Baking Powder +// Item 5: Bananas +``` 更多关于`for-in`循环的介绍请参见[for 循环](05_Control_Flow.html#for_loops)。 @@ -169,33 +197,43 @@ Swift 数组对存储数据有具体要求。 不同于 Objective-C 的`NSArray` 我们可以使用构造语法来创建一个由特定数据类型构成的空数组: - var someInts = Int[]() - println("someInts is of type Int[] with \(someInts.count) items。") - // 打印 "someInts is of type Int[] with 0 items。"(someInts是0数据项的Int[]数组) +```swift +var someInts = Int[]() +println("someInts is of type Int[] with \(someInts.count) items。") +// 打印 "someInts is of type Int[] with 0 items。"(someInts是0数据项的Int[]数组) +``` 注意`someInts`被设置为一个`Int[]`构造函数的输出所以它的变量类型被定义为`Int[]`。 除此之外,如果代码上下文中提供了类型信息, 例如一个函数参数或者一个已经定义好类型的常量或者变量,我们可以使用空数组语句创建一个空数组,它的写法很简单:`[]`(一对空方括号): - someInts.append(3) - // someInts 现在包含一个INT值 - someInts = [] - // someInts 现在是空数组,但是仍然是Int[]类型的。 +```swift +someInts.append(3) +// someInts 现在包含一个INT值 +someInts = [] +// someInts 现在是空数组,但是仍然是Int[]类型的。 +``` Swift 中的`Array`类型还提供一个可以创建特定大小并且所有数据都被默认的构造方法。我们可以把准备加入新数组的数据项数量(`count`)和适当类型的初始值(`repeatedValue`)传入数组构造函数: - var threeDoubles = Double[](count: 3, repeatedValue:0.0) - // threeDoubles 是一种 Double[]数组, 等于 [0.0, 0.0, 0.0] +```swift +var threeDoubles = Double[](count: 3, repeatedValue:0.0) +// threeDoubles 是一种 Double[]数组, 等于 [0.0, 0.0, 0.0] +``` 因为类型推断的存在,我们使用这种构造方法的时候不需要特别指定数组中存储的数据类型,因为类型可以从默认值推断出来: - var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5) - // anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5] +```swift +var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5) +// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5] +``` 最后,我们可以使用加法操作符(`+`)来组合两种已存在的相同类型数组。新数组的数据类型会被从两个数组的数据类型中推断出来: - var sixDoubles = threeDoubles + anotherThreeDoubles - // sixDoubles 被推断为 Double[], 等于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] +```swift +var sixDoubles = threeDoubles + anotherThreeDoubles +// sixDoubles 被推断为 Double[], 等于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] +``` ## 字典 @@ -215,17 +253,20 @@ Swift 的字典使用`Dictionary`定义,其中`KeyType`是 一个键值对是一个`key`和一个`value`的结合体。在字典字面语句中,每一个键值对的键和值都由冒号分割。这些键值对构成一个列表,其中这些键值对由方括号包含并且由逗号分割: - [key 1: value 1, key 2: value 2, key 3: value 3] +```swift +[key 1: value 1, key 2: value 2, key 3: value 3] +``` 下面的例子创建了一个存储国际机场名称的字典。在这个字典中键是三个字母的国际航空运输相关代码,值是机场名称: - var airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin"] +```swift +var airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin"] +``` `airports`字典被定义为一种`Dictionary`,它意味着这个字典的键和值都是`String`类型。 -> 注意: -> -> `airports`字典被声明为变量(用`var`关键字)而不是常量(`let`关键字)因为后来更多的机场信息会被添加到这个示例字典中。 +> 注意: +> `airports`字典被声明为变量(用`var`关键字)而不是常量(`let`关键字)因为后来更多的机场信息会被添加到这个示例字典中。 `airports`字典使用字典字面语句初始化,包含两个键值对。第一对的键是`TYO`,值是`Tokyo`。第二对的键是`DUB`,值是`Dublin`。 @@ -233,7 +274,9 @@ Swift 的字典使用`Dictionary`定义,其中`KeyType`是 和数组一样,如果我们使用字面语句构造字典就不用把类型定义清楚。`airports`的也可以用这种方法简短定义: - var airports = ["TYO": "Tokyo", "DUB": "Dublin"] +```swift +var airports = ["TYO": "Tokyo", "DUB": "Dublin"] +``` 因为这个语句中所有的键和值都分别是相同的数据类型,Swift 可以推断出`Dictionary`是`airports`字典的正确类型。 @@ -242,111 +285,137 @@ Swift 的字典使用`Dictionary`定义,其中`KeyType`是 我们可以通过字典的方法和属性来读取和修改字典,或者使用下标语法。和数组一样,我们可以通过字典的只读属性`count`来获取某个字典的数据项数量: - println("The dictionary of airports contains \(airports.count) items.") - // 打印 "The dictionary of airports contains 2 items."(这个字典有两个数据项) +```swift +println("The dictionary of airports contains \(airports.count) items.") +// 打印 "The dictionary of airports contains 2 items."(这个字典有两个数据项) +``` 我们也可以在字典中使用下标语法来添加新的数据项。可以使用一个合适类型的 key 作为下标索引,并且分配新的合适类型的值: - airports["LHR"] = "London" - // airports 字典现在有三个数据项 +```swift +airports["LHR"] = "London" +// airports 字典现在有三个数据项 +``` 我们也可以使用下标语法来改变特定键对应的值: - airports["LHR"] = "London Heathrow" - // "LHR"对应的值 被改为 "London Heathrow +```swift +airports["LHR"] = "London Heathrow" +// "LHR"对应的值 被改为 "London Heathrow +``` 作为另一种下标方法,字典的`updateValue(forKey:)`方法可以设置或者更新特定键对应的值。就像上面所示的示例,`updateValue(forKey:)`方法在这个键不存在对应值的时候设置值或者在存在时更新已存在的值。和上面的下标方法不一样,这个方法返回更新值之前的原值。这样方便我们检查更新是否成功。 `updateValue(forKey:)`函数会返回包含一个字典值类型的可选值。举例来说:对于存储`String`值的字典,这个函数会返回一个`String?`或者“可选 `String`”类型的值。如果值存在,则这个可选值值等于被替换的值,否则将会是`nil`。 - if let oldValue = airports.updateValue("Dublin Internation", forKey: "DUB") { - println("The old value for DUB was \(oldValue).") - } - // 输出 "The old value for DUB was Dublin."(DUB原值是dublin) +```swift +if let oldValue = airports.updateValue("Dublin Internation", forKey: "DUB") { + println("The old value for DUB was \(oldValue).") +} +// 输出 "The old value for DUB was Dublin."(DUB原值是dublin) +``` 我们也可以使用下标语法来在字典中检索特定键对应的值。由于使用一个没有值的键这种情况是有可能发生的,可选类型返回这个键存在的相关值,否则就返回`nil`: - if let airportName = airports["DUB"] { - println("The name of the airport is \(airportName).") - } else { - println("That airport is not in the airports dictionary.") - } - // 打印 "The name of the airport is Dublin Internation."(机场的名字是都柏林国际) +```swift +if let airportName = airports["DUB"] { + println("The name of the airport is \(airportName).") +} else { + println("That airport is not in the airports dictionary.") +} +// 打印 "The name of the airport is Dublin Internation."(机场的名字是都柏林国际) +``` 我们还可以使用下标语法来通过给某个键的对应值赋值为`nil`来从字典里移除一个键值对: - airports["APL"] = "Apple Internation" - // "Apple Internation"不是真的 APL机场, 删除它 - airports["APL"] = nil - // APL现在被移除了 +```swift +airports["APL"] = "Apple Internation" +// "Apple Internation"不是真的 APL机场, 删除它 +airports["APL"] = nil +// APL现在被移除了 +``` 另外,`removeValueForKey`方法也可以用来在字典中移除键值对。这个方法在键值对存在的情况下会移除该键值对并且返回被移除的value或者在没有值的情况下返回`nil`: - if let removedValue = airports.removeValueForKey("DUB") { - println("The removed airport's name is \(removedValue).") - } else { - println("The airports dictionary does not contain a value for DUB.") - } - // prints "The removed airport's name is Dublin International." +```swift +if let removedValue = airports.removeValueForKey("DUB") { + println("The removed airport's name is \(removedValue).") +} else { + println("The airports dictionary does not contain a value for DUB.") +} +// prints "The removed airport's name is Dublin International." +``` ### 字典遍历 我们可以使用`for-in`循环来遍历某个字典中的键值对。每一个字典中的数据项都由`(key, value)`元组形式返回,并且我们可以使用暂时性常量或者变量来分解这些元组: - for (airportCode, airportName) in airports { - println("\(airportCode): \(airportName)") - } - // TYO: Tokyo - // LHR: London Heathrow +```swift +for (airportCode, airportName) in airports { + println("\(airportCode): \(airportName)") +} +// TYO: Tokyo +// LHR: London Heathrow +``` `for-in`循环请参见[For 循环](05_Control_Flow.html#for_loops)。 我们也可以通过访问他的`keys`或者`values`属性(都是可遍历集合)检索一个字典的键或者值: - for airportCode in airports.keys { - println("Airport code: \(airportCode)") - } - // Airport code: TYO - // Airport code: LHR +```swift +for airportCode in airports.keys { + println("Airport code: \(airportCode)") +} +// Airport code: TYO +// Airport code: LHR +``` - for airportName in airports.values { - println("Airport name: \(airportName)") - } - // Airport name: Tokyo - // Airport name: London Heathrow +```swift +for airportName in airports.values { + println("Airport name: \(airportName)") +} +// Airport name: Tokyo +// Airport name: London Heathrow +``` 如果我们只是需要使用某个字典的键集合或者值集合来作为某个接受`Array`实例 API 的参数,可以直接使用`keys`或者`values`属性直接构造一个新数组: - let airportCodes = Array(airports.keys) - // airportCodes is ["TYO", "LHR"] +```swift +let airportCodes = Array(airports.keys) +// airportCodes is ["TYO", "LHR"] +``` - let airportNames = Array(airports.values) - // airportNames is ["Tokyo", "London Heathrow"] +```swift +let airportNames = Array(airports.values) +// airportNames is ["Tokyo", "London Heathrow"] +``` -> 注意: -> -> Swift 的字典类型是无序集合类型。其中字典键,值,键值对在遍历的时候会重新排列,而且其中顺序是不固定的。 +> 注意: +> Swift 的字典类型是无序集合类型。其中字典键,值,键值对在遍历的时候会重新排列,而且其中顺序是不固定的。 ### 创建一个空字典 我们可以像数组一样使用构造语法创建一个空字典: - var namesOfIntegers = Dictionary() - // namesOfIntegers 是一个空的 Dictionary +```swift +var namesOfIntegers = Dictionary() +// namesOfIntegers 是一个空的 Dictionary +``` 这个例子创建了一个`Int, String`类型的空字典来储存英语对整数的命名。它的键是`Int`型,值是`String`型。 如果上下文已经提供了信息类型,我们可以使用空字典字面语句来创建一个空字典,记作`[:]`(中括号中放一个冒号): - namesOfIntegers[16] = "sixteen" - // namesOfIntegers 现在包含一个键值对 - namesOfIntegers = [:] - // namesOfIntegers 又成为了一个 Int, String类型的空字典 +```swift +namesOfIntegers[16] = "sixteen" +// namesOfIntegers 现在包含一个键值对 +namesOfIntegers = [:] +// namesOfIntegers 又成为了一个 Int, String类型的空字典 +``` -> 注意: -> -> 在后台,Swift 的数组和字典都是由泛型集合来实现的,想了解更多泛型和集合信息请参见[泛型](22_Generics.html)。 +> 注意: +> 在后台,Swift 的数组和字典都是由泛型集合来实现的,想了解更多泛型和集合信息请参见[泛型](22_Generics.html)。 ## 集合的可变性 @@ -358,6 +427,6 @@ Swift 的字典使用`Dictionary`定义,其中`KeyType`是 Swift 数组的可变性行为同时影响了数组实例如何被分配和修改,想获取更多信息,请参见[集合在赋值和复制中的行为](09_Classes_and_Structures.html#assignment_and_copy_behavior_for_collection_types)。 -> 注意: -> -> 在我们不需要改变数组大小的时候创建不可变数组是很好的习惯。如此 Swift 编译器可以优化我们创建的集合。 +> 注意: +> 在我们不需要改变数组大小的时候创建不可变数组是很好的习惯。如此 Swift 编译器可以优化我们创建的集合。 + From a31e7908f7530c7541ea878b805c1546481c4bd3 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 16:50:46 +0800 Subject: [PATCH 10/24] fix 2.5 Control_Flow --- source/chapter2/05_Control_Flow.md | 109 ++++++++++++----------------- 1 file changed, 44 insertions(+), 65 deletions(-) diff --git a/source/chapter2/05_Control_Flow.md b/source/chapter2/05_Control_Flow.md index 82d3a5bb..6687b3f6 100644 --- a/source/chapter2/05_Control_Flow.md +++ b/source/chapter2/05_Control_Flow.md @@ -1,6 +1,5 @@ -> 翻译:vclwei, coverxit, NicePiao - -> 校对:coverxit +> 翻译:vclwei, coverxit, NicePiao +> 校对:coverxit, stanzhai # 控制流 ----------------- @@ -49,8 +48,7 @@ for index in 1...5 { 上面的例子中,`index`是一个每次循环遍历开始时被自动赋值的常量。这种情况下,`index`在使用前不需要声明,只需要将它包含在循环的声明中,就可以对其进行隐式声明,而无需使用`let`关键字声明。 ->注意: -> +>注意: `index`常量只存在于循环的生命周期里。如果你想在循环完成后访问`index`的值,又或者想让`index`成为一个变量而不是常量,你必须在循环之前自己进行声明。 如果你不需要知道区间内每一项的值,你可以使用下划线(`_`)替代变量名来忽略对值的访问: @@ -124,11 +122,9 @@ for var index = 0; index < 3; ++index { 下面是一般情况下这种循环方式的格式: -```swift -for `initialization`; `condition`; `increment` { - `statements` -} -``` +> for `initialization`; `condition`; `increment` { +> `statements` +> } 和 C 语言中一样,分号将循环的定义分为 3 个部分,不同的是,Swift 不需要使用圆括号将“initialization; condition; increment”包括起来。 @@ -141,13 +137,11 @@ for `initialization`; `condition`; `increment` { 上述描述和循环格式等同于: -```swift -`initialization` -while `condition` { - `statements` - `increment` -} -``` +> `initialization` +> while `condition` { +> `statements` +> `increment` +> } 在初始化表达式中声明的常量和变量(比如`var index = 0`)只在`for`循环的生命周期里有效。如果想在循环结束后访问`index`的值,你必须要在循环生命周期开始前声明`index`。 @@ -181,11 +175,9 @@ println("The loop statements were executed \(index) times") 下面是一般情况下 `while` 循环格式: -```swift -while `condition` { - `statements` -} -``` +> while `condition` { +> `statements` +> } 下面的例子来玩一个叫做_蛇和梯子(Snakes and Ladders)_的小游戏,也叫做_滑道和梯子(Chutes and Ladders)_: @@ -250,11 +242,9 @@ println("Game over!") 下面是一般情况下 `do-while`循环的格式: -```swift -do { - `statements` -} while `condition` -``` +> do { +> `statements` +> } while `condition` 还是蛇和梯子的游戏,使用`do-while`循环来替代`while`循环。`finalSquare`、`board`、`square`和`diceRoll`的值初始化同`while`循环一样: @@ -359,17 +349,15 @@ if temperatureInFahrenheit <= 32 { `switch`语句最简单的形式就是把某个值与一个或若干个相同类型的值作比较: -```swift -switch `some value to consider` { -case `value 1`: - `respond to value 1` -case `value 2`, -`value 3`: - `respond to value 2 or 3` -default: - `otherwise, do something else` -} -``` +> switch `some value to consider` { +> case `value 1`: +> `respond to value 1` +> case `value 2`, +> `value 3`: +> `respond to value 2 or 3` +> default: +> `otherwise, do something else` +> } `switch`语句都由*多个 case* 构成。为了匹配某些更特定的值,Swift 提供了几种更复杂的匹配模式,这些模式将在本节的稍后部分提到。 @@ -402,8 +390,7 @@ default: 与 C 语言和 Objective-C 中的`switch`语句不同,在 Swift 中,当匹配的 case 分支中的代码执行完毕后,程序会终止`switch`语句,而不会继续执行下一个 case 分支。这也就是说,不需要在 case 分支中显式地使用`break`语句。这使得`switch`语句更安全、更易用,也避免了因忘记写`break`语句而产生的错误。 -> 注意: -> +> 注意: 你依然可以在 case 分支中的代码执行完毕前跳出,详情请参考[Switch 语句中的 break](#break_in_a_switch_statement)。 每一个 case 分支都*必须*包含至少一条语句。像下面这样书写代码是无效的,因为第一个 case 分支是空的: @@ -424,15 +411,13 @@ default: 一个 case 也可以包含多个模式,用逗号把它们分开(如果太长了也可以分行写): -```swift -switch `some value to consider` { -case `value 1`, -`value 2`: - `statements` -} -``` +> switch `some value to consider` { +> case `value 1`, +> `value 2`: +> `statements` +> } -> 注意: +> 注意: 如果想要贯穿至特定的 case 分支中,请使用`fallthrough`语句,详情请参考[贯穿(Fallthrough)](#fallthrough)。 @@ -560,10 +545,10 @@ case let (x, y): 控制转移语句改变你代码的执行顺序,通过它你可以实现代码的跳转。Swift有四种控制转移语句。 -- continue -- break -- fallthrough -- return +- continue +- break +- fallthrough +- return 我们将会在下面讨论`continue`、`break`和`fallthrough`语句。`return`语句将会在[函数](../chapter2/06_Functions.html)章节讨论。 @@ -572,8 +557,7 @@ case let (x, y): `continue`语句告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。就好像在说“本次循环迭代我已经执行完了”,但是并不会离开整个循环体。 ->注意: -> +>注意: 在一个for条件递增(`for-condition-increment`)循环体中,在调用`continue`语句后,迭代增量仍然会被计算求值。循环体继续像往常一样工作,仅仅只是循环体中的执行代码会被跳过。 下面的例子把一个小写字符串中的元音字母和空格字符移除,生成了一个含义模糊的短句: @@ -612,8 +596,7 @@ println(puzzleOutput) 这种特性可以被用来匹配或者忽略一个或多个分支。因为 Swift 的`switch`需要包含所有的分支而且不允许有为空的分支,有时为了使你的意图更明显,需要特意匹配或者忽略某个分支。那么当你想忽略某个分支时,可以在该分支内写上`break`语句。当那个分支被匹配到时,分支内的`break`语句立即结束`switch`代码块。 ->注意: -> +>注意: 当一个`switch`分支仅仅包含注释时,会被报编译时错误。注释不是代码语句而且也不能让`switch`分支达到被忽略的效果。你总是可以使用`break`来忽略某个分支。 下面的例子通过`switch`来判断一个`Character`值是否代表下面四种语言之一。为了简洁,多个值被包含在了同一个分支情况中。 @@ -674,8 +657,7 @@ println(description) 当`switch`代码块执行完后,使用`println`函数打印该数字的描述。在这个例子中,数字`5`被准确的识别为了一个质数。 ->注意: -> +>注意: `fallthrough`关键字不会检查它下一个将会落入执行的 case 中的匹配条件。`fallthrough`简单地使代码执行继续连接到下一个 case 中的执行代码,这和 C 语言标准中的`switch`语句特性是一样的。 @@ -687,11 +669,9 @@ println(description) 产生一个带标签的语句是通过在该语句的关键词的同一行前面放置一个标签,并且该标签后面还需带着一个冒号。下面是一个`while`循环体的语法,同样的规则适用于所有的循环体和`switch`代码块。 -``` -`label name`: while `condition` { - `statements` -} -``` +> `label name`: while `condition` { +> `statements` +> } 下面的例子是在一个带有标签的`while`循环体中调用`break`和`continue`语句,该循环体是前面章节中_蛇和梯子_的改编版本。这次,游戏增加了一条额外的规则: @@ -745,7 +725,6 @@ println("Game over!") - 在剩余的所有情况中,骰子数产生的都是合法的移动。玩家向前移动骰子数个方格,然后游戏逻辑再处理玩家当前是否处于蛇头或者梯子的底部。本次循环迭代结束,控制跳转到`while`循环体的条件判断语句处,再决定是否能够继续执行下次循环迭代。 ->注意: -> +>注意: 如果上述的`break`语句没有使用`gameLoop`标签,那么它将会中断`switch`代码块而不是`while`循环体。使用`gameLoop`标签清晰的表明了`break`想要中断的是哪个代码块。 同时请注意,当调用`continue gameLoop`去跳转到下一次循环迭代时,这里使用`gameLoop`标签并不是严格必须的。因为在这个游戏中,只有一个循环体,所以`continue`语句会影响到哪个循环体是没有歧义的。然而,`continue`语句使用`gameLoop`标签也是没有危害的。这样做符合标签的使用规则,同时参照旁边的`break gameLoop`,能够使游戏的逻辑更加清晰和易于理解。 From 5c6cd039bf9010c4241af0c5d4a08b1973c60edb Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 16:53:26 +0800 Subject: [PATCH 11/24] fix 2.5 Control_Flow(2) --- source/chapter2/05_Control_Flow.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/source/chapter2/05_Control_Flow.md b/source/chapter2/05_Control_Flow.md index 6687b3f6..6acf2d7c 100644 --- a/source/chapter2/05_Control_Flow.md +++ b/source/chapter2/05_Control_Flow.md @@ -23,7 +23,6 @@ Swift 的`switch`语句比 C 语言中更加强大。在 C 语言中,如果某 `for`循环用来按照指定的次数多次执行一系列语句。Swift 提供两种`for`循环形式: * `for-in`用来遍历一个区间(range),序列(sequence),集合(collection),系列(progression)里面所有的元素执行一系列语句。 - * for条件递增(`for-condition-increment`)语句,用来重复执行一系列语句直到达成特定条件达成,一般通过在每次循环完成后增加计数器的值来实现。 @@ -165,7 +164,6 @@ println("The loop statements were executed \(index) times") `while`循环运行一系列语句直到条件变成`false`。这类循环适合使用在第一次迭代前迭代次数未知的情况下。Swift 提供两种`while`循环形式: * `while`循环,每次在循环开始时计算条件是否符合; - * `do-while`循环,每次在循环结束时计算条件是否符合。 @@ -720,9 +718,7 @@ println("Game over!") 每次循环迭代开始时掷骰子。与之前玩家掷完骰子就立即移动不同,这里使用了`switch`来考虑每次移动可能产生的结果,从而决定玩家本次是否能够移动。 - 如果骰子数刚好使玩家移动到最终的方格里,游戏结束。`break gameLoop`语句跳转控制去执行`while`循环体后的第一行代码,游戏结束。 - - 如果骰子数将会使玩家的移动超出最后的方格,那么这种移动是不合法的,玩家需要重新掷骰子。`continue gameLoop`语句结束本次`while`循环的迭代,开始下一次循环迭代。 - - 在剩余的所有情况中,骰子数产生的都是合法的移动。玩家向前移动骰子数个方格,然后游戏逻辑再处理玩家当前是否处于蛇头或者梯子的底部。本次循环迭代结束,控制跳转到`while`循环体的条件判断语句处,再决定是否能够继续执行下次循环迭代。 >注意: From 4857641a41bc02d3f5d2b13ec37a9c7b74054890 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:07:30 +0800 Subject: [PATCH 12/24] fix 2..6 Functions --- source/chapter2/06_Functions.md | 82 ++++++++++++++++----------------- 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/source/chapter2/06_Functions.md b/source/chapter2/06_Functions.md index 0e3fb9b8..7ca2b544 100644 --- a/source/chapter2/06_Functions.md +++ b/source/chapter2/06_Functions.md @@ -1,23 +1,23 @@ -> 翻译:honghaoz - -> 校对:LunaticM +> 翻译:honghaoz +> 校对:LunaticM # 函数(Functions) ----------------- 本页包含内容: -- [函数定义与调用(Defining and Calling Functions)](#Defining_and_Calling_Functions) -- [函数参数与返回值(Function Parameters and Return Values)](#Function_Parameters_and_Return_Values) -- [函数参数名称(Function Parameter Names)](#Function_Parameter_Names) -- [函数类型(Function Types)](#Function_Types) -- [函数嵌套(Nested Functions)](#Nested_Functions) +- [函数定义与调用(Defining and Calling Functions)](#Defining_and_Calling_Functions) +- [函数参数与返回值(Function Parameters and Return Values)](#Function_Parameters_and_Return_Values) +- [函数参数名称(Function Parameter Names)](#Function_Parameter_Names) +- [函数类型(Function Types)](#Function_Types) +- [函数嵌套(Nested Functions)](#Nested_Functions) 函数是用来完成特定任务的独立的代码块。你给一个函数起一个合适的名字,用来标示函数做什么,并且当函数需要执行的时候,这个名字会被“调用”。 Swift 统一的函数语法足够灵活,可以用来表示任何函数,包括从最简单的没有参数名字的 C 风格函数,到复杂的带局部和外部参数名的 Objective-C 风格函数。参数可以提供默认值,以简化函数调用。参数也可以即当做传入参数,也当做传出参数,也就是说,一旦函数执行结束,传入的参数值可以被修改。 在 Swift 中,每个函数都有一种类型,包括函数的参数值类型和返回值类型。你可以把函数类型当做任何其他普通变量类型一样处理,这样就可以更简单地把函数当做别的函数的参数,也可以从其他函数中返回函数。函数的定义可以写在在其他函数定义中,这样可以在嵌套函数范围内实现功能封装。 + ## 函数的定义与调用(Defining and Calling Functions) @@ -79,6 +79,7 @@ func halfOpenRangeLength(start: Int, end: Int) -> Int { println(halfOpenRangeLength(1, 10)) // prints "9 ``` + ### 无参函数(Functions Without Parameters) 函数可以没有参数。下面这个函数就是一个无参函数,当被调用时,它返回固定的 `String` 消息: @@ -107,9 +108,8 @@ sayGoodbye("Dave") 因为这个函数不需要返回值,所以这个函数的定义中没有返回箭头(->)和返回类型。 -> 注意: -> -> 严格上来说,虽然没有返回值被定义,`sayGoodbye` 函数依然返回了值。没有定义返回类型的函数会返回特殊的值,叫 `Void`。它其实是一个空的元组(tuple),没有任何元素,可以写成`()`。 +> 注意: +> 严格上来说,虽然没有返回值被定义,`sayGoodbye` 函数依然返回了值。没有定义返回类型的函数会返回特殊的值,叫 `Void`。它其实是一个空的元组(tuple),没有任何元素,可以写成`()`。 被调用时,一个函数的返回值可以被忽略: @@ -130,9 +130,8 @@ printWithoutCounting("hello, world") 第一个函数 `printAndCount`,输出一个字符串并返回 `Int` 类型的字符数。第二个函数 `printWithoutCounting`调用了第一个函数,但是忽略了它的返回值。当第二个函数被调用时,消息依然会由第一个函数输出,但是返回值不会被用到。 -> 注意: -> -> 返回值可以被忽略,但定义了有返回值的函数必须返回一个值,如果在函数定义底部没有返回任何值,这叫导致编译错误(compile-time error)。 +> 注意: +> 返回值可以被忽略,但定义了有返回值的函数必须返回一个值,如果在函数定义底部没有返回任何值,这叫导致编译错误(compile-time error)。 ### 多重返回值函数(Functions with Multiple Return Values) @@ -160,11 +159,14 @@ func count(string: String) -> (vowels: Int, consonants: Int, others: Int) { 你可以用 `count` 函数来处理任何一个字符串,返回的值将是一个包含三个 `Int` 型值的元组(tuple): - let total = count("some arbitrary string!") - println("\(total.vowels) vowels and \(total.consonants) consonants") - // prints "6 vowels and 13 consonants +```swift +let total = count("some arbitrary string!") +println("\(total.vowels) vowels and \(total.consonants) consonants") +// prints "6 vowels and 13 consonants +``` 需要注意的是,元组的成员不需要在函数中返回时命名,因为它们的名字已经在函数返回类型有有了定义。 + ## 函数参数名称(Function Parameter Names) @@ -192,9 +194,8 @@ func someFunction(externalParameterName localParameterName: Int) { } ``` -> 注意: -> -> 如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。 +> 注意: +> 如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名。 以下是个例子,这个函数使用一个`结合者(joiner)`把两个字符串联在一起: @@ -230,9 +231,8 @@ join(string: "hello", toString: "world", withJoiner: ", ") 使用外部参数名让第二个版本的 `join` 函数的调用更为有表现力,更为通顺,同时还保持了函数体是可读的和有明确意图的。 -> 注意: -> -> 当其他人在第一次读你的代码,函数参数的意图显得不明显时,考虑使用外部参数名。如果函数参数名的意图是很明显的,那就不需要定义外部参数名了。 +> 注意: +> 当其他人在第一次读你的代码,函数参数的意图显得不明显时,考虑使用外部参数名。如果函数参数名的意图是很明显的,那就不需要定义外部参数名了。 ### 简写外部参数名(Shorthand External Parameter Names) @@ -262,9 +262,8 @@ let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v") 你可以在函数体中为每个参数定义`默认值`。当默认值被定义后,调用这个函数时可以略去这个参数。 -> 注意: -> -> 将带有默认值的参数放在函数参数表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。 +> 注意: +> 将带有默认值的参数放在函数参数表的最后。这样可以保证在函数调用时,非默认参数的顺序是一致的,同时使得相同的函数在不同情况下调用时显得更为清晰。 以下是另一个版本的`join`函数,其中`joiner`有了默认参数值: @@ -287,6 +286,7 @@ join(string: "hello", toString: "world", withJoiner: "-") join(string: "hello", toString:"world") // returns "hello world" ``` + ### 默认值参数的外部参数名(External Names for Parameters with Default Values) 在大多数情况下,给带默认值的参数起一个外部参数名是很有用的。这样可以保证当函数被调用且带默认值的参数被提供值时,实参的意图是明显的。 @@ -308,9 +308,8 @@ join("hello", "world", joiner: "-") // returns "hello-world" ``` -> 注意: -> -> 你可以使用`下划线(_)`作为默认值参数的外部参数名,这样可以在调用时不用提供外部参数名。但是给带默认值的参数命名总是更加合适的。 +> 注意: +> 你可以使用`下划线(_)`作为默认值参数的外部参数名,这样可以在调用时不用提供外部参数名。但是给带默认值的参数命名总是更加合适的。 ### 可变参数(Variadic Parameters) @@ -324,7 +323,7 @@ join("hello", "world", joiner: "-") func arithmeticMean(numbers: Double...) -> Double { var total: Double = 0 for number in numbers { - total += number + total += number } return total / Double(numbers.count) } @@ -334,9 +333,8 @@ arithmeticMean(3, 8, 19) // returns 10.0, which is the arithmetic mean of these three numbers ``` -> 注意: -> -> 一个函数至多能有一个可变参数,而且它必须是参数表中最后的一个。这样做是为了避免函数调用时出现歧义。 +> 注意: +> 一个函数至多能有一个可变参数,而且它必须是参数表中最后的一个。这样做是为了避免函数调用时出现歧义。 如果函数有一个或多个带默认值的参数,而且还有一个可变参数,那么把可变参数放在参数表的最后。 @@ -368,9 +366,8 @@ let paddedString = alignRight(originalString, 10, "-") 该函数首先计算出多少个字符需要被添加到 `string` 的左边,以右对齐到总的字符串中。这个值存在局部常量 `amountToPad` 中。这个函数然后将 `amountToPad` 多的填充(pad)字符填充到 `string` 左边,并返回结果。它使用了 `string` 这个变量参数来进行所有字符串操作。 -> 注意: -> -> 对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中。 +> 注意: +> 对变量参数所进行的修改在函数调用结束后便消失了,并且对于函数体外是不可见的。变量参数仅仅存在于函数调用的生命周期中。 ### 输入输出参数(In-Out Parameters) @@ -380,9 +377,8 @@ let paddedString = alignRight(originalString, 10, "-") 你只能传入一个变量作为输入输出参数。你不能传入常量或者字面量(literal value),因为这些量是不能被修改的。当传入的参数作为输入输出参数时,需要在参数前加`&`符,表示这个值可以被函数修改。 -> 注意: -> -> 输入输出参数不能有默认值,而且可变参数不能用 `inout` 标记。如果你用 `inout` 标记一个参数,这个参数不能被 `var` 或者 `let` 标记。 +> 注意: +> 输入输出参数不能有默认值,而且可变参数不能用 `inout` 标记。如果你用 `inout` 标记一个参数,这个参数不能被 `var` 或者 `let` 标记。 下面是例子,`swapTwoInts` 函数,有两个分别叫做 `a` 和 `b` 的输出输出参数: @@ -408,9 +404,8 @@ println("someInt is now \(someInt), and anotherInt is now \(anotherInt)") 从上面这个例子中,我们可以看到 `someInt` 和 `anotherInt` 的原始值在 `swapTwoInts` 函数中被修改,尽管它们的定义在函数体外。 -> 注意: -> -> 输出输出参数和返回值是不一样的。上面的 `swapTwoInts` 函数并没有定义任何返回值,但仍然修改了 `someInt` 和 `anotherInt` 的值。输入输出参数是函数对函数体外产生影响的另一种方式。 +> 注意: +> 输出输出参数和返回值是不一样的。上面的 `swapTwoInts` 函数并没有定义任何返回值,但仍然修改了 `someInt` 和 `anotherInt` 的值。输入输出参数是函数对函数体外产生影响的另一种方式。 ## 函数类型(Function Types) @@ -477,6 +472,7 @@ println("Result: \(mathFunction(2, 3))") let anotherMathFunction = addTwoInts // anotherMathFunction is inferred to be of type (Int, Int) -> Int ``` + ### 函数类型作为参数类型(Function Types as Parameter Types) 你可以用`(Int, Int) -> Int`这样的函数类型作为另一个函数的参数类型。这样你可以将函数的一部分实现交由给函数的调用者。 @@ -574,4 +570,4 @@ println("zero!") // -2... // -1... // zero! -``` +``` \ No newline at end of file From fee9162d6c0d7dc9a1dcfa5162bd59808bb93b78 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:19:58 +0800 Subject: [PATCH 13/24] fix 2.7 closures --- source/chapter2/07_Closures.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/source/chapter2/07_Closures.md b/source/chapter2/07_Closures.md index 814d6277..9e4ee6fe 100644 --- a/source/chapter2/07_Closures.md +++ b/source/chapter2/07_Closures.md @@ -7,10 +7,10 @@ 本页包含内容: -- [闭包表达式(Closure Expressions)](#closure_expressions) -- [尾随闭包(Trailing Closures)](#trailing_closures) -- [值捕获(Capturing Values)](#capturing_values) -- [闭包是引用类型(Closures Are Reference Types)](#closures_are_reference_types) +- [闭包表达式(Closure Expressions)](#closure_expressions) +- [尾随闭包(Trailing Closures)](#trailing_closures) +- [值捕获(Capturing Values)](#capturing_values) +- [闭包是引用类型(Closures Are Reference Types)](#closures_are_reference_types) 闭包是自包含的函数代码块,可以在代码中被传递和使用。 Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的 lambdas 函数比较相似。 @@ -24,16 +24,16 @@ Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他 在[函数](../chapter2/06_Functions.html) 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一: -* 全局函数是一个有名字但不会捕获任何值的闭包 -* 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包 -* 闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包 +* 全局函数是一个有名字但不会捕获任何值的闭包 +* 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包 +* 闭包表达式是一个利用轻量级语法所写的可以捕获其上下文中变量或常量值的匿名闭包 Swift 的闭包表达式拥有简洁的风格,并鼓励在常见场景中进行语法优化,主要优化如下: -* 利用上下文推断参数和返回值类型 -* 隐式返回单表达式闭包,即单表达式闭包可以省略`return`关键字 -* 参数名称缩写 -* 尾随(Trailing)闭包语法 +* 利用上下文推断参数和返回值类型 +* 隐式返回单表达式闭包,即单表达式闭包可以省略`return`关键字 +* 参数名称缩写 +* 尾随(Trailing)闭包语法 ## 闭包表达式(Closure Expressions) @@ -60,8 +60,8 @@ let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] `sort`函数需要传入两个参数: -* 已知类型的数组 -* 闭包函数,该闭包函数需要传入与数组类型相同的两个值,并返回一个布尔类型值来告诉`sort`函数当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回`true`,反之返回`false`。 +* 已知类型的数组 +* 闭包函数,该闭包函数需要传入与数组类型相同的两个值,并返回一个布尔类型值来告诉`sort`函数当排序结束后传入的第一个参数排在第二个参数前面还是后面。如果第一个参数值出现在第二个参数值前面,排序闭包函数需要返回`true`,反之返回`false`。 该例子对一个`String`类型的数组进行排序,因此排序闭包函数类型需为`(String, String) -> Bool`。 @@ -103,7 +103,7 @@ var reversed = sort(names, backwards) ``` reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 - }) +}) ``` 需要注意的是内联闭包参数和返回值类型声明与`backwards`函数类型声明相同。 From 6b9026dd9bd578c857f098ed03e6461a0cd23abe Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:23:00 +0800 Subject: [PATCH 14/24] fix 2.7 closures(2) --- source/chapter2/07_Closures.md | 90 ++++++++++++++-------------------- 1 file changed, 38 insertions(+), 52 deletions(-) diff --git a/source/chapter2/07_Closures.md b/source/chapter2/07_Closures.md index 9e4ee6fe..c52115f7 100644 --- a/source/chapter2/07_Closures.md +++ b/source/chapter2/07_Closures.md @@ -1,6 +1,5 @@ -> 翻译:wh1100717 - -> 校对:lyuka +> 翻译:wh1100717 +> 校对:lyuka # 闭包(Closures) ----------------- @@ -18,9 +17,8 @@ Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他 闭包可以捕获和存储其所在上下文中任意常量和变量的引用。 这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。 -> 注意: -> -> 如果您不熟悉捕获(capturing)这个概念也不用担心,您可以在 [值捕获](#capturing_values) 章节对其进行详细了解。 +> 注意: +> 如果您不熟悉捕获(capturing)这个概念也不用担心,您可以在 [值捕获](#capturing_values) 章节对其进行详细了解。 在[函数](../chapter2/06_Functions.html) 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一: @@ -54,7 +52,7 @@ Swift 标准库提供了`sort`函数,会根据您提供的基于输出类型 下面的闭包表达式示例使用`sort`函数对一个`String`类型的数组进行字母逆序排序,以下是初始数组值: -``` +```swift let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] ``` @@ -67,7 +65,7 @@ let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] 提供排序闭包函数的一种方式是撰写一个符合其类型要求的普通函数,并将其作为`sort`函数的第二个参数传入: -``` +```swift func backwards(s1: String, s2: String) -> Bool { return s1 > s2 } @@ -88,7 +86,7 @@ var reversed = sort(names, backwards) 闭包表达式语法有如下一般形式: -``` +```swift { (parameters) -> returnType in statements } @@ -100,7 +98,7 @@ var reversed = sort(names, backwards) 下面的例子展示了之前`backwards`函数对应的闭包表达式版本的代码: -``` +```swift reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 }) @@ -115,7 +113,7 @@ reversed = sort(names, { (s1: String, s2: String) -> Bool in 因为这个闭包的函数体部分如此短以至于可以将其改写成一行代码: -``` +```swift reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } ) ``` @@ -128,7 +126,7 @@ reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } ) `sort`期望第二个参数是类型为`(String, String) -> Bool`的函数,因此实际上`String`,`String`和`Bool`类型并不需要作为闭包表达式定义中的一部分。 因为所有的类型都可以被正确推断,返回箭头 (`->`) 和围绕在参数周围的括号也可以被省略: -``` +```swift reversed = sort(names, { s1, s2 in return s1 > s2 } ) ``` @@ -139,7 +137,7 @@ reversed = sort(names, { s1, s2 in return s1 > s2 } ) 单行表达式闭包可以通过隐藏`return`关键字来隐式返回单行表达式的结果,如上版本的例子可以改写为: -``` +```swift reversed = sort(names, { s1, s2 in s1 > s2 } ) ``` @@ -154,7 +152,7 @@ Swift 自动为内联函数提供了参数名称缩写功能,您可以直接 如果您在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其的定义,并且对应参数名称缩写的类型会通过函数类型进行推断。 `in`关键字也同样可以被省略,因为此时闭包表达式完全由闭包函数体构成: -``` +```swift reversed = sort(names, { $0 > $1 } ) ``` @@ -168,7 +166,7 @@ Swift 的`String`类型定义了关于大于号 (`>`) 的字符串实现,其 而这正好与`sort`函数的第二个参数需要的函数类型相符合。 因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现: -``` +```swift reversed = sort(names, >) ``` @@ -181,32 +179,28 @@ reversed = sort(names, >) 如果您需要将一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。 尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。 -``` +```swift func someFunctionThatTakesAClosure(closure: () -> ()) { // 函数体部分 } // 以下是不使用尾随闭包进行函数调用 - someFunctionThatTakesAClosure({ // 闭包主体部分 - }) +}) // 以下是使用尾随闭包进行函数调用 - someFunctionThatTakesAClosure() { - // 闭包主体部分 + // 闭包主体部分 } ``` -> 注意: -> -> 如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把`()`省略掉。 - +> 注意: +> 如果函数只需要闭包表达式一个参数,当您使用尾随闭包时,您甚至可以把`()`省略掉。 在上例中作为`sort`函数参数的字符串排序闭包可以改写为: -``` +```swift reversed = sort(names) { $0 > $1 } ``` @@ -219,7 +213,7 @@ reversed = sort(names) { $0 > $1 } 下例介绍了如何在`map`方法中使用尾随闭包将`Int`类型数组`[16,58,510]`转换为包含对应`String`类型的数组`["OneSix", "FiveEight", "FiveOneZero"]`: -``` +```swift let digitNames = [ 0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four", 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine" @@ -233,7 +227,7 @@ let numbers = [16, 58, 510] 您现在可以通过传递一个尾随闭包给`numbers`的`map`方法来创建对应的字符串版本数组。 需要注意的时调用`numbers.map`不需要在`map`后面包含任何括号,因为其只需要传递闭包表达式这一个参数,并且该闭包表达式参数通过尾随方式进行撰写: -``` +```swift let strings = numbers.map { (var number) -> String in var output = "" @@ -255,11 +249,10 @@ let strings = numbers.map { 闭包表达式在每次被调用的时候创建了一个字符串并返回。 其使用求余运算符 (number % 10) 计算最后一位数字并利用`digitNames`字典获取所映射的字符串。 -> 注意: -> -> 字典`digitNames`下标后跟着一个叹号 (!),因为字典下标返回一个可选值 (optional value),表明即使该 key 不存在也不会查找失败。 -> 在上例中,它保证了`number % 10`可以总是作为一个`digitNames`字典的有效下标 key。 -> 因此叹号可以用于强制解析 (force-unwrap) 存储在可选下标项中的`String`类型值。 +> 注意: +> 字典`digitNames`下标后跟着一个叹号 (!),因为字典下标返回一个可选值 (optional value),表明即使该 key 不存在也不会查找失败。 +> 在上例中,它保证了`number % 10`可以总是作为一个`digitNames`字典的有效下标 key。 +> 因此叹号可以用于强制解析 (force-unwrap) 存储在可选下标项中的`String`类型值。 从`digitNames`字典中获取的字符串被添加到输出的前部,逆序建立了一个字符串版本的数字。 (在表达式`number % 10`中,如果number为16,则返回6,58返回8,510返回0)。 @@ -287,7 +280,7 @@ Swift最简单的闭包形式是嵌套函数,也就是定义在其他函数的 之后`makeIncrementor`将`incrementor`作为闭包返回。 每次调用`incrementor`时,其会以`amount`作为增量增加`runningTotal`的值。 -``` +```swift func makeIncrementor(forIncrement amount: Int) -> () -> Int { var runningTotal = 0 func incrementor() -> Int { @@ -313,7 +306,7 @@ func makeIncrementor(forIncrement amount: Int) -> () -> Int { 如果我们单独看这个函数,会发现看上去不同寻常: -``` +```swift func incrementor() -> Int { runningTotal += amount return runningTotal @@ -326,22 +319,21 @@ func incrementor() -> Int { 然而,因为每次调用该函数的时候都会修改`runningTotal`的值,`incrementor`捕获了当前`runningTotal`变量的引用,而不是仅仅复制该变量的初始值。捕获一个引用保证了当`makeIncrementor`结束时候并不会消失,也保证了当下一次执行`incrementor`函数时,`runningTotal`可以继续增加。 -> 注意: -> -> Swift 会决定捕获引用还是拷贝值。 -> 您不需要标注`amount`或者`runningTotal`来声明在嵌入的`incrementor`函数中的使用方式。 -> Swift 同时也处理`runingTotal`变量的内存管理操作,如果不再被`incrementor`函数使用,则会被清除。 +> 注意: +> Swift 会决定捕获引用还是拷贝值。 +> 您不需要标注`amount`或者`runningTotal`来声明在嵌入的`incrementor`函数中的使用方式。 +> Swift 同时也处理`runingTotal`变量的内存管理操作,如果不再被`incrementor`函数使用,则会被清除。 下面代码为一个使用`makeIncrementor`的例子: -``` +```swift let incrementByTen = makeIncrementor(forIncrement: 10) ``` 该例子定义了一个叫做`incrementByTen`的常量,该常量指向一个每次调用会加10的`incrementor`函数。 调用这个函数多次可以得到以下结果: -``` +```swift incrementByTen() // 返回的值为10 incrementByTen() @@ -353,7 +345,7 @@ incrementByTen() 如果您创建了另一个`incrementor`,其会有一个属于自己的独立的`runningTotal`变量的引用。 下面的例子中,`incrementBySevne`捕获了一个新的`runningTotal`变量,该变量和`incrementByTen`中捕获的变量没有任何联系: -``` +```swift let incrementBySeven = makeIncrementor(forIncrement: 7) incrementBySeven() // 返回的值为7 @@ -361,15 +353,13 @@ incrementByTen() // 返回的值为40 ``` -> 注意: -> -> 如果您闭包分配给一个类实例的属性,并且该闭包通过指向该实例或其成员来捕获了该实例,您将创建一个在闭包和实例间的强引用环。 -> Swift 使用捕获列表来打破这种强引用环。更多信息,请参考 [闭包引起的循环强引用](../chapter2/16_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)。 +> 注意: +> 如果您将闭包赋值给一个类实例的属性,并且该闭包通过指向该实例或其成员来捕获了该实例,您将创建一个在闭包和实例间的强引用环。 +> Swift 使用捕获列表来打破这种强引用环。更多信息,请参考 [闭包引起的循环强引用](../chapter2/16_Automatic_Reference_Counting.html#strong_reference_cycles_for_closures)。 ## 闭包是引用类型(Closures Are Reference Types) - 上面的例子中,`incrementBySeven`和`incrementByTen`是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量值。 这是因为函数和闭包都是引用类型。 @@ -378,12 +368,8 @@ incrementByTen() 这也意味着如果您将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包: -``` +```swift let alsoIncrementByTen = incrementByTen alsoIncrementByTen() // 返回的值为50 ``` - - - - From 23ccecdeb0c6b0e4584f360921da09f5152d9f75 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:28:44 +0800 Subject: [PATCH 15/24] fix 2.8 Enumerations --- source/chapter2/08_Enumerations.md | 210 +++++++++++++++++------------ 1 file changed, 121 insertions(+), 89 deletions(-) diff --git a/source/chapter2/08_Enumerations.md b/source/chapter2/08_Enumerations.md index ecee602e..be25fec2 100644 --- a/source/chapter2/08_Enumerations.md +++ b/source/chapter2/08_Enumerations.md @@ -1,17 +1,15 @@ -> 翻译:yankuangshi - -> 校对:shinyzhu +> 翻译:yankuangshi +> 校对:shinyzhu # 枚举(Enumerations) - --- 本页内容包含: -- [枚举语法(Enumeration Syntax)](#enumeration_syntax) -- [匹配枚举值与`Swith`语句(Matching Enumeration Values with a Switch Statement)](#matching_enumeration_values_with_a_switch_statement) -- [实例值(Associated Values)](#associated_values) -- [原始值(Raw Values)](#raw_values) +- [枚举语法(Enumeration Syntax)](#enumeration_syntax) +- [匹配枚举值与`Swith`语句(Matching Enumeration Values with a Switch Statement)](#matching_enumeration_values_with_a_switch_statement) +- [实例值(Associated Values)](#associated_values) +- [原始值(Raw Values)](#raw_values) 枚举定义了一个通用类型的一组相关的值,使你可以在你的代码中以一个安全的方式来使用这些值。 @@ -28,38 +26,47 @@ 使用`enum`关键词并且把它们的整个定义放在一对大括号内: - enum SomeEumeration { - // enumeration definition goes here - } +```swift +enum SomeEumeration { + // enumeration definition goes here +} +``` 以下是指南针四个方向的一个例子: - enum CompassPoint { - case North - case South - case East - case West - } +```swift +enum CompassPoint { + case North + case South + case East + case West +} +``` 一个枚举中被定义的值(例如 `North`,`South`,`East`和`West`)是枚举的***成员值***(或者***成员***)。`case`关键词表明新的一行成员值将被定义。 -> 注意: -> -> 不像 C 和 Objective-C 一样,Swift 的枚举成员在被创建时不会被赋予一个默认的整数值。在上面的`CompassPoints`例子中,`North`,`South`,`East`和`West`不是隐式的等于`0`,`1`,`2`和`3`。相反的,这些不同的枚举成员在`CompassPoint`的一种显示定义中拥有各自不同的值。 +> 注意: +> 不像 C 和 Objective-C 一样,Swift 的枚举成员在被创建时不会被赋予一个默认的整数值。在上面的`CompassPoints`例子中,`North`,`South`,`East`和`West`不是隐式的等于`0`,`1`,`2`和`3`。相反的,这些不同的枚举成员在`CompassPoint`的一种显示定义中拥有各自不同的值。 多个成员值可以出现在同一行上,用逗号隔开: - enum Planet { - case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Nepturn - } +```swift +enum Planet { + case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Nepturn +} +``` 每个枚举定义了一个全新的类型。像 Swift 中其他类型一样,它们的名字(例如`CompassPoint`和`Planet`)必须以一个大写字母开头。给枚举类型起一个单数名字而不是复数名字,以便于读起来更加容易理解: - var directionToHead = CompassPoint.West +```swift +var directionToHead = CompassPoint.West +``` `directionToHead`的类型被推断当它被`CompassPoint`的一个可能值初始化。一旦`directionToHead`被声明为一个`CompassPoint`,你可以使用更短的点(.)语法将其设置为另一个`CompassPoint`的值: - directionToHead = .East +```swift +directionToHead = .East +``` `directionToHead`的类型已知时,当设定它的值时,你可以不再写类型名。使用显示类型的枚举值可以让代码具有更好的可读性。 @@ -68,18 +75,20 @@ 你可以匹配单个枚举值和`switch`语句: - directionToHead = .South - switch directionToHead { - case .North: - println("Lots of planets have a north") - case .South: - println("Watch out for penguins") - case .East: - println("Where the sun rises") - case .West: - println("Where the skies are blue") - } - // 输出 "Watch out for penguins” +```swift +directionToHead = .South +switch directionToHead { +case .North: + println("Lots of planets have a north") +case .South: + println("Watch out for penguins") +case .East: + println("Where the sun rises") +case .West: + println("Where the skies are blue") +} +// 输出 "Watch out for penguins” +``` 你可以如此理解这段代码: @@ -91,14 +100,16 @@ 当不需要匹配每个枚举成员的时候,你可以提供一个默认`default`分支来涵盖所有未明确被提出的任何成员: - let somePlanet = Planet.Earth - switch somePlanet { - case .Earth: - println("Mostly harmless") - default: - println("Not a safe place for humans") - } - // 输出 "Mostly harmless” +```swift +let somePlanet = Planet.Earth +switch somePlanet { +case .Earth: + println("Mostly harmless") +default: + println("Not a safe place for humans") +} +// 输出 "Mostly harmless” +``` ## 实例值(Associated Values) @@ -119,10 +130,12 @@ 在 Swift 中,用来定义两种商品条码的枚举是这样子的: - enum Barcode { - case UPCA(Int, Int, Int) - case QRCode(String) - } +```swift +enum Barcode { + case UPCA(Int, Int, Int) + case QRCode(String) +} +``` 以上代码可以这么理解: @@ -132,35 +145,43 @@ 然后可以使用任何一种条码类型创建新的条码,如: - var productBarcode = Barcode.UPCA(8, 85909_51226, 3) +```swift +var productBarcode = Barcode.UPCA(8, 85909_51226, 3) +``` 以上例子创建了一个名为`productBarcode`的新变量,并且赋给它一个`Barcode.UPCA`的实例元组值`(8, 8590951226, 3)`。提供的“标识符”值在整数字中有一个下划线,使其便于阅读条形码。 同一个商品可以被分配给一个不同类型的条形码,如: - productBarcode = .QRCode("ABCDEFGHIJKLMNOP") +```swift +productBarcode = .QRCode("ABCDEFGHIJKLMNOP") +``` 这时,原始的`Barcode.UPCA`和其整数值被新的`Barcode.QRCode`和其字符串值所替代。条形码的常量和变量可以存储一个`.UPCA`或者一个`.QRCode`(连同它的实例值),但是在任何指定时间只能存储其中之一。 像以前那样,不同的条形码类型可以使用一个 switch 语句来检查,然而这次实例值可以被提取作为 switch 语句的一部分。你可以在`switch`的 case 分支代码中提取每个实例值作为一个常量(用`let`前缀)或者作为一个变量(用`var`前缀)来使用: - switch productBarcode { - case .UPCA(let numberSystem, let identifier, let check): - println("UPC-A with value of \(numberSystem), \(identifier), \(check).") - case .QRCode(let productCode): - println("QR code with value of \(productCode).") - } - // 输出 "QR code with value of ABCDEFGHIJKLMNOP.” +```swift +switch productBarcode { +case .UPCA(let numberSystem, let identifier, let check): + println("UPC-A with value of \(numberSystem), \(identifier), \(check).") +case .QRCode(let productCode): + println("QR code with value of \(productCode).") +} +// 输出 "QR code with value of ABCDEFGHIJKLMNOP.” +``` 如果一个枚举成员的所有实例值被提取为常量,或者它们全部被提取为变量,为了简洁,你可以只放置一个`var`或者`let`标注在成员名称前: - switch productBarcode { - case let .UPCA(numberSystem, identifier, check): - println("UPC-A with value of \(numberSystem), \(identifier), \(check).") - case let .QRCode(productCode): - println("QR code with value of \(productCode).") - } - // 输出 "QR code with value of ABCDEFGHIJKLMNOP." +```swift +switch productBarcode { +case let .UPCA(numberSystem, identifier, check): + println("UPC-A with value of \(numberSystem), \(identifier), \(check).") +case let .QRCode(productCode): + println("QR code with value of \(productCode).") +} +// 输出 "QR code with value of ABCDEFGHIJKLMNOP." +``` ## 原始值(Raw Values) @@ -169,11 +190,13 @@ 这里是一个枚举成员存储原始 ASCII 值的例子: - enum ASCIIControlCharacter: Character { - case Tab = "\t" - case LineFeed = "\n" - case CarriageReturn = "\r" - } +```swift +enum ASCIIControlCharacter: Character { + case Tab = "\t" + case LineFeed = "\n" + case CarriageReturn = "\r" +} +``` 在这里,称为`ASCIIControlCharacter`的枚举的原始值类型被定义为字符型`Character`,并被设置了一些比较常见的 ASCII 控制字符。字符值的描述请详见字符串和字符`Strings and Characters`部分。 @@ -183,37 +206,46 @@ 下面的枚举是对之前`Planet`这个枚举的一个细化,利用原始整型值来表示每个 planet 在太阳系中的顺序: - enum Planet: Int { - case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune - } +```swift +enum Planet: Int { + case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune +} +``` 自动递增意味着`Planet.Venus`的原始值是`2`,依次类推。 使用枚举成员的`toRaw`方法可以访问该枚举成员的原始值: - let earthsOrder = Planet.Earth.toRaw() - // earthsOrder is 3 +```swift +let earthsOrder = Planet.Earth.toRaw() +// earthsOrder is 3 +``` 使用枚举的`fromRaw`方法来试图找到具有特定原始值的枚举成员。这个例子通过原始值`7`识别`Uranus`: - let possiblePlanet = Planet.fromRaw(7) - // possiblePlanet is of type Planet? and equals Planet.Uranus +```swift +let possiblePlanet = Planet.fromRaw(7) +// possiblePlanet is of type Planet? and equals Planet.Uranus +``` 然而,并非所有可能的`Int`值都可以找到一个匹配的行星。正因为如此,`fromRaw`方法可以返回一个***可选***的枚举成员。在上面的例子中,`possiblePlanet`是`Planet?`类型,或“可选的`Planet`”。 如果你试图寻找一个位置为9的行星,通过`fromRaw`返回的可选`Planet`值将是`nil`: - let positionToFind = 9 - if let somePlanet = Planet.fromRaw(positionToFind) { - switch somePlanet { - case .Earth: - println("Mostly harmless") - default: - println("Not a safe place for humans") - } - } else { - println("There isn't a planet at position \(positionToFind)") - } - // 输出 "There isn't a planet at position 9 +```swift +let positionToFind = 9 +if let somePlanet = Planet.fromRaw(positionToFind) { + switch somePlanet { + case .Earth: + println("Mostly harmless") + default: + println("Not a safe place for humans") + } +} else { + println("There isn't a planet at position \(positionToFind)") +} +// 输出 "There isn't a planet at position 9 +``` 这个范例使用可选绑定(optional binding),通过原始值`9`试图访问一个行星。`if let somePlanet = Planet.fromRaw(9)`语句获得一个可选`Planet`,如果可选`Planet`可以被获得,把`somePlanet`设置成该可选`Planet`的内容。在这个范例中,无法检索到位置为`9`的行星,所以`else`分支被执行。 + From 514252d305d854c620a8fbe7f165e387cb3a6ddd Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:33:10 +0800 Subject: [PATCH 16/24] fix 2.9 classes and structures --- source/chapter2/09_Classes_and_Structures.md | 327 +++++++++++-------- 1 file changed, 189 insertions(+), 138 deletions(-) diff --git a/source/chapter2/09_Classes_and_Structures.md b/source/chapter2/09_Classes_and_Structures.md index 7553319d..2601140c 100644 --- a/source/chapter2/09_Classes_and_Structures.md +++ b/source/chapter2/09_Classes_and_Structures.md @@ -1,35 +1,33 @@ -> 翻译:JaySurplus - -> 校对:sg552 +> 翻译:JaySurplus +> 校对:sg552 # 类和结构体 本页包含内容: -- [类和结构体对比](#comparing_classes_and_structures) -- [结构体和枚举是值类型](#structures_and_enumerations_are_value_types) -- [类是引用类型](#classes_are_reference_types) -- [类和结构体的选择](#choosing_between_classes_and_structures) -- [集合(collection)类型的赋值与复制行为](#assignment_and_copy_behavior_for_collection_types) +- [类和结构体对比](#comparing_classes_and_structures) +- [结构体和枚举是值类型](#structures_and_enumerations_are_value_types) +- [类是引用类型](#classes_are_reference_types) +- [类和结构体的选择](#choosing_between_classes_and_structures) +- [集合(collection)类型的赋值与复制行为](#assignment_and_copy_behavior_for_collection_types) 类和结构体是人们构建代码所用的一种通用且灵活的构造体。为了在类和结构体中实现各种功能,我们必须要严格按照对于常量,变量以及函数所规定的语法规则来定义属性和添加方法。 与其他编程语言所不同的是,Swift 并不要求你为自定义类和结构去创建独立的接口和实现文件。你所要做的是在一个单一文件中定义一个类或者结构体,系统将会自动生成面向其它代码的外部接口。 -> 注意: -> +> 注意: 通常一个`类`的实例被称为`对象`。然而在Swift 中,类和结构体的关系要比在其他语言中更加的密切,本章中所讨论的大部分功能都可以用在类和结构体上。因此,我们会主要使用`实例`而不是`对象`。 ###类和结构体对比 Swift 中类和结构体有很多共同点。共同处在于: -* 定义属性用于储存值 -* 定义方法用于提供功能 -* 定义附属脚本用于访问值 -* 定义构造器用于生成初始化值 -* 通过扩展以增加默认实现的功能 -* 符合协议以对某类提供标准功能 +* 定义属性用于储存值 +* 定义方法用于提供功能 +* 定义附属脚本用于访问值 +* 定义构造器用于生成初始化值 +* 通过扩展以增加默认实现的功能 +* 符合协议以对某类提供标准功能 更多信息请参见 [属性](10_Properties.html),[方法](11_Methods.html),[附属脚本](12_Subscripts.html),[初始过程](14_Initialization.html),[扩展](20_Extensions.html),和[协议](21_Protocols.html)。 @@ -43,36 +41,38 @@ Swift 中类和结构体有很多共同点。共同处在于: 更多信息请参见[继承](http://),[类型转换](http://),[初始化](http://),和[自动引用计数](http://)。 -> 注意: -> +> 注意: 结构体总是通过被复制的方式在代码中传递,因此请不要使用引用计数。 ### 定义 类和结构体有着类似的定义方式。我们通过关键字`class`和`struct`来分别表示类和结构体,并在一对大括号中定义它们的具体内容: - class SomeClass { - // class definition goes here - } - struct SomeStructure { - // structure definition goes here - } +```swift +class SomeClass { + // class definition goes here +} +struct SomeStructure { + // structure definition goes here +} +``` -> 注意: -> +> 注意: 在你每次定义一个新类或者结构体的时候,实际上你是有效地定义了一个新的 Swift 类型。因此请使用 `UpperCamelCase` 这种方式来命名(如 `SomeClass` 和`SomeStructure`等),以便符合标准Swift 类型的大写命名风格(如`String`,`Int`和`Bool`)。相反的,请使用`lowerCamelCase`这种方式为属性和方法命名(如`framerate`和`incrementCount`),以便和类区分。 以下是定义结构体和定义类的示例: - struct Resolution { - var width = 0 - var heigth = 0 - } - class VideoMode { - var resolution = Resolution() - var interlaced = false - var frameRate = 0.0 - var name: String? - } +```swift +struct Resolution { + var width = 0 + var heigth = 0 +} +class VideoMode { + var resolution = Resolution() + var interlaced = false + var frameRate = 0.0 + var name: String? +} +``` 在上面的示例中我们定义了一个名为`Resolution`的结构体,用来描述一个显示器的像素分辨率。这个结构体包含了两个名为`width`和`height`的储存属性。储存属性是捆绑和储存在类或结构体中的常量或变量。当这两个属性被初始化为整数`0`的时候,它们会被推断为`Int`类型。 @@ -83,8 +83,10 @@ Swift 中类和结构体有很多共同点。共同处在于: 生成结构体和类实例的语法非常相似: - let someResolution = Resolution() - let someVideoMode = VideoMode() +```swift +let someResolution = Resolution() +let someVideoMode = VideoMode() +``` 结构体和类都使用构造器语法来生成新的实例。构造器语法的最简单形式是在结构体或者类的类型名称后跟随一个空括弧,如`Resolution()`或`VideoMode()`。通过这种方式所创建的类或者结构体实例,其属均会被初始化为默认值。[构造过程](14_Initialization.html)章节会对类和结构体的初始化进行更详细的讨论。 @@ -92,32 +94,38 @@ Swift 中类和结构体有很多共同点。共同处在于: ### 属性访问 通过使用*点语法*(*dot syntax*),你可以访问实例中所含有的属性。其语法规则是,实例名后面紧跟属性名,两者通过点号(.)连接: - println("The width of someResolution is \(someResolution.width)") - // 输出 "The width of someResolution is 0" +```swift +println("The width of someResolution is \(someResolution.width)") +// 输出 "The width of someResolution is 0" +``` 在上面的例子中,`someResolution.width`引用`someResolution`的`width`属性,返回`width`的初始值`0`。 你也可以访问子属性,如何`VideoMode`中`Resolution`属性的`width`属性: - println("The width of someVideoMode is \(someVideoMode.resolution.width)") - // 输出 "The width of someVideoMode is 0" +```swift +println("The width of someVideoMode is \(someVideoMode.resolution.width)") +// 输出 "The width of someVideoMode is 0" +``` 你也可以使用点语法为属性变量赋值: - someVideoMode.resolution.width = 12880 - println("The width of someVideoMode is now \(someVideoMode.resolution.width)") - // 输出 "The width of someVideoMode is now 1280" +```swift +someVideoMode.resolution.width = 12880 +println("The width of someVideoMode is now \(someVideoMode.resolution.width)") +// 输出 "The width of someVideoMode is now 1280" +``` -> 注意: -> +> 注意: 与 Objective-C 语言不同的是,Swift 允许直接设置结构体属性的子属性。上面的最后一个例子,就是直接设置了`someVideoMode`中`resolution`属性的`width`这个子属性,以上操作并不需要从新设置`resolution`属性。 -### 结构体类型的成员逐一构造器 -//Memberwise Initializers for structure Types +### 结构体类型的成员逐一构造器(Memberwise Initializers for structure Types) 所有结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器之中: - let vga = resolution(width:640, heigth: 480) +```swift +let vga = resolution(width:640, heigth: 480) +``` 与结构体不同,类实例没有默认的成员逐一构造器。[构造过程](14_Initialization.html)章节会对构造器进行更详细的讨论。 @@ -132,8 +140,10 @@ Swift 中类和结构体有很多共同点。共同处在于: 请看下面这个示例,其使用了前一个示例中`Resolution`结构体: - let hd = Resolution(width: 1920, height: 1080) - var cinema = hd +```swift +let hd = Resolution(width: 1920, height: 1080) +var cinema = hd +``` 在以上示例中,声明了一个名为`hd`的常量,其值为一个初始化为全高清视频分辨率(1920 像素宽,1080 像素高)的`Resolution`实例。 @@ -141,32 +151,40 @@ Swift 中类和结构体有很多共同点。共同处在于: 下面,为了符合数码影院放映的需求(2048 像素宽,1080 像素高),`cinema`的`width`属性需要作如下修改: - cinema.width = 2048 +```swift +cinema.width = 2048 +``` 这里,将会显示`cinema`的`width`属性确已改为了`2048`: - println("cinema is now \(cinema.width) pixels wide") - // 输出 "cinema is now 2048 pixels wide" +```swift +println("cinema is now \(cinema.width) pixels wide") +// 输出 "cinema is now 2048 pixels wide" +``` 然而,初始的`hd`实例中`width`属性还是`1920`: - println("hd is still \(hd.width ) pixels wide") - // 输出 "hd is still 1920 pixels wide" +```swift +println("hd is still \(hd.width ) pixels wide") +// 输出 "hd is still 1920 pixels wide" +``` 在将`hd`赋予给`cinema`的时候,实际上是将`hd`中所储存的`值(values)`进行拷贝,然后将拷贝的数据储存到新的`cinema`实例中。结果就是两个完全独立的实例碰巧包含有相同的数值。由于两者相互独立,因此将`cinema`的`width`修改为`2048`并不会影响`hd`中的宽(width)。 枚举也遵循相同的行为准则: - enum CompassPoint { - case North, South, East, West - } - var currentDirection = CompassPoint.West - let rememberedDirection = currentDirection - currentDirection = .East - if rememberDirection == .West { - println("The remembered direction is still .West") - } - // 输出 "The remembered direction is still .West" +```swift +enum CompassPoint { + case North, South, East, West +} +var currentDirection = CompassPoint.West +let rememberedDirection = currentDirection +currentDirection = .East +if rememberDirection == .West { + println("The remembered direction is still .West") +} +// 输出 "The remembered direction is still .West" +``` 上例中`rememberedDirection`被赋予了`currentDirection`的值(value),实际上它被赋予的是值(value)的一个拷贝。赋值过程结束后再修改`currentDirection`的值并不影响`rememberedDirection`所储存的原始值(value)的拷贝。 @@ -176,25 +194,31 @@ Swift 中类和结构体有很多共同点。共同处在于: 请看下面这个示例,其使用了之前定义的`VideoMode`类: - let tenEighty = VideoMode() - tenEighty.resolution = hd - tenEighty.interlaced = true - tenEighty.name = "1080i" - tenEighty.frameRate = 25.0 +```swift +let tenEighty = VideoMode() +tenEighty.resolution = hd +tenEighty.interlaced = true +tenEighty.name = "1080i" +tenEighty.frameRate = 25.0 +``` 以上示例中,声明了一个名为`tenEighty`的常量,其引用了一个`VideoMode`类的新实例。在之前的示例中,这个视频模式(video mode)被赋予了HD分辨率(1920*1080)的一个拷贝(`hd`)。同时设置为交错(interlaced),命名为`“1080i”`。最后,其帧率是`25.0`帧每秒。 然后,`tenEighty` 被赋予名为`alsoTenEighty`的新常量,同时对`alsoTenEighty`的帧率进行修改: - let alsoTenEighty = tenEighty - alsoTenEighty.frameRate = 30.0 +```swift +let alsoTenEighty = tenEighty +alsoTenEighty.frameRate = 30.0 +``` 因为类是引用类型,所以`tenEight`和`alsoTenEight`实际上引用的是相同的`VideoMode`实例。换句话说,它们只是同一个实例的两种叫法。 下面,通过查看`tenEighty`的`frameRate`属性,我们会发现它正确的显示了基本`VideoMode`实例的新帧率,其值为`30.0`: - println("The frameRate property of tenEighty is now \(tenEighty.frameRate)") - // 输出 "The frameRate property of theEighty is now 30.0" +```swift +println("The frameRate property of tenEighty is now \(tenEighty.frameRate)") +// 输出 "The frameRate property of theEighty is now 30.0" +``` 需要注意的是`tenEighty`和`alsoTenEighty`被声明为*常量((constants)*而不是变量。然而你依然可以改变`tenEighty.frameRate`和`alsoTenEighty.frameRate`,因为这两个常量本身不会改变。它们并不`储存`这个`VideoMode`实例,在后台仅仅是对`VideoMode`实例的引用。所以,改变的是被引用的基础`VideoMode`的`frameRate`参数,而不改变常量的值。 @@ -209,10 +233,12 @@ Swift 中类和结构体有很多共同点。共同处在于: 以下是运用这两个运算符检测两个常量或者变量是否引用同一个实例: - if tenEighty === alsoTenTighty { - println("tenTighty and alsoTenEighty refer to the same Resolution instance.") - } - //输出 "tenEighty and alsoTenEighty refer to the same Resolution instance." +```swift +if tenEighty === alsoTenTighty { + println("tenTighty and alsoTenEighty refer to the same Resolution instance.") +} +//输出 "tenEighty and alsoTenEighty refer to the same Resolution instance." +``` 请注意“等价于”(用三个等号表示,===) 与“等于”(用两个等号表示,==)的不同: @@ -251,8 +277,7 @@ Swift 中`数组(Array)`和`字典(Dictionary)`类型均以结构体的 以下对`数组`和`结构体`的行为描述与对`NSArray`和`NSDictionary`的行为描述在本质上不同,后者是以类的形式实现,前者是以结构体的形式实现。`NSArray`和`NSDictionary`实例总是以对已有实例引用,而不是拷贝的方式被赋值和传递。 -> 注意: -> +> 注意: 以下是对于数组,字典,字符串和其它值的`拷贝`的描述。 在你的代码中,拷贝好像是确实是在有拷贝行为的地方产生过。然而,在 Swift 的后台中,只有确有必要,`实际(actual)`拷贝才会被执行。Swift 管理所有的值拷贝以确保性能最优化的性能,所以你也没有必要去避免赋值以保证最优性能。(实际赋值由系统管理优化) @@ -263,16 +288,20 @@ Swift 中`数组(Array)`和`字典(Dictionary)`类型均以结构体的 下面的示例定义了一个名为`ages`的字典,其中储存了四个人的名字和年龄。`ages`字典被赋予了一个名为`copiedAges`的新变量,同时`ages`在赋值的过程中被拷贝。赋值结束后,`ages`和`copiedAges`成为两个相互独立的字典。 - var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19] - var copiedAges = ages +```swift +var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19] +var copiedAges = ages +``` 这个字典的键(keys)是`字符串(String)`类型,值(values)是`整(Int)`类型。这两种类型在Swift 中都是值类型(value types),所以当字典被拷贝时,两者都会被拷贝。 我们可以通过改变一个字典中的年龄值(age value),检查另一个字典中所对应的值,来证明`ages`字典确实是被拷贝了。如果在`copiedAges`字典中将`Peter`的值设为`24`,那么`ages`字典仍然会返回修改前的值`23`: - copiedAges["Peter"] = 24 - println(ages["Peter"]) - // 输出 "23" +```swift +copiedAges["Peter"] = 24 +println(ages["Peter"]) +// 输出 "23" +``` ### 数组的赋值和拷贝行为 @@ -284,42 +313,50 @@ Swift 中`数组(Array)`和`字典(Dictionary)`类型均以结构体的 下面的示例将一个`整数(Int)`数组赋给了一个名为`a`的变量,继而又被赋给了变量`b`和`c`: - var a = [1, 2, 3] - var b = a - var c = a +```swift +var a = [1, 2, 3] +var b = a +var c = a +``` 我们可以在`a`,`b`,`c`上使用下标语法以得到数组的第一个元素: - println(a[0]) - // 1 - println(b[0]) - // 1 - println(c[0]) - // 1 +```swift +println(a[0]) +// 1 +println(b[0]) +// 1 +println(c[0]) +// 1 +``` 如果通过下标语法修改数组中某一元素的值,那么`a`,`b`,`c`中的相应值都会发生改变。请注意当你用下标语法修改某一值时,并没有拷贝行为伴随发生,因为下表语法修改值时没有改变数组长度的可能: - a[0] = 42 - println(a[0]) - // 42 - println(b[0]) - // 42 - println(c[0]) - // 42 +```swift +a[0] = 42 +println(a[0]) +// 42 +println(b[0]) +// 42 +println(c[0]) +// 42 +``` 然而,当你给`a`附加新元素时,数组的长度`会`改变。 当附加元素这一事件发生时,Swift 会创建这个数组的一个拷贝。从此以后,`a`将会是原数组的一个独立拷贝。 拷贝发生后,如果再修改`a`中元素值的话,`a`将会返回与`b`,`c`不同的结果,因为后两者引用的是原来的数组: - a.append(4) - a[0] = 777 - println(a[0]) - // 777 - println(b[0]) - // 42 - println(c[0]) - // 42 +```swift +a.append(4) +a[0] = 777 +println(a[0]) +// 777 +println(b[0]) +// 42 +println(c[0]) +// 42 +``` ### 确保数组的唯一性 在操作一个数组,或将其传递给函数以及方法调用之前是很有必要先确定这个数组是有一个唯一拷贝的。通过在数组变量上调用`unshare`方法来确定数组引用的唯一性。(当数组赋给常量时,不能调用`unshare`方法) @@ -328,17 +365,21 @@ Swift 中`数组(Array)`和`字典(Dictionary)`类型均以结构体的 在上一个示例的最后,`b`和`c`都引用了同一个数组。此时在`b`上调用`unshare`方法则会将`b`变成一个唯一个拷贝: - b.unshare() +```swift +b.unshare() +``` 在`unshare`方法调用后再修改`b`中第一个元素的值,这三个数组(`a`,`b`,`c`)会返回不同的三个值: - b[0] = -105 - println(a[0]) - // 77 - println(b[0]) - // -105 - println(c[0]) - // 42 +```swift +b[0] = -105 +println(a[0]) +// 77 +println(b[0]) +// -105 +println(c[0]) +// 42 +``` ### 判定两个数组是否共用相同元素 @@ -347,22 +388,28 @@ Swift 中`数组(Array)`和`字典(Dictionary)`类型均以结构体的 下面这个示例使用了“等同(identical to)” 运算符(===) 来判定`b`和`c`是否共用相同的数组元素: - if b === c { - println("b and c still share the same array elements.") - } else { - println("b and c now refer to two independent sets of array elements.") - } +```swift +if b === c { + println("b and c still share the same array elements.") +} else { + println("b and c now refer to two independent sets of array elements.") +} +``` - // 输出 "b and c now refer totwo independent sets of array elements." +```swift +// 输出 "b and c now refer totwo independent sets of array elements." +``` 此外,我们还可以使用恒等运算符来判定两个子数组是否共用相同的元素。下面这个示例中,比较了`b`的两个相等的子数组,并且确定了这两个子数组都引用相同的元素: - if b[0...1] === b[0...1] { - println("These two subarrays share the same elements.") - } else { - println("These two subarrays do not share the same elements.") - } - // 输出 "These two subarrays share the same elements." +```swift +if b[0...1] === b[0...1] { + println("These two subarrays share the same elements.") +} else { + println("These two subarrays do not share the same elements.") +} +// 输出 "These two subarrays share the same elements." +``` ### 强制复制数组 @@ -370,15 +417,19 @@ Swift 中`数组(Array)`和`字典(Dictionary)`类型均以结构体的 下面这个示例中定义了一个`names`数组,其包含了七个人名。还定义了一个`copiedNames`变量,用以储存在`names`上调用`copy`方法所返回的结果: - var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"] - var copiedNames = names.copy() +```swift +var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"] +var copiedNames = names.copy() +``` 我们可以通过修改一个数组中某元素,并且检查另一个数组中对应元素的方法来判定`names`数组确已被复制。如果你将`copiedNames`中第一个元素从"`Mohsen`"修改为"`Mo`",则`names`数组返回的仍是拷贝发生前的"`Mohsen`": - copiedName[0] = "Mo" - println(name[0]) - // 输出 "Mohsen" +```swift +copiedName[0] = "Mo" +println(name[0]) +// 输出 "Mohsen" +``` -> 注意: -> +> 注意: 如果你仅需要确保你对数组的引用是唯一引用,请调用`unshare`方法,而不是`copy`方法。`unshare`方法仅会在确有必要时才会创建数组拷贝。`copy`方法会在任何时候都创建一个新的拷贝,即使引用已经是唯一引用。 + From 62edf92aeab868979a16a671e80591d1e3b2525f Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:39:24 +0800 Subject: [PATCH 17/24] fix 2.9 classes and structures --- source/chapter2/10_Properties.md | 98 ++++++++++++-------------------- 1 file changed, 37 insertions(+), 61 deletions(-) diff --git a/source/chapter2/10_Properties.md b/source/chapter2/10_Properties.md index 7dbeb082..6d4d1ffa 100644 --- a/source/chapter2/10_Properties.md +++ b/source/chapter2/10_Properties.md @@ -1,9 +1,7 @@ -> 翻译:shinyzhu - -> 校对:pp-prog +> 翻译:shinyzhu +> 校对:pp-prog # 属性 (Properties) - --- 本页包含内容: @@ -29,7 +27,7 @@ 下面的例子定义了一个名为`FixedLengthRange`的结构体,他描述了一个在创建后无法修改值域宽度的区间: -``` +```swift struct FixedLengthRange { var firstValue: Int let length: Int @@ -38,7 +36,6 @@ var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3) // 该区间表示整数0,1,2 rangeOfThreeItems.firstValue = 6 // 该区间现在表示整数6,7,8 - ``` `FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。 @@ -48,12 +45,11 @@ rangeOfThreeItems.firstValue = 6 如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性: -``` +```swift let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) // 该区间表示整数0,1,2,3 rangeOfFourItems.firstValue = 6 // 尽管 firstValue 是个变量属性,这里还是会报错 - ``` 因为`rangeOfFourItems`声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。 @@ -67,15 +63,14 @@ rangeOfFourItems.firstValue = 6 延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用`@lazy`来标示一个延迟存储属性。 -> 注意: -> -> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。 +> 注意: +> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。 延迟属性很有用,当属性的值依赖于在实例的构造过程结束前无法知道具体值的外部因素时,或者当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它。 下面的例子使用了延迟存储属性来避免复杂类的不必要的初始化。例子中定义了`DataImporter`和`DataManager`两个类,下面是部分代码: -``` +```swift class DataImporter { /* DataImporter 是一个将外部文件中的数据导入的类。 @@ -95,7 +90,6 @@ let manager = DataManager() manager.data += "Some data" manager.data += "Some more data" // DataImporter 实例的 importer 属性还没有被创建 - ``` `DataManager`类包含一个名为`data`的存储属性,初始值是一个空的字符串(`String`)数组。虽然没有写出全部代码,`DataManager`类的目的是管理和提供对这个字符串数组的访问。 @@ -106,12 +100,12 @@ manager.data += "Some more data" 由于使用了`@lazy`,`importer`属性只有在第一次被访问的时候才被创建。比如访问它的属性`fileName`时: -``` +```swift println(manager.importer.fileName) // DataImporter 实例的 importer 属性现在被创建了 // 输出 "data.txt” - ``` + ### 存储属性和实例变量 @@ -125,7 +119,7 @@ Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属 除存储属性外,类、结构体和枚举可以定义*计算属性*,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。 -``` +```swift struct Point { var x = 0.0, y = 0.0 } @@ -153,7 +147,6 @@ let initialSquareCenter = square.center square.center = Point(x: 15.0, y: 15.0) println("square.origin is now at (\(square.origin.x), \(square.origin.y))") // 输出 "square.origin is now at (10.0, 10.0)” - ``` 这个例子定义了 3 个几何形状的结构体: @@ -177,7 +170,7 @@ println("square.origin is now at (\(square.origin.x), \(square.origin.y))") 如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称`newValue`。下面是使用了便捷 setter 声明的`Rect`结构体代码: -``` +```swift struct AlternativeRect { var origin = Point() var size = Size() @@ -193,20 +186,19 @@ struct AlternativeRect { } } } - ``` + ### 只读计算属性 只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。 -> 注意: -> -> 必须使用`var`关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。 +> 注意: +> 必须使用`var`关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。 只读计算属性的声明可以去掉`get`关键字和花括号: -``` +```swift struct Cuboid { var width = 0.0, height = 0.0, depth = 0.0 var volume: Double { @@ -216,7 +208,6 @@ struct Cuboid { let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0) println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") // 输出 "the volume of fourByFiveByTwo is 40.0" - ``` 这个例子定义了一个名为`Cuboid`的结构体,表示三维空间的立方体,包含`width`、`height`和`depth`属性,还有一个名为`volume`的只读计算属性用来返回立方体的体积。设置`volume`的值毫无意义,因为通过`width`、`height`和`depth`就能算出`volume`。然而,`Cuboid`提供一个只读计算属性来让外部用户直接获取体积是很有用的。 @@ -228,9 +219,8 @@ println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") 可以为除了延迟存储属性之外的其他存储属性添加属性监视器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性监视器。属性重载请参考[继承](chapter/13_Inheritance.html)一章的[重载](chapter/13_Inheritance.html#overriding)。 -> 注意: -> -> 不需要为无法重载的计算属性添加属性监视器,因为可以通过 setter 直接监控和响应值的变化。 +> 注意: +> 不需要为无法重载的计算属性添加属性监视器,因为可以通过 setter 直接监控和响应值的变化。 可以为属性添加如下的一个或全部监视器: @@ -241,13 +231,12 @@ println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") 类似地,`didSet`监视器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名`oldValue`。 -> 注意: -> -> `willSet`和`didSet`监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。 +> 注意: +> `willSet`和`didSet`监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。 这里是一个`willSet`和`didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数,可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。 -``` +```swift class StepCounter { var totalSteps: Int = 0 { willSet(newTotalSteps) { @@ -270,7 +259,6 @@ stepCounter.totalSteps = 360 stepCounter.totalSteps = 896 // About to set totalSteps to 896 // Added 536 steps - ``` `StepCounter`类定义了一个`Int`类型的属性`totalSteps`,它是一个存储属性,包含`willSet`和`didSet`监视器。 @@ -281,9 +269,8 @@ stepCounter.totalSteps = 896 `didSet`监视器在`totalSteps`的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。`didSet`没有提供自定义名称,所以默认值`oldValue`表示旧值的参数名。 -> 注意: -> -> 如果在`didSet`监视器里为属性赋值,这个值会替换监视器之前设置的值。 +> 注意: +> 如果在`didSet`监视器里为属性赋值,这个值会替换监视器之前设置的值。 ##全局变量和局部变量 @@ -294,11 +281,9 @@ stepCounter.totalSteps = 896 另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义监视器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。 -> 注意: -> -> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`@lazy`特性。 -> -> 局部范围的常量或变量不会延迟计算。 +> 注意: +> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`@lazy`特性。 +> 局部范围的常量或变量不会延迟计算。 ##类型属性 @@ -313,9 +298,8 @@ stepCounter.totalSteps = 896 值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性。 -> 注意: -> -> 跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。 +> 注意: +> 跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。 ###类型属性语法 @@ -324,7 +308,7 @@ stepCounter.totalSteps = 896 使用关键字`static`来定义值类型的类型属性,关键字`class`来为类(class)定义类型属性。下面的例子演示了存储型和计算型类型属性的语法: -``` +```swift struct SomeStructure { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { @@ -342,19 +326,17 @@ class SomeClass { // 这里返回一个 Int 值 } } - ``` -> 注意: -> -> 例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。 +> 注意: +> 例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。 ###获取和设置类型属性的值 跟实例的属性一样,类型属性的访问也是通过点运算符来进行,但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如: -``` +```swift println(SomeClass.computedTypeProperty) // 输出 "42" @@ -363,7 +345,6 @@ println(SomeStructure.storedTypeProperty) SomeStructure.storedTypeProperty = "Another value." println(SomeStructure.storedTypeProperty) // 输出 "Another value.” - ``` 下面的例子定义了一个结构体,使用两个存储型类型属性来表示多个声道的声音电平值,每个声道有一个 0 到 10 之间的整数表示声音电平值。 @@ -374,7 +355,7 @@ println(SomeStructure.storedTypeProperty) 上面所描述的声道模型使用`AudioChannel`结构体来表示: -``` +```swift struct AudioChannel { static let thresholdLevel = 10 static var maxInputLevelForAllChannels = 0 @@ -391,7 +372,6 @@ struct AudioChannel { } } } - ``` 结构`AudioChannel`定义了 2 个存储型类型属性来实现上述功能。第一个是`thresholdLevel`,表示声音电平的最大上限阈值,它是一个取值为 10 的常量,对所有实例都可见,如果声音电平高于 10,则取最大上限值 10(见后面描述)。 @@ -405,36 +385,32 @@ struct AudioChannel { - 如果`currentLevel`的新值大于允许的阈值`thresholdLevel`,属性监视器将`currentLevel`的值限定为阈值`thresholdLevel`。 - 如果修正后的`currentLevel`值大于任何之前任意`AudioChannel`实例中的值,属性监视器将新值保存在静态属性`maxInputLevelForAllChannels`中。 -> 注意: -> -> 在第一个检查过程中,`didSet`属性监视器将`currentLevel`设置成了不同的值,但这时不会再次调用属性监视器。 +> 注意: +> 在第一个检查过程中,`didSet`属性监视器将`currentLevel`设置成了不同的值,但这时不会再次调用属性监视器。 可以使用结构体`AudioChannel`来创建表示立体声系统的两个声道`leftChannel`和`rightChannel`: -``` +```swift var leftChannel = AudioChannel() var rightChannel = AudioChannel() - ``` 如果将左声道的电平设置成 7,类型属性`maxInputLevelForAllChannels`也会更新成 7: -``` +```swift leftChannel.currentLevel = 7 println(leftChannel.currentLevel) // 输出 "7" println(AudioChannel.maxInputLevelForAllChannels) // 输出 "7" - ``` 如果试图将右声道的电平设置成 11,则会将右声道的`currentLevel`修正到最大值 10,同时`maxInputLevelForAllChannels`的值也会更新到 10: -``` +```swift rightChannel.currentLevel = 11 println(rightChannel.currentLevel) // 输出 "10" println(AudioChannel.maxInputLevelForAllChannels) // 输出 "10" - ``` From bd7ae8ef6ea9e6013004e2d283f19cac256a208e Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:39:24 +0800 Subject: [PATCH 18/24] fix 2.10 properties --- source/chapter2/10_Properties.md | 98 ++++++++++++-------------------- 1 file changed, 37 insertions(+), 61 deletions(-) diff --git a/source/chapter2/10_Properties.md b/source/chapter2/10_Properties.md index 7dbeb082..6d4d1ffa 100644 --- a/source/chapter2/10_Properties.md +++ b/source/chapter2/10_Properties.md @@ -1,9 +1,7 @@ -> 翻译:shinyzhu - -> 校对:pp-prog +> 翻译:shinyzhu +> 校对:pp-prog # 属性 (Properties) - --- 本页包含内容: @@ -29,7 +27,7 @@ 下面的例子定义了一个名为`FixedLengthRange`的结构体,他描述了一个在创建后无法修改值域宽度的区间: -``` +```swift struct FixedLengthRange { var firstValue: Int let length: Int @@ -38,7 +36,6 @@ var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3) // 该区间表示整数0,1,2 rangeOfThreeItems.firstValue = 6 // 该区间现在表示整数6,7,8 - ``` `FixedLengthRange`的实例包含一个名为`firstValue`的变量存储属性和一个名为`length`的常量存储属性。在上面的例子中,`length`在创建实例的时候被赋值,因为它是一个常量存储属性,所以之后无法修改它的值。 @@ -48,12 +45,11 @@ rangeOfThreeItems.firstValue = 6 如果创建了一个结构体的实例并赋值给一个常量,则无法修改实例的任何属性,即使定义了变量存储属性: -``` +```swift let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) // 该区间表示整数0,1,2,3 rangeOfFourItems.firstValue = 6 // 尽管 firstValue 是个变量属性,这里还是会报错 - ``` 因为`rangeOfFourItems`声明成了常量(用`let`关键字),即使`firstValue`是一个变量属性,也无法再修改它了。 @@ -67,15 +63,14 @@ rangeOfFourItems.firstValue = 6 延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用`@lazy`来标示一个延迟存储属性。 -> 注意: -> -> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。 +> 注意: +> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。 延迟属性很有用,当属性的值依赖于在实例的构造过程结束前无法知道具体值的外部因素时,或者当属性的值需要复杂或大量计算时,可以只在需要的时候来计算它。 下面的例子使用了延迟存储属性来避免复杂类的不必要的初始化。例子中定义了`DataImporter`和`DataManager`两个类,下面是部分代码: -``` +```swift class DataImporter { /* DataImporter 是一个将外部文件中的数据导入的类。 @@ -95,7 +90,6 @@ let manager = DataManager() manager.data += "Some data" manager.data += "Some more data" // DataImporter 实例的 importer 属性还没有被创建 - ``` `DataManager`类包含一个名为`data`的存储属性,初始值是一个空的字符串(`String`)数组。虽然没有写出全部代码,`DataManager`类的目的是管理和提供对这个字符串数组的访问。 @@ -106,12 +100,12 @@ manager.data += "Some more data" 由于使用了`@lazy`,`importer`属性只有在第一次被访问的时候才被创建。比如访问它的属性`fileName`时: -``` +```swift println(manager.importer.fileName) // DataImporter 实例的 importer 属性现在被创建了 // 输出 "data.txt” - ``` + ### 存储属性和实例变量 @@ -125,7 +119,7 @@ Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属 除存储属性外,类、结构体和枚举可以定义*计算属性*,计算属性不直接存储值,而是提供一个 getter 来获取值,一个可选的 setter 来间接设置其他属性或变量的值。 -``` +```swift struct Point { var x = 0.0, y = 0.0 } @@ -153,7 +147,6 @@ let initialSquareCenter = square.center square.center = Point(x: 15.0, y: 15.0) println("square.origin is now at (\(square.origin.x), \(square.origin.y))") // 输出 "square.origin is now at (10.0, 10.0)” - ``` 这个例子定义了 3 个几何形状的结构体: @@ -177,7 +170,7 @@ println("square.origin is now at (\(square.origin.x), \(square.origin.y))") 如果计算属性的 setter 没有定义表示新值的参数名,则可以使用默认名称`newValue`。下面是使用了便捷 setter 声明的`Rect`结构体代码: -``` +```swift struct AlternativeRect { var origin = Point() var size = Size() @@ -193,20 +186,19 @@ struct AlternativeRect { } } } - ``` + ### 只读计算属性 只有 getter 没有 setter 的计算属性就是*只读计算属性*。只读计算属性总是返回一个值,可以通过点运算符访问,但不能设置新的值。 -> 注意: -> -> 必须使用`var`关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。 +> 注意: +> 必须使用`var`关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。`let`关键字只用来声明常量属性,表示初始化后再也无法修改的值。 只读计算属性的声明可以去掉`get`关键字和花括号: -``` +```swift struct Cuboid { var width = 0.0, height = 0.0, depth = 0.0 var volume: Double { @@ -216,7 +208,6 @@ struct Cuboid { let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0) println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") // 输出 "the volume of fourByFiveByTwo is 40.0" - ``` 这个例子定义了一个名为`Cuboid`的结构体,表示三维空间的立方体,包含`width`、`height`和`depth`属性,还有一个名为`volume`的只读计算属性用来返回立方体的体积。设置`volume`的值毫无意义,因为通过`width`、`height`和`depth`就能算出`volume`。然而,`Cuboid`提供一个只读计算属性来让外部用户直接获取体积是很有用的。 @@ -228,9 +219,8 @@ println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") 可以为除了延迟存储属性之外的其他存储属性添加属性监视器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性监视器。属性重载请参考[继承](chapter/13_Inheritance.html)一章的[重载](chapter/13_Inheritance.html#overriding)。 -> 注意: -> -> 不需要为无法重载的计算属性添加属性监视器,因为可以通过 setter 直接监控和响应值的变化。 +> 注意: +> 不需要为无法重载的计算属性添加属性监视器,因为可以通过 setter 直接监控和响应值的变化。 可以为属性添加如下的一个或全部监视器: @@ -241,13 +231,12 @@ println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") 类似地,`didSet`监视器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名`oldValue`。 -> 注意: -> -> `willSet`和`didSet`监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。 +> 注意: +> `willSet`和`didSet`监视器在属性初始化过程中不会被调用,他们只会当属性的值在初始化之外的地方被设置时被调用。 这里是一个`willSet`和`didSet`的实际例子,其中定义了一个名为`StepCounter`的类,用来统计当人步行时的总步数,可以跟计步器或其他日常锻炼的统计装置的输入数据配合使用。 -``` +```swift class StepCounter { var totalSteps: Int = 0 { willSet(newTotalSteps) { @@ -270,7 +259,6 @@ stepCounter.totalSteps = 360 stepCounter.totalSteps = 896 // About to set totalSteps to 896 // Added 536 steps - ``` `StepCounter`类定义了一个`Int`类型的属性`totalSteps`,它是一个存储属性,包含`willSet`和`didSet`监视器。 @@ -281,9 +269,8 @@ stepCounter.totalSteps = 896 `didSet`监视器在`totalSteps`的值改变后被调用,它把新的值和旧的值进行对比,如果总的步数增加了,就输出一个消息表示增加了多少步。`didSet`没有提供自定义名称,所以默认值`oldValue`表示旧值的参数名。 -> 注意: -> -> 如果在`didSet`监视器里为属性赋值,这个值会替换监视器之前设置的值。 +> 注意: +> 如果在`didSet`监视器里为属性赋值,这个值会替换监视器之前设置的值。 ##全局变量和局部变量 @@ -294,11 +281,9 @@ stepCounter.totalSteps = 896 另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义监视器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。 -> 注意: -> -> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`@lazy`特性。 -> -> 局部范围的常量或变量不会延迟计算。 +> 注意: +> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`@lazy`特性。 +> 局部范围的常量或变量不会延迟计算。 ##类型属性 @@ -313,9 +298,8 @@ stepCounter.totalSteps = 896 值类型的存储型类型属性可以是变量或常量,计算型类型属性跟实例的计算属性一样定义成变量属性。 -> 注意: -> -> 跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。 +> 注意: +> 跟实例的存储属性不同,必须给存储型类型属性指定默认值,因为类型本身无法在初始化过程中使用构造器给类型属性赋值。 ###类型属性语法 @@ -324,7 +308,7 @@ stepCounter.totalSteps = 896 使用关键字`static`来定义值类型的类型属性,关键字`class`来为类(class)定义类型属性。下面的例子演示了存储型和计算型类型属性的语法: -``` +```swift struct SomeStructure { static var storedTypeProperty = "Some value." static var computedTypeProperty: Int { @@ -342,19 +326,17 @@ class SomeClass { // 这里返回一个 Int 值 } } - ``` -> 注意: -> -> 例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。 +> 注意: +> 例子中的计算型类型属性是只读的,但也可以定义可读可写的计算型类型属性,跟实例计算属性的语法类似。 ###获取和设置类型属性的值 跟实例的属性一样,类型属性的访问也是通过点运算符来进行,但是,类型属性是通过类型本身来获取和设置,而不是通过实例。比如: -``` +```swift println(SomeClass.computedTypeProperty) // 输出 "42" @@ -363,7 +345,6 @@ println(SomeStructure.storedTypeProperty) SomeStructure.storedTypeProperty = "Another value." println(SomeStructure.storedTypeProperty) // 输出 "Another value.” - ``` 下面的例子定义了一个结构体,使用两个存储型类型属性来表示多个声道的声音电平值,每个声道有一个 0 到 10 之间的整数表示声音电平值。 @@ -374,7 +355,7 @@ println(SomeStructure.storedTypeProperty) 上面所描述的声道模型使用`AudioChannel`结构体来表示: -``` +```swift struct AudioChannel { static let thresholdLevel = 10 static var maxInputLevelForAllChannels = 0 @@ -391,7 +372,6 @@ struct AudioChannel { } } } - ``` 结构`AudioChannel`定义了 2 个存储型类型属性来实现上述功能。第一个是`thresholdLevel`,表示声音电平的最大上限阈值,它是一个取值为 10 的常量,对所有实例都可见,如果声音电平高于 10,则取最大上限值 10(见后面描述)。 @@ -405,36 +385,32 @@ struct AudioChannel { - 如果`currentLevel`的新值大于允许的阈值`thresholdLevel`,属性监视器将`currentLevel`的值限定为阈值`thresholdLevel`。 - 如果修正后的`currentLevel`值大于任何之前任意`AudioChannel`实例中的值,属性监视器将新值保存在静态属性`maxInputLevelForAllChannels`中。 -> 注意: -> -> 在第一个检查过程中,`didSet`属性监视器将`currentLevel`设置成了不同的值,但这时不会再次调用属性监视器。 +> 注意: +> 在第一个检查过程中,`didSet`属性监视器将`currentLevel`设置成了不同的值,但这时不会再次调用属性监视器。 可以使用结构体`AudioChannel`来创建表示立体声系统的两个声道`leftChannel`和`rightChannel`: -``` +```swift var leftChannel = AudioChannel() var rightChannel = AudioChannel() - ``` 如果将左声道的电平设置成 7,类型属性`maxInputLevelForAllChannels`也会更新成 7: -``` +```swift leftChannel.currentLevel = 7 println(leftChannel.currentLevel) // 输出 "7" println(AudioChannel.maxInputLevelForAllChannels) // 输出 "7" - ``` 如果试图将右声道的电平设置成 11,则会将右声道的`currentLevel`修正到最大值 10,同时`maxInputLevelForAllChannels`的值也会更新到 10: -``` +```swift rightChannel.currentLevel = 11 println(rightChannel.currentLevel) // 输出 "10" println(AudioChannel.maxInputLevelForAllChannels) // 输出 "10" - ``` From 3aeba381d7eb0d44ef7d110e403a6459c06b795a Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:48:50 +0800 Subject: [PATCH 19/24] fix 2.11 methods --- source/chapter2/11_Methods.md | 61 +++++++++++++++++------------------ 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/source/chapter2/11_Methods.md b/source/chapter2/11_Methods.md index 6ddeb02c..059ac4c1 100644 --- a/source/chapter2/11_Methods.md +++ b/source/chapter2/11_Methods.md @@ -1,15 +1,13 @@ -> 翻译:pp-prog - -> 校对:zqp +> 翻译:pp-prog +> 校对:zqp # 方法(Methods) ----------------- - 本页包含内容: -- [实例方法(Instance Methods](#instance_methods) -- [类型方法(Type Methods)](#type_methods) +- [实例方法(Instance Methods](#instance_methods) +- [类型方法(Type Methods)](#type_methods) **方法**是与某些特定类型相关联的函数。类、结构体、枚举都可以定义实例方法;实例方法为给定类型的实例封装了具体的任务与功能。类、结构体、枚举也可以定义类型方法;类型方法与类型本身相关联。类型方法与 Objective-C 中的类方法(class methods)相似。 @@ -24,7 +22,7 @@ 下面的例子,定义一个很简单的类`Counter`,`Counter`能被用来对一个动作发生的次数进行计数: -``` +```swift class Counter { var count = 0 func increment() { @@ -48,7 +46,7 @@ class Counter { 和调用属性一样,用点语法(dot syntax)调用实例方法: -``` +```swift let counter = Counter() // 初始计数值是0 counter.increment() @@ -58,6 +56,7 @@ class Counter { counter.reset() // 计数值现在是0 ``` + ### 方法的局部参数名称和外部参数名称(Local and External Parameter Names for Methods) @@ -69,7 +68,7 @@ Swift 中的方法和 Objective-C 中的方法极其相似。像在 Objective-C 看看下面这个`Counter`的另一个版本(它定义了一个更复杂的`incrementBy`方法): -``` +```swift class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes: Int) { @@ -80,7 +79,7 @@ class Counter { `incrementBy`方法有两个参数: `amount`和`numberOfTimes`。默认情况下,Swift 只把`amount`当作一个局部名称,但是把`numberOfTimes`即看作局部名称又看作外部名称。下面调用这个方法: -``` +```swift let counter = Counter() counter.incrementBy(5, numberOfTimes: 3) // counter value is now 15 @@ -90,9 +89,9 @@ counter.incrementBy(5, numberOfTimes: 3) 这种默认的行为能够有效的处理方法(method),类似于在参数`numberOfTimes`前写一个井号(`#`): -``` +```swift func incrementBy(amount: Int, #numberOfTimes: Int) { - count += amount * numberOfTimes + count += amount * numberOfTimes } ``` @@ -111,7 +110,8 @@ func incrementBy(amount: Int, #numberOfTimes: Int) { 类型的每一个实例都有一个隐含属性叫做`self`,`self`完全等同于该实例本身。你可以在一个实例的实例方法中使用这个隐含的`self`属性来引用当前实例。 上面例子中的`increment`方法还可以这样写: -``` + +```swift func increment() { self.count++ } @@ -123,7 +123,7 @@ func increment() { 下面的例子中,`self`消除方法参数`x`和实例属性`x`之间的歧义: -``` +```swift struct Point { var x = 0.0, y = 0.0 func isToTheRightOfX(x: Double) -> Bool { @@ -148,7 +148,7 @@ if somePoint.isToTheRightOfX(1.0) { 要使用`变异`方法, 将关键字`mutating` 放到方法的`func`关键字之前就可以了: -``` +```swift struct Point { var x = 0.0, y = 0.0 mutating func moveByX(deltaX: Double, y deltaY: Double) { @@ -166,17 +166,18 @@ println("The point is now at (\(somePoint.x), \(somePoint.y))") 注意:不能在结构体类型常量上调用变异方法,因为常量的属性不能被改变,即使想改变的是常量的变量属性也不行,详情参见[存储属性和实例变量]("10_Properties.html") -``` +```swift let fixedPoint = Point(x: 3.0, y: 3.0) fixedPoint.moveByX(2.0, y: 3.0) // this will report an error ``` + ### 在变异方法中给self赋值(Assigning to self Within a Mutating Method) 变异方法能够赋给隐含属性`self`一个全新的实例。上面`Point`的例子可以用下面的方式改写: -``` +```swift struct Point { var x = 0.0, y = 0.0 mutating func moveByX(deltaX: Double, y deltaY: Double) { @@ -189,7 +190,7 @@ struct Point { 枚举的变异方法可以把`self`设置为相同的枚举类型中不同的成员: -``` +```swift enum TriStateSwitch { case Off, Low, High mutating func next() { @@ -217,13 +218,12 @@ ovenLight.next() 实例方法是被类型的某个实例调用的方法。你也可以定义类型本身调用的方法,这种方法就叫做**类型方法**。声明类的类型方法,在方法的`func`关键字之前加上关键字`class`;声明结构体和枚举的类型方法,在方法的`func`关键字之前加上关键字`static`。 -> 注意: - -> 在 Objective-C 里面,你只能为 Objective-C 的类定义类型方法(type-level methods)。在 Swift 中,你可以为所有的类、结构体和枚举定义类型方法:每一个类型方法都被它所支持的类型显式包含。 +> 注意: +> 在 Objective-C 里面,你只能为 Objective-C 的类定义类型方法(type-level methods)。在 Swift 中,你可以为所有的类、结构体和枚举定义类型方法:每一个类型方法都被它所支持的类型显式包含。 类型方法和实例方法一样用点语法调用。但是,你是在类型层面上调用这个方法,而不是在实例层面上调用。下面是如何在`SomeClass`类上调用类型方法的例子: -``` +```swift class SomeClass { class func someTypeMethod() { // type method implementation goes here @@ -240,7 +240,7 @@ SomeClass.someTypeMethod() 游戏初始时,所有的游戏等级(除了等级 1)都被锁定。每次有玩家完成一个等级,这个等级就对这个设备上的所有玩家解锁。`LevelTracker`结构体用静态属性和方法监测游戏的哪个等级已经被解锁。它还监测每个玩家的当前等级。 -``` +```swift struct LevelTracker { static var highestUnlockedLevel = 1 static func unlockLevel(level: Int) { @@ -271,7 +271,7 @@ struct LevelTracker { 下面,`Player`类使用`LevelTracker`来监测和更新每个玩家的发展进度: -``` +```swift class Player { var tracker = LevelTracker() let playerName: String @@ -289,22 +289,21 @@ class Player { 你还可以为一个新的玩家创建一个`Player`的实例,然后看这个玩家完成等级一时发生了什么: -``` +```swift var player = Player(name: "Argyrios") player.completedLevel(1) println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)") -// 输出 "highest unlocked level is now 2"(最高等级现在是2 -) +// 输出 "highest unlocked level is now 2"(最高等级现在是2) ``` 如果你创建了第二个玩家,并尝试让他开始一个没有被任何玩家解锁的等级,那么这次设置玩家当前等级的尝试将会失败: -``` +```swift player = Player(name: "Beto") if player.tracker.advanceToLevel(6) { -println("player is now on level 6") + println("player is now on level 6") } else { -println("level 6 has not yet been unlocked") + println("level 6 has not yet been unlocked") } // 输出 "level 6 has not yet been unlocked"(等级6还没被解锁) -``` +``` \ No newline at end of file From 4de16a1d896acaeffc9e1b034dfb15650639f6e9 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:51:36 +0800 Subject: [PATCH 20/24] fix 2.12 subscripts --- source/chapter2/12_Subscripts.md | 86 +++++++++++++++----------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/source/chapter2/12_Subscripts.md b/source/chapter2/12_Subscripts.md index 21af3d06..6449cb0e 100644 --- a/source/chapter2/12_Subscripts.md +++ b/source/chapter2/12_Subscripts.md @@ -1,6 +1,5 @@ -> 翻译:siemenliu - -> 校对:zq54zquan +> 翻译:siemenliu +> 校对:zq54zquan # 附属脚本(Subscripts) @@ -16,22 +15,22 @@ 对于同一个目标可以定义多个附属脚本,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。 -> 译者:这里附属脚本重载在本小节中原文并没有任何演示 +> 译者:这里附属脚本重载在本小节中原文并没有任何演示 ## 附属脚本语法 附属脚本允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例进行访问和赋值。语法类似于实例方法和计算型属性的混合。与定义实例方法类似,定义附属脚本使用`subscript`关键字,显式声明入参(一个或多个)和返回类型。与实例方法不同的是附属脚本可以设定为读写或只读。这种方式又有点像计算型属性的getter和setter: -``` +```swift subscript(index: Int) -> Int { - get { - // 返回与入参匹配的Int类型的值 - } + get { + // 返回与入参匹配的Int类型的值 + } - set(newValue) { - // 执行赋值操作 - } + set(newValue) { + // 执行赋值操作 + } } ``` @@ -39,20 +38,20 @@ subscript(index: Int) -> Int { 与只读计算型属性一样,可以直接将原本应该写在`get`代码块中的代码写在`subscript`中: -``` +```swift subscript(index: Int) -> Int { - // 返回与入参匹配的Int类型的值 + // 返回与入参匹配的Int类型的值 } ``` 下面代码演示了一个在`TimesTable`结构体中使用只读附属脚本的用法,该结构体用来展示传入整数的*n*倍。 -``` +```swift struct TimesTable { - let multiplier: Int - subscript(index: Int) -> Int { - return multiplier * index - } + let multiplier: Int + subscript(index: Int) -> Int { + return multiplier * index + } } let threeTimesTable = TimesTable(multiplier: 3) println("3的6倍是\(threeTimesTable[6])") @@ -63,9 +62,8 @@ println("3的6倍是\(threeTimesTable[6])") 你可以通过附属脚本来得到结果,比如`threeTimesTable[6]`。这条语句访问了`threeTimesTable`的第六个元素,返回`6`的`3`倍即`18`。 ->注意: -> -> `TimesTable`例子是基于一个固定的数学公式。它并不适合开放写权限来对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么附属脚本只定义为只读的原因。 +>注意: +> `TimesTable`例子是基于一个固定的数学公式。它并不适合开放写权限来对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么附属脚本只定义为只读的原因。 @@ -75,7 +73,7 @@ println("3的6倍是\(threeTimesTable[6])") 例如,Swift 的字典(Dictionary)实现了通过附属脚本来对其实例中存放的值进行存取操作。在附属脚本中使用和字典索引相同类型的值,并且把一个字典值类型的值赋值给这个附属脚本来为字典设值: -``` +```swift var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] numberOfLegs["bird"] = 2 ``` @@ -84,9 +82,8 @@ numberOfLegs["bird"] = 2 更多关于字典(Dictionary)附属脚本的信息请参考[读取和修改字典](../chapter2/04_Collection_Types.html) -> 注意: -> -> Swift 中字典的附属脚本实现中,在`get`部分返回值是`Int?`,上例中的`numberOfLegs`字典通过附属脚本返回的是一个`Int?`或者说“可选的int”,不是每个字典的索引都能得到一个整型值,对于没有设过值的索引的访问返回的结果就是`nil`;同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为`nil`即可。 +> 注意: +> Swift 中字典的附属脚本实现中,在`get`部分返回值是`Int?`,上例中的`numberOfLegs`字典通过附属脚本返回的是一个`Int?`或者说“可选的int”,不是每个字典的索引都能得到一个整型值,对于没有设过值的索引的访问返回的结果就是`nil`;同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为`nil`即可。 ## 附属脚本选项 @@ -97,16 +94,16 @@ numberOfLegs["bird"] = 2 一个附属脚本入参是最常见的情况,但只要有合适的场景也可以定义多个附属脚本入参。如下例定义了一个`Matrix`结构体,将呈现一个`Double`类型的二维矩阵。`Matrix`结构体的附属脚本需要两个整型参数: -``` +```swift struct Matrix { - let rows: Int, columns: Int - var grid: Double[] - init(rows: Int, columns: Int) { - self.rows = rows - self.columns = columns - grid = Array(count: rows * columns, repeatedValue: 0.0) - } - func indexIsValidForRow(row: Int, column: Int) -> Bool { + let rows: Int, columns: Int + var grid: Double[] + init(rows: Int, columns: Int) { + self.rows = rows + self.columns = columns + grid = Array(count: rows * columns, repeatedValue: 0.0) + } + func indexIsValidForRow(row: Int, column: Int) -> Bool { return row >= 0 && row < rows && column >= 0 && column < columns } subscript(row: Int, column: Int) -> Double { @@ -118,7 +115,7 @@ struct Matrix { assert(indexIsValidForRow(row, column: column), "Index out of range") grid[(row * columns) + columns] = newValue } - } + } } ``` @@ -126,38 +123,38 @@ struct Matrix { 你可以通过传入合适的`row`和`column`的数量来构造一个新的`Matrix`实例: -``` +```swift var matrix = Matrix(rows: 2, columns: 2) ``` 上例中创建了一个新的两行两列的`Matrix`实例。在阅读顺序从左上到右下的`Matrix`实例中的数组实例`grid`是矩阵二维数组的扁平化存储: -``` +```swift // 示意图 grid = [0.0, 0.0, 0.0, 0.0] - col0 col1 -row0 [0.0, 0.0, -row1 0.0, 0.0] + col0 col1 +row0 [0.0, 0.0, +row1 0.0, 0.0] ``` 将值赋给带有`row`和`column`附属脚本的`matrix`实例表达式可以完成赋值操作,附属脚本入参使用逗号分割 -``` +```swift matrix[0, 1] = 1.5 matrix[1, 0] = 3.2 ``` 上面两条语句分别`让matrix`的右上值为 1.5,坐下值为 3.2: -``` +```swift [0.0, 1.5, 3.2, 0.0] ``` `Matrix`附属脚本的`getter`和`setter`中同时调用了附属脚本入参的`row`和`column`是否有效的判断。为了方便进行断言,`Matrix`包含了一个名为`indexIsValid`的成员方法,用来确认入参的`row`或`column`值是否会造成数组越界: -``` +```swift func indexIsValidForRow(row: Int, column: Int) -> Bool { return row >= 0 && row < rows && column >= 0 && column < columns } @@ -165,8 +162,7 @@ func indexIsValidForRow(row: Int, column: Int) -> Bool { 断言在附属脚本越界时触发: -``` +```swift let someValue = matrix[2, 2] // 断言将会触发,因为 [2, 2] 已经超过了matrix的最大长度 ``` - From e13d4f3cb706811b946157b47fa01530d4877e91 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:55:09 +0800 Subject: [PATCH 21/24] fix 2.13 inheritance --- source/chapter2/13_Inheritance.md | 51 +++++++++++++++---------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/source/chapter2/13_Inheritance.md b/source/chapter2/13_Inheritance.md index 69c91a17..3f0b2d9f 100644 --- a/source/chapter2/13_Inheritance.md +++ b/source/chapter2/13_Inheritance.md @@ -1,6 +1,5 @@ -> 翻译:Hawstein - -> 校对:menlongsheng +> 翻译:Hawstein +> 校对:menlongsheng # 继承(Inheritance) ------------------- @@ -23,13 +22,12 @@ 不继承于其它类的类,称之为*基类(base calss)*。 -> 注意: -> +> 注意: Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。 下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了两个对所有车辆都通用的属性(`numberOfWheels`和`maxPassengers`)。这些属性在`description`方法中使用,这个方法返回一个`String`类型的,对车辆特征的描述: -``` +```swift class Vehicle { var numberOfWheels: Int var maxPassengers: Int @@ -49,7 +47,7 @@ class Vehicle { 构造器的最简单形式就像一个没有参数的实例方法,使用`init`关键字: -``` +```swift init() { // 执行构造过程 } @@ -57,7 +55,7 @@ init() { 如果要创建一个`Vehicle`类的新实例,使用*构造器*语法调用上面的初始化器,即类名后面跟一个空的小括号: -``` +```swift let someVehicle = Vehicle() ``` @@ -72,18 +70,19 @@ let someVehicle = Vehicle() 为了指明某个类的超类,将超类名写在子类名的后面,用冒号分隔: -``` +```swift class SomeClass: SomeSuperclass { // 类的定义 } ``` + 下一个例子,定义一个更具体的车辆类叫`Bicycle`。这个新类是在 `Vehicle`类的基础上创建起来。因此你需要将`Vehicle`类放在 `Bicycle`类后面,用冒号分隔。 我们可以将这读作: “定义一个新的类叫`Bicycle `,它继承了`Vehicle`的特性”; -``` +```swift class Bicycle: Vehicle { init() { super.init() @@ -91,19 +90,19 @@ class Bicycle: Vehicle { } } ``` + `Bicycle`是`Vehicle`的子类,`Vehicle`是`Bicycle`的超类。新的`Bicycle`类自动获得`Vehicle`类的特性,比如 `maxPassengers`和`numberOfWheels`属性。你可以在子类中定制这些特性,或添加新的特性来更好地描述`Bicycle`类。 `Bicycle`类定义了一个构造器来设置它定制的特性(自行车只有2个轮子)。`Bicycle`的构造器调用了它父类`Vehicle`的构造器 `super.init()`,以此确保在`Bicycle`类试图修改那些继承来的属性前`Vehicle`类已经初始化过它们了。 -> 注意: -> +> 注意: 不像 Objective-C,在 Swift 中,初始化器默认是不继承的,见[初始化器的继承与重写](../chapter2/_14Initialization.html#initializer_inheritance_and_ overriding) `Vehicle`类中`maxPassengers`的默认值对自行车来说已经是正确的,因此在`Bicycle`的构造器中并没有改变它。而`numberOfWheels`原来的值对自行车来说是不正确的,因此在初始化器中将它更改为 2。 `Bicycle`不仅可以继承`Vehicle`的属性,还可以继承它的方法。如果你创建了一个`Bicycle`类的实例,你就可以调用它继承来的`description`方法,并且可以看到,它输出的属性值已经发生了变化: -``` +```swift let bicycle = Bicycle() println("Bicycle: \(bicycle.description())") // Bicycle: 2 wheels; up to 1 passengers @@ -111,7 +110,7 @@ println("Bicycle: \(bicycle.description())") 子类还可以继续被其它类继承: -``` +```swift class Tandem: Bicycle { init() { super.init() @@ -122,13 +121,12 @@ class Tandem: Bicycle { 上面的例子创建了`Bicycle`的一个子类:双人自行车(tandem)。`Tandem`从`Bicycle`继承了两个属性,而这两个属性是`Bicycle`从`Vehicle`继承而来的。`Tandem`并不修改轮子的数量,因为它仍是一辆自行车,有 2 个轮子。但它需要修改`maxPassengers`的值,因为双人自行车可以坐两个人。 -> 注意: -> +> 注意: 子类只允许修改从超类继承来的变量属性,而不能修改继承来的常量属性。 创建一个`Tandem`类的实例,打印它的描述,即可看到它的属性已被更新: -``` +```swift let tandem = Tandem() println("Tandem: \(tandem.description())") // Tandem: 2 wheels; up to 2 passengers @@ -161,7 +159,7 @@ println("Tandem: \(tandem.description())") 下面的例子定义了`Vehicle`的一个新的子类,叫`Car`,它重写了从`Vehicle`类继承来的`description`方法: -``` +```swift class Car: Vehicle { var speed: Double = 0.0 init() { @@ -184,7 +182,7 @@ class Car: Vehicle { 如果你创建一个`Car`的新实例,并打印`description`方法的输出,你就会发现描述信息已经发生了改变: -``` +```swift let car = Car() println("Car: \(car.description())") // Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph @@ -200,13 +198,12 @@ println("Car: \(car.description())") 你可以将一个继承来的只读属性重写为一个读写属性,只需要你在重写版本的属性里提供 getter 和 setter 即可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。 -> 注意: -> +> 注意: 如果你在重写属性中提供了 setter,那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接返回`super.someProperty`来返回继承来的值。正如下面的`SpeedLimitedCar`的例子所示。 以下的例子定义了一个新类,叫`SpeedLimitedCar`,它是`Car`的子类。类`SpeedLimitedCar`表示安装了限速装置的车,它的最高速度只能达到40mph。你可以通过重写继承来的`speed`属性来实现这个速度限制: -``` +```swift class SpeedLimitedCar: Car { override var speed: Double { get { @@ -223,7 +220,7 @@ class SpeedLimitedCar: Car { 如果你尝试将`SpeedLimitedCar`实例的`speed`属性设置为一个大于40mph的数,然后打印`description`函数的输出,你会发现速度被限制在40mph: -``` +```swift let limitedCar = SpeedLimitedCar() limitedCar.speed = 60.0 println("SpeedLimitedCar: \(limitedCar.description())") @@ -234,13 +231,12 @@ println("SpeedLimitedCar: \(limitedCar.description())") 你可以在属性重写中为一个继承来的属性添加属性观察器。这样一来,当继承来的属性值发生改变时,你就会被通知到,无论那个属性原本是如何实现的。关于属性观察器的更多内容,请看[属性观察器](../chapter2/_10Properties.html#property_observer)。 -> 注意: -> +> 注意: 你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供`willSet`或`didSet`实现是不恰当。此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter,那么你在 setter 中就可以观察到任何值变化了。 下面的例子定义了一个新类叫`AutomaticCar`,它是`Car`的子类。`AutomaticCar`表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位。`AutomaticCar`也提供了定制的`description`方法,可以输出当前挡位。 -``` +```swift class AutomaticCar: Car { var gear = 1 override var speed: Double { @@ -256,7 +252,7 @@ class AutomaticCar: Car { 当你设置`AutomaticCar`的`speed`属性,属性的`didSet`观察器就会自动地设置`gear`属性,为新的速度选择一个合适的挡位。具体来说就是,属性观察器将新的速度值除以10,然后向下取得最接近的整数值,最后加1来得到档位`gear`的值。例如,速度为10.0时,挡位为1;速度为35.0时,挡位为4: -``` +```swift let automatic = AutomaticCar() automatic.speed = 35.0 println("AutomaticCar: \(automatic.description())") @@ -271,3 +267,4 @@ println("AutomaticCar: \(automatic.description())") 如果你重写了`final`方法,属性或附属脚本,在编译时会报错。在扩展中,你添加到类里的方法,属性或附属脚本也可以在扩展的定义里标记为 final。 你可以通过在关键字`class`前添加`@final`特性(`@final class`)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。 + From b0d128de2104960a158e571f5cfb08716a5a9a50 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:58:37 +0800 Subject: [PATCH 22/24] fix 2.14 initialization --- source/chapter2/13_Inheritance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/chapter2/13_Inheritance.md b/source/chapter2/13_Inheritance.md index 3f0b2d9f..280fbb94 100644 --- a/source/chapter2/13_Inheritance.md +++ b/source/chapter2/13_Inheritance.md @@ -90,7 +90,7 @@ class Bicycle: Vehicle { } } ``` - +preview `Bicycle`是`Vehicle`的子类,`Vehicle`是`Bicycle`的超类。新的`Bicycle`类自动获得`Vehicle`类的特性,比如 `maxPassengers`和`numberOfWheels`属性。你可以在子类中定制这些特性,或添加新的特性来更好地描述`Bicycle`类。 `Bicycle`类定义了一个构造器来设置它定制的特性(自行车只有2个轮子)。`Bicycle`的构造器调用了它父类`Vehicle`的构造器 `super.init()`,以此确保在`Bicycle`类试图修改那些继承来的属性前`Vehicle`类已经初始化过它们了。 From c27fad956abb85ee99c7b41d28b03c27fba0e1cb Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 17:59:04 +0800 Subject: [PATCH 23/24] =?UTF-8?q?fix=202.13=20inheritance=EF=BC=882?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/chapter2/14_Initialization.md | 461 +++++++++++++++------------ 1 file changed, 253 insertions(+), 208 deletions(-) diff --git a/source/chapter2/14_Initialization.md b/source/chapter2/14_Initialization.md index 36ad697b..ab12f262 100644 --- a/source/chapter2/14_Initialization.md +++ b/source/chapter2/14_Initialization.md @@ -1,6 +1,5 @@ -> 翻译:lifedim - -> 校对:lifedim +> 翻译:lifedim +> 校对:lifedim # 构造过程(Initialization) @@ -29,8 +28,7 @@ 你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。以下章节将详细介绍这两种方法。 ->注意: -> +>注意: 当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观测器(`property observers`)。 ### 构造器 @@ -39,16 +37,20 @@ 下面例子中定义了一个用来保存华氏温度的结构体`Fahrenheit`,它拥有一个`Double`类型的存储型属性`temperature`: - struct Fahrenheit { - var temperature: Double - init() { - temperature = 32.0 - } +```swift +struct Fahrenheit { + var temperature: Double + init() { + temperature = 32.0 } +} +``` - var f = Fahrenheit() - println("The default temperature is \(f.temperature)° Fahrenheit") - // 输出 "The default temperature is 32.0° Fahrenheit” +```swift +var f = Fahrenheit() +println("The default temperature is \(f.temperature)° Fahrenheit") +// 输出 "The default temperature is 32.0° Fahrenheit” +``` 这个结构体定义了一个不带参数的构造器`init`,并在里面将存储型属性`temperature`的值初始化为`32.0`(华摄氏度下水的冰点)。 @@ -56,15 +58,16 @@ 如前所述,你可以在构造器中为存储型属性设置初始值;同样,你也可以在属性声明时为其设置默认值。 ->注意: -> +>注意: 如果一个属性总是使用同一个初始值,可以为其设置一个默认值。无论定义默认值还是在构造器中赋值,最终它们实现的效果是一样的,只不过默认值跟属性构造过程结合的更紧密。使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型;同时,它也能让你充分利用默认构造器、构造器继承(后续章节将讲到)等特性。 你可以使用更简单的方式在定义结构体`Fahrenheit`时为属性`temperature`设置默认值: - struct Fahrenheit { - var temperature = 32.0 - } +```swift +struct Fahrenheit { + var temperature = 32.0 +} +``` ## 定制化构造过程 @@ -77,20 +80,24 @@ 下面例子中定义了一个包含摄氏度温度的结构体`Celsius`。它定义了两个不同的构造器:`init(fromFahrenheit:)`和`init(fromKelvin:)`,二者分别通过接受不同刻度表示的温度值来创建新的实例: - struct Celsius { - var temperatureInCelsius: Double = 0.0 - init(fromFahrenheit fahrenheit: Double) { - temperatureInCelsius = (fahrenheit - 32.0) / 1.8 - } - init(fromKelvin kelvin: Double) { - temperatureInCelsius = kelvin - 273.15 - } - } +```swift +struct Celsius { + var temperatureInCelsius: Double = 0.0 + init(fromFahrenheit fahrenheit: Double) { + temperatureInCelsius = (fahrenheit - 32.0) / 1.8 + } + init(fromKelvin kelvin: Double) { + temperatureInCelsius = kelvin - 273.15 + } +} +``` - let boilingPointOfWater = Celsius(fromFahrenheit: 212.0) - // boilingPointOfWater.temperatureInCelsius 是 100.0 - let freezingPointOfWater = Celsius(fromKelvin: 273.15) - // freezingPointOfWater.temperatureInCelsius 是 0.0” +```swift +let boilingPointOfWater = Celsius(fromFahrenheit: 212.0) +// boilingPointOfWater.temperatureInCelsius 是 100.0 +let freezingPointOfWater = Celsius(fromKelvin: 273.15) +// freezingPointOfWater.temperatureInCelsius 是 0.0” +``` 第一个构造器拥有一个构造参数,其外部名字为`fromFahrenheit`,内部名字为`fahrenheit`;第二个构造器也拥有一个构造参数,其外部名字为`fromKelvin`,内部名字为`kelvin`。这两个构造器都将唯一的参数值转换成摄氏温度值,并保存在属性`temperatureInCelsius`中。 @@ -100,31 +107,36 @@ 然而,构造器并不像函数和方法那样在括号前有一个可辨别的名字。所以在调用构造器时,主要通过构造器中的参数名和类型来确定需要调用的构造器。正因为参数如此重要,如果你在定义构造器时没有提供参数的外部名字,Swift 会为每个构造器的参数自动生成一个跟内部名字相同的外部名,就相当于在每个构造参数之前加了一个哈希符号。 -> 注意: -> +> 注意: 如果你不希望为构造器的某个参数提供外部名字,你可以使用下划线`_`来显示描述它的外部名,以此覆盖上面所说的默认行为。 以下例子中定义了一个结构体`Color`,它包含了三个常量:`red`、`green`和`blue`。这些属性可以存储0.0到1.0之间的值,用来指示颜色中红、绿、蓝成分的含量。 `Color`提供了一个构造器,其中包含三个`Double`类型的构造参数: - struct Color { - let red = 0.0, green = 0.0, blue = 0.0 - init(red: Double, green: Double, blue: Double) { - self.red = red - self.green = green - self.blue = blue - } - } +```swift +struct Color { + let red = 0.0, green = 0.0, blue = 0.0 + init(red: Double, green: Double, blue: Double) { + self.red = red + self.green = green + self.blue = blue + } +} +``` 每当你创建一个新的`Color`实例,你都需要通过三种颜色的外部参数名来传值,并调用构造器。 - let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) +```swift +let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) +``` 注意,如果不通过外部参数名字传值,你是没法调用这个构造器的。只要构造器定义了某个外部参数名,你就必须使用它,忽略它将导致编译错误: - let veryGreen = Color(0.0, 1.0, 0.0) - // 报编译时错误,需要外部名称 +```swift +let veryGreen = Color(0.0, 1.0, 0.0) +// 报编译时错误,需要外部名称 +``` ### 可选属性类型 @@ -132,20 +144,22 @@ 下面例子中定义了类`SurveyQuestion`,它包含一个可选字符串属性`response`: - class SurveyQuestion { - var text: String - var response: String? - init(text: String) { - self.text = text - } - func ask() { - println(text) - } - } - let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?") - cheeseQuestion.ask() - // 输出 "Do you like cheese?" - cheeseQuestion.response = "Yes, I do like cheese. +```swift +class SurveyQuestion { + var text: String + var response: String? + init(text: String) { + self.text = text + } + func ask() { + println(text) + } +} +let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?") +cheeseQuestion.ask() +// 输出 "Do you like cheese?" +cheeseQuestion.response = "Yes, I do like cheese. +``` 调查问题在问题提出之后,我们才能得到回答。所以我们将属性回答`response`声明为`String?`类型,或者说是可选字符串类型`optional String`。当`SurveyQuestion`实例化时,它将自动赋值为空`nil`,表明暂时还不存在此字符串。 @@ -153,26 +167,27 @@ 只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值。 ->注意: -> +>注意: 对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。 你可以修改上面的`SurveyQuestion`示例,用常量属性替代变量属性`text`,指明问题内容`text`在其创建之后不会再被修改。尽管`text`属性现在是常量,我们仍然可以在其类的构造器中修改它的值: - class SurveyQuestion { - let text: String - var response: String? - init(text: String) { - self.text = text - } - func ask() { - println(text) - } - } - let beetsQuestion = SurveyQuestion(text: "How about beets?") - beetsQuestion.ask() - // 输出 "How about beets?" - beetsQuestion.response = "I also like beets. (But not with cheese.) +```swift +class SurveyQuestion { + let text: String + var response: String? + init(text: String) { + self.text = text + } + func ask() { + println(text) + } +} +let beetsQuestion = SurveyQuestion(text: "How about beets?") +beetsQuestion.ask() +// 输出 "How about beets?" +beetsQuestion.response = "I also like beets. (But not with cheese.) +``` ## 默认构造器 @@ -181,12 +196,14 @@ Swift 将为所有属性已提供默认值的且自身没有定义任何构造 下面例子中创建了一个类`ShoppingListItem`,它封装了购物清单中的某一项的属性:名字(`name`)、数量(`quantity`)和购买状态 `purchase state`。 - class ShoppingListItem { - var name: String? - var quantity = 1 - var purchased = false - } - var item = ShoppingListItem() +```swift +class ShoppingListItem { + var name: String? + var quantity = 1 + var purchased = false +} +var item = ShoppingListItem() +``` 由于`ShoppingListItem`类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个可以为所有属性设置默认值的默认构造器(尽管代码中没有显式为`name`属性设置默认值,但由于`name`是可选字符串类型,它将默认设置为`nil`)。上面例子中使用默认构造器创造了一个`ShoppingListItem`类的实例(使用`ShoppingListItem()`形式的构造器语法),并将其赋值给变量`item`。 @@ -200,10 +217,12 @@ Swift 将为所有属性已提供默认值的且自身没有定义任何构造 由于这两个存储型属性都有默认值,结构体`Size`自动获得了一个逐一成员构造器 `init(width:height:)`。 你可以用它来为`Size`创建新的实例: - struct Size { - var width = 0.0, height = 0.0 - } - let twoByTwo = Size(width: 2.0, height: 2.0) +```swift +struct Size { + var width = 0.0, height = 0.0 +} +let twoByTwo = Size(width: 2.0, height: 2.0) +``` ## 值类型的构造器代理 @@ -216,57 +235,65 @@ Swift 将为所有属性已提供默认值的且自身没有定义任何构造 注意,如果你为某个值类型定义了一个定制的构造器,你将无法访问到默认构造器(如果是结构体,则无法访问逐一对象构造器)。这个限制可以防止你在为值类型定义了一个更复杂的,完成了重要准备构造器之后,别人还是错误的使用了那个自动生成的构造器。 ->注意: -> +>注意: 假如你想通过默认构造器、逐一对象构造器以及你自己定制的构造器为值类型创建实例,我们建议你将自己定制的构造器写到扩展(`extension`)中,而不是跟值类型定义混在一起。想查看更多内容,请查看[扩展](../chapter2/20_Extensions.html)章节。 下面例子将定义一个结构体`Rect`,用来展现几何矩形。这个例子需要两个辅助的结构体`Size`和`Point`,它们各自为其所有的属性提供了初始值`0.0`。 - struct Size { - var width = 0.0, height = 0.0 - } - struct Point { - var x = 0.0, y = 0.0 - } +```swift +struct Size { + var width = 0.0, height = 0.0 +} +struct Point { + var x = 0.0, y = 0.0 +} +``` 你可以通过以下三种方式为`Rect`创建实例--使用默认的0值来初始化`origin`和`size`属性;使用特定的`origin`和`size`实例来初始化;使用特定的`center`和`size`来初始化。在下面`Rect`结构体定义中,我们为着三种方式提供了三个自定义的构造器: - struct Rect { - var origin = Point() - var size = Size() - init() {} - init(origin: Point, size: Size) { - self.origin = origin - self.size = size - } - init(center: Point, size: Size) { - let originX = center.x - (size.width / 2) - let originY = center.y - (size.height / 2) - self.init(origin: Point(x: originX, y: originY), size: size) - } - } +```swift +struct Rect { + var origin = Point() + var size = Size() + init() {} + init(origin: Point, size: Size) { + self.origin = origin + self.size = size + } + init(center: Point, size: Size) { + let originX = center.x - (size.width / 2) + let originY = center.y - (size.height / 2) + self.init(origin: Point(x: originX, y: originY), size: size) + } +} +``` 第一个`Rect`构造器`init()`,在功能上跟没有自定义构造器时自动获得的默认构造器是一样的。这个构造器是一个空函数,使用一对大括号`{}`来描述,它没有执行任何定制的构造过程。调用这个构造器将返回一个`Rect`实例,它的`origin`和`size`属性都使用定义时的默认值`Point(x: 0.0, y: 0.0)`和`Size(width: 0.0, height: 0.0)`: - let basicRect = Rect() - // basicRect 的原点是 (0.0, 0.0),尺寸是 (0.0, 0.0) +```swift +let basicRect = Rect() +// basicRect 的原点是 (0.0, 0.0),尺寸是 (0.0, 0.0) +``` 第二个`Rect`构造器`init(origin:size:)`,在功能上跟结构体在没有自定义构造器时获得的逐一成员构造器是一样的。这个构造器只是简单的将`origin`和`size`的参数值赋给对应的存储型属性: - let originRect = Rect(origin: Point(x: 2.0, y: 2.0), - size: Size(width: 5.0, height: 5.0)) - // originRect 的原点是 (2.0, 2.0),尺寸是 (5.0, 5.0) +```swift +let originRect = Rect(origin: Point(x: 2.0, y: 2.0), + size: Size(width: 5.0, height: 5.0)) +// originRect 的原点是 (2.0, 2.0),尺寸是 (5.0, 5.0) +``` 第三个`Rect`构造器`init(center:size:)`稍微复杂一点。它先通过`center`和`size`的值计算出`origin`的坐标。然后再调用(或代理给)`init(origin:size:)`构造器来将新的`origin`和`size`值赋值到对应的属性中: let centerRect = Rect(center: Point(x: 4.0, y: 4.0), - size: Size(width: 3.0, height: 3.0)) +```swift +size: Size(width: 3.0, height: 3.0)) +``` // centerRect 的原点是 (2.5, 2.5),尺寸是 (3.0, 3.0) 构造器`init(center:size:)`可以自己将`origin`和`size`的新值赋值到对应的属性中。然而尽量利用现有的构造器和它所提供的功能来实现`init(center:size:)`的功能,是更方便、更清晰和更直观的方法。 ->注意: -> +>注意: 如果你想用另外一种不需要自己定义`init()`和`init(origin:size:)`的方式来实现这个例子,请参考[扩展](../chapter2/20_Extensions.html)。 @@ -313,8 +340,7 @@ Swift 提供了两种类型的类构造器来确保所有类实例中存储型 子类中包含两个指定构造器和一个便利构造器。便利构造器必须调用两个指定构造器中的任意一个,因为它只能调用同一个类里的其他构造器。这满足了上面提到的规则2和3。而两个指定构造器必须调用父类中唯一的指定构造器,这满足了规则1。 -> 注意: -> +> 注意: 这些规则不会影响使用时,如何用类去创建实例。任何上图中展示的构造器都可以用来完整创建对应类的实例。这些规则只在实现类的定义时有影响。 下面图例中展示了一种更复杂的类层级结构。它演示了指定构造器是如果在类层级中充当“管道”的作用,在类的构造器链上简化了类之间的内部关系。 @@ -328,8 +354,7 @@ Swift 中类的构造过程包含两个阶段。第一个阶段,每个存储 两段式构造过程的使用让构造过程更安全,同时在整个类层级结构中给予了每个类完全的灵活性。两段式构造过程可以防止属性值在初始化之前被访问;也可以防止属性被另外一个构造器意外地赋予不同的值。 -> 注意: -> +> 注意: Swift的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于阶段 1,Objective-C 给每一个属性赋值`0`或空值(比如说`0`或`nil`)。Swift 的构造流程则更加灵活,它允许你设置定制的初始值,并自如应对某些属性不能以`0`或`nil`作为合法默认值的情况。 Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程能顺利完成: @@ -400,8 +425,7 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造 如果你重载的构造器是一个便利构造器,你的重载过程必须通过调用同一类中提供的其它指定构造器来实现。这一规则的详细内容请参考[构造器链](#initialization_chain)。 ->注意: -> +>注意: 与方法、属性和下标不同,在重载构造器时你没有必要使用关键字`override`。 @@ -421,23 +445,26 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造 即使你在子类中添加了更多的便利构造器,这两条规则仍然适用。 ->注意: -> +>注意: 子类可以通过部分满足规则2的方式,使用子类便利构造器来实现父类的指定构造器。 ### 指定构造器和便利构造器的语法 类的指定构造器的写法跟值类型简单构造器一样: - init(parameters) { - statements - } +```swift +init(parameters) { + statements +} +``` 便利构造器也采用相同样式的写法,但需要在`init`关键字之前放置`convenience`关键字,并使用空格将它们俩分开: - convenience init(parameters) { - statements - } +```swift +convenience init(parameters) { + statements +} +``` ### 指定构造器和便利构造器实战 @@ -445,15 +472,17 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造 类层次中的基类是`Food`,它是一个简单的用来封装食物名字的类。`Food`类引入了一个叫做`name`的`String`类型属性,并且提供了两个构造器来创建`Food`实例: - class Food { - var name: String - init(name: String) { - self.name = name - } - convenience init() { - self.init(name: "[Unnamed]") - } - } +```swift +class Food { + var name: String + init(name: String) { + self.name = name + } + convenience init() { + self.init(name: "[Unnamed]") + } +} +``` 下图中展示了`Food`的构造器链: @@ -461,28 +490,34 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造 类没有提供一个默认的逐一成员构造器,所以`Food`类提供了一个接受单一参数`name`的指定构造器。这个构造器可以使用一个特定的名字来创建新的`Food`实例: - let namedMeat = Food(name: "Bacon") - // namedMeat 的名字是 "Bacon” +```swift +let namedMeat = Food(name: "Bacon") +// namedMeat 的名字是 "Bacon” +``` `Food`类中的构造器`init(name: String)`被定义为一个指定构造器,因为它能确保所有新`Food`实例的中存储型属性都被初始化。`Food`类没有父类,所以`init(name: String)`构造器不需要调用`super.init()`来完成构造。 `Food`类同样提供了一个没有参数的便利构造器 `init()`。这个`init()`构造器为新食物提供了一个默认的占位名字,通过代理调用同一类中定义的指定构造器`init(name: String)`并给参数`name`传值`[Unnamed]`来实现: - let mysteryMeat = Food() - // mysteryMeat 的名字是 [Unnamed] +```swift +let mysteryMeat = Food() +// mysteryMeat 的名字是 [Unnamed] +``` 类层级中的第二个类是`Food`的子类`RecipeIngredient`。`RecipeIngredient`类构建了食谱中的一味调味剂。它引入了`Int`类型的数量属性`quantity`(以及从`Food`继承过来的`name`属性),并且定义了两个构造器来创建`RecipeIngredient`实例: - class RecipeIngredient: Food { - var quantity: Int - init(name: String, quantity: Int) { - self.quantity = quantity - super.init(name: name) - } - convenience init(name: String) { - self.init(name: name, quantity: 1) - } - } +```swift +class RecipeIngredient: Food { + var quantity: Int + init(name: String, quantity: Int) { + self.quantity = quantity + super.init(name: name) + } + convenience init(name: String) { + self.init(name: name, quantity: 1) + } +} +``` 下图中展示了`RecipeIngredient`类的构造器链: @@ -498,25 +533,28 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造 所有的这三种构造器都可以用来创建新的`RecipeIngredient`实例: - let oneMysteryItem = RecipeIngredient() - let oneBacon = RecipeIngredient(name: "Bacon") - let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6) +```swift +let oneMysteryItem = RecipeIngredient() +let oneBacon = RecipeIngredient(name: "Bacon") +let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6) +``` 类层级中第三个也是最后一个类是`RecipeIngredient`的子类,叫做`ShoppingListItem`。这个类构建了购物单中出现的某一种调味料。 购物单中的每一项总是从`unpurchased`未购买状态开始的。为了展现这一事实,`ShoppingListItem`引入了一个布尔类型的属性`purchased`,它的默认值是`false`。`ShoppingListItem`还添加了一个计算型属性`description`,它提供了关于`ShoppingListItem`实例的一些文字描述: - class ShoppingListItem: RecipeIngredient { - var purchased = false - var description: String { - var output = "\(quantity) x \(name.lowercaseString)" - output += purchased ? " ✔" : " ✘" - return output - } - } +```swift +class ShoppingListItem: RecipeIngredient { + var purchased = false + var description: String { + var output = "\(quantity) x \(name.lowercaseString)" + output += purchased ? " ✔" : " ✘" + return output + } +} +``` -> 注意: -> +> 注意: `ShoppingListItem`没有定义构造器来为`purchased`提供初始化值,这是因为任何添加到购物单的项的初始状态总是未购买。 由于它为自己引入的所有属性都提供了默认值,并且自己没有定义任何构造器,`ShoppingListItem`将自动继承所有父类中的指定构造器和便利构造器。 @@ -527,19 +565,21 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造 你可以使用全部三个继承来的构造器来创建`ShoppingListItem`的新实例: - var breakfastList = [ - ShoppingListItem(), - ShoppingListItem(name: "Bacon"), - ShoppingListItem(name: "Eggs", quantity: 6), - ] - breakfastList[0].name = "Orange juice" - breakfastList[0].purchased = true - for item in breakfastList { - println(item.description) - } - // 1 x orange juice ✔ - // 1 x bacon ✘ - // 6 x eggs ✘ +```swift +var breakfastList = [ + ShoppingListItem(), + ShoppingListItem(name: "Bacon"), + ShoppingListItem(name: "Eggs", quantity: 6), +] +breakfastList[0].name = "Orange juice" +breakfastList[0].purchased = true +for item in breakfastList { + println(item.description) +} +// 1 x orange juice ✔ +// 1 x bacon ✘ +// 6 x eggs ✘ +``` 如上所述,例子中通过字面量方式创建了一个新数组`breakfastList`,它包含了三个新的`ShoppingListItem`实例,因此数组的类型也能自动推导为`ShoppingListItem[]`。在数组创建完之后,数组中第一个`ShoppingListItem`实例的名字从`[Unnamed]`修改为`Orange juice`,并标记为已购买。接下来通过遍历数组每个元素并打印它们的描述值,展示了所有项当前的默认状态都已按照预期完成了赋值。 @@ -552,18 +592,19 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造 下面列举了闭包如何提供默认值的代码概要: - class SomeClass { - let someProperty: SomeType = { - // 在这个闭包中给 someProperty 创建一个默认值 - // someValue 必须和 SomeType 类型相同 - return someValue - }() - } +```swift +class SomeClass { + let someProperty: SomeType = { + // 在这个闭包中给 someProperty 创建一个默认值 + // someValue 必须和 SomeType 类型相同 + return someValue + }() +} +``` 注意闭包结尾的大括号后面接了一对空的小括号。这是用来告诉 Swift 需要立刻执行此闭包。如果你忽略了这对括号,相当于是将闭包本身作为值赋值给了属性,而不是将闭包的返回值赋值给属性。 ->注意: -> +>注意: 如果你使用闭包来初始化属性的值,请记住在闭包执行时,实例的其它部分都还没有初始化。这意味着你不能够在闭包里访问其它的属性,就算这个属性有默认值也不允许。同样,你也不能使用隐式的`self`属性,或者调用其它的实例方法。 下面例子中定义了一个结构体`Checkerboard`,它构建了西洋跳棋游戏的棋盘: @@ -574,28 +615,32 @@ Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造 `boardColor`数组是通过一个闭包来初始化和组装颜色值的: - struct Checkerboard { - let boardColors: Bool[] = { - var temporaryBoard = Bool[]() - var isBlack = false - for i in 1...10 { - for j in 1...10 { - temporaryBoard.append(isBlack) - isBlack = !isBlack - } - isBlack = !isBlack - } - return temporaryBoard - }() - func squareIsBlackAtRow(row: Int, column: Int) -> Bool { - return boardColors[(row * 10) + column] - } - } +```swift +struct Checkerboard { + let boardColors: Bool[] = { + var temporaryBoard = Bool[]() + var isBlack = false + for i in 1...10 { + for j in 1...10 { + temporaryBoard.append(isBlack) + isBlack = !isBlack + } + isBlack = !isBlack + } + return temporaryBoard + }() + func squareIsBlackAtRow(row: Int, column: Int) -> Bool { + return boardColors[(row * 10) + column] + } +} +``` 每当一个新的`Checkerboard`实例创建时,对应的赋值闭包会执行,一系列颜色值会被计算出来作为默认值赋值给`boardColors`。上面例子中描述的闭包将计算出棋盘中每个格子合适的颜色,将这些颜色值保存到一个临时数组`temporaryBoard`中,并在构建完成时将此数组作为闭包返回值返回。这个返回的值将保存到`boardColors`中,并可以通`squareIsBlackAtRow`这个工具函数来查询。 - let board = Checkerboard() - println(board.squareIsBlackAtRow(0, column: 1)) - // 输出 "true" - println(board.squareIsBlackAtRow(9, column: 9)) - // 输出 "false" +```swift +let board = Checkerboard() +println(board.squareIsBlackAtRow(0, column: 1)) +// 输出 "true" +println(board.squareIsBlackAtRow(9, column: 9)) +// 输出 "false" +``` \ No newline at end of file From affa64a08b757d82bc46a8952c9be0fefef58784 Mon Sep 17 00:00:00 2001 From: stanzhai Date: Sat, 14 Jun 2014 18:05:49 +0800 Subject: [PATCH 24/24] fix 2.15 Deinitialization --- source/chapter2/15_Deinitialization.md | 97 ++++++++++++++------------ 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/source/chapter2/15_Deinitialization.md b/source/chapter2/15_Deinitialization.md index 3b8d3bfb..5085b494 100644 --- a/source/chapter2/15_Deinitialization.md +++ b/source/chapter2/15_Deinitialization.md @@ -1,6 +1,5 @@ -> 翻译:bruce0505 - -> 校对:fd5788 +> 翻译:bruce0505 +> 校对:fd5788 # 析构过程(Deinitialization) @@ -20,9 +19,11 @@ Swift 会自动释放不再需要的实例以释放资源。如[自动引用计 在类的定义中,每个类最多只能有一个析构函数。析构函数不带任何参数,在写法上不带括号: - deinit { - // 执行析构过程 - } +```swift +deinit { + // 执行析构过程 +} +``` 析构函数是在实例释放发生前一步被自动调用。不允许主动调用自己的析构函数。子类继承了父类的析构函数,并且在子类析构函数实现的最后,父类的析构函数被自动调用。即使子类没有提供自己的析构函数,父类的析构函数也总是被调用。 @@ -33,17 +34,19 @@ Swift 会自动释放不再需要的实例以释放资源。如[自动引用计 这里是一个析构函数操作的例子。这个例子是一个简单的游戏,定义了两种新类型,`Bank`和`Player`。`Bank`结构体管理一个虚拟货币的流通,在这个流通中`Bank`永远不可能拥有超过 10,000 的硬币。在这个游戏中有且只能有一个`Bank`存在,因此`Bank`由带有静态属性和静态方法的结构体实现,从而存储和管理其当前的状态。 - struct Bank { - static var coinsInBank = 10_000 - static func vendCoins(var numberOfCoinsToVend: Int) -> Int { - numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank) - coinsInBank -= numberOfCoinsToVend - return numberOfCoinsToVend - } - static func receiveCoins(coins: Int) { +```swift +struct Bank { + static var coinsInBank = 10_000 + static func vendCoins(var numberOfCoinsToVend: Int) -> Int { + numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank) + coinsInBank -= numberOfCoinsToVend + return numberOfCoinsToVend + } + static func receiveCoins(coins: Int) { coinsInBank += coins - } - } + } +} +``` `Bank`根据它的`coinsInBank`属性来跟踪当前它拥有的硬币数量。银行还提供两个方法——`vendCoins`和`receiveCoins`——用来处理硬币的分发和收集。 @@ -53,46 +56,54 @@ Swift 会自动释放不再需要的实例以释放资源。如[自动引用计 `Player`类描述了游戏中的一个玩家。每一个 player 在任何时刻都有一定数量的硬币存储在他们的钱包中。这通过 player 的`coinsInPurse`属性来体现: - class Player { - var coinsInPurse: Int - init(coins: Int) { - coinsInPurse = Bank.vendCoins(coins) - } - func winCoins(coins: Int) { - coinsInPurse += Bank.vendCoins(coins) - } - deinit { - Bank.receiveCoins(coinsInPurse) - } - } +```swift +class Player { + var coinsInPurse: Int + init(coins: Int) { + coinsInPurse = Bank.vendCoins(coins) + } + func winCoins(coins: Int) { + coinsInPurse += Bank.vendCoins(coins) + } + deinit { + Bank.receiveCoins(coinsInPurse) + } +} +``` 每个`Player`实例都由一个指定数目硬币组成的启动额度初始化,这些硬币在 bank 初始化的过程中得到。如果没有足够的硬币可用,`Player`实例可能收到比指定数目少的硬币。 `Player`类定义了一个`winCoins`方法,该方法从银行获取一定数量的硬币,并把它们添加到玩家的钱包。`Player`类还实现了一个析构函数,这个析构函数在`Player`实例释放前一步被调用。这里析构函数只是将玩家的所有硬币都返回给银行: - var playerOne: Player? = Player(coins: 100) - println("A new player has joined the game with \(playerOne!.coinsInPurse) coins") - // 输出 "A new player has joined the game with 100 coins" - println("There are now \(Bank.coinsInBank) coins left in the bank") - // 输出 "There are now 9900 coins left in the bank" +```swift +var playerOne: Player? = Player(coins: 100) +println("A new player has joined the game with \(playerOne!.coinsInPurse) coins") +// 输出 "A new player has joined the game with 100 coins" +println("There are now \(Bank.coinsInBank) coins left in the bank") +// 输出 "There are now 9900 coins left in the bank" +``` 一个新的`Player`实例随着一个 100 个硬币(如果有)的请求而被创建。这`个Player`实例存储在一个名为`playerOne`的可选`Player`变量中。这里使用一个可选变量,是因为玩家可以随时离开游戏。设置为可选使得你可以跟踪当前是否有玩家在游戏中。 因为`playerOne`是可选的,所以由一个感叹号(`!`)来修饰,每当其`winCoins`方法被调用时,`coinsInPurse`属性被访问并打印出它的默认硬币数目。 - playerOne!.winCoins(2_000) - println("PlayerOne won 2000 coins & now has \ (playerOne!.coinsInPurse) coins") - // 输出 "PlayerOne won 2000 coins & now has 2100 coins" - println("The bank now only has \(Bank.coinsInBank) coins left") - // 输出 "The bank now only has 7900 coins left" +```swift +playerOne!.winCoins(2_000) +println("PlayerOne won 2000 coins & now has \ (playerOne!.coinsInPurse) coins") +// 输出 "PlayerOne won 2000 coins & now has 2100 coins" +println("The bank now only has \(Bank.coinsInBank) coins left") +// 输出 "The bank now only has 7900 coins left" +``` 这里,player 已经赢得了 2,000 硬币。player 的钱包现在有 2,100 硬币,bank 只剩余 7,900 硬币。 - playerOne = nil - println("PlayerOne has left the game") - // 输出 "PlayerOne has left the game" - println("The bank now has \(Bank.coinsInBank) coins") - // 输出 "The bank now has 10000 coins" +```swift +playerOne = nil +println("PlayerOne has left the game") +// 输出 "PlayerOne has left the game" +println("The bank now has \(Bank.coinsInBank) coins") +// 输出 "The bank now has 10000 coins" +``` 玩家现在已经离开了游戏。这表明是要将可选的`playerOne`变量设置为`nil`,意思是“没有`Player`实例”。当这种情况发生的时候,`playerOne`变量对`Player`实例的引用被破坏了。没有其它属性或者变量引用`Player`实例,因此为了清空它占用的内存从而释放它。在这发生前一步,其析构函数被自动调用,其硬币被返回到银行。