diff --git a/source/chapter2/03_Strings_and_Characters.md b/source/chapter2/03_Strings_and_Characters.md index 13d5dd3d..1ad844a4 100755 --- a/source/chapter2/03_Strings_and_Characters.md +++ b/source/chapter2/03_Strings_and_Characters.md @@ -51,14 +51,14 @@ Swift 的`String`和`Character`类型提供了一个快速的,兼容 Unicode 要创建一个空字符串作为初始值,可以将空的字符串字面量赋值给变量,也可以初始化一个新的`String`实例: -``` +```swift var emptyString = "" // 空字符串字面量 var anotherEmptyString = String() // 初始化方法 // 两个字符串均为空并等价。 ``` 您可以通过检查其`Boolean`类型的`isEmpty`属性来判断该字符串是否为空: -``` +```swift if emptyString.isEmpty { print("Nothing to see here") } @@ -70,7 +70,7 @@ if emptyString.isEmpty { 您可以通过将一个特定字符串分配给一个变量来对其进行修改,或者分配给一个常量来保证其不会被修改: -``` +```swift var variableString = "Horse" variableString += " and carriage" // variableString 现在为 "Horse and carriage" @@ -104,7 +104,7 @@ Swift 默认字符串拷贝的方式保证了在函数/方法中传递的是字 您可通过`for-in`循环来遍历字符串中的`characters`属性来获取每一个字符的值: -``` +```swift for character in "Dog!🐶".characters { print(character) } @@ -119,12 +119,12 @@ for-in 循环在 [For Loops](05_Control_Flow.html#for_loops) 中进行了详细 另外,通过标明一个`Character`类型并用字符字面量进行赋值,可以建立一个独立的字符常量或变量: -``` +```swift let exclamationMark: Charater = "!" ``` 字符串可以通过传递一个值类型为`Charater`的数组作为自变量来初始化: -``` +```swift let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"] let catString = String(catCharacters) print(catString) @@ -136,7 +136,7 @@ print(catString) 字符串可以通过加法运算符(`+`)相加在一起(或称“连接”)创建一个新的字符串: -``` +```swift let string1 = "hello" let string2 = " there" var welcome = string1 + string2 @@ -145,7 +145,7 @@ var welcome = string1 + string2 您也可以通过加法赋值运算符 (`+=`) 将一个字符串添加到一个已经存在字符串变量上: -``` +```swift var instruction = "look over" instruction += string2 // instruction 现在等于 "look over there" @@ -153,7 +153,7 @@ instruction += string2 您可以用`append`方法将一个字符附加到一个字符串变量的尾部: -``` +```swift let exclamationMark: Character = "!" welcome.append(exclamationMark) // welcome 现在等于 "hello there!" @@ -169,7 +169,7 @@ welcome.append(exclamationMark) 字符串插值是一种构建新字符串的方式,可以在其中包含常量、变量、字面量和表达式。 您插入的字符串字面量的每一项都在以反斜线为前缀的圆括号中: -``` +```swift let multiplier = 3 let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)" // message 是 "3 times 2.5 is 7.5" @@ -215,7 +215,7 @@ Unicode 标量是对应字符的唯一21位数字或者修饰符,例如`U+0061 `wiseWords`常量包含了两个双引号; `dollarSign`、`blackHeart`和`sparklingHeart`常量演示了三种不同格式的 Unicode 标量: -``` +```swift let wiseWords = "\"Imagination is more important than knowledge\" - Einstein" // "Imageination is more important than knowledge" - Enistein let dollarSign = "\u{24}" // $, Unicode 标量 U+0024 @@ -232,7 +232,7 @@ let sparklingHeart = "\u{1F496}" // 💖, Unicode 标量 U+1F496 在这两种情况中,字母 é 代表了一个单一的 Swift 的字符串,同时代表了一个可扩展的字形群。 在第一种情况,这个字形群包含一个单一标量;而在第二种情况,它是包含两个标量的字形群: -``` +```swift let eAcute: Character = "\u{E9}" // é let combinedEAcute: Character = "\u{65}\u{301}" // e 后面加上 ́ // eAcute 是 é, combinedEAcute 是 é @@ -243,7 +243,7 @@ let combinedEAcute: Character = "\u{65}\u{301}" // e 后面加上 ́ 在 Swift 都会表示为同一个单一的字符: -``` +```swift let precomposed: Character = "\u{D55C}" // 한 let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ // precomposed 是 한, decomposed 是 한 @@ -251,7 +251,7 @@ let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ 可拓展的字符群集可以使包围记号(例如`COMBINING ENCLOSING CIRCLE`或者`U+20DD`)的标量包围其他 Unicode 标量,作为一个单一的字符: -``` +```swift let enclosedEAcute: Character = "\u{E9}\u{20DD}" // enclosedEAcute 是 é⃝ ``` @@ -259,7 +259,7 @@ let enclosedEAcute: Character = "\u{E9}\u{20DD}" 局部的指示符号的 Unicode 标量可以组合成一个单一的字符,例如 `REGIONAL INDICATOR SYMBOL LETTER U`(`U+1F1FA`)和`REGIONAL INDICATOR SYMBOL LETTER S`(`U+1F1F8`): -``` +```swift let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}" // regionalIndicatorForUS 是 🇺🇸 ``` @@ -270,7 +270,7 @@ let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}" 调用字符串的`count`属性,就可以获取一个字符串的字符数量: -``` +```swift let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪" print("unusualMenagerie has \(unusualMenagerie.characters.count) characters") // 打印输出:"unusualMenagerie has 40 characters" @@ -279,7 +279,7 @@ print("unusualMenagerie has \(unusualMenagerie.characters.count) characters") 注意在 Swift 中,使用可拓展的字符群集作为字符来连接或改变字符串时,并不一定会更改字符串的字符数量。 例如,如果你用四个字符的单词 cafe 初始化一个新的字符串,然后添加一个 `COMBINING ACTUE ACCENT`(`U+0301`)作为字符串的结尾。最终这个字符串的字符数量仍然是4,因为第四个字符是 é ,而不是 e : -``` +```swift var word = "cafe" print("the number of characters in \(word) is \(word.characters.count)") // 打印输出 "the number of characters in cafe is 4" @@ -305,7 +305,7 @@ print("the number of characters in \(word) is \(word.characters.count)") 通过调用`String.Index`的`predecessor()`方法,可以立即得到前面一个索引,调用`successor()`方法可以立即得到后面一个索引。任何一个字符串的索引都可以通过锁链作用的这些方法来获取另一个索引,也可以调用`advance(start:n:)`函数来获取。但如果尝试获取出界的字符串索引,就会抛出一个运行时错误。 你可以使用下标语法来访问字符在字符串的确切索引。尝试获取出界的字符串索引,仍然抛出一个运行时错误。 -``` +```swift let greeting = "Guten Tag" greeting[greeting.startIndex] // G @@ -322,7 +322,7 @@ greeting.endIndex.successor() // 错误 使用`characters`属性的`indices`会创建一个包含全部索引的范围(`Range`),用来在一个字符串中访问分立的字符。 -``` +```swift for index in greeting.characters.indices { print("\(greeting[index]) ", appendNewline: false) } @@ -333,7 +333,7 @@ for index in greeting.characters.indices { ### 插入和删除 (Inserting and Removing) 调用`insert(_:atIndex:)`方法可以在一个字符串的指定索引插入一个字符。 -``` +```swift var welcome = "hello" welcome.insert("!", atIndex: welcome.endIndex) // welcome now 现在等于 "hello!" @@ -341,14 +341,14 @@ welcome.insert("!", atIndex: welcome.endIndex) 调用`splice(_:atIndex:)`方法可以在一个字符串的指定索引插入一个字符串。 -``` +```swift welcome.splice(" there".characters, atIndex: welcome.endIndex.predecessor()) // welcome 现在等于 "hello there!" ``` 调用`removeAtIndex(_:)`方法可以在一个字符串的指定索引删除一个字符。 -``` +```swift welcome.removeAtIndex(welcome.endIndex.predecessor()) // welcome 现在等于 "hello there" // 翻译的人解释:最后还有一个换行符,所以这里删除的是 ! @@ -356,7 +356,7 @@ welcome.removeAtIndex(welcome.endIndex.predecessor()) 调用`removeRange(_:)`方法可以在一个字符串的指定索引删除一个子字符串。 -``` +```swift let range = advance(welcome.endIndex, -6).. -``` +```swift for codeUnit in dogString.utf8 { print("\(codeUnit) ", appendNewline: false) } @@ -584,7 +584,7 @@ print("") -``` +```swift for codeUnit in dogString.utf16 { print("\(codeUnit) ", appendNewline: false) } @@ -638,7 +638,7 @@ print("") -``` +```swift for scalar in dogString.unicodeScalars { print("\(scalar.value) ", appendNewline: false) } @@ -652,7 +652,7 @@ print("") 作为查询字符值属性的一种替代方法,每个`UnicodeScalar`值也可以用来构建一个新的字符串值,比如在字符串插值中使用: -``` +```swift for scalar in dogString.unicodeScalars { print("\(scalar) ") } diff --git a/source/chapter2/11_Methods.md b/source/chapter2/11_Methods.md index 2f925d5c..ab00d474 100755 --- a/source/chapter2/11_Methods.md +++ b/source/chapter2/11_Methods.md @@ -14,19 +14,19 @@ 结构体和枚举能够定义方法是 Swift 与 C/Objective-C 的主要区别之一。在 Objective-C 中,类是唯一能定义方法的类型。但在 Swift 中,你不仅能选择是否要定义一个类/结构体/枚举,还能灵活的在你创建的类型(类/结构体/枚举)上定义方法。 -## 实例方法(Instance Methods) +## 实例方法 (Instance Methods) **实例方法**是属于某个特定类、结构体或者枚举类型实例的方法。实例方法提供访问和修改实例属性的方法或提供与实例目的相关的功能,并以此来支撑实例的功能。实例方法的语法与函数完全一致,详情参见[函数](../charpter2/06_Functions.md)。 实例方法要写在它所属的类型的前后大括号之间。实例方法能够隐式访问它所属类型的所有的其他实例方法和属性。实例方法只能被它所属的类的某个特定实例调用。实例方法不能脱离于现存的实例而被调用。 -下面的例子,定义一个很简单的类`Counter`,`Counter`能被用来对一个动作发生的次数进行计数: +下面的例子,定义一个很简单的`Counter`类,`Counter`能被用来对一个动作发生的次数进行计数: ```swift class Counter { var count = 0 func increment() { - count++ + ++count } func incrementBy(amount: Int) { count += amount @@ -60,13 +60,13 @@ class Counter { ### 方法的局部参数名称和外部参数名称(Local and External Parameter Names for Methods) -函数参数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用),详情参见[函数的外部参数名](06_Functions.html)。方法参数也一样(因为方法就是函数,只是这个函数与某个类型相关联了)。但是,方法和函数的局部名称和外部名称的默认行为是不一样的。 +函数参数可以同时有一个局部名称(在函数体内部使用)和一个外部名称(在调用函数时使用),详情参见[函数的外部参数名](06_Functions.html)。方法参数也一样(因为方法就是函数,只是这个函数与某个类型相关联了)。 -Swift 中的方法和 Objective-C 中的方法极其相似。像在 Objective-C 中一样,Swift 中方法的名称通常用一个介词指向方法的第一个参数,比如:`with`,`for`,`by`等等。前面的`Counter`类的例子中`incrementBy`方法就是这样的。介词的使用让方法在被调用时能像一个句子一样被解读。和函数参数不同,对于方法的参数,Swift 使用不同的默认处理方式,这可以让方法命名规范更容易写。 +Swift 中的方法和 Objective-C 中的方法极其相似。像在 Objective-C 中一样,Swift 中方法的名称通常用一个介词指向方法的第一个参数,比如:`with`,`for`,`by`等等。前面的`Counter`类的例子中`incrementBy(_:)`方法就是这样的。介词的使用让方法在被调用时能像一个句子一样被解读。 -具体来说,Swift 默认仅给方法的第一个参数名称一个局部参数名称;默认同时给第二个和后续的参数名称局部参数名称和外部参数名称。这个约定与典型的命名和调用约定相适应,与你在写 Objective-C 的方法时很相似。这个约定还让表达式方法在调用时不需要再限定参数名称。 +具体来说,Swift 默认仅给方法的第一个参数名称一个局部参数名称;默认同时给第二个和后续的参数名称局部参数名称和外部参数名称。这个约定与典型的命名和调用约定相适应,与你在写 Objective-C 的方法时很相似。这个约定还让表达式方法在调用时不需要再限定参数名称。 -看看下面这个`Counter`的另一个版本(它定义了一个更复杂的`incrementBy`方法): +看看下面这个`Counter`的另一个版本(它定义了一个更复杂的`incrementBy(_:)`方法): ```swift class Counter { @@ -77,35 +77,28 @@ class Counter { } ``` -`incrementBy`方法有两个参数: `amount`和`numberOfTimes`。默认情况下,Swift 只把`amount`当作一个局部名称,但是把`numberOfTimes`即看作局部名称又看作外部名称。下面调用这个方法: +`incrementBy(_:numverOfTimes:)`方法有两个参数: `amount`和`numberOfTimes`。默认情况下,Swift 只把`amount`当作一个局部名称,但是把`numberOfTimes`即看作局部名称又看作外部名称。下面调用这个方法: ```swift let counter = Counter() counter.incrementBy(5, numberOfTimes: 3) -// counter value is now 15 +// counter 的值现在是 15 ``` -你不必为第一个参数值再定义一个外部变量名:因为从函数名`incrementBy`已经能很清楚地看出它的作用。但是第二个参数,就要被一个外部参数名称所限定,以便在方法被调用时明确它的作用。 +你不必为第一个参数值再定义一个外部变量名:因为从函数名`incrementBy(_numberOfTimes:)`已经能很清楚地看出它的作用。但是第二个参数,就要被一个外部参数名称所限定,以便在方法被调用时明确它的作用。 +这种默认行为使上面代码意味着:在 Swift 中定义方法使用了与 Objective-C 同样的语法风格,并且方法将以自然表达式的方式被调用。 -这种默认的行为能够有效的处理方法(method),类似于在参数`numberOfTimes`前写一个井号(`#`): -```swift -func incrementBy(amount: Int, #numberOfTimes: Int) { - count += amount * numberOfTimes -} -``` - -这种默认行为使上面代码意味着:在 Swift 中定义方法使用了与 Objective-C 同样的语法风格,并且方法将以自然表达式的方式被调用。 - - + ### 修改方法的外部参数名称(Modifying External Parameter Name Behavior for Methods) 有时为方法的第一个参数提供一个外部参数名称是非常有用的,尽管这不是默认的行为。你可以自己添加一个显式的外部名称或者用一个井号(`#`)作为第一个参数的前缀来把这个局部名称当作外部名称使用。 相反,如果你不想为方法的第二个及后续的参数提供一个外部名称,可以通过使用下划线(`_`)作为该参数的显式外部名称,这样做将覆盖默认行为。 + - -## `self`属性(The self Property) + +### self 属性(The self Property) 类型的每一个实例都有一个隐含属性叫做`self`,`self`完全等同于该实例本身。你可以在一个实例的实例方法中使用这个隐含的`self`属性来引用当前实例。 @@ -132,14 +125,14 @@ struct Point { } let somePoint = Point(x: 4.0, y: 5.0) if somePoint.isToTheRightOfX(1.0) { - println("This point is to the right of the line where x == 1.0") + print("This point is to the right of the line where x == 1.0") } -// 输出 "This point is to the right of the line where x == 1.0"(这个点在x等于1.0这条线的右边) +// 打印输出: This point is to the right of the line where x == 1.0 ``` 如果不使用`self`前缀,Swift 就认为两次使用的`x`都指的是名称为`x`的函数参数。 - + ### 在实例方法中修改值类型(Modifying Value Types from Within Instance Methods) 结构体和枚举是**值类型**。一般情况下,值类型的属性不能在它的实例方法中被修改。 @@ -158,21 +151,21 @@ struct Point { } var somePoint = Point(x: 1.0, y: 1.0) somePoint.moveByX(2.0, y: 3.0) -println("The point is now at (\(somePoint.x), \(somePoint.y))") -// 输出 "The point is now at (3.0, 4.0)" +print("The point is now at (\(somePoint.x), \(somePoint.y))") +// 打印输出: "The point is now at (3.0, 4.0)" ``` -上面的`Point`结构体定义了一个变异方法(mutating method)`moveByX`,`moveByX`用来移动点。`moveByX`方法在被调用时修改了这个点,而不是返回一个新的点。方法定义时加上`mutating`关键字,这才让方法可以修改值类型的属性。 +上面的`Point`结构体定义了一个变异方法(mutating method)`moveByX(_:y:)`用来移动点。`moveByX`方法在被调用时修改了这个点,而不是返回一个新的点。方法定义时加上`mutating`关键字,这才让方法可以修改值类型的属性。 -注意:不能在结构体类型常量上调用变异方法,因为常量的属性不能被改变,即使想改变的是常量的变量属性也不行,详情参见[存储属性和实例变量](10_Properties.html#global_and_local_variables) +注意:不能在结构体类型常量上调用变异方法,因为常量的属性不能被改变,即使想改变的是常量的变量属性也不行,详情参见[存储属性和实例变量](10_Properties.html#global_and_local_variables): ```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`的例子可以用下面的方式改写: @@ -186,7 +179,7 @@ struct Point { } ``` -新版的变异方法`moveByX`创建了一个新的结构(它的 x 和 y 的值都被设定为目标值)。调用这个版本的方法和调用上个版本的最终结果是一样的。 +新版的变异方法`moveByX(_:y:)`创建了一个新的结构(它的 x 和 y 的值都被设定为目标值)。调用这个版本的方法和调用上个版本的最终结果是一样的。 枚举的变异方法可以把`self`设置为相同的枚举类型中不同的成员: @@ -214,9 +207,9 @@ ovenLight.next() 上面的例子中定义了一个三态开关的枚举。每次调用`next`方法时,开关在不同的电源状态(`Off`,`Low`,`High`)之前循环切换。 -## 类型方法(Type Methods) +## 类型方法 (Type Methods) -实例方法是被类型的某个实例调用的方法。你也可以定义类型本身调用的方法,这种方法就叫做**类型方法**。声明类的类型方法,在方法的`func`关键字之前加上关键字`class`;声明结构体和枚举的类型方法,在方法的`func`关键字之前加上关键字`static`。 +实例方法是被类型的某个实例调用的方法。你也可以定义类型本身调用的方法,这种方法就叫做**类型方法**。声明结构体和枚举的类型方法,在方法的`func`关键字之前加上关键字`static`。类可能会用关键字`Class`来允许子类重写父类的实现方法。 > 注意: > 在 Objective-C 里面,你只能为 Objective-C 的类定义类型方法(type-level methods)。在 Swift 中,你可以为所有的类、结构体和枚举定义类型方法:每一个类型方法都被它所支持的类型显式包含。 @@ -241,23 +234,23 @@ SomeClass.someTypeMethod() 游戏初始时,所有的游戏等级(除了等级 1)都被锁定。每次有玩家完成一个等级,这个等级就对这个设备上的所有玩家解锁。`LevelTracker`结构体用静态属性和方法监测游戏的哪个等级已经被解锁。它还监测每个玩家的当前等级。 ```swift -struct LevelTracker { - static var highestUnlockedLevel = 1 - static func unlockLevel(level: Int) { - if level > highestUnlockedLevel { highestUnlockedLevel = level } - } - static func levelIsUnlocked(level: Int) -> Bool { - return level <= highestUnlockedLevel - } - var currentLevel = 1 - mutating func advanceToLevel(level: Int) -> Bool { - if LevelTracker.levelIsUnlocked(level) { - currentLevel = level - return true - } else { - return false - } - } +struct LevelTracker { + static var highestUnlockedLevel = 1 + static func unlockLevel(level: Int) { + if level > highestUnlockedLevel { highestUnlockedLevel = level } + } + static func levelIsUnlocked(level: Int) -> Bool { + return level <= highestUnlockedLevel + } + var currentLevel = 1 + mutating func advanceToLevel(level: Int) -> Bool { + if LevelTracker.levelIsUnlocked(level) { + currentLevel = level + return true + } else { + return false + } + } } ``` @@ -285,25 +278,25 @@ class Player { } ``` -`Player`类创建一个新的`LevelTracker`实例来监测这个用户的发展进度。它提供了`completedLevel`方法:一旦玩家完成某个指定等级就调用它。这个方法为所有玩家解锁下一等级,并且将当前玩家的进度更新为下一等级。(我们忽略了`advanceToLevel`返回的布尔值,因为之前调用`LevelTracker.unlockLevel`时就知道了这个等级已经被解锁了)。 +`Player`类创建一个新的`LevelTracker`实例来监测这个用户的进度。它提供了`completedLevel`方法:一旦玩家完成某个指定等级就调用它。这个方法为所有玩家解锁下一等级,并且将当前玩家的进度更新为下一等级。(我们忽略了`advanceToLevel`返回的布尔值,因为之前调用`LevelTracker.unlockLevel`时就知道了这个等级已经被解锁了)。 你还可以为一个新的玩家创建一个`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) +print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)") +// 打印输出:highest unlocked level is now 2 ``` -如果你创建了第二个玩家,并尝试让它开始一个没有被任何玩家解锁的等级,那么这次设置玩家当前等级的尝试将会失败: +如果你创建了第二个玩家,并尝试让他开始一个没有被任何玩家解锁的等级,那么这次设置玩家当前等级的尝试将会失败: ```swift player = Player(name: "Beto") if player.tracker.advanceToLevel(6) { - println("player is now on level 6") + print("player is now on level 6") } else { - println("level 6 has not yet been unlocked") + print("level 6 has not yet been unlocked") } -// 输出 "level 6 has not yet been unlocked"(等级6还没被解锁) +// 打印输出:level 6 has not yet been unlocked ```