From 863441dc3b21974dd5c6cb355b4e0c74fb5d62c4 Mon Sep 17 00:00:00 2001 From: shanksyang Date: Wed, 28 Oct 2015 22:39:43 +0800 Subject: [PATCH] chapter2, 08, enumerations for swift 2.1 --- source/chapter2/08_Enumerations.md | 10 +- source/chapter2/19_Nested_Types.md | 99 ----------- source/chapter2/20_Type_Casting.md | 261 ----------------------------- 3 files changed, 8 insertions(+), 362 deletions(-) delete mode 100644 source/chapter2/19_Nested_Types.md delete mode 100644 source/chapter2/20_Type_Casting.md diff --git a/source/chapter2/08_Enumerations.md b/source/chapter2/08_Enumerations.md index 81565015..6305d85a 100755 --- a/source/chapter2/08_Enumerations.md +++ b/source/chapter2/08_Enumerations.md @@ -8,6 +8,9 @@ > 2.0 > 翻译+校对:[futantan](https://github.com/futantan) +> 2.1 +> 校对:[shanks](http://codebuild.me) + 本页内容包含: - [枚举语法(Enumeration Syntax)](#enumeration_syntax) @@ -24,7 +27,7 @@ 在 Swift 中,枚举类型是一等公民(first-class)。它们采用了很多传统上只被类(class)所支持的特征,例如计算型属性(computed properties),用于提供关于枚举当前值的附加信息,实例方法(instance methods),用于提供和枚举所代表的值相关联的功能。枚举也可以定义构造函数(initializers)来提供一个初始值;可以在原始的实现基础上扩展它们的功能;可以遵守协议(protocols)来提供标准的功能。 -欲了解更多相关信息,请参见[属性(Properties)](./10_Properties.html),[方法(Methods)](./11_Methods.html),[构造过程(Initialization)](./14_Initialization.html),[扩展(Extensions)](./20_Extensions.html)和[协议(Protocols)](./21_Protocols.html)。 +欲了解更多相关信息,请参见[属性(Properties)](./10_Properties.html),[方法(Methods)](./11_Methods.html),[构造过程(Initialization)](./14_Initialization.html),[扩展(Extensions)](./21_Extensions.html)和[协议(Protocols)](./22_Protocols.html)。 ## 枚举语法 @@ -211,6 +214,8 @@ enum ASCIIControlCharacter: Character { >注意: >原始值和相关值是不相同的。当你开始在你的代码中定义枚举的时候原始值是被预先填充的值,像上述三个 ASCII 码。对于一个特定的枚举成员,它的原始值始终是相同的。相关值是当你在创建一个基于枚举成员的新常量或变量时才会被设置,并且每次当你这么做得时候,它的值可以是不同的。 + + ### 原始值的隐式赋值(Implicitly Assigned Raw Values) 在使用原始值为整数或者字符串类型的枚举时,不需要显式的为每一个成员赋值,这时,Swift将会自动为你赋值。 @@ -249,6 +254,7 @@ let sunsetDirection = CompassPoint.West.rawValue // sunsetDirection 值为 "West" ``` + ### 使用原始值初始化枚举变量(Initializing from a Raw Value) 如果在定义枚举类型的时候使用了原始值,那么将会自动获得一个初始化方法,这个方法将原始值类型作为参数,返回值是枚举成员或`nil`。你可以使用这种初始化方法来创建一个新的枚举变量。 @@ -263,7 +269,7 @@ let possiblePlanet = Planet(rawValue: 7) 然而,并非所有可能的`Int`值都可以找到一个匹配的行星。正因为如此,构造函数可以返回一个**可选**的枚举成员。在上面的例子中,`possiblePlanet`是`Planet?`类型,或“可选的`Planet`”。 >注意: ->原始值构造器是一个可失败构造器,因为并不是每一个原始值都有与之对应的枚举成员。更多信息请参见[可失败构造器](../chapter3/05_Declarations#failable_initializers) +>原始值构造器是一个可失败构造器,因为并不是每一个原始值都有与之对应的枚举成员。更多信息请参见[可失败构造器](../chapter3/05_Declarations.html#failable_initializers) 如果你试图寻找一个位置为9的行星,通过参数为`rawValue`构造函数返回的可选`Planet`值将是`nil`: diff --git a/source/chapter2/19_Nested_Types.md b/source/chapter2/19_Nested_Types.md deleted file mode 100644 index fe0bf822..00000000 --- a/source/chapter2/19_Nested_Types.md +++ /dev/null @@ -1,99 +0,0 @@ -> 1.0 -> 翻译:[Lin-H](https://github.com/Lin-H) -> 校对:[shinyzhu](https://github.com/shinyzhu) - -> 2.0 -> 翻译+校对:[SergioChan](https://github.com/SergioChan) - -# 嵌套类型 ------------------ - -本页包含内容: - -- [嵌套类型实例](#nested_types_in_action) -- [嵌套类型的引用](#referring_to_nested_types) - -枚举类型常被用于实现特定类或结构体的功能。也能够在有多种变量类型的环境中,方便地定义通用类或结构体来使用,为了实现这种功能,Swift允许你定义嵌套类型,可以在枚举类型、类和结构体中定义支持嵌套的类型。 - -要在一个类型中嵌套另一个类型,将需要嵌套的类型的定义写在被嵌套类型的区域{}内,而且可以根据需要定义多级嵌套。 - - -##嵌套类型实例 - -下面这个例子定义了一个结构体`BlackjackCard`(二十一点),用来模拟`BlackjackCard`中的扑克牌点数。`BlackjackCard`结构体包含2个嵌套定义的枚举类型`Suit` 和 `Rank`。 - -在`BlackjackCard`规则中,`Ace`牌可以表示1或者11,`Ace`牌的这一特征用一个嵌套在枚举型`Rank`的结构体`Values`来表示。 - -```swift -struct BlackjackCard { - // 嵌套定义枚举型Suit - enum Suit: Character { - case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣" - } - - // 嵌套定义枚举型Rank - enum Rank: Int { - case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten - case Jack, Queen, King, Ace - struct Values { - let first: Int, second: Int? - } - var values: Values { - switch self { - case .Ace: - return Values(first: 1, second: 11) - case .Jack, .Queen, .King: - return Values(first: 10, second: nil) - default: - return Values(first: self.rawValue, second: nil) - } - } - } - - // BlackjackCard 的属性和方法 - let rank: Rank, suit: Suit - var description: String { - var output = "suit is \(suit.rawValue)," - output += " value is \(rank.values.first)" - if let second = rank.values.second { - output += " or \(second)" - } - return output - } -} -``` - -枚举型的`Suit`用来描述扑克牌的四种花色,并分别用一个`Character`类型的值代表花色符号。 - -枚举型的`Rank`用来描述扑克牌从`Ace`~10,`J`,`Q`,`K`,13张牌,并分别用一个`Int`类型的值表示牌的面值。(这个`Int`类型的值不适用于`Ace`,`J`,`Q`,`K`的牌)。 - -如上文所提到的,枚举型`Rank`在自己内部定义了一个嵌套结构体`Values`。在这个结构体中,只有`Ace`有两个数值,其余牌都只有一个数值。结构体`Values`中定义的两个属性: - -`first`, 为` Int` -`second`, 为 `Int?`, 或 “optional `Int`” - -`Rank`定义了一个计算属性`values`,它将会返回一个结构体`Values`的实例。这个计算属性会根据牌的面值,用适当的数值去初始化`Values`实例,并赋值给`values`。对于`J`,`Q`,`K`,`Ace`会使用特殊数值,对于数字面值的牌使用`Int`类型的值。 - -`BlackjackCard`结构体自身有两个属性—`rank`与`suit`,也同样定义了一个计算属性`description`,`description`属性用`rank`和`suit`的中内容来构建对这张扑克牌名字和数值的描述,并用可选类型`second`来检查是否存在第二个值,若存在,则在原有的描述中增加对第二数值的描述。 - -因为`BlackjackCard`是一个没有自定义构造函数的结构体,在[结构体的逐一成员构造器](./14_Initialization.html#memberwise_initializers_for_structure_types)中知道结构体有默认的成员构造函数,所以你可以用默认的`initializer`去初始化新的常量`theAceOfSpades`: - -```swift -let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades) -print("theAceOfSpades: \(theAceOfSpades.description)") -// 打印出 "theAceOfSpades: suit is ♠, value is 1 or 11" -``` - -尽管`Rank`和`Suit`嵌套在`BlackjackCard`中,但仍可被引用,所以在初始化实例时能够通过枚举类型中的成员名称单独引用。在上面的例子中`description`属性能正确得输出对`Ace`牌有1和11两个值。 - - -##嵌套类型的引用 - -在外部对嵌套类型的引用,以被嵌套类型的名字为前缀,加上所要引用的属性名: - -```swift -let heartsSymbol = BlackjackCard.Suit.Hearts.rawValue -// 红心的符号 为 "♡" -``` - -对于上面这个例子,这样可以使`Suit`, `Rank`, 和 `Values`的名字尽可能的短,因为它们的名字会自然的由定义它们的上下文来限定。 diff --git a/source/chapter2/20_Type_Casting.md b/source/chapter2/20_Type_Casting.md deleted file mode 100644 index 8ecbbfb7..00000000 --- a/source/chapter2/20_Type_Casting.md +++ /dev/null @@ -1,261 +0,0 @@ -> 1.0 -> 翻译:[xiehurricane](https://github.com/xiehurricane) -> 校对:[happyming](https://github.com/happyming) - -> 2.0 -> 翻译+校对:[yangsiy](https://github.com/yangsiy) - -# 类型转换(Type Casting) ------------------ - -本页包含内容: - -- [定义一个类层次作为例子](#defining_a_class_hierarchy_for_type_casting) -- [检查类型](#checking_type) -- [向下转型(Downcasting)](#downcasting) -- [`Any`和`AnyObject`的类型转换](#type_casting_for_any_and_anyobject) - - -_类型转换_可以判断实例的类型,也可以将实例看做是其父类或者子类的实例。 - -类型转换在 Swift 中使用 `is` 和 `as` 操作符实现。这两个操作符提供了一种简单达意的方式去检查值的类型或者转换它的类型。 - -你也可以用它来检查一个类是否实现了某个协议,就像在 [检验协议的一致性](./22_Protocols.html#checking_for_protocol_conformance)部分讲述的一样。 - - -## 定义一个类层次作为例子 - -你可以将类型转换用在类和子类的层次结构上,检查特定类实例的类型并且转换这个类实例的类型成为这个层次结构中的其他类型。下面的三个代码段定义了一个类层次和一个包含了几个这些类实例的数组,作为类型转换的例子。 - -第一个代码片段定义了一个新的基础类 `MediaItem`。这个类为任何出现在数字媒体库的媒体项提供基础功能。特别的,它声明了一个 `String` 类型的 `name` 属性,和一个 `init name` 初始化器。(假定所有的媒体项都有个名称。) - -```swift -class MediaItem { - var name: String - init(name: String) { - self.name = name - } -} -``` - -下一个代码段定义了 `MediaItem` 的两个子类。第一个子类 `Movie` 封装了与电影相关的额外信息,在父类(或者说基类)的基础上增加了一个 `director`(导演)属性,和相应的初始化器。第二个子类 `Song`,在父类的基础上增加了一个 `artist`(艺术家)属性,和相应的初始化器: - -```swift -class Movie: MediaItem { - var director: String - init(name: String, director: String) { - self.director = director - super.init(name: name) - } -} - -class Song: MediaItem { - var artist: String - init(name: String, artist: String) { - self.artist = artist - super.init(name: name) - } -} -``` - -最后一个代码段创建了一个数组常量 `library`,包含两个 `Movie` 实例和三个 `Song` 实例。`library` 的类型是在它被初始化时根据它数组中所包含的内容推断来的。Swift的类型检测器能够推理出 `Movie` 和 `Song` 有共同的父类 `MediaItem`,所以它推断出 `[MediaItem]` 类作为 `library` 的类型。 - -```swift -let library = [ - Movie(name: "Casablanca", director: "Michael Curtiz"), - Song(name: "Blue Suede Shoes", artist: "Elvis Presley"), - Movie(name: "Citizen Kane", director: "Orson Welles"), - Song(name: "The One And Only", artist: "Chesney Hawkes"), - Song(name: "Never Gonna Give You Up", artist: "Rick Astley") -] -// the type of "library" is inferred to be [MediaItem] -``` - -在幕后 `library` 里存储的媒体项依然是 `Movie` 和 `Song` 类型的。但是,若你迭代它,依次取出的实例会是 `MediaItem` 类型的,而不是 `Movie` 和 `Song` 类型。为了让它们作为原本的类型工作,你需要检查它们的类型或者向下转换它们到其它类型,就像下面描述的一样。 - - -## 检查类型(Checking Type) - -用类型检查操作符(`is`)来检查一个实例是否属于特定子类型。若实例属于那个子类型,类型检查操作符返回 `true`,否则返回 `false`。 - -下面的例子定义了两个变量,`movieCount` 和 `songCount`,用来计算数组 `library` 中 `Movie` 和 `Song` 类型的实例数量。 - -```swift -var movieCount = 0 -var songCount = 0 - -for item in library { - if item is Movie { - ++movieCount - } else if item is Song { - ++songCount - } -} - -print("Media library contains \(movieCount) movies and \(songCount) songs") -// prints "Media library contains 2 movies and 3 songs" -``` - -示例迭代了数组 `library` 中的所有项。每一次,`for`-`in` 循环设置 -`item` 为数组中的下一个 `MediaItem`。 - -若当前 `MediaItem` 是一个 `Movie` 类型的实例,`item is Movie` 返回 -`true`,相反返回 `false`。同样的,`item is -Song` 检查item是否为 `Song` 类型的实例。在循环结束后,`movieCount` 和 `songCount` 的值就是被找到属于各自的类型的实例数量。 - - -## 向下转型(Downcasting) - -某类型的一个常量或变量可能在幕后实际上属于一个子类。当确定是这种情况时,你可以尝试向下转到它的子类型,用类型转换操作符(`as?` 或 `as!`) - -因为向下转型可能会失败,类型转型操作符带有两种不同形式。条件形式(conditional form) `as?` 返回一个你试图向下转成的类型的可选值(optional value)。强制形式 `as!` 把试图向下转型和强制解包(force-unwraps)结果作为一个混合动作。 - -当你不确定向下转型可以成功时,用类型转换的条件形式(`as?`)。条件形式的类型转换总是返回一个可选值(optional value),并且若下转是不可能的,可选值将是 `nil`。这使你能够检查向下转型是否成功。 - -只有你可以确定向下转型一定会成功时,才使用强制形式(`as!`)。当你试图向下转型为一个不正确的类型时,强制形式的类型转换会触发一个运行时错误。 - -下面的例子,迭代了 `library` 里的每一个 `MediaItem`,并打印出适当的描述。要这样做,`item` 需要真正作为 `Movie` 或 `Song` 的类型来使用,不仅仅是作为 `MediaItem`。为了能够在描述中使用 `Movie` 或 `Song` 的 `director` 或 `artist` 属性,这是必要的。 - -在这个示例中,数组中的每一个 `item` 可能是 `Movie` 或 `Song`。事前你不知道每个 `item` 的真实类型,所以这里使用条件形式的类型转换(`as?`)去检查循环里的每次下转。 - -```swift -for item in library { - if let movie = item as? Movie { - print("Movie: '\(movie.name)', dir. \(movie.director)") - } else if let song = item as? Song { - print("Song: '\(song.name)', by \(song.artist)") - } -} - -// Movie: 'Casablanca', dir. Michael Curtiz -// Song: 'Blue Suede Shoes', by Elvis Presley -// Movie: 'Citizen Kane', dir. Orson Welles -// Song: 'The One And Only', by Chesney Hawkes -// Song: 'Never Gonna Give You Up', by Rick Astley -``` - -示例首先试图将 `item` 下转为 `Movie`。因为 `item` 是一个 `MediaItem` -类型的实例,它可能是一个 `Movie`;同样,它也可能是一个 `Song`,或者仅仅是基类 -`MediaItem`。因为不确定,`as?`形式在试图下转时将返回一个可选值。`item as? Movie` 的返回值是 `Movie?` 或 “可选 `Movie`”类型。 - -当向下转型为 `Movie` 应用在两个 `Song` -实例时将会失败。为了处理这种情况,上面的例子使用了可选绑定(optional binding)来检查可选 `Movie` 真的包含一个值(这个是为了判断下转是否成功。)可选绑定是这样写的“`if let movie = item as? Movie`”,可以这样解读: - -“尝试将 `item` 转为 `Movie` 类型。若成功,设置一个新的临时常量 `movie` 来存储返回的可选 `Movie`” - -若向下转型成功,然后 `movie` 的属性将用于打印一个 `Movie` 实例的描述,包括它的导演的名字 `director` 。相近的原理被用来检测 `Song` 实例,当 `Song` 被找到时则打印它的描述(包含 `artist` 的名字)。 - -> 注意: -> 转换没有真的改变实例或它的值。潜在的根本的实例保持不变;只是简单地把它作为它被转换成的类来使用。 - - -## `Any`和`AnyObject`的类型转换 - -Swift为不确定类型提供了两种特殊类型别名: - -* `AnyObject`可以代表任何class类型的实例。 -* `Any`可以表示任何类型,包括方法类型(function types)。 - -> 注意: -> 只有当你明确的需要它的行为和功能时才使用`Any`和`AnyObject`。在你的代码里使用你期望的明确的类型总是更好的。 - - -### `AnyObject`类型 - -当在工作中使用 Cocoa APIs,我们一般会接收一个`[AnyObject]`类型的数组,或者说“一个任何对象类型的数组”。这是因为 Objective-C 没有明确的类型化数组。但是,你常常可以从 API 提供的信息中清晰地确定数组中对象的类型。 - -在这些情况下,你可以使用强制形式的类型转换(`as`)来下转在数组中的每一项到比 `AnyObject` 更明确的类型,不需要可选解析(optional unwrapping)。 - -下面的示例定义了一个 `[AnyObject]` 类型的数组并填入三个`Movie`类型的实例: - -```swift -let someObjects: [AnyObject] = [ - Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"), - Movie(name: "Moon", director: "Duncan Jones"), - Movie(name: "Alien", director: "Ridley Scott") -] -``` - -因为知道这个数组只包含 `Movie` 实例,你可以直接用(`as!`)下转并解包到不可选的`Movie`类型: - -```swift -for object in someObjects { - let movie = object as! Movie - print("Movie: '\(movie.name)', dir. \(movie.director)") -} -// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick -// Movie: 'Moon', dir. Duncan Jones -// Movie: 'Alien', dir. Ridley Scott -``` - -为了变为一个更短的形式,下转`someObjects`数组为`[Movie]`类型来代替下转数组中每一项的方式。 - -```swift -for movie in someObjects as! [Movie] { - print("Movie: '\(movie.name)', dir. \(movie.director)") -} -// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick -// Movie: 'Moon', dir. Duncan Jones -// Movie: 'Alien', dir. Ridley Scott -``` - -### `Any`类型 - -这里有个示例,使用 `Any` 类型来和混合的不同类型一起工作,包括方法类型和非 `class` 类型。它创建了一个可以存储`Any`类型的数组 `things`。 - -```swift -var things = [Any]() - -things.append(0) -things.append(0.0) -things.append(42) -things.append(3.14159) -things.append("hello") -things.append((3.0, 5.0)) -things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman")) -things.append({ (name: String) -> String in "Hello, \(name)" }) -``` - -`things` 数组包含两个 `Int` 值,2个 `Double` 值,1个 `String` 值,一个元组 `(Double, Double)` ,电影“Ghostbusters”,和一个获取 `String` 值并返回另一个 `String` 值的闭包表达式。 - -你可以在 `switch` 表达式的cases中使用 `is` 和 `as` 操作符来发觉只知道是 `Any` 或 `AnyObject` 的常量或变量的类型。下面的示例迭代 `things` 数组中的每一项的并用`switch`语句查找每一项的类型。这几种 `switch` 语句的情形绑定它们匹配的值到一个规定类型的常量,让它们的值可以被打印: - -```swift -for thing in things { - switch thing { - case 0 as Int: - print("zero as an Int") - case 0 as Double: - print("zero as a Double") - case let someInt as Int: - print("an integer value of \(someInt)") - case let someDouble as Double where someDouble > 0: - print("a positive double value of \(someDouble)") - case is Double: - print("some other double value that I don't want to print") - case let someString as String: - print("a string value of \"\(someString)\"") - case let (x, y) as (Double, Double): - print("an (x, y) point at \(x), \(y)") - case let movie as Movie: - print("a movie called '\(movie.name)', dir. \(movie.director)") - case let stringConverter as String -> String: - print(stringConverter("Michael")) - default: - print("something else") - } -} - -// zero as an Int -// zero as a Double -// an integer value of 42 -// a positive double value of 3.14159 -// a string value of "hello" -// an (x, y) point at 3.0, 5.0 -// a movie called 'Ghostbusters', dir. Ivan Reitman -// Hello, Michael -``` - - -> 注意: -> 在一个switch语句的case中使用强制形式的类型转换操作符(as, 而不是 as?)来检查和转换到一个明确的类型。在 `switch` case 语句的内容中这种检查总是安全的。