From 355374055607172847fbb7ec3ee6536cd5c66d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qi=20Tao=20=28=E7=A5=81=E6=B6=9B=29?= Date: Mon, 9 Jun 2014 13:53:41 +0800 Subject: [PATCH 001/261] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 工作认领:米尔、导演 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 45701fb..8832a3a 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ The Swift Programming Language 中文化项目 * 枚举 [认领 by 灵吾] * 类和结构体 [认领 by 晓毒] * 属性 - * 方法 + * 方法 [认领 by 米尔] * 下标 [已完成 by 递归] * 继承 * 构造过程 @@ -29,7 +29,7 @@ The Swift Programming Language 中文化项目 * 自动引用计数 * 可选链 * 类型检查 - * 嵌套类型 + * 嵌套类型 [认领 by 导演] * 扩展 * 接口 * 泛型 From 1aa649db11bdfaff7e9e5273e9ab0c6d9ce44df5 Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Mon, 9 Jun 2014 14:27:22 +0800 Subject: [PATCH 002/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc2ce21..44bfa98 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ The Swift Programming Language 中文化项目 * 枚举 [认领 by 灵吾] * 类和结构体 [认领 by 晓毒] * 属性 [认领 by 周源] - * 方法 + * 方法 [认领 by 袁鹏] * 下标 [已完成 by 递归] * 继承 * 构造过程 From 8c523f654122328f9309184aa4e54c2ad48a49ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qi=20Tao=20=28=E7=A5=81=E6=B6=9B=29?= Date: Mon, 9 Jun 2014 14:30:52 +0800 Subject: [PATCH 003/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8832a3a..0b5fd9a 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ The Swift Programming Language 中文化项目 * 自动引用计数 * 可选链 * 类型检查 - * 嵌套类型 [认领 by 导演] + * 嵌套类型 * 扩展 * 接口 * 泛型 From ed8cf6b7f637f36d081274e298b23855f83169f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Mon, 9 Jun 2014 16:02:31 +0800 Subject: [PATCH 004/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45701fb..5259306 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The Swift Programming Language 中文化项目 * 析构过程 * 自动引用计数 * 可选链 - * 类型检查 + * 类型检查[认领 by 孟志昂] * 嵌套类型 * 扩展 * 接口 From aef7b0c7b150ce9817c6638455469d02bf039175 Mon Sep 17 00:00:00 2001 From: Xiao Du Date: Mon, 9 Jun 2014 20:37:57 +0800 Subject: [PATCH 005/261] =?UTF-8?q?=E5=B8=AE=E8=83=A1=E8=A1=8D=E6=98=8E?= =?UTF-8?q?=E8=AE=A4=E9=A2=86[=E6=B3=9B=E5=9E=8B]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e5001e..4ddd701 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The Swift Programming Language 中文化项目 * 嵌套类型 [认领 by 祁涛] * 扩展 [认领 by 袁鹏] * 接口 [认领 by 姜天意] - * 泛型 + * 泛型 [认领 by 胡衍明] * 高级操作符 [认领 by 林晚] * 语言参考 * 关于语言参考 [认领 by 筱强] From 96dc79e3f9ba8a26062804c13ed0111340f12211 Mon Sep 17 00:00:00 2001 From: Xiao Du Date: Mon, 9 Jun 2014 20:56:22 +0800 Subject: [PATCH 006/261] =?UTF-8?q?Revert=20"=E5=B8=AE=E8=83=A1=E8=A1=8D?= =?UTF-8?q?=E6=98=8E=E8=AE=A4=E9=A2=86[=E6=B3=9B=E5=9E=8B]"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit aef7b0c7b150ce9817c6638455469d02bf039175. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ddd701..9e5001e 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The Swift Programming Language 中文化项目 * 嵌套类型 [认领 by 祁涛] * 扩展 [认领 by 袁鹏] * 接口 [认领 by 姜天意] - * 泛型 [认领 by 胡衍明] + * 泛型 * 高级操作符 [认领 by 林晚] * 语言参考 * 关于语言参考 [认领 by 筱强] From a27937dfb4d8c590f0fe8c8fe33eed72553c01f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Mon, 9 Jun 2014 23:03:08 +0800 Subject: [PATCH 007/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 201 ++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index e69de29..040bc08 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -0,0 +1,201 @@ +Type Casting +On This Page +Type casting is a way to check the type of an instance, and/or to treat that instance as if it is a different superclass or subclass from somewhere else in its own class hierarchy. + +Type casting in Swift is implemented with the is and as operators. These two operators provide a simple and expressive way to check the type of a value or cast a value to a different type. + +You can also use type casting to check whether a type conforms to a protocol, as described in Checking for Protocol Conformance. + +Defining a Class Hierarchy for Type Casting + +You can use type casting with a hierarchy of classes and subclasses to check the type of a particular class instance and to cast that instance to another class within the same hierarchy. The three code snippets below define a hierarchy of classes and an array containing instances of those classes, for use in an example of type casting. + +The first snippet defines a new base class called MediaItem. This class provides basic functionality for any kind of item that appears in a digital media library. Specifically, it declares a name property of type String, and an init name initializer. (It is assumed that all media items, including all movies and songs, will have a name.) + +class MediaItem { + var name: String + init(name: String) { + self.name = name + } +} +The next snippet defines two subclasses of MediaItem. The first subclass, Movie, encapsulates additional information about a movie or film. It adds a director property on top of the base MediaItem class, with a corresponding initializer. The second subclass, Song, adds an artist property and initializer on top of the base class: + +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) + } +} +The final snippet creates a constant array called library, which contains two Movie instances and three Song instances. The type of the library array is inferred by initializing it with the contents of an array literal. Swift’s type checker is able to deduce that Movie and Song have a common superclass of MediaItem, and so it infers a type of MediaItem[] for the library array: + +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[] +The items stored in library are still Movie and Song instances behind the scenes. However, if you iterate over the contents of this array, the items you receive back are typed as MediaItem, and not as Movie or Song. In order to work with them as their native type, you need to check their type, or downcast them to a different type, as described below. + +Checking Type + +Use the type check operator (is) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not. + +The example below defines two variables, movieCount and songCount, which count the number of Movie and Song instances in the library array: + +var movieCount = 0 +var songCount = 0 + +for item in library { + if item is Movie { + ++movieCount + } else if item is Song { + ++songCount + } +} + +println("Media library contains \(movieCount) movies and \(songCount) songs") +// prints "Media library contains 2 movies and 3 songs" +This example iterates through all items in the library array. On each pass, the for-in loop sets the item constant to the next MediaItem in the array. + +item is Movie returns true if the current MediaItem is a Movie instance and false if it is not. Similarly, item is Song checks whether the item is a Song instance. At the end of the for-in loop, the values of movieCount and songCount contain a count of how many MediaItem instances were found of each type. + +Downcasting + +A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with the type cast operator (as). + +Because downcasting can fail, the type cast operator comes in two different forms. The optional form, as?, returns an optional value of the type you are trying to downcast to. The forced form, as, attempts the downcast and force-unwraps the result as a single compound action. + +Use the optional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast. + +Use the forced form of the type cast operator (as) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type. + +The example below iterates over each MediaItem in library, and prints an appropriate description for each item. To do this, it needs to access each item as a true Movie or Song, and not just as a MediaItem. This is necessary in order for it to be able to access the director or artist property of a Movie or Song for use in the description. + +In this example, each item in the array might be a Movie, or it might be a Song. You don’t know in advance which actual class to use for each item, and so it is appropriate to use the optional form of the type cast operator (as?) to check the downcast each time through the loop: + +for item in library { + if let movie = item as? Movie { + println("Movie: '\(movie.name)', dir. \(movie.director)") + } else if let song = item as? Song { + println("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 +The example starts by trying to downcast the current item as a Movie. Because item is a MediaItem instance, it’s possible that it might be a Movie; equally, it’s also possible that it might a Song, or even just a base MediaItem. Because of this uncertainty, the as? form of the type cast operator returns an optional value when attempting to downcast to a subclass type. The result of item as Movie is of type Movie?, or “optional Movie”. + +Downcasting to Movie fails when applied to the two Song instances in the library array. To cope with this, the example above uses optional binding to check whether the optional Movie actually contains a value (that is, to find out whether the downcast succeeded.) This optional binding is written “if let movie = item as? Movie”, which can be read as: + +“Try to access item as a Movie. If this is successful, set a new temporary constant called movie to the value stored in the returned optional Movie.” + +If the downcasting succeeds, the properties of movie are then used to print a description for that Movie instance, including the name of its director. A similar principle is used to check for Song instances, and to print an appropriate description (including artist name) whenever a Song is found in the library. + +NOTE + +Casting does not actually modify the instance or change its values. The underlying instance remains the same; it is simply treated and accessed as an instance of the type to which it has been cast. + +Type Casting for Any and AnyObject + +Swift provides two special type aliases for working with non-specific types: + +AnyObject can represent an instance of any class type. +Any can represent an instance of any type at all, apart from function types. +NOTE + +Use Any and AnyObject only when you explicitly need the behavior and capabilities they provide. It is always better to be specific about the types you expect to work with in your code. + +AnyObject + +When working with Cocoa APIs, it is common to receive an array with a type of AnyObject[], or “an array of values of any object type”. This is because Objective-C does not have explicitly typed arrays. However, you can often be confident about the type of objects contained in such an array just from the information you know about the API that provided the array. + +In these situations, you can use the forced version of the type cast operator (as) to downcast each item in the array to a more specific class type than AnyObject, without the need for optional unwrapping. + +The example below defines an array of type AnyObject[] and populates this array with three instances of the Movie class: + +let someObjects: AnyObject[] = [ + Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"), + Movie(name: "Moon", director: "Duncan Jones"), + Movie(name: "Alien", director: "Ridley Scott") +] +Because this array is known to contain only Movie instances, you can downcast and unwrap directly to a non-optional Movie with the forced version of the type cast operator (as): + +for object in someObjects { + let movie = object as Movie + println("Movie: '\(movie.name)', dir. \(movie.director)") +} +// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick +// Movie: 'Moon', dir. Duncan Jones +// Movie: 'Alien', dir. Ridley Scott +For an even shorter form of this loop, downcast the someObjects array to a type of Movie[] instead of downcasting each item: + +for movie in someObjects as Movie[] { + println("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 + +Here’s an example of using Any to work with a mix of different types, including non-class types. The example creates an array called things, which can store values of type Any: + +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")) +The things array contains two Int values, two Double values, a String value, a tuple of type (Double, Double), and the movie “Ghostbusters”, directed by Ivan Reitman. + +You can use the is and as operators in a switch statement’s cases to discover the specific type of a constant or variable that is known only to be of type Any or AnyObject. The example below iterates over the items in the things array and queries the type of each item with a switch statement. Several of the switch statement’s cases bind their matched value to a constant of the specified type to enable its value to be printed: + +for thing in things { + switch thing { + case 0 as Int: + println("zero as an Int") + case 0 as Double: + println("zero as a Double") + case let someInt as Int: + println("an integer value of \(someInt)") + case let someDouble as Double where someDouble > 0: + println("a positive double value of \(someDouble)") + case is Double: + println("some other double value that I don't want to print") + case let someString as String: + println("a string value of \"\(someString)\"") + case let (x, y) as (Double, Double): + println("an (x, y) point at \(x), \(y)") + case let movie as Movie: + println("a movie called '\(movie.name)', dir. \(movie.director)") + default: + println("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 +NOTE + +The cases of a switch statement use the forced version of the type cast operator (as, not as?) to check and cast to a specific type. This check is always safe within the context of a switch case statement. From b4df20e401732da06969f5d5c5257910e2c27d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Mon, 9 Jun 2014 23:03:39 +0800 Subject: [PATCH 008/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index 040bc08..7e60d87 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -1,5 +1,5 @@ -Type Casting -On This Page +#Type Casting +#On This Page Type casting is a way to check the type of an instance, and/or to treat that instance as if it is a different superclass or subclass from somewhere else in its own class hierarchy. Type casting in Swift is implemented with the is and as operators. These two operators provide a simple and expressive way to check the type of a value or cast a value to a different type. From d681acff585236cda11ea4399e9ace886e159208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Mon, 9 Jun 2014 23:03:54 +0800 Subject: [PATCH 009/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index 7e60d87..4ce268a 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -1,5 +1,5 @@ #Type Casting -#On This Page + Type casting is a way to check the type of an instance, and/or to treat that instance as if it is a different superclass or subclass from somewhere else in its own class hierarchy. Type casting in Swift is implemented with the is and as operators. These two operators provide a simple and expressive way to check the type of a value or cast a value to a different type. From 164335805e1d7d9d96a43e621bcbba8379c34a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Mon, 9 Jun 2014 23:08:49 +0800 Subject: [PATCH 010/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 237 ++++++++++++++++---------------- 1 file changed, 119 insertions(+), 118 deletions(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index 4ce268a..0fbc12f 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -6,71 +6,71 @@ Type casting in Swift is implemented with the is and as operators. These two ope You can also use type casting to check whether a type conforms to a protocol, as described in Checking for Protocol Conformance. -Defining a Class Hierarchy for Type Casting +##Defining a Class Hierarchy for Type Casting You can use type casting with a hierarchy of classes and subclasses to check the type of a particular class instance and to cast that instance to another class within the same hierarchy. The three code snippets below define a hierarchy of classes and an array containing instances of those classes, for use in an example of type casting. The first snippet defines a new base class called MediaItem. This class provides basic functionality for any kind of item that appears in a digital media library. Specifically, it declares a name property of type String, and an init name initializer. (It is assumed that all media items, including all movies and songs, will have a name.) -class MediaItem { - var name: String - init(name: String) { - self.name = name + class MediaItem { + var name: String + init(name: String) { + self.name = name + } } -} The next snippet defines two subclasses of MediaItem. The first subclass, Movie, encapsulates additional information about a movie or film. It adds a director property on top of the base MediaItem class, with a corresponding initializer. The second subclass, Song, adds an artist property and initializer on top of the base class: -class Movie: MediaItem { - var director: String - init(name: String, director: String) { - self.director = director - super.init(name: name) + 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) + + class Song: MediaItem { + var artist: String + init(name: String, artist: String) { + self.artist = artist + super.init(name: name) + } } -} The final snippet creates a constant array called library, which contains two Movie instances and three Song instances. The type of the library array is inferred by initializing it with the contents of an array literal. Swift’s type checker is able to deduce that Movie and Song have a common superclass of MediaItem, and so it infers a type of MediaItem[] for the library array: -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[] + 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[] The items stored in library are still Movie and Song instances behind the scenes. However, if you iterate over the contents of this array, the items you receive back are typed as MediaItem, and not as Movie or Song. In order to work with them as their native type, you need to check their type, or downcast them to a different type, as described below. -Checking Type +##Checking Type Use the type check operator (is) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not. The example below defines two variables, movieCount and songCount, which count the number of Movie and Song instances in the library array: -var movieCount = 0 -var songCount = 0 - -for item in library { - if item is Movie { - ++movieCount - } else if item is Song { - ++songCount + var movieCount = 0 + var songCount = 0 + + for item in library { + if item is Movie { + ++movieCount + } else if item is Song { + ++songCount + } } -} - -println("Media library contains \(movieCount) movies and \(songCount) songs") -// prints "Media library contains 2 movies and 3 songs" + + println("Media library contains \(movieCount) movies and \(songCount) songs") + // prints "Media library contains 2 movies and 3 songs" This example iterates through all items in the library array. On each pass, the for-in loop sets the item constant to the next MediaItem in the array. item is Movie returns true if the current MediaItem is a Movie instance and false if it is not. Similarly, item is Song checks whether the item is a Song instance. At the end of the for-in loop, the values of movieCount and songCount contain a count of how many MediaItem instances were found of each type. -Downcasting +##Downcasting A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with the type cast operator (as). @@ -84,19 +84,19 @@ The example below iterates over each MediaItem in library, and prints an appropr In this example, each item in the array might be a Movie, or it might be a Song. You don’t know in advance which actual class to use for each item, and so it is appropriate to use the optional form of the type cast operator (as?) to check the downcast each time through the loop: -for item in library { - if let movie = item as? Movie { - println("Movie: '\(movie.name)', dir. \(movie.director)") - } else if let song = item as? Song { - println("Song: '\(song.name)', by \(song.artist)") + for item in library { + if let movie = item as? Movie { + println("Movie: '\(movie.name)', dir. \(movie.director)") + } else if let song = item as? Song { + println("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 + + // 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 The example starts by trying to downcast the current item as a Movie. Because item is a MediaItem instance, it’s possible that it might be a Movie; equally, it’s also possible that it might a Song, or even just a base MediaItem. Because of this uncertainty, the as? form of the type cast operator returns an optional value when attempting to downcast to a subclass type. The result of item as Movie is of type Movie?, or “optional Movie”. Downcasting to Movie fails when applied to the two Song instances in the library array. To cope with this, the example above uses optional binding to check whether the optional Movie actually contains a value (that is, to find out whether the downcast succeeded.) This optional binding is written “if let movie = item as? Movie”, which can be read as: @@ -105,11 +105,11 @@ Downcasting to Movie fails when applied to the two Song instances in the library If the downcasting succeeds, the properties of movie are then used to print a description for that Movie instance, including the name of its director. A similar principle is used to check for Song instances, and to print an appropriate description (including artist name) whenever a Song is found in the library. -NOTE - -Casting does not actually modify the instance or change its values. The underlying instance remains the same; it is simply treated and accessed as an instance of the type to which it has been cast. +> NOTE -Type Casting for Any and AnyObject +> Casting does not actually modify the instance or change its values. The underlying instance remains the same; it is >simply treated and accessed as an instance of the type to which it has been cast. + +##Type Casting for Any and AnyObject Swift provides two special type aliases for working with non-specific types: @@ -119,7 +119,7 @@ NOTE Use Any and AnyObject only when you explicitly need the behavior and capabilities they provide. It is always better to be specific about the types you expect to work with in your code. -AnyObject +###AnyObject When working with Cocoa APIs, it is common to receive an array with a type of AnyObject[], or “an array of values of any object type”. This is because Objective-C does not have explicitly typed arrays. However, you can often be confident about the type of objects contained in such an array just from the information you know about the API that provided the array. @@ -127,75 +127,76 @@ In these situations, you can use the forced version of the type cast operator (a The example below defines an array of type AnyObject[] and populates this array with three instances of the Movie class: -let someObjects: AnyObject[] = [ - Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"), - Movie(name: "Moon", director: "Duncan Jones"), - Movie(name: "Alien", director: "Ridley Scott") -] + let someObjects: AnyObject[] = [ + Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"), + Movie(name: "Moon", director: "Duncan Jones"), + Movie(name: "Alien", director: "Ridley Scott") + ] Because this array is known to contain only Movie instances, you can downcast and unwrap directly to a non-optional Movie with the forced version of the type cast operator (as): -for object in someObjects { - let movie = object as Movie - println("Movie: '\(movie.name)', dir. \(movie.director)") -} -// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick -// Movie: 'Moon', dir. Duncan Jones -// Movie: 'Alien', dir. Ridley Scott + for object in someObjects { + let movie = object as Movie + println("Movie: '\(movie.name)', dir. \(movie.director)") + } + // Movie: '2001: A Space Odyssey', dir. Stanley Kubrick + // Movie: 'Moon', dir. Duncan Jones + // Movie: 'Alien', dir. Ridley Scott For an even shorter form of this loop, downcast the someObjects array to a type of Movie[] instead of downcasting each item: -for movie in someObjects as Movie[] { - println("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 + for movie in someObjects as Movie[] { + println("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 Here’s an example of using Any to work with a mix of different types, including non-class types. The example creates an array called things, which can store values of type Any: -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")) + 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")) The things array contains two Int values, two Double values, a String value, a tuple of type (Double, Double), and the movie “Ghostbusters”, directed by Ivan Reitman. You can use the is and as operators in a switch statement’s cases to discover the specific type of a constant or variable that is known only to be of type Any or AnyObject. The example below iterates over the items in the things array and queries the type of each item with a switch statement. Several of the switch statement’s cases bind their matched value to a constant of the specified type to enable its value to be printed: -for thing in things { - switch thing { - case 0 as Int: - println("zero as an Int") - case 0 as Double: - println("zero as a Double") - case let someInt as Int: - println("an integer value of \(someInt)") - case let someDouble as Double where someDouble > 0: - println("a positive double value of \(someDouble)") - case is Double: - println("some other double value that I don't want to print") - case let someString as String: - println("a string value of \"\(someString)\"") - case let (x, y) as (Double, Double): - println("an (x, y) point at \(x), \(y)") - case let movie as Movie: - println("a movie called '\(movie.name)', dir. \(movie.director)") - default: - println("something else") + for thing in things { + switch thing { + case 0 as Int: + println("zero as an Int") + case 0 as Double: + println("zero as a Double") + case let someInt as Int: + println("an integer value of \(someInt)") + case let someDouble as Double where someDouble > 0: + println("a positive double value of \(someDouble)") + case is Double: + println("some other double value that I don't want to print") + case let someString as String: + println("a string value of \"\(someString)\"") + case let (x, y) as (Double, Double): + println("an (x, y) point at \(x), \(y)") + case let movie as Movie: + println("a movie called '\(movie.name)', dir. \(movie.director)") + default: + println("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 -NOTE - -The cases of a switch statement use the forced version of the type cast operator (as, not as?) to check and cast to a specific type. This check is always safe within the context of a switch case statement. + + // 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 +>NOTE + +>The cases of a switch statement use the forced version of the type cast operator (as, not as?) to check and cast to a >specific type. This check is always safe within the context of a switch case statement. From d60a00b38e5c2fd22cffebfabdf3bdb0a67eda10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Mon, 9 Jun 2014 23:21:36 +0800 Subject: [PATCH 011/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index 0fbc12f..dc643d0 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -6,6 +6,12 @@ Type casting in Swift is implemented with the is and as operators. These two ope You can also use type casting to check whether a type conforms to a protocol, as described in Checking for Protocol Conformance. +# 类型转换 +类型转换是一种方法来检查一个实例的类型,和/或处理该实例,就好像它是一个不同的超类或子类从别的在自己的类层次结构中的某个地方。 + +类型转换使用is和as操作符来实现。这两个操作符提供了一种简单和富有表现力的方法来检查一个值的类型或把某个值转换为不同的类型。 +你还可以使用类型转换来检查类型是否符合,如在检查协议一致性描述。 + ##Defining a Class Hierarchy for Type Casting You can use type casting with a hierarchy of classes and subclasses to check the type of a particular class instance and to cast that instance to another class within the same hierarchy. The three code snippets below define a hierarchy of classes and an array containing instances of those classes, for use in an example of type casting. From 82240a9625e4d5e75bc514468cf07da8b11030c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Mon, 9 Jun 2014 23:25:32 +0800 Subject: [PATCH 012/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index dc643d0..6d65d6b 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -12,12 +12,18 @@ You can also use type casting to check whether a type conforms to a protocol, as 类型转换使用is和as操作符来实现。这两个操作符提供了一种简单和富有表现力的方法来检查一个值的类型或把某个值转换为不同的类型。 你还可以使用类型转换来检查类型是否符合,如在检查协议一致性描述。 -##Defining a Class Hierarchy for Type Casting +##定义一个类继承为类型转换 You can use type casting with a hierarchy of classes and subclasses to check the type of a particular class instance and to cast that instance to another class within the same hierarchy. The three code snippets below define a hierarchy of classes and an array containing instances of those classes, for use in an example of type casting. The first snippet defines a new base class called MediaItem. This class provides basic functionality for any kind of item that appears in a digital media library. Specifically, it declares a name property of type String, and an init name initializer. (It is assumed that all media items, including all movies and songs, will have a name.) +## 定义一个类继承为类型转换 + +您可以使用类型转换与类和子类的层次结构来检查一个特定的类实例的类型和投该实例到另一个类中的同一层级内。下面的三个代码片段定义的类层次结构和包含这些类的实例数组,用于类型转换的一个例子使用。 + +第一个片段定义了一个名为MediaItem新的基类。这个类提供基本功能,任何类型的项目出现在一个数字媒体库。具体来说,它声明一个String类型的name属性,以及一个init名称初始值设定项。 (假设所有的媒体项目,包括所有的电影和歌曲,将有一个名称。) + class MediaItem { var name: String init(name: String) { From e29a6290a4cbe43e473b2f790963ce96b762bce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Mon, 9 Jun 2014 23:26:11 +0800 Subject: [PATCH 013/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index 6d65d6b..dced732 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -12,7 +12,7 @@ You can also use type casting to check whether a type conforms to a protocol, as 类型转换使用is和as操作符来实现。这两个操作符提供了一种简单和富有表现力的方法来检查一个值的类型或把某个值转换为不同的类型。 你还可以使用类型转换来检查类型是否符合,如在检查协议一致性描述。 -##定义一个类继承为类型转换 +##Defining a Class Hierarchy for Type Casting You can use type casting with a hierarchy of classes and subclasses to check the type of a particular class instance and to cast that instance to another class within the same hierarchy. The three code snippets below define a hierarchy of classes and an array containing instances of those classes, for use in an example of type casting. From 76bd96196f516b2521a6675207d3ace9e6b9d05d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Mon, 9 Jun 2014 23:29:42 +0800 Subject: [PATCH 014/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index dced732..d319a32 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -32,6 +32,8 @@ The first snippet defines a new base class called MediaItem. This class provides } The next snippet defines two subclasses of MediaItem. The first subclass, Movie, encapsulates additional information about a movie or film. It adds a director property on top of the base MediaItem class, with a corresponding initializer. The second subclass, Song, adds an artist property and initializer on top of the base class: +接下来的片断定义MediaItem的两个子类。第一个子类,电影,封装了有关电影或电影的附加信息。它增加了一个属性主任在基MediaItem类的顶部,有一个相应的初始化。第二个亚类,宋,增加了一个艺术家财产和初始化基类的顶部: + class Movie: MediaItem { var director: String init(name: String, director: String) { @@ -49,6 +51,8 @@ The next snippet defines two subclasses of MediaItem. The first subclass, Movie, } The final snippet creates a constant array called library, which contains two Movie instances and three Song instances. The type of the library array is inferred by initializing it with the contents of an array literal. Swift’s type checker is able to deduce that Movie and Song have a common superclass of MediaItem, and so it infers a type of MediaItem[] for the library array: +最后的代码片断创建一个常量数组叫做库,其中包含两个电影实例和三首歌曲的实例。图书馆数组的类型是由具有数组文本的内容初始化它的推断。斯威夫特的类型检查是能够演绎出电影和歌曲有MediaItem一个共同的超类,所以它会推断图书馆数组类型MediaItem[]中: + let library = [ Movie(name: "Casablanca", director: "Michael Curtiz"), Song(name: "Blue Suede Shoes", artist: "Elvis Presley"), @@ -59,12 +63,20 @@ The final snippet creates a constant array called library, which contains two Mo // the type of "library" is inferred to be MediaItem[] The items stored in library are still Movie and Song instances behind the scenes. However, if you iterate over the contents of this array, the items you receive back are typed as MediaItem, and not as Movie or Song. In order to work with them as their native type, you need to check their type, or downcast them to a different type, as described below. +存储在库中的项目仍然在幕后电影和歌曲实例。但是,如果你遍历这个数组的内容,您会收到回项目类型为MediaItem,而不是电影或歌曲。为了与他们合作,因为他们自身的类型,你需要检查它们的类型,或将它们向下转换为不同的类型,如下所述。 + ##Checking Type Use the type check operator (is) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not. The example below defines two variables, movieCount and songCount, which count the number of Movie and Song instances in the library array: +##检查类型 + +使用类型检查运算符(是)来检查一个实例是否是一个子类的类型。如果实例是子类的类型和虚假的,如果它不是类型检查运算符返回true。 + +下面的例子定义了两个变量,movieCount和songCount,这算电影和歌曲实例库中的数组数: + var movieCount = 0 var songCount = 0 @@ -78,6 +90,7 @@ The example below defines two variables, movieCount and songCount, which count t println("Media library contains \(movieCount) movies and \(songCount) songs") // prints "Media library contains 2 movies and 3 songs" + This example iterates through all items in the library array. On each pass, the for-in loop sets the item constant to the next MediaItem in the array. item is Movie returns true if the current MediaItem is a Movie instance and false if it is not. Similarly, item is Song checks whether the item is a Song instance. At the end of the for-in loop, the values of movieCount and songCount contain a count of how many MediaItem instances were found of each type. From 563f7566fd25e3cb52623fc381ccda51f6687416 Mon Sep 17 00:00:00 2001 From: Xiao Du Date: Mon, 9 Jun 2014 23:33:06 +0800 Subject: [PATCH 015/261] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E7=B1=BB=E5=92=8C?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E4=BD=933=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + src/chapter2/09_Classes_and_Structures.md | 102 ++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index e69de29..9e45542 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -0,0 +1,102 @@ +## Classes and Structures +## 类与结构体 + +*Classes* and *structures* are general-purpose, flexible constructs that become the building blocks of your program’s code. You define properties and methods to add functionality to your classes and structures by using exactly the same syntax as for constants, variables, and functions.” + +*类*和*结构体*是通用的、灵活的结构,是您搭建代码的基石。您可以使用和定义常量、变量或函数相同的句法,为类添加属性和方法以增加新的功能。 + +Unlike other programming languages, Swift does not require you to create separate interface and implementation files for custom classes and structures. In Swift, you define a class or a structure in a single file, and the external interface to that class or structure is automatically made available for other code to use. + +与其他编程语言不同,Swift并不强制要求分隔自定义类或结构体的头文件和实现文件。在Swift中,你只需将类或结构体定义在一个文件中,这个类或结构体的外部接口就自动能被其他代码使用。 + +``` +NOTE + +An instance of a class is traditionally known as an object. However, Swift classes and structures are much closer in functionality than in other languages, and much of this chapter describes functionality that can apply to instances of either a class or a structure type. Because of this, the more general term instance is used. +``` + +``` +注意 +类的实例通常被当作为一个对象。但与其他语言相比,Swift中的类和结构体从功能上来说更为相似。本章中介绍的大部分功能,可以适用于任何一个类或者结构体的实例。因此我们将使用一个更加宽泛的词语--实例(instance)来描述类和结构体。 +``` + +### Comparing Classes and Structures +### 比较类和结构体 +Classes and structures in Swift have many things in common. Both can: + +* Define properties to store values +* Define methods to provide functionality +* Define subscripts to provide access to their values using subscript syntax +* Define initializers to set up their initial state +* Be extended to expand their functionality beyond a default implementation +* Conform to protocols to provide standard functionality of a certain kind + +For more information, see [Properties](), [Methods](), [Subscripts](), [Initialization](), [Extensions](), and [Protocols](). + + +在Swift中类和结构体有许多相同之处,它们都有如下功能: + +* 能定义属性以便存储数据 +* 能定义方法以便提供功能 +* ~~定义了下标以便使用下标语法来访问实例的值~~ +* 能定义设定初始状态的初始化方法 +* 能被扩展,使其有默认实现之外的功能 +* 遵从协议(protocol)规则,以便提供~~协议所规定类型的标准功能~~ + +欲了解更多信息,请参见[属性](),[方法](),[下标](),[构造过程](),[扩展]()和[协议]()章节。 + +Classes have additional capabilities that structures do not: + +* Inheritance enables one class to inherit the characteristics of another. +* Type casting enables you to check and interpret the type of a class instance at runtime. +* Deinitializers enable an instance of a class to free up any resources it has assigned. +* Reference counting allows more than one reference to a class instance. + +For more information, see [Inheritance](), [Type Casting](), [Initialization](), and [Automatic Reference Counting](). + +不过类也有一些结构体没有的额外功能: + +* 继承使得一个类能继承来自另一个类的特性。 +* 类型转换可以在运行时检查和解析一个类的实例的类型。 +* 析构方法让类的实例被~~指派给了其他内存~~时能够释放自己的资源。 +* 引用计数允许一个类的实例被多处引用。 + +欲了解更多信息,请参见[继承](),[类型转换](),[构造过程](),[自动引用计数]()章节。 + +``` +NOTE + +Structures are always copied when they are passed around in your code, and do not use reference counting. +``` + +``` +注意: +结构体在代码中被传递时始终是传值,不会涉及到引用计数 + +``` + +‌ +### Definition Syntax +### 定义语法 + +Classes and structures have a similar definition syntax. You introduce classes with the `class` keyword and structures with the `struct` keyword. Both place their entire definition within a pair of braces: + +``` +class SomeClass { + // class definition goes here +} +struct SomeStructure { + // structure definition goes here +} +``` + +定义类和结构体的语法相似。定义类以关键词`class`开头,而定义结构体以关键词`struct`开头。类和结构体的所有定义都写在一对大括号内: + +``` +class SomeClass { + // class definition goes here +} +struct SomeStructure { + // structure definition goes here +} +``` \ No newline at end of file From 684efdae29fbfdb863a2eda3f485a96b675bbac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Mon, 9 Jun 2014 23:46:19 +0800 Subject: [PATCH 016/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 71 ++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index d319a32..3a092f9 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -71,7 +71,7 @@ Use the type check operator (is) to check whether an instance is of a certain su The example below defines two variables, movieCount and songCount, which count the number of Movie and Song instances in the library array: -##检查类型 +## 检查类型 使用类型检查运算符(是)来检查一个实例是否是一个子类的类型。如果实例是子类的类型和虚假的,如果它不是类型检查运算符返回true。 @@ -95,20 +95,38 @@ This example iterates through all items in the library array. On each pass, the item is Movie returns true if the current MediaItem is a Movie instance and false if it is not. Similarly, item is Song checks whether the item is a Song instance. At the end of the for-in loop, the values of movieCount and songCount contain a count of how many MediaItem instances were found of each type. +通过图书馆阵列中的所有项目本示例循环。在每个传中,for-in循环设置项常量数组中的下一个MediaItem。 + +产品如果当前MediaItem是一个Movie实例和虚假的,如果它不是电影返回true。同样,产品松检查项目是否为宋实例。在for-in循环的结束,movieCount和songCount的值包含多少MediaItem实例中发现每种类型的计数。 + ##Downcasting A constant or variable of a certain class type may actually refer to an instance of a subclass behind the scenes. Where you believe this is the case, you can try to downcast to the subclass type with the type cast operator (as). Because downcasting can fail, the type cast operator comes in two different forms. The optional form, as?, returns an optional value of the type you are trying to downcast to. The forced form, as, attempts the downcast and force-unwraps the result as a single compound action. +## 向下转换 + +某一类类型的常量或变量可能实际上是指在幕后一个子类的实例。在那里你认为是这样的话,你可以尝试向下转换与类型转换运算符(如)的子类型。 + +因为向下转换可能会失败,类型转换运算符有两种不同的形式。可选的形式,?,返回你试图向下转换到该类型的可选值。强制的形式,如,试图丧气和强制解开的结果作为一个单一的复合动作。 + Use the optional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast. Use the forced form of the type cast operator (as) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type. +使用类型转换运算符的可选形式(as?)时,你是不知道,如果向下转换会成功。这种形式的运算符将始终返回一个可选值,该值将为零,如果向下转换是不可能的。这使您可以检查是否有成功的垂头丧气。 + +使用类型转换运算符的强制形式(如)只有当你确定低垂将始终成功。如果您尝试向下转换到一个不正确的类类型这种形式的操作会触发一个运行时错误。 + The example below iterates over each MediaItem in library, and prints an appropriate description for each item. To do this, it needs to access each item as a true Movie or Song, and not just as a MediaItem. This is necessary in order for it to be able to access the director or artist property of a Movie or Song for use in the description. In this example, each item in the array might be a Movie, or it might be a Song. You don’t know in advance which actual class to use for each item, and so it is appropriate to use the optional form of the type cast operator (as?) to check the downcast each time through the loop: +下面遍历每个MediaItem库,并打印每个项目的适当描述的例子。要做到这一点,它需要访问每个项目作为一个真正的电影或歌曲,而不是仅仅作为一个MediaItem。这是必要的,以便它能够访问一个电影或歌曲的导演或艺人属性在描述中使用。 + +在这个例子中,数组中的每个项目可能是电影,也可能是一首乐曲。你不事先知道哪一个实际的类使用的每个项目,所以它是适合使用类型转换运算符的可选形式(如?)通过每次循环检查垂头丧气: + for item in library { if let movie = item as? Movie { println("Movie: '\(movie.name)', dir. \(movie.director)") @@ -124,16 +142,29 @@ In this example, each item in the array might be a Movie, or it might be a Song. // Song: 'Never Gonna Give You Up', by Rick Astley The example starts by trying to downcast the current item as a Movie. Because item is a MediaItem instance, it’s possible that it might be a Movie; equally, it’s also possible that it might a Song, or even just a base MediaItem. Because of this uncertainty, the as? form of the type cast operator returns an optional value when attempting to downcast to a subclass type. The result of item as Movie is of type Movie?, or “optional Movie”. +这个例子开始试图通过向下转换当前项目作为电影。因为项目是一个MediaItem例如,它是可能的,它可能是一个电影;同样,它也有可能是它可能的乐曲,甚至只是一个基础MediaItem。由于这种不确定性,将作为?试图向下转换到子类类型时,类型转换运算符的形式返回一个可选值。项目作为电影的结果是类型的电影?,或“可选的电影”。 + Downcasting to Movie fails when applied to the two Song instances in the library array. To cope with this, the example above uses optional binding to check whether the optional Movie actually contains a value (that is, to find out whether the downcast succeeded.) This optional binding is written “if let movie = item as? Movie”, which can be read as: +当在库阵列施加到两个乐曲实例向下转换到电影失败。为了解决这个问题,上面的示例使用可选的绑定检查可选电影实际上是否包含一个值(也就是要找出垂头丧气是否成功。)这个可选的结合上记着说“如果让电影=项目作为?电影“,这可以被理解为: + “Try to access item as a Movie. If this is successful, set a new temporary constant called movie to the value stored in the returned optional Movie.” +“尝试访问项目作为一个电影。如果这是成功,树立了新的临时常数,称为电影存储在返回的可选电影的价值。“ + If the downcasting succeeds, the properties of movie are then used to print a description for that Movie instance, including the name of its director. A similar principle is used to check for Song instances, and to print an appropriate description (including artist name) whenever a Song is found in the library. +如果向下转型成功,电影的属性,然后用于打印的Movie实例说明,包括其导演的名字。类似的原理是用来检查宋实例,并打印相应的描述(包括艺术家的名字),每当乐曲库中找到。 + > NOTE > Casting does not actually modify the instance or change its values. The underlying instance remains the same; it is >simply treated and accessed as an instance of the type to which it has been cast. + + >注意 + +>铸造实际上并不修改实例或改变其值。相关实例保持不变;它是>简单的处理,并作为访问到它已被转换到的类型的一个实例。 + ##Type Casting for Any and AnyObject Swift provides two special type aliases for working with non-specific types: @@ -144,21 +175,43 @@ NOTE Use Any and AnyObject only when you explicitly need the behavior and capabilities they provide. It is always better to be specific about the types you expect to work with in your code. + +## 类型转换为任何和AnyObject + +swift 提供了两种特殊类型的别名与非特定类型的工作: + +AnyObject可以代表任何类类型的实例。 +任何可以代表任何类型的实例可言,除了函数类型。 +注 + +使用任何与AnyObject只有当你明确需要他们提供的行为和能力。它始终是更好地具体说明你希望在你的代码工作的类型。 + ###AnyObject When working with Cocoa APIs, it is common to receive an array with a type of AnyObject[], or “an array of values of any object type”. This is because Objective-C does not have explicitly typed arrays. However, you can often be confident about the type of objects contained in such an array just from the information you know about the API that provided the array. +### AnyObject + +当Cocoa API的工作,是很常见的接收数组与一类AnyObject[],或者“任何对象类型的值的数组”。这是因为Objective-C中没有显式类型的数组。但是,你常常可以充满信心包含在刚刚从你了解所提供的数组的API的信息,例如一个数组对象的类型。 + In these situations, you can use the forced version of the type cast operator (as) to downcast each item in the array to a more specific class type than AnyObject, without the need for optional unwrapping. The example below defines an array of type AnyObject[] and populates this array with three instances of the Movie class: +在这些情况下,您可以使用类型转换运算符的强迫版本(如)向下转换到每个项目在数组中以一个更具体的类类型比AnyObject,而不需要选配解缠。 + +下面的例子定义类型AnyObject[]数组,并填充这个数组的Movie类的三个实例: + let someObjects: AnyObject[] = [ Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"), Movie(name: "Moon", director: "Duncan Jones"), Movie(name: "Alien", director: "Ridley Scott") ] + Because this array is known to contain only Movie instances, you can downcast and unwrap directly to a non-optional Movie with the forced version of the type cast operator (as): +因为这个数组是已知含有唯一的电影实例,则可以向下转换,直接解开到一个非可选的电影与类型转换运算符(如)的强迫版本: + for object in someObjects { let movie = object as Movie println("Movie: '\(movie.name)', dir. \(movie.director)") @@ -168,6 +221,8 @@ Because this array is known to contain only Movie instances, you can downcast an // Movie: 'Alien', dir. Ridley Scott For an even shorter form of this loop, downcast the someObjects array to a type of Movie[] instead of downcasting each item: +对于这个循环的一个更短的形式,向下转型的someObjects阵列的类型电影[]的,而不是向下转换每个项目: + for movie in someObjects as Movie[] { println("Movie: '\(movie.name)', dir. \(movie.director)") } @@ -179,6 +234,10 @@ For an even shorter form of this loop, downcast the someObjects array to a type Here’s an example of using Any to work with a mix of different types, including non-class types. The example creates an array called things, which can store values of type Any: +### Any + +下面是使用Any与混合不同类型的,包括非类类型的工作的一个例子。该示例创建一个名为事情一个数组,它可以存储任何类型的值: + var things = Any[]() things.append(0) @@ -188,10 +247,16 @@ Here’s an example of using Any to work with a mix of different types, includin things.append("hello") things.append((3.0, 5.0)) things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman")) + + The things array contains two Int values, two Double values, a String value, a tuple of type (Double, Double), and the movie “Ghostbusters”, directed by Ivan Reitman. You can use the is and as operators in a switch statement’s cases to discover the specific type of a constant or variable that is known only to be of type Any or AnyObject. The example below iterates over the items in the things array and queries the type of each item with a switch statement. Several of the switch statement’s cases bind their matched value to a constant of the specified type to enable its value to be printed: +事情数组包含两个int值,两个Double值,一个字符串值,类型(Double,Double)的一个元组,和电影“捉鬼敢死队”,导演伊万·瑞特曼。 + +您可以使用is和as在switch语句的情况下,运营商发现,只知道是任何类型或AnyObject的常量或变量的具体类型。下面迭代的事情阵列项目的例子,查询每个项目的用switch语句的类型。几个switch语句的情况下,其匹配的值绑定到指定的类型,使其值要打印的常数: + for thing in things { switch thing { case 0 as Int: @@ -225,3 +290,7 @@ You can use the is and as operators in a switch statement’s cases to discover >NOTE >The cases of a switch statement use the forced version of the type cast operator (as, not as?) to check and cast to a >specific type. This check is always safe within the context of a switch case statement. + +>注意 + +> switch语句的情况下使用的类型转换运算符的强迫版本(作为,不作为?)检查并转换成一个>特定类型。这种检查始终是一个安全的switch case语句的上下文中。 From 614c7094cf5503c12e1ca8ec7d81862418f57c77 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Tue, 10 Jun 2014 10:27:19 +0800 Subject: [PATCH 017/261] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AE=A4=E9=A2=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 认领完成 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 36f02c3..4ebf964 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The Swift Programming Language 中文化项目 * 嵌套类型 [认领 by 祁涛] * 扩展 [认领 by 袁鹏] * 协议 [认领 by 姜天意] - * 泛型 + * 泛型 [认领 by 韩建亚] * 高级操作符 [认领 by 林晚] * 语言参考 * 关于语言参考 [认领 by 筱强] From 1e6201c6e81e6e113b35c6bd0e743169cd75b269 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Tue, 10 Jun 2014 10:27:52 +0800 Subject: [PATCH 018/261] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=AE=A4=E9=A2=86=20?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=AE=A4=E9=A2=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ebf964..5fd5f0a 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The Swift Programming Language 中文化项目 * 嵌套类型 [认领 by 祁涛] * 扩展 [认领 by 袁鹏] * 协议 [认领 by 姜天意] - * 泛型 [认领 by 韩建亚] + * 泛型 [认领 by 晴时] * 高级操作符 [认领 by 林晚] * 语言参考 * 关于语言参考 [认领 by 筱强] From e1b38b7e41bb7e4faaedd9a4647042dad050334b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=8E=89=E6=9E=97=28=E9=A3=9E=E9=95=BF=29?= Date: Tue, 10 Jun 2014 10:53:49 +0800 Subject: [PATCH 019/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5fd5f0a..7acd7b3 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ The Swift Programming Language 中文化项目 * 词法结构 [认领 by 筱强] * 类型 [认领 by 兰梦] * 表达式 [认领 by 懂象] - * 声明 + * 声明 [认领 by 墨峰] * 属性 * 模式 * 泛型参数 From 06cc17f416915669da9d501d63c490e892ed5100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=8E=89=E6=9E=97=28=E9=A3=9E=E9=95=BF=29?= Date: Tue, 10 Jun 2014 10:56:06 +0800 Subject: [PATCH 020/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7acd7b3..8322b95 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ The Swift Programming Language 中文化项目 * 表达式 [认领 by 懂象] * 声明 [认领 by 墨峰] * 属性 - * 模式 + * 模式 [认领 by 栖邀] * 泛型参数 * 语法总结 From 78b8ad6daa3fb447f425f31bdb5f6eab354b99f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=8E=89=E6=9E=97=28=E9=A3=9E=E9=95=BF=29?= Date: Tue, 10 Jun 2014 11:17:36 +0800 Subject: [PATCH 021/261] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8322b95..9d4ee59 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,9 @@ The Swift Programming Language 中文化项目 * 词法结构 [认领 by 筱强] * 类型 [认领 by 兰梦] * 表达式 [认领 by 懂象] - * 声明 [认领 by 墨峰] - * 属性 + * Statements [认领 by 墨峰] + * Declarations + * 属性 [认领 by 隐若] * 模式 [认领 by 栖邀] * 泛型参数 * 语法总结 From 5f3457c11182647d72ac1464e88e1f63106f0107 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Tue, 10 Jun 2014 11:31:17 +0800 Subject: [PATCH 022/261] =?UTF-8?q?=E8=A1=A5=E4=BA=86=E7=BC=BA=E5=A4=B1?= =?UTF-8?q?=E7=9A=84Statements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter3/05_Statements.md | 1 + src/chapter3/{05_Declarations.md => 06_Declarations.md} | 0 src/chapter3/{06_Attributes.md => 07_Attributes.md} | 0 src/chapter3/{07_Patterns.md => 08_Patterns.md} | 0 ...s_and_Arguments.md => 09_Generic_Parameters_and_Arguments.md} | 0 ...09_Summary_of_the_Grammar.md => 10_Summary_of_the_Grammar.md} | 0 6 files changed, 1 insertion(+) create mode 100644 src/chapter3/05_Statements.md rename src/chapter3/{05_Declarations.md => 06_Declarations.md} (100%) rename src/chapter3/{06_Attributes.md => 07_Attributes.md} (100%) rename src/chapter3/{07_Patterns.md => 08_Patterns.md} (100%) rename src/chapter3/{08_Generic_Parameters_and_Arguments.md => 09_Generic_Parameters_and_Arguments.md} (100%) rename src/chapter3/{09_Summary_of_the_Grammar.md => 10_Summary_of_the_Grammar.md} (100%) diff --git a/src/chapter3/05_Statements.md b/src/chapter3/05_Statements.md new file mode 100644 index 0000000..6075542 --- /dev/null +++ b/src/chapter3/05_Statements.md @@ -0,0 +1 @@ +Statements \ No newline at end of file diff --git a/src/chapter3/05_Declarations.md b/src/chapter3/06_Declarations.md similarity index 100% rename from src/chapter3/05_Declarations.md rename to src/chapter3/06_Declarations.md diff --git a/src/chapter3/06_Attributes.md b/src/chapter3/07_Attributes.md similarity index 100% rename from src/chapter3/06_Attributes.md rename to src/chapter3/07_Attributes.md diff --git a/src/chapter3/07_Patterns.md b/src/chapter3/08_Patterns.md similarity index 100% rename from src/chapter3/07_Patterns.md rename to src/chapter3/08_Patterns.md diff --git a/src/chapter3/08_Generic_Parameters_and_Arguments.md b/src/chapter3/09_Generic_Parameters_and_Arguments.md similarity index 100% rename from src/chapter3/08_Generic_Parameters_and_Arguments.md rename to src/chapter3/09_Generic_Parameters_and_Arguments.md diff --git a/src/chapter3/09_Summary_of_the_Grammar.md b/src/chapter3/10_Summary_of_the_Grammar.md similarity index 100% rename from src/chapter3/09_Summary_of_the_Grammar.md rename to src/chapter3/10_Summary_of_the_Grammar.md From 6be86448edcfb71199c36b90f854f4e46511ad4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=8E=89=E6=9E=97=28=E9=A3=9E=E9=95=BF=29?= Date: Tue, 10 Jun 2014 11:31:38 +0800 Subject: [PATCH 023/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d4ee59..9453e70 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The Swift Programming Language 中文化项目 * Declarations * 属性 [认领 by 隐若] * 模式 [认领 by 栖邀] - * 泛型参数 + * 泛型参数 [认领 by 龙刚] * 语法总结 # 分工 From 8e693e36b5763ada470473069068152f09ae2f83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=8E=89=E6=9E=97=28=E9=A3=9E=E9=95=BF=29?= Date: Tue, 10 Jun 2014 11:34:14 +0800 Subject: [PATCH 024/261] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9453e70..60a958b 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,12 @@ The Swift Programming Language 中文化项目 * 词法结构 [认领 by 筱强] * 类型 [认领 by 兰梦] * 表达式 [认领 by 懂象] - * Statements [认领 by 墨峰] - * Declarations + * Statements + * Declarations [认领 by 墨峰] * 属性 [认领 by 隐若] * 模式 [认领 by 栖邀] * 泛型参数 [认领 by 龙刚] - * 语法总结 + * 语法总结 [认领 by 无独] # 分工 * 西溪分会 10人 第一部分1-2章 第二部分1-8章 From 8ba673c91301d70acd6abf4a4d765d042cff7f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=8E=89=E6=9E=97=28=E9=A3=9E=E9=95=BF=29?= Date: Tue, 10 Jun 2014 11:43:00 +0800 Subject: [PATCH 025/261] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 60a958b..aa28474 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ The Swift Programming Language 中文化项目 * 词法结构 [认领 by 筱强] * 类型 [认领 by 兰梦] * 表达式 [认领 by 懂象] - * Statements - * Declarations [认领 by 墨峰] + * 语句 + * 声明 [认领 by 墨峰] * 属性 [认领 by 隐若] * 模式 [认领 by 栖邀] * 泛型参数 [认领 by 龙刚] From 5920490f3baea518976aa59f1adcd0f6e251b1e2 Mon Sep 17 00:00:00 2001 From: "playman.me" Date: Tue, 10 Jun 2014 12:32:33 +0800 Subject: [PATCH 026/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aa28474..0965fdb 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ The Swift Programming Language 中文化项目 * 词法结构 [认领 by 筱强] * 类型 [认领 by 兰梦] * 表达式 [认领 by 懂象] - * 语句 + * 语句 [认领 by 玩家] * 声明 [认领 by 墨峰] * 属性 [认领 by 隐若] * 模式 [认领 by 栖邀] From 175755e10db59388a6f088bc29e8cee928066741 Mon Sep 17 00:00:00 2001 From: Zeng Yun Date: Tue, 10 Jun 2014 13:09:17 +0800 Subject: [PATCH 027/261] =?UTF-8?q?=E7=BF=BB=E8=AF=91=E5=88=B0272=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/09_Classes_and_Structures.md | 36 +++++++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index 9e45542..3c26b9b 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -81,6 +81,8 @@ Structures are always copied when they are passed around in your code, and do no Classes and structures have a similar definition syntax. You introduce classes with the `class` keyword and structures with the `struct` keyword. Both place their entire definition within a pair of braces: +定义类和结构体的语法相似。定义类以关键词`class`开头,而定义结构体以关键词`struct`开头。类和结构体的所有定义都写在一对大括号内: + ``` class SomeClass { // class definition goes here @@ -90,13 +92,35 @@ struct SomeStructure { } ``` -定义类和结构体的语法相似。定义类以关键词`class`开头,而定义结构体以关键词`struct`开头。类和结构体的所有定义都写在一对大括号内: - + + ``` -class SomeClass { - // class definition goes here +NOTE + +Whenever you define a new class or structure, you effectively define a brand new Swift type. Give types UpperCamelCase names (such as SomeClass and SomeStructure here) to match the capitalization of standard Swift types (such as String, Int, and Bool). Conversely, always give properties and methods lowerCamelCase names (such as frameRate and incrementCount) to differentiate them from type names. +``` + + +``` +注意: + +当你定义一个新的类或者结构体时,你实际上定义了一种新的Swift类型。为了和Swift标准类型(像String,Int,Bool)保持一致,请使用首字母大写的驼峰命名法(例如SomeClass或者SomeStructure)。相反的,为了和类型名区分,属性和方法名建议使用小写驼峰命名法(如frameRate或者incrementCount)。 +``` + +Here’s an example of a structure definition and a class definition: + +下方给出了结构体和类定义的例子: + + +``` +struct Resolution { + var width = 0 + var height = 0 } -struct SomeStructure { - // structure definition goes here +class VideoMode { + var resolution = Resolution() + var interlaced = false + var frameRate = 0.0 + var name: String? } ``` \ No newline at end of file From 799e14fcf6a813e120a3b4d408a822697a4bdf69 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Tue, 10 Jun 2014 14:13:24 +0800 Subject: [PATCH 028/261] =?UTF-8?q?=E6=B3=9B=E5=9E=8B=E5=90=88=E4=BD=9C?= =?UTF-8?q?=E7=BF=BB=E8=AF=91=E8=AE=A4=E9=A2=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0965fdb..71b5223 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The Swift Programming Language 中文化项目 * 嵌套类型 [认领 by 祁涛] * 扩展 [认领 by 袁鹏] * 协议 [认领 by 姜天意] - * 泛型 [认领 by 晴时] + * 泛型 [认领 by 晴时 & 胡衍明] * 高级操作符 [认领 by 林晚] * 语言参考 * 关于语言参考 [认领 by 筱强] From 42600373074bc8cce07a8a23dd1a6c0e008f9e15 Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Wed, 11 Jun 2014 19:09:19 +0800 Subject: [PATCH 029/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index e69de29..1a4df85 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -0,0 +1,4 @@ +Extensions + +Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) +扩展为已有的类,结构,枚举添加新的功能。 From fcb6b9562c3433db17dddce2cdddd03214e18dde Mon Sep 17 00:00:00 2001 From: Zeng Yun Date: Wed, 11 Jun 2014 19:14:40 +0800 Subject: [PATCH 030/261] update --- src/chapter2/09_Classes_and_Structures.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index 3c26b9b..3fbd129 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -123,4 +123,8 @@ class VideoMode { var frameRate = 0.0 var name: String? } -``` \ No newline at end of file +``` + +The example above defines a new structure called Resolution, to describe a pixel-based display resolution. This structure has two stored properties called width and height. Stored properties are constants or variables that are bundled up and stored as part of the class or structure. These two properties are inferred to be of type Int by setting them to an initial integer value of 0. + +以上例子定义了一个叫Resolution的结构体,用来描述一个基于像素的显示方案。这个结构体有两个属性:宽和高。 \ No newline at end of file From b3d581f669a5ebe24a13b513790c3cc92064333b Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Wed, 11 Jun 2014 19:43:51 +0800 Subject: [PATCH 031/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index 1a4df85..908866b 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -1,4 +1,27 @@ Extensions Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) -扩展为已有的类,结构,枚举添加新的功能。 +扩展为已有的类,结构,枚举添加新的功能。其中包括扩展没有访问权代码权限的类型(即追溯建模)。扩展和 Objective-C 当中的分类很相似。(与 Objective-C 中的分类不同的是,Swift 的扩展没有名字) + + + Extensions in Swift can: + Add computed properties and computed static properties + Define instance methods and type methods + Provide new initializers + Define subscripts + Define and use new nested types + Make an existing type conform to a protocol + +Swift 的扩展可以: +- 增加计算属性和静态计算属性 +- 定义实例方法和类型方法 +- 提供新的构造器 +- 定义下标 +- 定义和使用新的嵌套类型 +- 将既有类型转换为符合某一个协议 + + +Note +If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined. + +注意 From fcbe5913f1cfd8182e89aadda87f5d449b2d9cf9 Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Wed, 11 Jun 2014 20:08:21 +0800 Subject: [PATCH 032/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 63 ++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index 908866b..19fb1c6 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -18,10 +18,71 @@ Swift 的扩展可以: - 提供新的构造器 - 定义下标 - 定义和使用新的嵌套类型 -- 将既有类型转换为符合某一个协议 +- 将已有的类型转换为符合某一个协议 Note If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined. 注意 +如果定义一个扩展用来在已有的类型上增加新的功能,那么新功能会应用在所有已经存在的实例上,即使是在扩展被定义之前实例化的。 + + +Extension Syntax +Declare extensions with the extension keyword: + + +扩展的语法 +使用 extension 关键字来声明扩展 + + extension SomeType { + // new functionality to add to SomeType goes here + } + +An extension can extend an existing type to make it adopt one or more protocols. Where this is the case, the protocol names are written in exactly the same way as for a class or structure: +一个扩展可以扩展一个已有的类型,使它能适配一个或多个的协议。如果是这种情况的话,协议的命名方式应该与类和结构体的命名方式完全一致。 + + extension SomeType: SomeProtocol, AnotherProtocol { + // implementation of protocol requirements goes here + } + +Adding protocol conformance in this way is described in Adding Protocol Conformance with an Extension. +这种增加协议一致性的方式被称为通过扩展增加协议一致性 + + +Computed Properties +计算属性 + +Extensions can add computed instance properties and computed type properties to existing types. This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From fb111bbd7af5cbabb27dc9fe55124ade84a30b58 Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Wed, 11 Jun 2014 21:29:33 +0800 Subject: [PATCH 033/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 50 +++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index 19fb1c6..a0cc388 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -54,6 +54,56 @@ Computed Properties 计算属性 Extensions can add computed instance properties and computed type properties to existing types. This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units: +扩展可以为已有的类型增加计算实力属性和计算类型属性。这个例子向 Swift 内建类型 Double 添加五个计算实例类型,用来提供转换为距离单位的基本支持 + + extension Double { + var km: Double { return self * 1_000.0 } + var m: Double { return self } + var cm: Double { return self / 100.0 } + var mm: Double { return self / 1_000.0 } + var ft: Double { return self / 3.28084 } + } + let oneInch = 25.4.mm + println("One inch is \(oneInch) meters") + // prints "One inch is 0.0254 meters" + let threeFeet = 3.ft + println("Three feet is \(threeFeet) meters") + // prints "Three feet is 0.914399970739201 meters" + +These computed properties express that a Double value should be considered as a certain unit of length. Although they are implemented as computed properties, the names of these properties can be appended to a floating-point literal value with dot syntax, as a way to use that literal value to perform distance conversions. +这些计算属性表达的是一个 Double 类型的值是某种长度单位下的值。尽管是计算属性,但他们仍然可以接在一个带有 dot 语法的字面值后面,用来将字面值转换成距离。 + +In this example, a Double value of 1.0 is considered to represent “one meter”. This is why the m computed property returns self—the expression 1.m is considered to calculate a Double value of 1.0. +在上述的例子中,一个 Double 类型的值 1.0 代表“一米”。这是为什么计算属性 m 仅仅返回 self ——表达式 1.m 的值 Double 类型的值 1.0 。 + +Other units require some conversion to be expressed as a value measured in meters. One kilometer is the same as 1,000 meters, so the km computed property multiplies the value by 1_000.00 to convert into a number expressed in meters. Similarly, there are 3.28024 feet in a meter, and so the ft computed property divides the underlying Double value by 3.28024, to convert it from feet to meters. +其他单位转换为以米为单位的数值需要进行一些转换。1千米等于1,000米,所以计算属性 km 要转换成以米为单位的数值,需要把值乘以 1_000.00 。同样,1英尺等于 3.28084 米,所以计算属性 ft 需要把值除以 3.28024 才能把英尺转换成米。 + +These properties are read-only computed properties, and so they are expressed without the get keyword, for brevity. Their return value is of type Double, and can be used within mathematical calculations wherever a Double is accepted: +这些都是只读的计算属性,所以为了简便起见,不需要关键字 keyword 进行表示。他们的返回值都是 Double 类型的,所以可以用在所有可以接受 Double 类型的数学计算中: + + let aMarathon = 42.km + 195.m + println("A marathon is \(aMarathon) meters long") + // prints "A marathon is 42195.0 meters long" + +Note +Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties. + +注意 +扩展可以添加新的计算属性,但是不能添加存储属性,也不能向已有属性添加属性观察器。 + + + +Initializers +构造器 + +Extensions can add new initializers to existing types. This enables you to extend other types to accept your own custom types as initializer parameters, or to provide additional initialization options that were not included as part of the type’s original implementation. +扩展能向已有类型添加新的构造器。这允许你用自己定义的类型作为构造器参数扩展其他的类型,或者提供原始实现没有提供的额外的初始化选项 + +Extensions can add new convenience initializers to a class, but they cannot add new designated initializers or deinitializers to a class. Designated initializers and deinitializers must always be provided by the original class implementation. +扩展能向类添加新的简便构造器,但是不能添加新的指定构造器或者析构器。指定构造器和析构器必须在类的原始实现中提供。 + + From 95ff4a061f7d6ed6275a623d4ec5fe6fa83992ab Mon Sep 17 00:00:00 2001 From: Xiao Du Date: Thu, 12 Jun 2014 00:39:20 +0800 Subject: [PATCH 034/261] update to page 290 --- src/chapter2/09_Classes_and_Structures.md | 102 +++++++++++++++++++++- 1 file changed, 100 insertions(+), 2 deletions(-) diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index 3fbd129..8668264 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -125,6 +125,104 @@ class VideoMode { } ``` -The example above defines a new structure called Resolution, to describe a pixel-based display resolution. This structure has two stored properties called width and height. Stored properties are constants or variables that are bundled up and stored as part of the class or structure. These two properties are inferred to be of type Int by setting them to an initial integer value of 0. +The example above defines a new structure called `Resolution`, to describe a pixel-based display resolution. This structure has two stored properties called `width` and `height`. Stored properties are constants or variables that are bundled up and stored as part of the class or structure. These two properties are inferred to be of type `Int` by setting them to an initial integer value of 0. -以上例子定义了一个叫Resolution的结构体,用来描述一个基于像素的显示方案。这个结构体有两个属性:宽和高。 \ No newline at end of file +例子定义了一个名叫`Resolution`的新结构体,用来描述一个基于像素的显示方案。这个结构体有两个~~属性~~:`宽`和`高`。~~属性~~是捆绑存储在类和结构体中的变量活常量。这两个属性的类型将被编译器推断为`Int`,并赋予初始值0。 + +The example above also defines a new class called `VideoMode`, to describe a specific video mode for video display. This class has four variable stored properties. The first, `resolution`, is initialized with a new `Resolution` structure instance, which infers a property type of `Resolution`. For the other three properties, new `VideoMode` instances will be initialized with an `interlaced` setting of `false` (meaning “non-interlaced video”), a playback frame rate of `0.0`, and an optional `String` value called `name`. The `name` property is automatically given a default value of `nil`, or “no `name` value”, because it is of an optional type. + +例子中也定义了一个名叫`VideoMode`的新类,用来表示视频显示的模式。VideoMode类中有四个属性。第一个是`resolution`,它在这里被初始化为一个新的`Resolution`结构体实例,而编译器将自动推断分辨率的类型为`Resolution`。除此之外新的`VideoMode`实例还将初始化三个属性,默认为`false`的`interlaced`(意味着这是个“不交错的视频”),默认值为`0.0`表示播放帧速率的`frameRate`,以及一个值可选类型为`String`的`name`。属性`name`将自动赋值为`nil`,或者说`name`无值,因为它的值是可选的。 + +### Class and Structure Instances +### 类和结构体的实例 + +The `Resolution` structure definition and the `VideoMode` class definition only describe what a `Resolution` or `VideoMode` will look like. They themselves do not describe a specific resolution or video mode. To do that, you need to create an instance of the structure or class. + +结构体`Resolution`和类`VideoMode`的定义只是告诉你`Resolution`和`VideoMode`含有什么内容。但他们本身并不描述一个特定的分辨率或者视频模式。要做到这一点,我们要生成一个他们的实例。 + +The syntax for creating instances is very similar for both structures and classes: + +生成结构体实例和生成类实例的语法非常类似: + +``` +let someResolution = Resolution() +let someVideoMode = VideoMode() +``` + +Structures and classes both use initializer syntax for new instances. The simplest form of initializer syntax uses the type name of the class or structure followed by empty parentheses, such as `Resolution()` or `VideoMode()`. This creates a new instance of the class or structure, with any properties initialized to their default values. Class and structure initialization is described in more detail in [Initialization](). + +结构体和类都是用初始化语法来生成新的实例。初始化语法最简单的形式是结构体或类的类型名后加上空括号,例如`Resolution()`和`VideoMode()`。这将创建一个所有的属性都是默认值的结构体或类。类和结构体的初始化在[构造过程]()章节中有更详细的说明。 + +### Accessing Properties +### 属性的访问 +You can access the properties of an instance using *dot syntax*. In dot syntax, you write the property name immediately after the instance name, separated by a period (.), without any spaces: + +你可以使用*点语法*访问实例的属性。使用点语法时,属性名将紧跟在实例名之后,中间以句号(.)隔开: + +``` +println("The width of someResolution is \(someResolution.width)") +// prints "The width of someResolution is 0 +``` + +In this example, `someResolution.width` refers to the `width` property of `someResolution`, and returns its default initial value of `0`. + +在这个例子中,`someResolution.width`表示`someResolution`的`width`属性,且返回默认初始值`0`。 + +You can drill down into sub-properties, such as the `width` property in the `resolution` property of a `VideoMode`: + +你可以继续使用点语法来访问属性的属性,例如`VideoMode`中`resolution`的属性`width`: + +``` +println("The width of someVideoMode is \(someVideoMode.resolution.width)") +// prints "The width of someVideoMode is 0" +``` + +You can also use dot syntax to assign a new value to a variable property: +我们还可以使用点语法来为属性变量赋值: + +``` +someVideoMode.resolution.width = 1280 +println("The width of someVideoMode is now \(someVideoMode.resolution.width)") +// prints "The width of someVideoMode is now 1280" +``` + +``` +NOTE + +Unlike Objective-C, Swift enables you to set sub-properties of a structure property directly. In the last example above, the width property of the resolution property of someVideoMode is set directly, without your needing to set the entire resolution property to a new value. +``` +``` +注意: + +与Objective-C不同,Swift允许直接为结构体的属性的子属性赋值。在上方的例子中,someVideoMode中属性resolution的子属性width被直接赋值了,不再需要给整个resolution属性赋予新值。 +``` +‌ +### Memberwise Initializers for Structure Types +### 结构体带参数的初始化方法 + +All structures have an automatically-generated memberwise initializer, which you can use to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name: + +所有结构体都有一个自动生成的带参数的初始化方法,用于新结构体实例成员属性的初始化。新实例属性的初值会通过变量名传递到带参数的初始化方法里: + +``` +let vga = Resolution(width: 640, height: 480) +``` + +Unlike structures, class instances do not receive a default memberwise initializer. Initializers are described in more detail in [Initialization](). +与结构体不同,类市里没有默认的带参数的初始化方法。对初始化方法的详细说明见[构造过程]()章节。 + +‌ +### Structures and Enumerations Are Value Types +### 结构体和枚举都是值类型 + +A value *type* is a type that is copied when it is assigned to a variable or constant, or when it is passed to a function. +值*类型*的变量在赋值给一个变量、常量或作为参数传给函数时,传递的是该变量值的拷贝。 + +You’ve actually been using value types extensively throughout the previous chapters. In fact, all of the basic types in Swift—integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types, and are implemented as structures behind the scenes. + +All structures and enumerations are value types in Swift. This means that any structure and enumeration instances you create—and any value types they have as properties—are always copied when they are passed around in your code. + +Consider this example, which uses the Resolution structure from the previous example: + +let hd = Resolution(width: 1920, height: 1080) +var cinema = hd From 86defc549f4295186bd7a2929f2536269d7bb03e Mon Sep 17 00:00:00 2001 From: Xiao Du Date: Thu, 12 Jun 2014 00:55:29 +0800 Subject: [PATCH 035/261] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E9=94=99=E5=88=AB=E5=AD=97=EF=BC=8C=E6=B4=BB=E6=94=B9?= =?UTF-8?q?=E6=88=90=E6=88=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/09_Classes_and_Structures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index 8668264..5c0e56e 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -127,7 +127,7 @@ class VideoMode { The example above defines a new structure called `Resolution`, to describe a pixel-based display resolution. This structure has two stored properties called `width` and `height`. Stored properties are constants or variables that are bundled up and stored as part of the class or structure. These two properties are inferred to be of type `Int` by setting them to an initial integer value of 0. -例子定义了一个名叫`Resolution`的新结构体,用来描述一个基于像素的显示方案。这个结构体有两个~~属性~~:`宽`和`高`。~~属性~~是捆绑存储在类和结构体中的变量活常量。这两个属性的类型将被编译器推断为`Int`,并赋予初始值0。 +例子定义了一个名叫`Resolution`的新结构体,用来描述一个基于像素的显示方案。这个结构体有两个~~属性~~:`宽`和`高`。~~属性~~是捆绑存储在类和结构体中的变量或常量。这两个属性的类型将被编译器推断为`Int`,并赋予初始值0。 The example above also defines a new class called `VideoMode`, to describe a specific video mode for video display. This class has four variable stored properties. The first, `resolution`, is initialized with a new `Resolution` structure instance, which infers a property type of `Resolution`. For the other three properties, new `VideoMode` instances will be initialized with an `interlaced` setting of `false` (meaning “non-interlaced video”), a playback frame rate of `0.0`, and an optional `String` value called `name`. The `name` property is automatically given a default value of `nil`, or “no `name` value”, because it is of an optional type. From 7f2fbeab81b5d288ecf609e8cb11b5d9390d5297 Mon Sep 17 00:00:00 2001 From: Zeng Yun Date: Thu, 12 Jun 2014 21:53:51 +0800 Subject: [PATCH 036/261] update to 277 --- src/chapter2/09_Classes_and_Structures.md | 31 ++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index 5c0e56e..f944696 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -220,9 +220,38 @@ A value *type* is a type that is copied when it is assigned to a variable or con You’ve actually been using value types extensively throughout the previous chapters. In fact, all of the basic types in Swift—integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types, and are implemented as structures behind the scenes. +实际上在前面章节我们已经广泛使用了值类型。事实上Swift中几乎所有的基本类型---如整数、浮点数、布尔值、字符串、数组和字典,都是值类型,并在底层都以结构体的方式来实现。 + All structures and enumerations are value types in Swift. This means that any structure and enumeration instances you create—and any value types they have as properties—are always copied when they are passed around in your code. -Consider this example, which uses the Resolution structure from the previous example: +Swift中的所有结构体和枚举都是值类型。这意味着你创建的任何一个结构体或枚举的实例,以及他们的属性在代码中被传递的时候都会被复制。 + +Consider this example, which uses the `Resolution` structure from the previous example: +让我们来看看这个例子,它使用了先前例子中定义的`Resolution`: + +``` let hd = Resolution(width: 1920, height: 1080) var cinema = hd +``` + +This example declares a constant called `hd` and sets it to a `Resolution` instance initialized with the width and height of full HD video (`1920` pixels wide by `1080` pixels high). + +例子中声明了一个名叫`hd`的常量,它的值是一个初始化成全高清视频分辨率(宽`1920`长`1080`)的`Resolution`实例。 + +It then declares a variable called cinema and sets it to the current value of hd. Because Resolution is a structure, a copy of the existing instance is made, and this new copy is assigned to cinema. Even though hd and cinema now have the same width and height, they are two completely different instances behind the scenes. + + + +Next, the width property of cinema is amended to be the width of the slightly-wider 2K standard used for digital cinema projection (2048 pixels wide and 1080 pixels high): + +cinema.width = 2048 +Checking the width property of cinema shows that it has indeed changed to be 2048: + +println("cinema is now \(cinema.width) pixels wide") +// prints "cinema is now 2048 pixels wide" +However, the width property of the original hd instance still has the old value of 1920: + +println("hd is still \(hd.width) pixels wide") +// prints "hd is still 1920 pixels wide" +When cinema was given the current value of hd, the values stored in \ No newline at end of file From 02189c8edc31851736f32a66ef38ed886e75596f Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Fri, 13 Jun 2014 21:44:08 +0800 Subject: [PATCH 037/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 174 +++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index a0cc388..b261886 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -100,39 +100,211 @@ Initializers Extensions can add new initializers to existing types. This enables you to extend other types to accept your own custom types as initializer parameters, or to provide additional initialization options that were not included as part of the type’s original implementation. 扩展能向已有类型添加新的构造器。这允许你用自己定义的类型作为构造器参数扩展其他的类型,或者提供原始实现没有提供的额外的初始化选项 -Extensions can add new convenience initializers to a class, but they cannot add new designated initializers or deinitializers to a class. Designated initializers and deinitializers must always be provided by the original class implementation. +Extensions can add new convenience initializers to a class, but they cannot add new designated initializers or deinitializers to a class. Designated initializers and deinitializers must always be provided by the original class implementation. 扩展能向类添加新的简便构造器,但是不能添加新的指定构造器或者析构器。指定构造器和析构器必须在类的原始实现中提供。 +Note +If you use an extension to add an initializer to a value type that provides default values for all of its stored properties and does not define any custom initializers, you can call the default initializer and memberwise initializer for that value type from within your extension’s initializer. +This would not be the case if you had written the initializer as part of the value type’s original implementation, as described in Initializer Delegation for Value Types. +注意 +如果使用扩展向一个值类型添加构造器,该构造器向所有存储属性提供默认值并且未定义任何其他的自定义构造器,你可以调用默认的构造和成员构造器来为你扩展的构造器当中的值类型赋值。 +正如 ``构造器对值类型的构造委托一问所说的那样`` 如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 +The example below defines a custom Rect structure to represent a geometric rectangle. The example also defines two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties: +在下面的例子里,定义了一个用于描述几何矩形的结构体 ``Rect`` 。同时定义了两个辅助性结构体 ``Size``,``Point``,两个结构体当中的属性默认值都为 ``0.0``。 + struct Size { + var width = 0.0, height = 0.0 + } + struct Point { + var x = 0.0, y = 0.0 + } + struct Rect { + var origin = Point() + var size = Size() + } + +Because the Rect structure provides default values for all of its properties, it receives a default initializer and a memberwise initializer automatically, as described in Default Initializers. These initializers can be used to create new Rect instances: +因为 结构体 Rect 为所有的属性都提供了默认值,正如默认构造器一节所说的,它可以自动接受默认构造器和成员构造器。这些构造器可以用来创建新的 Rect 实例。 + let defaultRect = Rect() + let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), + size: Size(width: 5.0, height: 5.0)) +You can extend the Rect structure to provide an additional initializer that takes a specific center point and size: +你可以使用扩展来为结构体 Rect 额外提供一个以中心点和大小作为参数的构造器 + extension Rect { + 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) + } + } +This new initializer starts by calculating an appropriate origin point based on the provided center point and size value. The initializer then calls the structure’s automatic memberwise initializer init(origin:size:), which stores the new origin and size values in the appropriate properties: +新构造器通过中心点和大小两个参数计算出合适的原点值,然后调用结构体的自动成员构造器 init(origin:size:) ,把计算出的值存储到合适的属性上。 + let centerRect = Rect(center: Point(x: 4.0, y: 4.0), + size: Size(width: 3.0, height: 3.0)) + // centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0) +Note +If you provide a new initializer with an extension, you are still responsible for making sure that each instance is fully initialized once the initializer completes. +注意 +如果使用扩展来提供新的构造器,那么你仍要确保构造过程中,每一个实例都被完全初始化了。 +Methods +方法 +Extensions can add new instance methods and type methods to existing types. The following example adds a new instance method called repetitions to the Int type: +扩展可以向已有类型添加新的实例方法和类型方法。下面的例子中,向 类型 Int 中添加了新的实例方法 repetitions + extension Int { + func repetitions(task: () -> ()) { + for i in 0..self { + task() + } + } + } +The repetitions method takes a single argument of type () -> (), which indicates a function that has no parameters and does not return a value. +repetitions 方法的参数是 () -> (),说明参数是一个无参数无返回值的函数 +After defining this extension, you can call the repetitions method on any integer number to perform a task that many number of times: +扩展被定义之后,你就可以在任何整数上调用 repetitions 方法,来多次执行某个任务。 + 3.repetitions({ + println("Hello!") + }) + // Hello! + // Hello! + // Hello! +Use trailing closure syntax to make the call more succinct: +使用尾随闭包语法可以使调用更简洁 + 3.repetitions { + println("Goodbye!") + } + // Goodbye! + // Goodbye! + // Goodbye! +Mutating Instance Methods +可变实例方法 +Instance methods added with an extension can also modify (or mutate) the instance itself. Structure and enumeration methods that modify self or its properties must mark the instance method as mutating, just like mutating methods from an original implementation. +通过扩展添加的实例方法也可以修改实例本身。结构体和枚举类型的方法中改变 self 或者其中的属性,必须标记实例的方法为 mutating ,就像原始实现中的声明变异方法一样。 +The example below adds a new mutating method called square to Swift’s Int type, which squares the original value: +下面的例子为 Swift 中的 Int 类型添加了一个新的变异方法 square,用来计算原始值的平方。 + extension Int { + mutating func square() { + self = self * self + } + } + var someInt = 3 + someInt.square() + // someInt is now 9 +Subscripts +下标 +Extensions can add new subscripts to an existing type. This example adds an integer subscript to Swift’s built-in Int type. This subscript [n] returns the decimal digit n places in from the right of the number: +扩展可以为已有类型添加新的下标。下面的例子为 Swift 中的内建类型 Int 添加一个整型下标。下标 [n] 返回 十进制数从右往左第 n 位上的数字。 + 123456789[0] returns 9 + 123456789[1] returns 8 +…and so on: +以此类推 + extension Int { + subscript(digitIndex: Int) -> Int { + var decimalBase = 1 + for _ in 1...digitIndex { + decimalBase *= 10 + } + return (self / decimalBase) % 10 + } + } + 746381295[0] + // returns 5 + 746381295[1] + // returns 9 + 746381295[2] + // returns 2 + 746381295[8] + // returns 7 + +If the Int value does not have enough digits for the requested index, the subscript implementation returns 0, as if the number had been padded with zeroes to the left: +如果 Int 值没有足够的位数与请求对应,即下标越界,则下标会返回 0 ,就好像它自动在数字左边补0一样。 + + 746381295[9] + // returns 0, as if you had requested: + 0746381295[9] + +Nested Types +嵌套类型 + +Extensions can add new nested types to existing classes, structures and enumerations: +扩展可以向已有的类,结构体和枚举类型添加新的嵌套类型。 + + extension Character { + enum Kind { + case Vowel, Consonant, Other + } + var kind: Kind { + switch String(self).lowercaseString { + case "a", "e", "i", "o", "u": + return .Vowel + case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", + "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": + return .Consonant + default: + return .Other + } + } + } +This example adds a new nested enumeration to Character. This enumeration, called Kind, expresses the kind of letter that a particular character represents. Specifically, it expresses whether the character is a vowel or a consonant in a standard Latin script (without taking into account accents or regional variations), or whether it is another kind of character. +上面的例子为 Character 添加了新的嵌套枚举。枚举类型的 Kind 表示一个字符所属的种类。具体来说就是一个字符是拉丁字母的元音,辅音,还是其他种类的字符(不考虑口语和地方变种的情况下)。 + +This example also adds a new computed instance property to Character, called kind, which returns the appropriate Kind enumeration member for that character. +这个例子中同时也为 Character 添加了一个新的实例计算属性:kind,用来返回字符对应的枚举成员 Kind + +The nested enumeration can now be used with Character values: +现在嵌套枚举可以在 Character 上面使用了: + + func printLetterKinds(word: String) { + println("'\(word)' is made up of the following kinds of letters:") + for character in word { + switch character.kind { + case .Vowel: + print("vowel ") + case .Consonant: + print("consonant ") + case .Other: + print("other ") + } + } + print("\n") + } + printLetterKinds("Hello") + // 'Hello' is made up of the following kinds of letters: + // consonant vowel consonant consonant vowel +This function, printLetterKinds, takes an input String value and iterates over its characters. For each character, it considers the kind computed property for that character, and prints an appropriate description of that kind. The printLetterKinds function can then be called to print the kinds of letters in an entire word, as shown here for the word "Hello". +printLetterKinds 函数迭代 String 值参数的每一个字母,。每一次迭代都根据当前字母包含的计算属性 kind,输出对应的类型描述。这样,printLetterKinds 函数就输出了一个单词内所有字母的类型,正如上面例子中的单词 "word"。 +Note +character.kind is already known to be of type Character.Kind. Because of this, all of the Character.Kind member values can be written in shorthand form inside the switch statement, such as .Vowel rather than Character.Kind.Vowel. +注意 +因为已知 character.kind 的类型是 Character.Kind,所以所有 Character.Kind 的成员值都可以在 switch 语句中使用简写形式,比如使用 .Vowel 来代替 Character.Kind.Vowel。 From 8d866a4acc696ff5397b0d68c3120b39c01531ea Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Fri, 13 Jun 2014 21:45:54 +0800 Subject: [PATCH 038/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index b261886..e39d985 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -299,7 +299,7 @@ The nested enumeration can now be used with Character values: // consonant vowel consonant consonant vowel This function, printLetterKinds, takes an input String value and iterates over its characters. For each character, it considers the kind computed property for that character, and prints an appropriate description of that kind. The printLetterKinds function can then be called to print the kinds of letters in an entire word, as shown here for the word "Hello". -printLetterKinds 函数迭代 String 值参数的每一个字母,。每一次迭代都根据当前字母包含的计算属性 kind,输出对应的类型描述。这样,printLetterKinds 函数就输出了一个单词内所有字母的类型,正如上面例子中的单词 "word"。 +printLetterKinds 函数迭代 String 类型的参数的每一个字母。每次迭代都根据当前字母包含的计算属性 kind 输出对应的类型描述。这样,printLetterKinds 函数就输出了一个单词内所有字母的类型,正如上面例子中的单词 "word"。 Note From 0a1388f8b864f50dadff86de0cd02c3e2a4492ef Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 19:08:47 +0800 Subject: [PATCH 039/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index e39d985..1ca547a 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -1,4 +1,6 @@ -Extensions +# Extensions +# 扩展 + Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) 扩展为已有的类,结构,枚举添加新的功能。其中包括扩展没有访问权代码权限的类型(即追溯建模)。扩展和 Objective-C 当中的分类很相似。(与 Objective-C 中的分类不同的是,Swift 的扩展没有名字) From 6e808de3f60b4688d7e2adb1a599e7effba361c4 Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 19:11:44 +0800 Subject: [PATCH 040/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index 1ca547a..f12700c 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -3,18 +3,21 @@ Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) + + 扩展为已有的类,结构,枚举添加新的功能。其中包括扩展没有访问权代码权限的类型(即追溯建模)。扩展和 Objective-C 当中的分类很相似。(与 Objective-C 中的分类不同的是,Swift 的扩展没有名字) - Extensions in Swift can: - Add computed properties and computed static properties - Define instance methods and type methods - Provide new initializers - Define subscripts - Define and use new nested types - Make an existing type conform to a protocol +Extensions in Swift can: +- Add computed properties and computed static properties +- Define instance methods and type methods +- Provide new initializers +- Define subscripts +- Define and use new nested types +- Make an existing type conform to a protocol + -Swift 的扩展可以: +Swift 中的扩展可以: - 增加计算属性和静态计算属性 - 定义实例方法和类型方法 - 提供新的构造器 @@ -26,8 +29,9 @@ Swift 的扩展可以: Note If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined. -注意 -如果定义一个扩展用来在已有的类型上增加新的功能,那么新功能会应用在所有已经存在的实例上,即使是在扩展被定义之前实例化的。 + +> 提示 +> 如果定义一个扩展用来在已有的类型上增加新的功能,那么新功能会应用在所有已经存在的实例上,即使是在扩展被定义之前实例化的。 Extension Syntax From 87dd76f3814c949ceb0a3b1bd93b39c46afef066 Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 19:25:16 +0800 Subject: [PATCH 041/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 322 ++++++++++++++++++++-------------- 1 file changed, 190 insertions(+), 132 deletions(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index f12700c..c8d4457 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -1,13 +1,11 @@ # Extensions -# 扩展 +# 扩展 Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) - 扩展为已有的类,结构,枚举添加新的功能。其中包括扩展没有访问权代码权限的类型(即追溯建模)。扩展和 Objective-C 当中的分类很相似。(与 Objective-C 中的分类不同的是,Swift 的扩展没有名字) - Extensions in Swift can: - Add computed properties and computed static properties - Define instance methods and type methods @@ -16,7 +14,6 @@ Extensions in Swift can: - Define and use new nested types - Make an existing type conform to a protocol - Swift 中的扩展可以: - 增加计算属性和静态计算属性 - 定义实例方法和类型方法 @@ -25,169 +22,206 @@ Swift 中的扩展可以: - 定义和使用新的嵌套类型 - 将已有的类型转换为符合某一个协议 - -Note -If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined. - +> Note +> If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined. > 提示 > 如果定义一个扩展用来在已有的类型上增加新的功能,那么新功能会应用在所有已经存在的实例上,即使是在扩展被定义之前实例化的。 +## Extension Syntax +## 扩展的语法 -Extension Syntax Declare extensions with the extension keyword: - -扩展的语法 使用 extension 关键字来声明扩展 - extension SomeType { - // new functionality to add to SomeType goes here - } +``` +extension SomeType { + // new functionality to add to SomeType goes here +} +``` An extension can extend an existing type to make it adopt one or more protocols. Where this is the case, the protocol names are written in exactly the same way as for a class or structure: + 一个扩展可以扩展一个已有的类型,使它能适配一个或多个的协议。如果是这种情况的话,协议的命名方式应该与类和结构体的命名方式完全一致。 - extension SomeType: SomeProtocol, AnotherProtocol { - // implementation of protocol requirements goes here - } +``` +extension SomeType: SomeProtocol, AnotherProtocol { + // implementation of protocol requirements goes here +} +``` Adding protocol conformance in this way is described in Adding Protocol Conformance with an Extension. + 这种增加协议一致性的方式被称为通过扩展增加协议一致性 +## Computed Properties -Computed Properties -计算属性 +## 计算属性 Extensions can add computed instance properties and computed type properties to existing types. This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units: + 扩展可以为已有的类型增加计算实力属性和计算类型属性。这个例子向 Swift 内建类型 Double 添加五个计算实例类型,用来提供转换为距离单位的基本支持 - extension Double { +``` +extension Double { var km: Double { return self * 1_000.0 } var m: Double { return self } var cm: Double { return self / 100.0 } var mm: Double { return self / 1_000.0 } var ft: Double { return self / 3.28084 } - } - let oneInch = 25.4.mm - println("One inch is \(oneInch) meters") - // prints "One inch is 0.0254 meters" - let threeFeet = 3.ft - println("Three feet is \(threeFeet) meters") - // prints "Three feet is 0.914399970739201 meters" - -These computed properties express that a Double value should be considered as a certain unit of length. Although they are implemented as computed properties, the names of these properties can be appended to a floating-point literal value with dot syntax, as a way to use that literal value to perform distance conversions. +} +let oneInch = 25.4.mm +println("One inch is \(oneInch) meters") +// prints "One inch is 0.0254 meters" +let threeFeet = 3.ft +println("Three feet is \(threeFeet) meters") +// prints "Three feet is 0.914399970739201 meters" +``` + +These computed properties express that a Double value should be considered as a certain unit of length. Although they are implemented as computed properties, the names of these properties can be appended to a floating-point literal value with dot syntax, as a way to use that literal value to perform distance conversions. + 这些计算属性表达的是一个 Double 类型的值是某种长度单位下的值。尽管是计算属性,但他们仍然可以接在一个带有 dot 语法的字面值后面,用来将字面值转换成距离。 -In this example, a Double value of 1.0 is considered to represent “one meter”. This is why the m computed property returns self—the expression 1.m is considered to calculate a Double value of 1.0. +In this example, a Double value of 1.0 is considered to represent “one meter”. This is why the m computed property returns self—the expression 1.m is considered to calculate a Double value of 1.0. + 在上述的例子中,一个 Double 类型的值 1.0 代表“一米”。这是为什么计算属性 m 仅仅返回 self ——表达式 1.m 的值 Double 类型的值 1.0 。 Other units require some conversion to be expressed as a value measured in meters. One kilometer is the same as 1,000 meters, so the km computed property multiplies the value by 1_000.00 to convert into a number expressed in meters. Similarly, there are 3.28024 feet in a meter, and so the ft computed property divides the underlying Double value by 3.28024, to convert it from feet to meters. + 其他单位转换为以米为单位的数值需要进行一些转换。1千米等于1,000米,所以计算属性 km 要转换成以米为单位的数值,需要把值乘以 1_000.00 。同样,1英尺等于 3.28084 米,所以计算属性 ft 需要把值除以 3.28024 才能把英尺转换成米。 These properties are read-only computed properties, and so they are expressed without the get keyword, for brevity. Their return value is of type Double, and can be used within mathematical calculations wherever a Double is accepted: + 这些都是只读的计算属性,所以为了简便起见,不需要关键字 keyword 进行表示。他们的返回值都是 Double 类型的,所以可以用在所有可以接受 Double 类型的数学计算中: - let aMarathon = 42.km + 195.m - println("A marathon is \(aMarathon) meters long") - // prints "A marathon is 42195.0 meters long" +``` +let aMarathon = 42.km + 195.m +println("A marathon is \(aMarathon) meters long") +// prints "A marathon is 42195.0 meters long" +``` + +> Note +> Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties. -Note -Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties. +> 提示 +> 扩展可以添加新的计算属性,但是不能添加存储属性,也不能向已有属性添加属性观察器。 -注意 -扩展可以添加新的计算属性,但是不能添加存储属性,也不能向已有属性添加属性观察器。 +## Initializers -Initializers -构造器 +## 构造器 Extensions can add new initializers to existing types. This enables you to extend other types to accept your own custom types as initializer parameters, or to provide additional initialization options that were not included as part of the type’s original implementation. + 扩展能向已有类型添加新的构造器。这允许你用自己定义的类型作为构造器参数扩展其他的类型,或者提供原始实现没有提供的额外的初始化选项 Extensions can add new convenience initializers to a class, but they cannot add new designated initializers or deinitializers to a class. Designated initializers and deinitializers must always be provided by the original class implementation. + 扩展能向类添加新的简便构造器,但是不能添加新的指定构造器或者析构器。指定构造器和析构器必须在类的原始实现中提供。 -Note -If you use an extension to add an initializer to a value type that provides default values for all of its stored properties and does not define any custom initializers, you can call the default initializer and memberwise initializer for that value type from within your extension’s initializer. -This would not be the case if you had written the initializer as part of the value type’s original implementation, as described in Initializer Delegation for Value Types. -注意 -如果使用扩展向一个值类型添加构造器,该构造器向所有存储属性提供默认值并且未定义任何其他的自定义构造器,你可以调用默认的构造和成员构造器来为你扩展的构造器当中的值类型赋值。 -正如 ``构造器对值类型的构造委托一问所说的那样`` 如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 +> Note +> If you use an extension to add an initializer to a value type that provides default values for all of its stored properties and does not define any custom initializers, you can call the default initializer and memberwise initializer for that value type from within your extension’s initializer. +> This would not be the case if you had written the initializer as part of the value type’s original implementation, as described in Initializer Delegation for Value Types. + +> 提示 +> 如果使用扩展向一个值类型添加构造器,该构造器向所有存储属性提供默认值并且未定义任何其他的自定义构造器,你可以调用默认的构造和成员构造器来为你扩展的构造器当中的值类型赋值。 +> 正如 ``构造器对值类型的构造委托一问所说的那样`` 如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 The example below defines a custom Rect structure to represent a geometric rectangle. The example also defines two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties: + 在下面的例子里,定义了一个用于描述几何矩形的结构体 ``Rect`` 。同时定义了两个辅助性结构体 ``Size``,``Point``,两个结构体当中的属性默认值都为 ``0.0``。 - struct Size { +``` +struct Size { var width = 0.0, height = 0.0 - } - struct Point { +} +struct Point { var x = 0.0, y = 0.0 - } - struct Rect { +} +struct Rect { var origin = Point() var size = Size() - } +} +``` Because the Rect structure provides default values for all of its properties, it receives a default initializer and a memberwise initializer automatically, as described in Default Initializers. These initializers can be used to create new Rect instances: + 因为 结构体 Rect 为所有的属性都提供了默认值,正如默认构造器一节所说的,它可以自动接受默认构造器和成员构造器。这些构造器可以用来创建新的 Rect 实例。 - let defaultRect = Rect() - let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), +``` +let defaultRect = Rect() +let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0)) +``` You can extend the Rect structure to provide an additional initializer that takes a specific center point and size: + 你可以使用扩展来为结构体 Rect 额外提供一个以中心点和大小作为参数的构造器 - extension Rect { +``` +extension Rect { 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) - } + let originX = center.x - (size.width / 2) + let originY = center.y - (size.height / 2) + self.init(origin: Point(x: originX, y: originY), size: size) } +} +``` This new initializer starts by calculating an appropriate origin point based on the provided center point and size value. The initializer then calls the structure’s automatic memberwise initializer init(origin:size:), which stores the new origin and size values in the appropriate properties: + 新构造器通过中心点和大小两个参数计算出合适的原点值,然后调用结构体的自动成员构造器 init(origin:size:) ,把计算出的值存储到合适的属性上。 - let centerRect = Rect(center: Point(x: 4.0, y: 4.0), +``` +let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0)) - // centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0) +// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0) +``` + +> Note +> If you provide a new initializer with an extension, you are still responsible for making sure that each instance is fully initialized once the initializer completes. + +> 提示 +> 如果使用扩展来提供新的构造器,那么你仍要确保构造过程中,每一个实例都被完全初始化了。 -Note -If you provide a new initializer with an extension, you are still responsible for making sure that each instance is fully initialized once the initializer completes. -注意 -如果使用扩展来提供新的构造器,那么你仍要确保构造过程中,每一个实例都被完全初始化了。 +## Methods -Methods -方法 +## 方法 Extensions can add new instance methods and type methods to existing types. The following example adds a new instance method called repetitions to the Int type: + 扩展可以向已有类型添加新的实例方法和类型方法。下面的例子中,向 类型 Int 中添加了新的实例方法 repetitions - extension Int { +``` +extension Int { func repetitions(task: () -> ()) { - for i in 0..self { - task() - } - } + for i in 0..self { + task() + } } +} +``` The repetitions method takes a single argument of type () -> (), which indicates a function that has no parameters and does not return a value. + repetitions 方法的参数是 () -> (),说明参数是一个无参数无返回值的函数 After defining this extension, you can call the repetitions method on any integer number to perform a task that many number of times: + 扩展被定义之后,你就可以在任何整数上调用 repetitions 方法,来多次执行某个任务。 - 3.repetitions({ +``` +3.repetitions({ println("Hello!") - }) - // Hello! - // Hello! - // Hello! +}) +// Hello! +// Hello! +// Hello! +``` Use trailing closure syntax to make the call more succinct: 使用尾随闭包语法可以使调用更简洁 @@ -199,118 +233,142 @@ Use trailing closure syntax to make the call more succinct: // Goodbye! // Goodbye! -Mutating Instance Methods -可变实例方法 +## Mutating Instance Methods + +## 可变实例方法 Instance methods added with an extension can also modify (or mutate) the instance itself. Structure and enumeration methods that modify self or its properties must mark the instance method as mutating, just like mutating methods from an original implementation. + 通过扩展添加的实例方法也可以修改实例本身。结构体和枚举类型的方法中改变 self 或者其中的属性,必须标记实例的方法为 mutating ,就像原始实现中的声明变异方法一样。 The example below adds a new mutating method called square to Swift’s Int type, which squares the original value: + 下面的例子为 Swift 中的 Int 类型添加了一个新的变异方法 square,用来计算原始值的平方。 - extension Int { +``` +extension Int { mutating func square() { - self = self * self + self = self * self } - } - var someInt = 3 - someInt.square() - // someInt is now 9 +} +var someInt = 3 +someInt.square() +// someInt is now 9 +``` + +## Subscripts -Subscripts -下标 +## 下标 Extensions can add new subscripts to an existing type. This example adds an integer subscript to Swift’s built-in Int type. This subscript [n] returns the decimal digit n places in from the right of the number: + 扩展可以为已有类型添加新的下标。下面的例子为 Swift 中的内建类型 Int 添加一个整型下标。下标 [n] 返回 十进制数从右往左第 n 位上的数字。 - 123456789[0] returns 9 - 123456789[1] returns 8 +- 123456789[0] returns 9 +- 123456789[1] returns 8 …and so on: + 以此类推 - extension Int { +``` +extension Int { subscript(digitIndex: Int) -> Int { - var decimalBase = 1 - for _ in 1...digitIndex { - decimalBase *= 10 + var decimalBase = 1 + for _ in 1...digitIndex { + decimalBase *= 10 + } + return (self / decimalBase) % 10 } - return (self / decimalBase) % 10 - } - } - 746381295[0] - // returns 5 - 746381295[1] - // returns 9 - 746381295[2] - // returns 2 - 746381295[8] - // returns 7 +} +746381295[0] +// returns 5 +746381295[1] +// returns 9 +746381295[2] +// returns 2 +746381295[8] +// returns 7 +``` If the Int value does not have enough digits for the requested index, the subscript implementation returns 0, as if the number had been padded with zeroes to the left: + 如果 Int 值没有足够的位数与请求对应,即下标越界,则下标会返回 0 ,就好像它自动在数字左边补0一样。 - 746381295[9] - // returns 0, as if you had requested: - 0746381295[9] +``` +746381295[9] +// returns 0, as if you had requested: +0746381295[9] +``` + +## Nested Types -Nested Types -嵌套类型 +## 嵌套类型 Extensions can add new nested types to existing classes, structures and enumerations: + 扩展可以向已有的类,结构体和枚举类型添加新的嵌套类型。 - extension Character { +``` +extension Character { enum Kind { - case Vowel, Consonant, Other + case Vowel, Consonant, Other } var kind: Kind { switch String(self).lowercaseString { case "a", "e", "i", "o", "u": - return .Vowel + return .Vowel case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": - return .Consonant + return .Consonant default: - return .Other - } - } + return .Other + } } +} +``` This example adds a new nested enumeration to Character. This enumeration, called Kind, expresses the kind of letter that a particular character represents. Specifically, it expresses whether the character is a vowel or a consonant in a standard Latin script (without taking into account accents or regional variations), or whether it is another kind of character. + 上面的例子为 Character 添加了新的嵌套枚举。枚举类型的 Kind 表示一个字符所属的种类。具体来说就是一个字符是拉丁字母的元音,辅音,还是其他种类的字符(不考虑口语和地方变种的情况下)。 This example also adds a new computed instance property to Character, called kind, which returns the appropriate Kind enumeration member for that character. + 这个例子中同时也为 Character 添加了一个新的实例计算属性:kind,用来返回字符对应的枚举成员 Kind The nested enumeration can now be used with Character values: + 现在嵌套枚举可以在 Character 上面使用了: - func printLetterKinds(word: String) { +``` +func printLetterKinds(word: String) { println("'\(word)' is made up of the following kinds of letters:") for character in word { - switch character.kind { - case .Vowel: - print("vowel ") - case .Consonant: - print("consonant ") - case .Other: - print("other ") - } + switch character.kind { + case .Vowel: + print("vowel ") + case .Consonant: + print("consonant ") + case .Other: + print("other ") + } } print("\n") - } - printLetterKinds("Hello") - // 'Hello' is made up of the following kinds of letters: - // consonant vowel consonant consonant vowel +} +printLetterKinds("Hello") +// 'Hello' is made up of the following kinds of letters: +// consonant vowel consonant consonant vowel +``` This function, printLetterKinds, takes an input String value and iterates over its characters. For each character, it considers the kind computed property for that character, and prints an appropriate description of that kind. The printLetterKinds function can then be called to print the kinds of letters in an entire word, as shown here for the word "Hello". + printLetterKinds 函数迭代 String 类型的参数的每一个字母。每次迭代都根据当前字母包含的计算属性 kind 输出对应的类型描述。这样,printLetterKinds 函数就输出了一个单词内所有字母的类型,正如上面例子中的单词 "word"。 -Note -character.kind is already known to be of type Character.Kind. Because of this, all of the Character.Kind member values can be written in shorthand form inside the switch statement, such as .Vowel rather than Character.Kind.Vowel. -注意 -因为已知 character.kind 的类型是 Character.Kind,所以所有 Character.Kind 的成员值都可以在 switch 语句中使用简写形式,比如使用 .Vowel 来代替 Character.Kind.Vowel。 +> Note +> character.kind is already known to be of type Character.Kind. Because of this, all of the Character.Kind member values can be written in shorthand form inside the switch statement, such as .Vowel rather than Character.Kind.Vowel. + +> 提示 +> 因为已知 character.kind 的类型是 Character.Kind,所以所有 Character.Kind 的成员值都可以在 switch 语句中使用简写形式,比如使用 .Vowel 来代替 Character.Kind.Vowel。 From c499d9c97a6a7d079ceb19966bb329e9c531964d Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 19:25:47 +0800 Subject: [PATCH 042/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index c8d4457..34c9f6f 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -27,6 +27,7 @@ Swift 中的扩展可以: > 提示 > 如果定义一个扩展用来在已有的类型上增加新的功能,那么新功能会应用在所有已经存在的实例上,即使是在扩展被定义之前实例化的。 + ## Extension Syntax ## 扩展的语法 From 1955d82c0ff135ff97ce808f2ea72fb46bbed88f Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 19:30:02 +0800 Subject: [PATCH 043/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index 34c9f6f..fcf4d9c 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -54,7 +54,7 @@ extension SomeType: SomeProtocol, AnotherProtocol { Adding protocol conformance in this way is described in Adding Protocol Conformance with an Extension. -这种增加协议一致性的方式被称为通过扩展增加协议一致性 +这种增加协议一致性的方式在 [通过扩展增加协议一致性](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_355) 中有记述 ## Computed Properties From e35dd0aacc5db337edde82d88fc615df40dda89d Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 19:34:41 +0800 Subject: [PATCH 044/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index fcf4d9c..d5febca 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -2,6 +2,7 @@ # 扩展 + Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) 扩展为已有的类,结构,枚举添加新的功能。其中包括扩展没有访问权代码权限的类型(即追溯建模)。扩展和 Objective-C 当中的分类很相似。(与 Objective-C 中的分类不同的是,Swift 的扩展没有名字) @@ -23,9 +24,12 @@ Swift 中的扩展可以: - 将已有的类型转换为符合某一个协议 > Note +> > If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined. + > 提示 +> > 如果定义一个扩展用来在已有的类型上增加新的功能,那么新功能会应用在所有已经存在的实例上,即使是在扩展被定义之前实例化的。 ## Extension Syntax @@ -54,7 +58,8 @@ extension SomeType: SomeProtocol, AnotherProtocol { Adding protocol conformance in this way is described in Adding Protocol Conformance with an Extension. -这种增加协议一致性的方式在 [通过扩展增加协议一致性](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_355) 中有记述 +这种增加协议一致性的方式在 [通过扩展增加协议一致性](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_355) 一文中有记述。 + ## Computed Properties @@ -103,13 +108,15 @@ println("A marathon is \(aMarathon) meters long") ``` > Note +> > Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties. + > 提示 +> > 扩展可以添加新的计算属性,但是不能添加存储属性,也不能向已有属性添加属性观察器。 - ## Initializers ## 构造器 @@ -124,10 +131,13 @@ Extensions can add new convenience initializers to a class, but they cannot add > Note +> > If you use an extension to add an initializer to a value type that provides default values for all of its stored properties and does not define any custom initializers, you can call the default initializer and memberwise initializer for that value type from within your extension’s initializer. > This would not be the case if you had written the initializer as part of the value type’s original implementation, as described in Initializer Delegation for Value Types. + > 提示 +> > 如果使用扩展向一个值类型添加构造器,该构造器向所有存储属性提供默认值并且未定义任何其他的自定义构造器,你可以调用默认的构造和成员构造器来为你扩展的构造器当中的值类型赋值。 > 正如 ``构造器对值类型的构造委托一问所说的那样`` 如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 @@ -183,9 +193,12 @@ let centerRect = Rect(center: Point(x: 4.0, y: 4.0), ``` > Note +> > If you provide a new initializer with an extension, you are still responsible for making sure that each instance is fully initialized once the initializer completes. + > 提示 +> > 如果使用扩展来提供新的构造器,那么你仍要确保构造过程中,每一个实例都被完全初始化了。 @@ -227,12 +240,15 @@ After defining this extension, you can call the repetitions method on any intege Use trailing closure syntax to make the call more succinct: 使用尾随闭包语法可以使调用更简洁 - 3.repetitions { +``` +3.repetitions { println("Goodbye!") - } - // Goodbye! - // Goodbye! - // Goodbye! +} +// Goodbye! +// Goodbye! +// Goodbye! +``` + ## Mutating Instance Methods @@ -257,6 +273,7 @@ someInt.square() // someInt is now 9 ``` + ## Subscripts ## 下标 @@ -302,6 +319,7 @@ If the Int value does not have enough digits for the requested index, the subscr 0746381295[9] ``` + ## Nested Types ## 嵌套类型 @@ -367,9 +385,12 @@ printLetterKinds 函数迭代 String 类型的参数的每一个字母。每次 > Note +> > character.kind is already known to be of type Character.Kind. Because of this, all of the Character.Kind member values can be written in shorthand form inside the switch statement, such as .Vowel rather than Character.Kind.Vowel. + > 提示 +> > 因为已知 character.kind 的类型是 Character.Kind,所以所有 Character.Kind 的成员值都可以在 switch 语句中使用简写形式,比如使用 .Vowel 来代替 Character.Kind.Vowel。 From 83c53348a5034b5941a5cd054e3a243e62d3927a Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 19:38:18 +0800 Subject: [PATCH 045/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index d5febca..37aaba9 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -139,7 +139,7 @@ Extensions can add new convenience initializers to a class, but they cannot add > 提示 > > 如果使用扩展向一个值类型添加构造器,该构造器向所有存储属性提供默认值并且未定义任何其他的自定义构造器,你可以调用默认的构造和成员构造器来为你扩展的构造器当中的值类型赋值。 -> 正如 ``构造器对值类型的构造委托一问所说的那样`` 如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 +> 正如[构造器对值类型的构造委托](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_281) 一文所说的那样,如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 The example below defines a custom Rect structure to represent a geometric rectangle. The example also defines two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties: From 751ed95523507dd85361c1683e220aede57a28d2 Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 20:14:26 +0800 Subject: [PATCH 046/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 67 ++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index 37aaba9..bae4513 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -1,11 +1,11 @@ # Extensions -# 扩展 +# 扩展(Extensions) Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) -扩展为已有的类,结构,枚举添加新的功能。其中包括扩展没有访问权代码权限的类型(即追溯建模)。扩展和 Objective-C 当中的分类很相似。(与 Objective-C 中的分类不同的是,Swift 的扩展没有名字) +扩展为已有的类,结构,枚举添加新的功能。其中包括扩展没有代码访问权限的类型(即追溯建模,retroactive modeling)。扩展和 Objective-C 当中的分类(category)很相似。(与 Objective-C 中的分类不同的是,Swift 的扩展没有名字) Extensions in Swift can: - Add computed properties and computed static properties @@ -38,7 +38,7 @@ Swift 中的扩展可以: Declare extensions with the extension keyword: -使用 extension 关键字来声明扩展 +使用 ``extension`` 关键字来声明扩展 ``` extension SomeType { @@ -48,7 +48,7 @@ extension SomeType { An extension can extend an existing type to make it adopt one or more protocols. Where this is the case, the protocol names are written in exactly the same way as for a class or structure: -一个扩展可以扩展一个已有的类型,使它能适配一个或多个的协议。如果是这种情况的话,协议的命名方式应该与类和结构体的命名方式完全一致。 +一个扩展可以扩展一个已有的类型,使它能适配一个或多个的协议(protocol)。如果是这种情况的话,协议的命名方式应该与类和结构体的命名方式完全一致。 ``` extension SomeType: SomeProtocol, AnotherProtocol { @@ -58,16 +58,16 @@ extension SomeType: SomeProtocol, AnotherProtocol { Adding protocol conformance in this way is described in Adding Protocol Conformance with an Extension. -这种增加协议一致性的方式在 [通过扩展增加协议一致性](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_355) 一文中有记述。 +这种增加协议一致性(protocol conformance)的方式在 [通过扩展增加协议一致性](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_355) 一文中有记述。 ## Computed Properties -## 计算属性 +## 计算属性(Computed Properties) Extensions can add computed instance properties and computed type properties to existing types. This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units: -扩展可以为已有的类型增加计算实力属性和计算类型属性。这个例子向 Swift 内建类型 Double 添加五个计算实例类型,用来提供转换为距离单位的基本支持 +扩展可以为已有的类型增加实例计算属性和类型计算属性。这个例子向 Swift 内建类型 ``Double`` 添加五个实例计算类型,用来提供转换为距离单位的基本功能 ``` extension Double { @@ -87,19 +87,19 @@ println("Three feet is \(threeFeet) meters") These computed properties express that a Double value should be considered as a certain unit of length. Although they are implemented as computed properties, the names of these properties can be appended to a floating-point literal value with dot syntax, as a way to use that literal value to perform distance conversions. -这些计算属性表达的是一个 Double 类型的值是某种长度单位下的值。尽管是计算属性,但他们仍然可以接在一个带有 dot 语法的字面值后面,用来将字面值转换成距离。 +这些计算属性表达的是一个 ``Double`` 类型的值是某种长度单位下的值。尽管是计算属性,但他们仍然可以接在一个带有 dot 语法的字面值的后面,用来将字面值转换成距离。 In this example, a Double value of 1.0 is considered to represent “one meter”. This is why the m computed property returns self—the expression 1.m is considered to calculate a Double value of 1.0. -在上述的例子中,一个 Double 类型的值 1.0 代表“一米”。这是为什么计算属性 m 仅仅返回 self ——表达式 1.m 的值 Double 类型的值 1.0 。 +在上述的例子中,``Double`` 类型的 ``1.0`` 代表 “一米” 。这是为什么计算属性 ``m`` 仅仅返回 ``self`` ——表达式 ``1.m`` 最终结果是 ``Double`` 类型的值 ``1.0`` 。 Other units require some conversion to be expressed as a value measured in meters. One kilometer is the same as 1,000 meters, so the km computed property multiplies the value by 1_000.00 to convert into a number expressed in meters. Similarly, there are 3.28024 feet in a meter, and so the ft computed property divides the underlying Double value by 3.28024, to convert it from feet to meters. -其他单位转换为以米为单位的数值需要进行一些转换。1千米等于1,000米,所以计算属性 km 要转换成以米为单位的数值,需要把值乘以 1_000.00 。同样,1英尺等于 3.28084 米,所以计算属性 ft 需要把值除以 3.28024 才能把英尺转换成米。 +其他单位转换为以米为单位的数值需要进行一些转换。1千米等于1,000米,所以计算属性 ``km`` 要把数值转换成以米为单位,需要把值乘以 ''1_000.00''。同样,1英尺等于 ''3.28084'' 米,所以计算属性 ''ft'' 需要把值除以 ''3.28024'' 才能把英尺转换成米。 These properties are read-only computed properties, and so they are expressed without the get keyword, for brevity. Their return value is of type Double, and can be used within mathematical calculations wherever a Double is accepted: -这些都是只读的计算属性,所以为了简便起见,不需要关键字 keyword 进行表示。他们的返回值都是 Double 类型的,所以可以用在所有可以接受 Double 类型的数学计算中: +因为这些都是只读的计算属性,所以为了简便起见,不需要关键字 ''keyword'' 进行表示。他们的返回值都是 ``Double`` 类型的,所以可以用在所有可以接受 ``Double`` 类型的数学计算中: ``` let aMarathon = 42.km + 195.m @@ -114,12 +114,12 @@ println("A marathon is \(aMarathon) meters long") > 提示 > -> 扩展可以添加新的计算属性,但是不能添加存储属性,也不能向已有属性添加属性观察器。 +> 扩展可以添加新的计算属性,但是不能添加存储属性,也不能向已有属性添加属性观察器(property observer)。 ## Initializers -## 构造器 +## 构造器(Initializers) Extensions can add new initializers to existing types. This enables you to extend other types to accept your own custom types as initializer parameters, or to provide additional initialization options that were not included as part of the type’s original implementation. @@ -160,7 +160,7 @@ struct Rect { Because the Rect structure provides default values for all of its properties, it receives a default initializer and a memberwise initializer automatically, as described in Default Initializers. These initializers can be used to create new Rect instances: -因为 结构体 Rect 为所有的属性都提供了默认值,正如默认构造器一节所说的,它可以自动接受默认构造器和成员构造器。这些构造器可以用来创建新的 Rect 实例。 +因为 结构体 ``Rect`` 为所有的属性都提供了默认值,正如默认构造器一节所说的,它可以自动接受默认构造器和成员构造器。这些构造器可以用来创建新的 ``Rect`` 实例。 ``` let defaultRect = Rect() @@ -170,7 +170,7 @@ let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), You can extend the Rect structure to provide an additional initializer that takes a specific center point and size: -你可以使用扩展来为结构体 Rect 额外提供一个以中心点和大小作为参数的构造器 +你可以使用扩展来为结构体 ``Rect`` 额外提供一个以中心点和大小作为参数的构造器 ``` extension Rect { @@ -184,7 +184,7 @@ extension Rect { This new initializer starts by calculating an appropriate origin point based on the provided center point and size value. The initializer then calls the structure’s automatic memberwise initializer init(origin:size:), which stores the new origin and size values in the appropriate properties: -新构造器通过中心点和大小两个参数计算出合适的原点值,然后调用结构体的自动成员构造器 init(origin:size:) ,把计算出的值存储到合适的属性上。 +新构造器通过中心点和大小两个参数计算出合适的原点值,然后调用结构体的自动成员构造器 ``init(origin:size:)`` ,把计算出的值存储到合适的属性上。 ``` let centerRect = Rect(center: Point(x: 4.0, y: 4.0), @@ -204,11 +204,11 @@ let centerRect = Rect(center: Point(x: 4.0, y: 4.0), ## Methods -## 方法 +## 方法(Methods) Extensions can add new instance methods and type methods to existing types. The following example adds a new instance method called repetitions to the Int type: -扩展可以向已有类型添加新的实例方法和类型方法。下面的例子中,向 类型 Int 中添加了新的实例方法 repetitions +扩展可以向已有类型添加新的实例方法和类型方法。下面的例子中,向 类型 ``Int`` 中添加了新的实例方法 ``repetitions`` : ``` extension Int { @@ -222,11 +222,11 @@ extension Int { The repetitions method takes a single argument of type () -> (), which indicates a function that has no parameters and does not return a value. -repetitions 方法的参数是 () -> (),说明参数是一个无参数无返回值的函数 +``repetitions`` 方法的参数是 ``() -> ()``,说明参数是一个无参数无返回值的函数 After defining this extension, you can call the repetitions method on any integer number to perform a task that many number of times: -扩展被定义之后,你就可以在任何整数上调用 repetitions 方法,来多次执行某个任务。 +扩展被定义之后,你就可以在任何整数上调用 ``repetitions`` 方法,来多次执行某个任务。 ``` 3.repetitions({ @@ -238,7 +238,8 @@ After defining this extension, you can call the repetitions method on any intege ``` Use trailing closure syntax to make the call more succinct: -使用尾随闭包语法可以使调用更简洁 + +使用尾随闭包(trailing closure)语法可以使调用更简洁: ``` 3.repetitions { @@ -252,15 +253,15 @@ Use trailing closure syntax to make the call more succinct: ## Mutating Instance Methods -## 可变实例方法 +## 可变实例方法(Mutating Instance Methods) Instance methods added with an extension can also modify (or mutate) the instance itself. Structure and enumeration methods that modify self or its properties must mark the instance method as mutating, just like mutating methods from an original implementation. -通过扩展添加的实例方法也可以修改实例本身。结构体和枚举类型的方法中改变 self 或者其中的属性,必须标记实例的方法为 mutating ,就像原始实现中的声明变异方法一样。 +通过扩展添加的实例方法也可以修改实例本身。结构体和枚举类型的方法中改变 ``self`` 或者其中的属性,必须标记实例的方法为 ``mutating`` ,就像原始实现中的声明变异方法(mutating method)一样。 The example below adds a new mutating method called square to Swift’s Int type, which squares the original value: -下面的例子为 Swift 中的 Int 类型添加了一个新的变异方法 square,用来计算原始值的平方。 +下面的例子为 Swift 中的 ``Int`` 类型添加了一个新的变异方法 ``square``,用来计算原始值的平方。 ``` extension Int { @@ -276,11 +277,11 @@ someInt.square() ## Subscripts -## 下标 +## 下标(Subscripts) Extensions can add new subscripts to an existing type. This example adds an integer subscript to Swift’s built-in Int type. This subscript [n] returns the decimal digit n places in from the right of the number: -扩展可以为已有类型添加新的下标。下面的例子为 Swift 中的内建类型 Int 添加一个整型下标。下标 [n] 返回 十进制数从右往左第 n 位上的数字。 +扩展可以为已有类型添加新的下标。下面的例子为 Swift 中的内建类型 ``Int`` 添加一个整型下标。下标 ``[n]`` 返回 十进制数从右往左第 n 位上的数字。 - 123456789[0] returns 9 - 123456789[1] returns 8 @@ -311,7 +312,7 @@ extension Int { If the Int value does not have enough digits for the requested index, the subscript implementation returns 0, as if the number had been padded with zeroes to the left: -如果 Int 值没有足够的位数与请求对应,即下标越界,则下标会返回 0 ,就好像它自动在数字左边补0一样。 +如果该 ``Int`` 值没有足够的位数与请求对应,即下标越界,则下标会返回 ``0`` ,就好像它自动在数字左边补0一样: ``` 746381295[9] @@ -322,7 +323,7 @@ If the Int value does not have enough digits for the requested index, the subscr ## Nested Types -## 嵌套类型 +## 嵌套类型(Nested Types) Extensions can add new nested types to existing classes, structures and enumerations: @@ -349,15 +350,15 @@ extension Character { This example adds a new nested enumeration to Character. This enumeration, called Kind, expresses the kind of letter that a particular character represents. Specifically, it expresses whether the character is a vowel or a consonant in a standard Latin script (without taking into account accents or regional variations), or whether it is another kind of character. -上面的例子为 Character 添加了新的嵌套枚举。枚举类型的 Kind 表示一个字符所属的种类。具体来说就是一个字符是拉丁字母的元音,辅音,还是其他种类的字符(不考虑口语和地方变种的情况下)。 +上面的例子为 ``Character`` 添加了新的嵌套枚举。枚举类型的 ``Kind`` 表示一个字符所属的种类。具体来说就是一个字符是拉丁字母的元音,辅音,还是其他种类的字符(不考虑口语和地方变种的情况下)。 This example also adds a new computed instance property to Character, called kind, which returns the appropriate Kind enumeration member for that character. -这个例子中同时也为 Character 添加了一个新的实例计算属性:kind,用来返回字符对应的枚举成员 Kind +这个例子中同时也为 ``Character`` 添加了一个新的实例计算属性 ``kind``,用来返回字符对应的枚举成员 ``Kind`` The nested enumeration can now be used with Character values: -现在嵌套枚举可以在 Character 上面使用了: +现在嵌套枚举可以在 ``Character`` 上面使用了: ``` func printLetterKinds(word: String) { @@ -381,7 +382,7 @@ printLetterKinds("Hello") This function, printLetterKinds, takes an input String value and iterates over its characters. For each character, it considers the kind computed property for that character, and prints an appropriate description of that kind. The printLetterKinds function can then be called to print the kinds of letters in an entire word, as shown here for the word "Hello". -printLetterKinds 函数迭代 String 类型的参数的每一个字母。每次迭代都根据当前字母包含的计算属性 kind 输出对应的类型描述。这样,printLetterKinds 函数就输出了一个单词内所有字母的类型,正如上面例子中的单词 "word"。 +``printLetterKinds`` 函数迭代 ``String`` 类型的参数的每一个字母。每次迭代都根据当前字母包含的计算属性 ``kind`` 输出对应的类型描述。这样,``printLetterKinds`` 函数就输出了一个单词内所有字母的类型,正如上面例子中的单词 "word" 一样。 > Note @@ -391,6 +392,6 @@ printLetterKinds 函数迭代 String 类型的参数的每一个字母。每次 > 提示 > -> 因为已知 character.kind 的类型是 Character.Kind,所以所有 Character.Kind 的成员值都可以在 switch 语句中使用简写形式,比如使用 .Vowel 来代替 Character.Kind.Vowel。 +> 因为已知 ``character.kind`` 的类型是 ``Character.Kind``,所以所有 ``Character.Kind`` 的成员值都可以在 ``switch`` 语句中使用简写形式,比如使用 ``.Vowel`` 来代替 ``Character.Kind.Vowel``。 From b5252c76d76cb6db931d948bd03db3bf2c2e3537 Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 20:18:13 +0800 Subject: [PATCH 047/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index bae4513..af0b353 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -38,7 +38,7 @@ Swift 中的扩展可以: Declare extensions with the extension keyword: -使用 ``extension`` 关键字来声明扩展 +使用 ``extension`` 关键字来声明扩展: ``` extension SomeType { @@ -67,7 +67,7 @@ Adding protocol conformance in this way is described in Adding Protocol Conforma Extensions can add computed instance properties and computed type properties to existing types. This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units: -扩展可以为已有的类型增加实例计算属性和类型计算属性。这个例子向 Swift 内建类型 ``Double`` 添加五个实例计算类型,用来提供转换为距离单位的基本功能 +扩展可以为已有的类型增加实例计算属性和类型计算属性。这个例子向 Swift 内建类型 ``Double`` 添加五个实例计算类型,用来提供转换为距离单位的基本功能: ``` extension Double { @@ -143,7 +143,7 @@ Extensions can add new convenience initializers to a class, but they cannot add The example below defines a custom Rect structure to represent a geometric rectangle. The example also defines two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties: -在下面的例子里,定义了一个用于描述几何矩形的结构体 ``Rect`` 。同时定义了两个辅助性结构体 ``Size``,``Point``,两个结构体当中的属性默认值都为 ``0.0``。 +在下面的例子里,定义了一个用于描述几何矩形的结构体 ``Rect`` 。同时定义了两个辅助性结构体 ``Size``,``Point``,两个结构体当中的属性默认值都为 ``0.0``: ``` struct Size { @@ -160,7 +160,7 @@ struct Rect { Because the Rect structure provides default values for all of its properties, it receives a default initializer and a memberwise initializer automatically, as described in Default Initializers. These initializers can be used to create new Rect instances: -因为 结构体 ``Rect`` 为所有的属性都提供了默认值,正如默认构造器一节所说的,它可以自动接受默认构造器和成员构造器。这些构造器可以用来创建新的 ``Rect`` 实例。 +因为 结构体 ``Rect`` 为所有的属性都提供了默认值,正如默认构造器一节所说的,它可以自动接受默认构造器和成员构造器。这些构造器可以用来创建新的 ``Rect`` 实例: ``` let defaultRect = Rect() @@ -170,7 +170,7 @@ let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), You can extend the Rect structure to provide an additional initializer that takes a specific center point and size: -你可以使用扩展来为结构体 ``Rect`` 额外提供一个以中心点和大小作为参数的构造器 +你可以使用扩展来为结构体 ``Rect`` 额外提供一个以中心点和大小作为参数的构造器: ``` extension Rect { @@ -184,7 +184,7 @@ extension Rect { This new initializer starts by calculating an appropriate origin point based on the provided center point and size value. The initializer then calls the structure’s automatic memberwise initializer init(origin:size:), which stores the new origin and size values in the appropriate properties: -新构造器通过中心点和大小两个参数计算出合适的原点值,然后调用结构体的自动成员构造器 ``init(origin:size:)`` ,把计算出的值存储到合适的属性上。 +新构造器通过中心点和大小两个参数计算出合适的原点值,然后调用结构体的自动成员构造器 ``init(origin:size:)`` ,把计算出的值存储到合适的属性上: ``` let centerRect = Rect(center: Point(x: 4.0, y: 4.0), @@ -208,7 +208,7 @@ let centerRect = Rect(center: Point(x: 4.0, y: 4.0), Extensions can add new instance methods and type methods to existing types. The following example adds a new instance method called repetitions to the Int type: -扩展可以向已有类型添加新的实例方法和类型方法。下面的例子中,向 类型 ``Int`` 中添加了新的实例方法 ``repetitions`` : +扩展可以向已有类型添加新的实例方法和类型方法。下面的例子中,向 类型 ``Int`` 中添加了新的实例方法 ``repetitions``: ``` extension Int { @@ -226,7 +226,7 @@ The repetitions method takes a single argument of type () -> (), which indicates After defining this extension, you can call the repetitions method on any integer number to perform a task that many number of times: -扩展被定义之后,你就可以在任何整数上调用 ``repetitions`` 方法,来多次执行某个任务。 +扩展被定义之后,你就可以在任何整数上调用 ``repetitions`` 方法,来多次执行某个任务: ``` 3.repetitions({ @@ -261,7 +261,7 @@ Instance methods added with an extension can also modify (or mutate) the instanc The example below adds a new mutating method called square to Swift’s Int type, which squares the original value: -下面的例子为 Swift 中的 ``Int`` 类型添加了一个新的变异方法 ``square``,用来计算原始值的平方。 +下面的例子为 Swift 中的 ``Int`` 类型添加了一个新的变异方法 ``square``,用来计算原始值的平方: ``` extension Int { @@ -281,14 +281,14 @@ someInt.square() Extensions can add new subscripts to an existing type. This example adds an integer subscript to Swift’s built-in Int type. This subscript [n] returns the decimal digit n places in from the right of the number: -扩展可以为已有类型添加新的下标。下面的例子为 Swift 中的内建类型 ``Int`` 添加一个整型下标。下标 ``[n]`` 返回 十进制数从右往左第 n 位上的数字。 +扩展可以为已有类型添加新的下标。下面的例子为 Swift 中的内建类型 ``Int`` 添加一个整型下标。下标 ``[n]`` 返回 十进制数从右往左第 n 位上的数字: - 123456789[0] returns 9 - 123456789[1] returns 8 …and so on: -以此类推 +……以此类推: ``` extension Int { @@ -327,7 +327,7 @@ If the Int value does not have enough digits for the requested index, the subscr Extensions can add new nested types to existing classes, structures and enumerations: -扩展可以向已有的类,结构体和枚举类型添加新的嵌套类型。 +扩展可以向已有的类,结构体和枚举类型添加新的嵌套类型: ``` extension Character { From af4e714eb793db9123b91d773c77a1af03ecfe8c Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 20:19:25 +0800 Subject: [PATCH 048/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index af0b353..fe6a95a 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -139,7 +139,7 @@ Extensions can add new convenience initializers to a class, but they cannot add > 提示 > > 如果使用扩展向一个值类型添加构造器,该构造器向所有存储属性提供默认值并且未定义任何其他的自定义构造器,你可以调用默认的构造和成员构造器来为你扩展的构造器当中的值类型赋值。 -> 正如[构造器对值类型的构造委托](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_281) 一文所说的那样,如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 +> 正如 [构造器对值类型的构造委托](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_281) 一文所说的那样,如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 The example below defines a custom Rect structure to represent a geometric rectangle. The example also defines two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties: From 3ee144f2153711c3d5926b68230fa8e48e330ccc Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Sat, 14 Jun 2014 20:43:34 +0800 Subject: [PATCH 049/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71b5223..946f88b 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ The Swift Programming Language 中文化项目 * 可选链 [认领 by 重鱼] * 类型转换 [认领 by 孟志昂] * 嵌套类型 [认领 by 祁涛] - * 扩展 [认领 by 袁鹏] + * 扩展 [已完成 by 袁鹏] * 协议 [认领 by 姜天意] * 泛型 [认领 by 晴时 & 胡衍明] * 高级操作符 [认领 by 林晚] From 4175c94e1ef8b9ad5960e6f119bad3fc2a1d303e Mon Sep 17 00:00:00 2001 From: Henry Ge Date: Sun, 15 Jun 2014 12:35:43 +0800 Subject: [PATCH 050/261] Update 13_Inheritance.md --- src/chapter2/13_Inheritance.md | 292 ++++++++++++++++++++++++++++++++- 1 file changed, 291 insertions(+), 1 deletion(-) diff --git a/src/chapter2/13_Inheritance.md b/src/chapter2/13_Inheritance.md index f9bf1ab..2f3fc8f 100644 --- a/src/chapter2/13_Inheritance.md +++ b/src/chapter2/13_Inheritance.md @@ -1 +1,291 @@ -#TODO +##Inheritance +##继承 + +A class can *inherit* methods, properties, and other characteristics from another class. When one class inherits from another, the inheriting class is known as a *subclass*, and the class it inherits from is known as its *superclass*. + +一个类可以从另外一个类中*继承*方法,属性以及其他特性。当一个类继承另外一个类时,这个类被称作为*子类*,而被继承的类被称作为*父类*。 + +Inheritance is a fundamental behavior that differentiates classes from other types in Swift. +Classes in Swift can call and access methods, properties, and subscripts belonging to their superclass and can provide their own overriding versions of those methods, properties, and subscripts to refine or modify their behavior. Swift helps to ensure your overrides are correct by checking that the override definition has a matching superclass definition. + +在Swift语言中,继承是区分类与其他类型的一个基本行为。一个类可以访问并调用其父类中的方法,属性和下标,也可以通过重写它们来修改或优化它们的行为。Swift通过检查重写的定义是否能与一个父类中的定义匹配来确保重写的正确性。 + +Classes can also add property observers to inherited properties in order to be notified when the value of a property changes. Property observers can be added to any property, regardless of whether it was originally defined as a stored or computed property. + +类也可以通过对继承的属性添加观察器来监听它们的变化。属性观察器可以被添加用于监听任何属性,无论被监听的属性最初是被定义为存储属性还是计算属性。 + +##Defining a Base Class +##定义一个基类 + +Any class that does not inherit from another class is known as a *base* class. +一个没有继承其他类的类被称为*基类*。 + +``` +NOTE +Swift classes do not inherit from a universal base class. Classes you define without specifying a superclass automatically become base classes for you to build upon. +``` + +``` +注意 +Swift中的类没有继承一个全局的基类。没有指定父类的类会自动成为一个可用来被扩展的基类。 +``` + +The example below defines a base class called `Vehicle`. This base class declares two properties(`numberOfWheels` and `maxPassengers`) that are universal to all vehicles. These properties are used by a method called `description`, which returns a `String` description of the vehicle’s characteristics: + +下面的例子定义了一个基类`Vehicle`。类中声明了两个所有车辆都通用的属性(`numberOfWheels`和`maxPassengers`)。这两个属性在方法`description`中被使用,这个方法返回一个`String`类型的值来描述车辆的特性。 + +``` +class Vehicle { + var numberOfWheels: Int + var maxPassengers: Int + func description() -> String { + return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers" + } + init() { + numberOfWheels = 0 + maxPassengers = 1 + } +} +``` + +The Vehicle class also defines an initializer to set up its properties. Initializers are described in detail in Initialization, but a brief introduction is required here in order to illustrate how inherited properties can be modified by subclasses. +Vehicle类中还定义了一个构造器来初始化它的属性。构造器在构造过程章节中有详细描述,不过在这里会简单介绍一下被继承的属性是如何被子类修改的。 + +You use initializers to create a new instance of a type. Although initializers are not methods, they are written in a very similar syntax to instance methods. An initializer prepares a new instance for use, and ensures that all properties of the instance have valid initial values. +构造器会被用来创建一个类型的实例。尽管构造器并不是方法,但是书写它们的语法和实例方法非常类似。构造器准备一个新的实例供使用,并确保实例中所有的属性都有合法的初始值。 + +In its simplest form, an initializer is like an instance method with no parameters, written using the init keyword: +在最简单的形式中,构造器就像是一个没有参数的实例方法,用关键词init来声明。 + +1 init() { +2 // perform some initialization here +3 } + +To create a new instance of Vehicle, call this initializer with initializer syntax, written as TypeName followed by empty parentheses: +创建一个Vehicle类实例需要通过使用构造器语法来调用构造器,写法是在类名后加上一对空的括号。 + +let someVehicle = Vehicle() + +The initializer for Vehicle sets some initial property values (numberOfWheels = 0 and maxPassengers = 1) for an arbitrary vehicle. +Vehicle类的构造器为一个车辆初始化了一些属性(numberOfWheels = 0 和 maxPassengers = 1)。 + +The Vehicle class defines common characteristics for an arbitrary vehicle, but is not much use in itself. To make it more useful, you need to refine it to describe more specific kinds of vehicle. +Vehicle类为车辆定义了一些公用的特性,但是这些特性对类本身来说并没有太多作用。为了提高这些特性的可用性,需要描述更多不同特定种类的车辆。 + +Subclassing +子类化 +Subclassing is the act of basing a new class on an existing class. The subclass inherits characteristics from the existing class, which you can refine. You can also add new characteristics to the subclass. +子类化是指在一个已有类的基础上建立一个新的类。新建的子类会继承已有类的特性,并可以优化它们。在子类中还可以增加新的特性。 + +To indicate that a class has a superclass, write the superclass name after the original class name, separated by a colon: +当声明一个类的父类时,需要将父类的名字写在原有类之后,并用冒号分隔: +1 class SomeClass: SomeSuperclass { +2 // class definition goes here +3 } + +The next example defines a second, more specific vehicle called Bicycle. This new class is based on the existing capabilities of Vehicle. You indicate this by placing the name of the class the subclass builds upon (Vehicle) after its own name (Bicycle), separated by a colon. +下面的例子定义了另一个更具体的车辆类Bicycle。新定义的类基于Vehicle类中存在的功能。定义的时候需要把父类的名字(Vehicle)放在新定义类的名字(Bicycle)之后,并用冒号分隔。 + +This can be read as: +“Define a new class called Bicycle, which inherits the characteristics of Vehicle”: +下面的语句可以这样来解读: +“定义一个新的名为Bicycle的类,它继承了Vehicle类的特性。” +1 class Bicycle: Vehicle { +2 init() { +3 super.init() +4 numberOfWheels = 2 +5 } +6 } + +Bicycle is a subclass of Vehicle, and Vehicle is the superclass of Bicycle. The new Bicycle class +automatically gains all characteristics of Vehicle, such as its maxPassengers and numberOfWheels properties.You can tailor those characteristics and add new ones to better match the requirements of the Bicycle class. +Bicycle是Vehicle的子类, 反而言之Vehicle是Bicycle的父类. 新创建的Bicycle类自动获得了Vehicle类的所有特性,比如它的maxPassengers与numberOfWheels属性。为了更好的满足Bicycle类的需求,你可以修改这些特性或者增加新的特性。 + +The Bicycle class also defines an initializer to set up its tailored characteristics. The initializer for Bicycle calls super.init(), the initializer for the Bicycle class’s superclass, Vehicle, and ensures that all of the inherited properties are initialized by Vehicle before Bicycle tries to modify them. +Bicycle类同样定义了一个构造器来初始化其修改过的特性。Bicycle的构造器通过调用其父类Vehicle的构造器super.init()来确保所有继承下来的属性在被修改前都已被Vehicle类成功初始化。 + +注意 +Unlike Objective-C, initializers are not inherited by default in Swift. For more information, see Initializer +Inheritance and Overriding. +与Objective-C不同的是,在Swift中构造器是不会默认被继承的。更多信息请参考构造器的继承和重写。 + +The default value of maxPassengers provided by Vehicle is already correct for a bicycle, and so it is not changed within the initializer for Bicycle. The original value of numberOfWheels is not correct, however, and is replaced with a new value of 2. +Vehicle类中为maxPassengers提供的默认值对于一辆自行车来说已经是正确的了,所以在Bicycle类的构造器中没有做修改。而numberOfWheels的原始值对于一辆自行车来说是错误的,所以它被替换成了一个新的值2。 + +As well as inheriting the properties of Vehicle, Bicycle also inherits its methods. If you create an instance of Bicycle, you can call its inherited description method to see how its properties have been updated: +除了继承了Vehicle类中的属性,Bicycle类还继承了它的方法。创建了一个Bicycle的实例后,可以通过调用它继承过来的description方法来观察类中属性的更新。 +1 let bicycle = Bicycle() +2 println("Bicycle: \(bicycle.description())") +3 // Bicycle: 2 wheels; up to 1 passengers + +Subclasses can themselves be subclassed: +子类可以被继续继承: +1 class Tandem: Bicycle { +2 init() { +3 super.init() +4 maxPassengers = 2 +5 } +6 } + +This example creates a subclass of Bicycle for a two-seater bicycle known as a “tandem”. Tandem inherits the two properties from Bicycle, which in turn inherits these properties from Vehicle. Tandem doesn’t change the number of wheels—it’s still a bicycle, after all—but it does update maxPassengers to have the correct value for a tandem. +上面的例子创建了一个Bicycle类的子类双人自行车(Tandem)。Tandem类继承了Bicycle类中的两个属性,而这两个属性又是从Vehicle类继承下来的。由于Tandem仍然是自行车的一种,所以类中没有改变车轮数量的属性numberOfWheels,但是它更新了表示最大乘客数的属性maxPassengers以满足一辆双人自行车的要求。 + +N OT E +Subclasses are only allowed to modify variable properties of superclasses during initialization. You can’t +modify inherited constant properties of subclasses. +注意 +在初始化过程中,子类只允许修改父类中的变量属性,而常量属性是不能被修改的。 + +Creating an instance of Tandem and printing its description shows how its properties have been updated: +下面通过创建一个Tandem的实例并打印其描述来观察它的属性更新: + +1 let tandem = Tandem() +2 println("Tandem: \(tandem.description())") +3 // Tandem: 2 wheels; up to 2 passengers + +Note that the description method is also inherited by Tandem. Instance methods of a class are inherited by any and all subclasses of that class. +注意description方法也是Tandem类继承下来的。一个类中的实例方法会被它所有的子类继承。 + +Overriding +重写 +A subclass can provide its own custom implementation of an instance method, class method, instance property, or subscript that it would otherwise inherit from a superclass. This is known as overriding. +子类可以为继承过来的实例方法,类方法,实例属性或脚本提供它自己的实现,这个行为被称作重写。 + +To override a characteristic that would otherwise be inherited, you prefix your overriding definition with the override keyword. Doing so clarifies that you intend to provide an override and have not provided a matching definition by mistake. Overriding by accident can cause unexpected behavior, and any overrides without the override keyword are diagnosed as an error when your code is compiled. +如果要重写某个属性,你需要在重写的定义前加上override关键字。这么做是为了表明你是为了提供一个重写的版本而不是错误地提供了一个同样的定义。意外地重写会引起不可预知的错误,没有加关键字override的重写都会在编译时被诊断为错误。 + +The override keyword also prompts the Swift compiler to check that your overriding class’s superclass (or one of its parents) has a declaration that matches the one you provided for the override. This check ensures that your overriding definition is correct. +Override关键字也会提醒Swift编译器去校验被继承的父类(或其中中一个父类)中是否有匹配的声明用于被重写。这个检查可以确保你的重写定义是正确的。 +Accessing Superclass Methods, Properties, and Subscripts +访问父类的方法,属性和脚本 + +When you provide a method, property, or subscript override for a subclass, it is sometimes useful to use the existing superclass implementation as part of your override. For example, you can refine the behavior of that existing implementation or store a modified value in an existing inherited variable. +当你访问父类的方法,属性或脚本时,有时在你的重写版本中使用已存在的父类实现会很有作用。比如你可以优化一个已有的实现或者在一个继承来的变量重储存一个修改过的值。 + +Where this is appropriate, you access the superclass version of a method, property, or subscript by using the super prefix: +在适当的地方,你可以通过super前缀来访问父类版本的方法,属性或脚本: + An overridden method named someMethod can call the superclass version of someMethod by callingsuper.someMethod() within the overriding method implementation. +一个重写的方法someMethod可以在方法实现中通过super.someMethod()来调用父类版本的someMethod。 + An overridden property called someProperty can access the superclass version of someProperty assuper.someProperty within the overriding getter or setter implementation. +一个重写的属性someProperty可以在getter和setter方法的重写实现中通过super.someProperty来访问父类版本的someProperty。 + An overridden subscript for someIndex can access the superclass version of the same subscript as super[someIndex] from within the overriding subscript implementation. +一个重写的脚本someIndex可以在脚本实现中通过super[someIndex]来调用父类版本的someIndex。 + +Overriding Methods +重写方法 +You can override an inherited instance or class method to provide a tailored or alternative implementation of the method within your subclass. +在子类中你可以通过提供一个定制或替代的实现来重写一个继承过来的实例方法或类方法。 +The following example defines a new subclass of Vehicle called Car, which overrides the description method it inherits from Vehicle: +下面的例子定义了Vehicle类的一个新子类Car, 子类中重写了从父类中继承过来的方法description: +1 class Car: Vehicle { +2 var speed: Double = 0.0 +3 init() { +4 super.init() +5 maxPassengers = 5 +6 numberOfWheels = 4 +7 } +8 override func description() -> String { +9 return super.description() + "; " +10 + "traveling at \(speed) mph" +11 } +12 } + +Car declares a new stored Double property called speed. This property defaults to 0.0, meaning “zero miles per hour”. Car also has a custom initializer, which sets the maximum number of passengers to 5, and the default number of wheels to 4. +Car类中声明了一个新的Double类存储型属性speed,默认值是0.0,代表”时速为每小时0英里”。Car类还有自定义构造器,构造器中设置最大乘客量为5,默认车轮数为4。 + +Car overrides its inherited description method by providing a method with the same declaration as the description method from Vehicle. The overriding method definition is prefixed with the override keyword. +Car类重写了继承来的description方法,它的声明和父类Vehicle中一致。被重写的方法定义前加上了override关键字。 + +Rather than providing a completely custom implementation of description, the overriding method actually starts by calling super.description to retrieve the description provided by Vehicle. It then appends some additional information about the car’s current speed. +重写的方法并没有完全自定义方法description的实现,它在开始时通过调用super.description来使用父类Vehicle中的方法实现,之后再为车辆的当前速度追加了一些额外信息。 + +If you create a new instance of Car, and print the output of its description method, you can see that the description has indeed changed: +如果你创建一个Car类的实例,并打印description方法的输出,你会发现描述的信息已经发生了改变。 +1 let car = Car() +2 println("Car: \(car.description())") +3 // Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph + +Overriding Properties +重写属性 +You can override an inherited instance or class property to provide your own custom getter and setter for that property, or to add property observers to enable the overriding property to observe when the underlying property value changes. +你可以重写继承来的实例属性或类属性来提供自定义的getter和setter方法,或添加属性观察器来使被重写的属性观察属性值什么时候发生改变。 + +Overriding Property Getters and Setters +重写属性的Getters和Setters +You can provide a custom getter (and setter, if appropriate) to override any inherited property, regardless of whether the inherited property is implemented as a stored or computed property at its source. The stored or computed nature of an inherited property is not known by a subclass—it only knows that the inherited property has a certain name and type. You must always state both the name and the type of the property you are overriding, to enable the compiler to check that your override matches a superclass property with the same name and type. +你可以提供自定义的getter(或setter,如适用)来重写任何被继承的属性,无论被继承的属性是存储型的还是计算型的。子类并不知道继承来的属性是存储型的还是计算型的,它只知道继承来的属性有名字和类型。在你重写一个属性时,必须声明它的名字和类型。这是为了让编译器检测你重写的属性在父类中有相同的名字和类型。 + +You can present an inherited read-only property as a read-write property by providing both a getter and a setter in your subclass property override. You cannot, however, present an inherited read-write property as a read-only property. +你可以通过提供getter和setter来将继承来的一个只读属性重写为一个读写属性。但是你无法将一个继承来的读写属性重写成一个只读属性。 + +N OT E +If you provide a setter as part of a property override, you must also provide a getter for that override. If you don’t want to modify the inherited property’s value within the overriding getter, you can simply pass through the inherited value by returning super.someProperty from the getter, as in the SpeedLimitedCar example below. +注意 +如果你在重写时为一个属性提供了setter,那么你必须同时要提供一个getter。如果你不想在重写版本的getter中修改继承来的属性值,你可以直接返回super.someProperty,正如下面SpeedLimitedCar的例子所示。 + +The following example defines a new class called SpeedLimitedCar, which is a subclass of Car. The SpeedLimitedCar class represents a car that has been fitted with a speed-limiting device, which prevents the car from traveling faster than 40mph. You implement this limitation by overriding the inherited speed property: +下面的例子定义了一个新的类SpeedLimitedCar,这个类是Car类的子类。SpeedLimitedCar类表示安装了限速装置的车来防止车的时速超过40英里。你需要通过重写speed属性来实现这个速度限制: +1 class SpeedLimitedCar: Car { +2 override var speed: Double { +3 get { +4 return super.speed +5 } +6 set { +7 super.speed = min(newValue, 40.0) +8 } +9 } +10 } + +Whenever you set the speed property of a SpeedLimitedCar instance, the property’s setter implementation checks the new value and limits it to 40mph. It does this by setting the underlying speed property of its superclass to be the smaller of newValue and 40.0. The smaller of these two values is determined by passing them to the min function, which is a global function provided by the Swift standard library. The min function takes two or more values and returns the smallest one of those values. +当你设置一个SpeedLimitedCar实例的speed属性时,属性的setter方法会检验新设置的值并把它限制在时速40英里以内,这是通过选择新设置的值和40之间最小的值来实现的。这个比较会通过调用min函数实现,它是Swift标准库中的一个方法。min函数接受两个或更多的参数并返回其中最小的一个。 + +If you try to set the speed property of a SpeedLimitedCar instance to more than 40mph, and then print the output of its description method, you see that the speed has been limited: +如果你尝试将SpeedLimitedCar实例中的speed属性设置成时速40英里以上,然后打印description方法的输出,你会看到车速已经被限制了: +1 let limitedCar = SpeedLimitedCar() +2 limitedCar.speed = 60.0 +3 println("SpeedLimitedCar: \(limitedCar.description())") +4 // SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph + +Overriding Property Observers +覆盖属性观察器 +You can use property overriding to add property observers to an inherited property. This enables you to be notified when the value of the inherited property changes, regardless of how that property was originally implemented. For more information on property observers, see Property Observers. +你可以在属性重写时为一个继承来的属性添加属性观察器。当继承来的属性被修改时,你就会被通知到,无论那个属性原来是如何被实现的。关于属性观察器的更多内容,请参考属属性观察器。 + +N OT E +You cannot add property observers to inherited constant stored properties or inherited read-only computed properties. The value of these properties cannot be set, and so it is not appropriate to provide a willSet or didSet implementation as part of an override. +Note also that you cannot provide both an overriding setter and an overriding property observer. If you want to observe changes to a property’s value, and you are already providing a custom setter for that property, you can simply observe any value changes from within the custom setter. +注意 +你不可以为继承来的常量存储型属性或只读计算型属性添加属性观察器。这些属性的值是不可以被修改的,所以在重写时为它们提供willSet和didSet的实现是不恰当的。 +注意你也不能同事提供重写的setter方法和属性观察期。如果你想要观察属性值的变化,并且你已经给那个属性提供了定制的setter方法,在setter方法中你就已经可以观察到任何属性值的变化了。 + +The following example defines a new class called AutomaticCar, which is a subclass of Car. The AutomaticCar class represents a car with an automatic gearbox, which automatically selects an appropriate gear to use based on the current speed. AutomaticCar also provides a custom description method to print the current gear. +下面的例子定义了一个新类AutomaticCar,它是Car类的子类。AutomaticCar类表示自动档汽车,它会根据当前的车速选择一个合适的档位。AutomaticCar提供了一个定制的description方法来输出当前的档位。 +1 class AutomaticCar: Car { +2 var gear = 1 +3 override var speed: Double { +4 didSet { +5 gear = Int(speed / 10.0) + 1 +6 } +7 } +8 override func description() -> String { +9 return super.description() + " in gear \(gear)" +10 } +11 } + +Whenever you set the speed property of an AutomaticCar instance, the property’s didSet observer automatically sets the gear property to an appropriate choice of gear for the new speed. Specifically, the property observer chooses a gear which is the new speed value divided by 10, rounded down to the nearest integer, plus 1. A speed of 10.0 produces a gear of 1, and a speed of 35.0 produces a gear of 4: +当你为一个AutomaticCar实例设置speed属性时,属性的didSet观察器会自动设置gear属性到一个合适的档位。具体的计算方法是,属性观察者将新设置的速度值除以10,向下取整之后再加1。例如速度是10的时候档位是1,速度是35.0的时候档位是4。 + +1 let automatic = AutomaticCar() +2 automatic.speed = 35.0 +3 println("AutomaticCar: \(automatic.description())") +4 // AutomaticCar: 4 wheels; up to 5 passengers; traveling at 35.0 mph in gear 4 + +Preventing Overrides +防止重写 +You can prevent a method, property, or subscript from being overridden by marking it as final. Do this by writing the @final attribute before its introducer keyword (such as @final var, @final func, @final class func, and @final subscript). +你可以通过标记一个属性,方法或附属脚本为final来防止它们被重写。具体方法是在声明它们的关键字前加上@final (例如@final var, @final func, @final class func, @final subscript)。 + +Any attempts to override a final method, property, or subscript in a subclass are reported as a compile-time error. Methods, properties or subscripts that you add to a class in an extension can also be marked as final within the extension’s definition. +如果被标记为final的方法,属性或附属脚本在子类中被尝试重写,在编译时便会报错。在扩展时被添加到类中的方法,属性或附属脚本也可以在扩展的定义中标记为final。 +You can mark an entire class as final by writing the @final attribute before the class keyword in its class definition (@final class). Any attempts to subclass a final class will be reported as a compile-time error. +你也可以通过在关键字class前添加@final属性(@final class)来把整个类标记为final。如此以来这个类就不可以被继承,否则在编译时会报错。 From 0c7049562ab7757da678074a2fdd7246cc960cbd Mon Sep 17 00:00:00 2001 From: Neekey Date: Sun, 15 Jun 2014 15:38:57 +0800 Subject: [PATCH 051/261] Update 07_Attributes.md --- src/chapter3/07_Attributes.md | 107 ++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/chapter3/07_Attributes.md b/src/chapter3/07_Attributes.md index e69de29..c41ec85 100644 --- a/src/chapter3/07_Attributes.md +++ b/src/chapter3/07_Attributes.md @@ -0,0 +1,107 @@ +# Attributes + +# 属性 + +*Attributes* provide more information about a declaration or type. There are two kinds of attributes in Swift, those that apply to declarations and those that apply to types. For instance, the `required` attribute—when applied to a designated or convenience initializer declaration of a class—indicates that every subclass must implement that initializer. And the `noreturn` attribute—when applied to a function or method type—indicates that the function or method doesn’t return to its caller. + +You specify an attribute by writing the `@` symbol followed by the attribute’s name and any arguments that the attribute accepts: + +``` + @attribute name + @attribute name(attribute arguments) +``` + +Some declaration attributes accept arguments that specify more information about the attribute and how it applies to a particular declaration. These *attribute arguments* are enclosed in parentheses, and their format is defined by the attribute they belong to. + +## Declaration Attributes + +You can apply a declaration attribute to declarations only. However, you can also apply the `noreturn` attribute to a function or method *type*. + +`assignment` +> Apply this attribute to functions that overload a compound assignment operator. Functions that overload a compound assignment operator must mark their initial input parameter as inout. For an example of how to use the assignment attribute, see [Compound Assignment Operators](#). + +`class_protocol` +> Apply this attribute to a protocol to indicate that the protocol can be adopted by class types only. + +> If you apply the `objc` attribute to a protocol, the `class_protocol` attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the `class_protocol` attribute explicitly. + +`exported` +> Apply this attribute to an import declaration to export the imported module, submodule, or declaration from the current module. If another module imports the current module, that other module can access the items exported by the current module. + +`final` +> Apply this attribute to a class or to a property, method, or subscript member of a class. It’s applied to a class to indicate that the class can’t be subclassed. It’s applied to a property, method, or subscript of a class to indicate that that class member can’t be overridden in any subclass. + +`lazy` +> Apply this attribute to a stored variable property of a class or structure to indicate that the property’s initial value is calculated and stored at most once, when the property is first accessed. For an example of how to use the `lazy` attribute, see [Lazy Stored Properties](#). + +`noreturn` +> Apply this attribute to a function or method declaration to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. You can mark a function or method type with this attribute to indicate that the function or method doesn’t return to its caller. + +> You can override a function or method that is not marked with the `noreturn` attribute with a function or method that is. That said, you can’t override a function or method that is marked with the `noreturn` attribute with a function or method that is not. Similar rules apply when you implement a protocol method in a conforming type. + +`NSCopying` +> Apply this attribute to a stored variable property of a class. This attribute causes the property’s setter to be synthesized with a *copy* of the property’s value—returned by the `copyWithZone` method—instead of the value of the property itself. The type of the property must conform to the `NSCopying` protocol. + +> The `NSCopying` attribute behaves in a way similar to the Objective-C `copy` property attribute. + +`NSManaged` +> Apply this attribute to a stored variable property of a class that inherits from `NSManagedObject` to indicate that the storage and implementation of the property are provided dynamically by Core Data at runtime based on the associated entity description. + +`objc` +> Apply this attribute to any declaration that can be represented in Objective-C—for example, non-nested classes, protocols, properties and methods (including getters and setters) of classes and protocols, initializers, deinitializers, and subscripts. The `objc` attribute tells the compiler that a declaration is available to use in Objective-C code. + +> If you apply the `objc` attribute to a class or protocol, it’s implicitly applied to the members of that class or protocol. The compiler also implicitly adds the `objc` attribute to a class that inherits from another class marked with the `objc` attribute. Protocols marked with the `objc` attribute can’t inherit from protocols that aren’t. + +> The `objc` attribute optionally accepts a single attribute argument, which consists of an identifier. Use this attribute when you want to expose a different name to Objective-C for the entity the `objc` attribute applies to. You can use this argument to name classes, protocols, methods, getters, setters, and initializers. The example below exposes the getter for the enabled property of the `ExampleClass` to Objective-C code as `isEnabled` rather than just as the name of the property itself. + +``` + @objc + class ExampleClass { + var enabled: Bool { + @objc(isEnabled) get { + // Return the appropriate value + } + } + } +``` + +`optional` +> Apply this attribute to a protocol’s property, method, or subscript members to indicate that a conforming type isn’t required to implement those members. + +> You can apply the `optional` attribute only to protocols that are marked with the `objc` attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. For more information about how to use the `optional` attribute and for guidance about how to access optional protocol members—for example, when you’re not sure whether a conforming type implements them—see [Optional Protocol Requirements](#). + +`required` +> Apply this attribute to a designated or convenience initializer of a class to indicate that every subclass must implement that initializer. + +> Required designated initializers must be implemented explicitly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or when the subclass overrides the designated initializers with convenience initializers). + +### Declaration Attributes Used by Interface Builder + +Interface Builder attributes are declaration attributes used by Interface Builder to synchronize with Xcode. Swift provides the following Interface Builder attributes: `IBAction`, `IBDesignable`, `IBInspectable`, and `IBOutlet`. These attributes are conceptually the same as their Objective-C counterparts. + +You apply the `IBOutlet` and `IBInspectable` attributes to property declarations of a class. You apply the `IBAction` attribute to method declarations of a class and the `IBDesignable` attribute to class declarations. + +## Type Attributes + +You can apply type attributes to types only. However, you can also apply the `noreturn` attribute to a function or method *declaration*. + +`auto_closure` +> This attribute is used to delay the evaluation of an expression by automatically wrapping that expression in a closure with no arguments. Apply this attribute to a function or method type that takes no arguments and that returns the type of the expression. For an example of how to use the `auto_closure` attribute, see [Function Type](#). + +`noreturn` +Apply this attribute to the type of a function or method to indicate that the function or method doesn’t return to its caller. You can also mark a function or method declaration with this attribute to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. + +> GRAMMAR OF AN ATTRIBUTE + +‌> attribute → @attribute-nameattribute-argument-clauseopt +‌> attribute-name → identifier +‌> attribute-argument-clause → (balanced-tokensopt) +‌> attributes → attributeattributesopt +‌> balanced-tokens → balanced-tokenbalanced-tokensopt +‌> balanced-token → (balanced-tokensopt) +‌> balanced-token → [balanced-tokensopt] +‌> balanced-token → {balanced-tokensopt} +‌> balanced-token → Any identifier, keyword, literal, or operator +‌> balanced-token → Any punctuation except (, ), [, ], {, or } + + From b002e13802d5a276786220431ed007bcf995b603 Mon Sep 17 00:00:00 2001 From: Neekey Date: Sun, 15 Jun 2014 15:41:18 +0800 Subject: [PATCH 052/261] Update 07_Attributes.md --- src/chapter3/07_Attributes.md | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/chapter3/07_Attributes.md b/src/chapter3/07_Attributes.md index c41ec85..5abc873 100644 --- a/src/chapter3/07_Attributes.md +++ b/src/chapter3/07_Attributes.md @@ -93,15 +93,24 @@ Apply this attribute to the type of a function or method to indicate that the fu > GRAMMAR OF AN ATTRIBUTE -‌> attribute → @attribute-nameattribute-argument-clauseopt -‌> attribute-name → identifier -‌> attribute-argument-clause → (balanced-tokensopt) -‌> attributes → attributeattributesopt -‌> balanced-tokens → balanced-tokenbalanced-tokensopt -‌> balanced-token → (balanced-tokensopt) -‌> balanced-token → [balanced-tokensopt] -‌> balanced-token → {balanced-tokensopt} -‌> balanced-token → Any identifier, keyword, literal, or operator -‌> balanced-token → Any punctuation except (, ), [, ], {, or } +> attribute → @attribute-nameattribute-argument-clauseopt + +> attribute-name → identifier + +> attribute-argument-clause → (balanced-tokensopt) + +> attributes → attributeattributesopt + +> balanced-tokens → balanced-tokenbalanced-tokensopt + +> balanced-token → (balanced-tokensopt) + +> balanced-token → [balanced-tokensopt] + +> balanced-token → {balanced-tokensopt} + +> balanced-token → Any identifier, keyword, literal, or operator + +> balanced-token → Any punctuation except (, ), [, ], {, or } From 2b482c0c495416ad033e24f3798f04b106da7b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Sun, 15 Jun 2014 16:40:27 +0800 Subject: [PATCH 053/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index 3a092f9..2a459f2 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -6,10 +6,10 @@ Type casting in Swift is implemented with the is and as operators. These two ope You can also use type casting to check whether a type conforms to a protocol, as described in Checking for Protocol Conformance. -# 类型转换 -类型转换是一种方法来检查一个实例的类型,和/或处理该实例,就好像它是一个不同的超类或子类从别的在自己的类层次结构中的某个地方。 +# 类型检查 +类型检查是一种方法来检查一个实例的类型,并且/或者处理该实例,就好像它是一个不同的超类或子类从别的在自己的类层次结构中的某个地方。 -类型转换使用is和as操作符来实现。这两个操作符提供了一种简单和富有表现力的方法来检查一个值的类型或把某个值转换为不同的类型。 +类型转换使用'is'和'as'操作符来实现。这两个操作符提供了一种简单和富有表现力的方法来检查一个值的类型或者把某个值转换为不同的类型。 你还可以使用类型转换来检查类型是否符合,如在检查协议一致性描述。 ##Defining a Class Hierarchy for Type Casting From 95ca99f66945c22bd03926f0afcd2a740f82c7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Sun, 15 Jun 2014 16:40:56 +0800 Subject: [PATCH 054/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index 2a459f2..7f1ce63 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -9,7 +9,7 @@ You can also use type casting to check whether a type conforms to a protocol, as # 类型检查 类型检查是一种方法来检查一个实例的类型,并且/或者处理该实例,就好像它是一个不同的超类或子类从别的在自己的类层次结构中的某个地方。 -类型转换使用'is'和'as'操作符来实现。这两个操作符提供了一种简单和富有表现力的方法来检查一个值的类型或者把某个值转换为不同的类型。 +类型转换使用`is`和`as`操作符来实现。这两个操作符提供了一种简单和富有表现力的方法来检查一个值的类型或者把某个值转换为不同的类型。 你还可以使用类型转换来检查类型是否符合,如在检查协议一致性描述。 ##Defining a Class Hierarchy for Type Casting From 041c517d9fef9f567f79e40ce7903ec388e8229a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Sun, 15 Jun 2014 17:12:16 +0800 Subject: [PATCH 055/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index 7f1ce63..e93bfda 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -22,7 +22,7 @@ The first snippet defines a new base class called MediaItem. This class provides 您可以使用类型转换与类和子类的层次结构来检查一个特定的类实例的类型和投该实例到另一个类中的同一层级内。下面的三个代码片段定义的类层次结构和包含这些类的实例数组,用于类型转换的一个例子使用。 -第一个片段定义了一个名为MediaItem新的基类。这个类提供基本功能,任何类型的项目出现在一个数字媒体库。具体来说,它声明一个String类型的name属性,以及一个init名称初始值设定项。 (假设所有的媒体项目,包括所有的电影和歌曲,将有一个名称。) +第一个片段定义了一个名为`MediaItem`新的基类。这个类提供基本功能,任何类型的项目出现在一个数字媒体库。具体来说,它声明一个`String`类型的`name`属性,以及一个`init`名称初始值设定项。 (假设所有的媒体项目,包括所有的电影和歌曲,将有一个名称。) class MediaItem { var name: String @@ -32,7 +32,7 @@ The first snippet defines a new base class called MediaItem. This class provides } The next snippet defines two subclasses of MediaItem. The first subclass, Movie, encapsulates additional information about a movie or film. It adds a director property on top of the base MediaItem class, with a corresponding initializer. The second subclass, Song, adds an artist property and initializer on top of the base class: -接下来的片断定义MediaItem的两个子类。第一个子类,电影,封装了有关电影或电影的附加信息。它增加了一个属性主任在基MediaItem类的顶部,有一个相应的初始化。第二个亚类,宋,增加了一个艺术家财产和初始化基类的顶部: +接下来的代码定义了`MediaItem`的两个子类。第一个子类,`Movie`,封装了有关`Movie`或`Movie`的附加信息。它增加了一个属性`director`,还有相应的初始化方法。第二个`Song`,增加了一个`artist`和初始化方法: class Movie: MediaItem { var director: String @@ -51,7 +51,7 @@ The next snippet defines two subclasses of MediaItem. The first subclass, Movie, } The final snippet creates a constant array called library, which contains two Movie instances and three Song instances. The type of the library array is inferred by initializing it with the contents of an array literal. Swift’s type checker is able to deduce that Movie and Song have a common superclass of MediaItem, and so it infers a type of MediaItem[] for the library array: -最后的代码片断创建一个常量数组叫做库,其中包含两个电影实例和三首歌曲的实例。图书馆数组的类型是由具有数组文本的内容初始化它的推断。斯威夫特的类型检查是能够演绎出电影和歌曲有MediaItem一个共同的超类,所以它会推断图书馆数组类型MediaItem[]中: +最后的代码创建一个常量数组叫做`library`,其中包含两个`Movie`实例和三首`Song`的实例。`library`数组的类型是由它里面包含的内容决定的。Swift能够识别出`Movie`和`Song`有MediaItem一个共同的父类,所以它会推断出`library`是一个`MediaItem[] `类型的数组。 let library = [ Movie(name: "Casablanca", director: "Michael Curtiz"), @@ -63,7 +63,7 @@ The final snippet creates a constant array called library, which contains two Mo // the type of "library" is inferred to be MediaItem[] The items stored in library are still Movie and Song instances behind the scenes. However, if you iterate over the contents of this array, the items you receive back are typed as MediaItem, and not as Movie or Song. In order to work with them as their native type, you need to check their type, or downcast them to a different type, as described below. -存储在库中的项目仍然在幕后电影和歌曲实例。但是,如果你遍历这个数组的内容,您会收到回项目类型为MediaItem,而不是电影或歌曲。为了与他们合作,因为他们自身的类型,你需要检查它们的类型,或将它们向下转换为不同的类型,如下所述。 +在系统里存储在`library`中的项目仍然是`Movie`和`Song`实例。但是,如果你遍历这个数组,您会收到回项目类型为`MediaItem`,而不是`Movie`或`Song`。为了使用他们原来的类型,你需要检查它们的类型,或将它们向下转换为不同的类型,如下所述。 ##Checking Type @@ -73,9 +73,9 @@ The example below defines two variables, movieCount and songCount, which count t ## 检查类型 -使用类型检查运算符(是)来检查一个实例是否是一个子类的类型。如果实例是子类的类型和虚假的,如果它不是类型检查运算符返回true。 +使用类型检查运算符(`is`)来检查一个实例是否是一个子类的类型。如果是,则返回`true`,否则返回`false` -下面的例子定义了两个变量,movieCount和songCount,这算电影和歌曲实例库中的数组数: +下面的例子定义了两个变量,`movieCount`和`songCount`,用来计算数组中`Movie` 和`Song` 的数量。 var movieCount = 0 var songCount = 0 @@ -89,15 +89,16 @@ The example below defines two variables, movieCount and songCount, which count t } println("Media library contains \(movieCount) movies and \(songCount) songs") - // prints "Media library contains 2 movies and 3 songs" + // 打印出 "Media library 包含 2 movies and 3 songs" This example iterates through all items in the library array. On each pass, the for-in loop sets the item constant to the next MediaItem in the array. item is Movie returns true if the current MediaItem is a Movie instance and false if it is not. Similarly, item is Song checks whether the item is a Song instance. At the end of the for-in loop, the values of movieCount and songCount contain a count of how many MediaItem instances were found of each type. -通过图书馆阵列中的所有项目本示例循环。在每个传中,for-in循环设置项常量数组中的下一个MediaItem。 +这个例子遍历了数组中的所有元素,每一次循环,都会把数组中的一个实例赋值给`item`。 + +如果`item`是`Movie`类型,则返回 `true`否则返回`false`,同样,也会检查`item`是否是`Song`类型。最后, `movieCount`和`songCount`就能统计出到底每个类型有多少个。 -产品如果当前MediaItem是一个Movie实例和虚假的,如果它不是电影返回true。同样,产品松检查项目是否为宋实例。在for-in循环的结束,movieCount和songCount的值包含多少MediaItem实例中发现每种类型的计数。 ##Downcasting @@ -105,7 +106,7 @@ A constant or variable of a certain class type may actually refer to an instance Because downcasting can fail, the type cast operator comes in two different forms. The optional form, as?, returns an optional value of the type you are trying to downcast to. The forced form, as, attempts the downcast and force-unwraps the result as a single compound action. -## 向下转换 +## 向下转型 某一类类型的常量或变量可能实际上是指在幕后一个子类的实例。在那里你认为是这样的话,你可以尝试向下转换与类型转换运算符(如)的子类型。 From e3157239a0feeeb74f366e04a7ad0fb3efdb42d6 Mon Sep 17 00:00:00 2001 From: Henry Ge Date: Sun, 15 Jun 2014 17:28:37 +0800 Subject: [PATCH 056/261] =?UTF-8?q?Inheritance=E7=BF=BB=E8=AF=91=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/13_Inheritance.md | 465 ++++++++++++++++++++------------- 1 file changed, 283 insertions(+), 182 deletions(-) diff --git a/src/chapter2/13_Inheritance.md b/src/chapter2/13_Inheritance.md index 2f3fc8f..43126f7 100644 --- a/src/chapter2/13_Inheritance.md +++ b/src/chapter2/13_Inheritance.md @@ -16,7 +16,6 @@ Classes can also add property observers to inherited properties in order to be n ##Defining a Base Class ##定义一个基类 - Any class that does not inherit from another class is known as a *base* class. 一个没有继承其他类的类被称为*基类*。 @@ -24,7 +23,6 @@ Any class that does not inherit from another class is known as a *base* class. NOTE Swift classes do not inherit from a universal base class. Classes you define without specifying a superclass automatically become base classes for you to build upon. ``` - ``` 注意 Swift中的类没有继承一个全局的基类。没有指定父类的类会自动成为一个可用来被扩展的基类。 @@ -40,7 +38,7 @@ class Vehicle { var maxPassengers: Int func description() -> String { return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers" - } + } init() { numberOfWheels = 0 maxPassengers = 1 @@ -48,244 +46,347 @@ class Vehicle { } ``` -The Vehicle class also defines an initializer to set up its properties. Initializers are described in detail in Initialization, but a brief introduction is required here in order to illustrate how inherited properties can be modified by subclasses. -Vehicle类中还定义了一个构造器来初始化它的属性。构造器在构造过程章节中有详细描述,不过在这里会简单介绍一下被继承的属性是如何被子类修改的。 +The `Vehicle` class also defines an initializer to set up its properties. Initializers are described in detail in [Initialization](), but a brief introduction is required here in order to illustrate how inherited properties can be modified by subclasses. + +`Vehicle`类中还定义了一个构造器来初始化它的属性。构造器在[构造过程]()章节中有详细描述,不过在这里会简单介绍一下被继承的属性是如何被子类修改的。 You use initializers to create a new instance of a type. Although initializers are not methods, they are written in a very similar syntax to instance methods. An initializer prepares a new instance for use, and ensures that all properties of the instance have valid initial values. + 构造器会被用来创建一个类型的实例。尽管构造器并不是方法,但是书写它们的语法和实例方法非常类似。构造器准备一个新的实例供使用,并确保实例中所有的属性都有合法的初始值。 -In its simplest form, an initializer is like an instance method with no parameters, written using the init keyword: -在最简单的形式中,构造器就像是一个没有参数的实例方法,用关键词init来声明。 +In its simplest form, an initializer is like an instance method with no parameters, written using the `init` keyword: + +在最简单的形式中,构造器就像是一个没有参数的实例方法,用关键词`init`来声明。 + +``` +init() { +// perform some initialization here +} +``` -1 init() { -2 // perform some initialization here -3 } +To create a new instance of `Vehicle`, call this initializer with *initializer syntax*, written as `TypeName` followed by empty parentheses: -To create a new instance of Vehicle, call this initializer with initializer syntax, written as TypeName followed by empty parentheses: -创建一个Vehicle类实例需要通过使用构造器语法来调用构造器,写法是在类名后加上一对空的括号。 +创建一个`Vehicle`类实例需要通过使用*构造器语法*来调用构造器,写法是在类名后加上一对空的括号。 +``` let someVehicle = Vehicle() +``` + +The initializer for `Vehicle` sets some initial property values (`numberOfWheels = 0` and `maxPassengers = 1`) for an arbitrary vehicle. -The initializer for Vehicle sets some initial property values (numberOfWheels = 0 and maxPassengers = 1) for an arbitrary vehicle. -Vehicle类的构造器为一个车辆初始化了一些属性(numberOfWheels = 0 和 maxPassengers = 1)。 +`Vehicle`类的构造器为一个车辆初始化了一些属性(`numberOfWheels = 0` 和 `maxPassengers = 1`)。 -The Vehicle class defines common characteristics for an arbitrary vehicle, but is not much use in itself. To make it more useful, you need to refine it to describe more specific kinds of vehicle. -Vehicle类为车辆定义了一些公用的特性,但是这些特性对类本身来说并没有太多作用。为了提高这些特性的可用性,需要描述更多不同特定种类的车辆。 +The `Vehicle` class defines common characteristics for an arbitrary vehicle, but is not much use in itself. To make it more useful, you need to refine it to describe more specific kinds of vehicle. -Subclassing -子类化 -Subclassing is the act of basing a new class on an existing class. The subclass inherits characteristics from the existing class, which you can refine. You can also add new characteristics to the subclass. -子类化是指在一个已有类的基础上建立一个新的类。新建的子类会继承已有类的特性,并可以优化它们。在子类中还可以增加新的特性。 +`Vehicle类`为车辆定义了一些公用的特性,但是这些特性对类本身来说并没有太多作用。为了提高这些特性的可用性,需要描述更多不同特定种类的车辆。 + +##Subclassing +##子类化 + +*Subclassing* is the act of basing a new class on an existing class. The subclass inherits characteristics from the existing class, which you can refine. You can also add new characteristics to the subclass. + +*子类化*是指在一个已有类的基础上建立一个新的类。新建的子类会继承已有类的特性,并可以优化它们。在子类中还可以增加新的特性。 To indicate that a class has a superclass, write the superclass name after the original class name, separated by a colon: + 当声明一个类的父类时,需要将父类的名字写在原有类之后,并用冒号分隔: -1 class SomeClass: SomeSuperclass { -2 // class definition goes here -3 } -The next example defines a second, more specific vehicle called Bicycle. This new class is based on the existing capabilities of Vehicle. You indicate this by placing the name of the class the subclass builds upon (Vehicle) after its own name (Bicycle), separated by a colon. -下面的例子定义了另一个更具体的车辆类Bicycle。新定义的类基于Vehicle类中存在的功能。定义的时候需要把父类的名字(Vehicle)放在新定义类的名字(Bicycle)之后,并用冒号分隔。 +``` +class SomeClass: SomeSuperclass { +// class definition goes here +} +``` + +The next example defines a second, more specific vehicle called `Bicycle`. This new class is based on the existing capabilities of `Vehicle`. You indicate this by placing the name of the class the subclass builds upon (`Vehicle`) after its own name (`Bicycle`), separated by a colon. + +下面的例子定义了另一个更具体的车辆类`Bicycle`。新定义的类基于`Vehicle`类中存在的功能。定义的时候需要把父类的名字(`Vehicle`)放在新定义类的名字(`Bicycle`)之后,并用冒号分隔。 This can be read as: -“Define a new class called Bicycle, which inherits the characteristics of Vehicle”: +“Define a new class called `Bicycle`, which inherits the characteristics of `Vehicle`”: 下面的语句可以这样来解读: -“定义一个新的名为Bicycle的类,它继承了Vehicle类的特性。” -1 class Bicycle: Vehicle { -2 init() { -3 super.init() -4 numberOfWheels = 2 -5 } -6 } -Bicycle is a subclass of Vehicle, and Vehicle is the superclass of Bicycle. The new Bicycle class -automatically gains all characteristics of Vehicle, such as its maxPassengers and numberOfWheels properties.You can tailor those characteristics and add new ones to better match the requirements of the Bicycle class. -Bicycle是Vehicle的子类, 反而言之Vehicle是Bicycle的父类. 新创建的Bicycle类自动获得了Vehicle类的所有特性,比如它的maxPassengers与numberOfWheels属性。为了更好的满足Bicycle类的需求,你可以修改这些特性或者增加新的特性。 +“定义一个新的名为`Bicycle`的类,它继承了`Vehicle`类的特性。” + +``` +class Bicycle: Vehicle { + init() { + super.init() + numberOfWheels = 2 + } +} +``` + +`Bicycle` is a subclass of `Vehicle`, and `Vehicle` is the superclass of `Bicycle`. The new `Bicycle` class automatically gains all characteristics of `Vehicle`, such as its `maxPassengers` and `numberOfWheels` properties.You can tailor those characteristics and add new ones to better match the requirements of the `Bicycle` class. + +`Bicycle`是`Vehicle`的子类, 反而言之`Vehicle`是`Bicycle`的父类。新创建的`Bicycle`类自动获得了`Vehicle`类的所有特性,比如它的`maxPassengers`与`numberOfWheels`属性。为了更好的满足`Bicycle`类的需求,你可以修改这些特性或者增加新的特性。 + +The `Bicycle` class also defines an initializer to set up its tailored characteristics. The initializer for `Bicycle` calls `super.init()`, the initializer for the `Bicycle` class’s superclass, `Vehicle`, and ensures that all of the inherited properties are initialized by `Vehicle` before `Bicycle` tries to modify them. -The Bicycle class also defines an initializer to set up its tailored characteristics. The initializer for Bicycle calls super.init(), the initializer for the Bicycle class’s superclass, Vehicle, and ensures that all of the inherited properties are initialized by Vehicle before Bicycle tries to modify them. -Bicycle类同样定义了一个构造器来初始化其修改过的特性。Bicycle的构造器通过调用其父类Vehicle的构造器super.init()来确保所有继承下来的属性在被修改前都已被Vehicle类成功初始化。 +`Bicycle`类同样定义了一个构造器来初始化其修改过的特性。`Bicycle`的构造器通过调用其父类`Vehicle`的构造器`super.init()`来确保所有继承下来的属性在被修改前都已被`Vehicle`类成功初始化。 +``` +Note +Unlike Objective-C, initializers are not inherited by default in Swift. For more information, see [Initializer +Inheritance and Overriding](). +``` + +``` 注意 -Unlike Objective-C, initializers are not inherited by default in Swift. For more information, see Initializer -Inheritance and Overriding. -与Objective-C不同的是,在Swift中构造器是不会默认被继承的。更多信息请参考构造器的继承和重写。 +与Objective-C不同的是,在Swift中构造器是不会默认被继承的。更多信息请参考[构造器的继承和重写]()。 +``` + +The default value of `maxPassengers` provided by `Vehicle` is already correct for a bicycle, and so it is not changed within the initializer for `Bicycle`. The original value of `numberOfWheels` is not correct, however, and is replaced with a new value of `2`. + +`Vehicle`类中为`maxPassengers`提供的默认值对于一辆自行车来说已经是正确的了,所以在`Bicycle`类的构造器中没有做修改。而`numberOfWheels`的原始值对于一辆自行车来说是错误的,所以它被替换成了一个新的值`2`。 -The default value of maxPassengers provided by Vehicle is already correct for a bicycle, and so it is not changed within the initializer for Bicycle. The original value of numberOfWheels is not correct, however, and is replaced with a new value of 2. -Vehicle类中为maxPassengers提供的默认值对于一辆自行车来说已经是正确的了,所以在Bicycle类的构造器中没有做修改。而numberOfWheels的原始值对于一辆自行车来说是错误的,所以它被替换成了一个新的值2。 +As well as inheriting the properties of `Vehicle`, `Bicycle` also inherits its methods. If you create an instance of `Bicycle`, you can call its inherited `description` method to see how its properties have been updated: -As well as inheriting the properties of Vehicle, Bicycle also inherits its methods. If you create an instance of Bicycle, you can call its inherited description method to see how its properties have been updated: -除了继承了Vehicle类中的属性,Bicycle类还继承了它的方法。创建了一个Bicycle的实例后,可以通过调用它继承过来的description方法来观察类中属性的更新。 -1 let bicycle = Bicycle() -2 println("Bicycle: \(bicycle.description())") -3 // Bicycle: 2 wheels; up to 1 passengers +除了继承了`Vehicle`类中的属性,`Bicycle`类还继承了它的方法。创建了一个`Bicycle`的实例后,可以通过调用它继承过来的`description`方法来观察类中属性的更新。 + +``` +let bicycle = Bicycle() +println("Bicycle: \(bicycle.description())") +// Bicycle: 2 wheels; up to 1 passengers +``` Subclasses can themselves be subclassed: + 子类可以被继续继承: -1 class Tandem: Bicycle { -2 init() { -3 super.init() -4 maxPassengers = 2 -5 } -6 } -This example creates a subclass of Bicycle for a two-seater bicycle known as a “tandem”. Tandem inherits the two properties from Bicycle, which in turn inherits these properties from Vehicle. Tandem doesn’t change the number of wheels—it’s still a bicycle, after all—but it does update maxPassengers to have the correct value for a tandem. -上面的例子创建了一个Bicycle类的子类双人自行车(Tandem)。Tandem类继承了Bicycle类中的两个属性,而这两个属性又是从Vehicle类继承下来的。由于Tandem仍然是自行车的一种,所以类中没有改变车轮数量的属性numberOfWheels,但是它更新了表示最大乘客数的属性maxPassengers以满足一辆双人自行车的要求。 +``` +class Tandem: Bicycle { + init() { + super.init() + maxPassengers = 2 + } +} +``` + +This example creates a subclass of `Bicycle` for a two-seater bicycle known as a “tandem”. `Tandem` inherits the two properties from `Bicycle`, which in turn inherits these properties from `Vehicle`. `Tandem` doesn’t change the number of wheels—it’s still a bicycle, after all—but it does update `maxPassengers` to have the correct value for a tandem. + +上面的例子创建了一个`Bicycle`类的子类双人自行车`Tandem`。`Tandem`类继承了`Bicycle`类中的两个属性,而这两个属性又是从`Vehicle`类继承下来的。由于`Tandem`仍然是自行车的一种,所以类中没有改变车轮数量的属性`numberOfWheels`,但是它更新了表示最大乘客数的属性`maxPassengers`以满足一辆双人自行车的要求。 -N OT E +``` +NOTE Subclasses are only allowed to modify variable properties of superclasses during initialization. You can’t modify inherited constant properties of subclasses. +``` + +``` 注意 在初始化过程中,子类只允许修改父类中的变量属性,而常量属性是不能被修改的。 +``` + +Creating an instance of `Tandem` and printing its description shows how its properties have been updated: + +下面通过创建一个`Tandem`的实例并打印其描述来观察它的属性更新: + +``` +let tandem = Tandem() +println("Tandem: \(tandem.description())") +// Tandem: 2 wheels; up to 2 passengers +``` + +Note that the `description` method is also inherited by `Tandem`. Instance methods of a class are inherited by any and all subclasses of that class. + +注意`description`方法也是`Tandem`类继承下来的。一个类中的实例方法会被它所有的子类继承。 -Creating an instance of Tandem and printing its description shows how its properties have been updated: -下面通过创建一个Tandem的实例并打印其描述来观察它的属性更新: +##Overriding +##重写 +A subclass can provide its own custom implementation of an instance method, class method, instance property, or subscript that it would otherwise inherit from a superclass. This is known as *overriding*. -1 let tandem = Tandem() -2 println("Tandem: \(tandem.description())") -3 // Tandem: 2 wheels; up to 2 passengers +子类可以为继承过来的实例方法,类方法,实例属性或脚本提供它自己的实现,这个行为被称作*重写*。 -Note that the description method is also inherited by Tandem. Instance methods of a class are inherited by any and all subclasses of that class. -注意description方法也是Tandem类继承下来的。一个类中的实例方法会被它所有的子类继承。 +To override a characteristic that would otherwise be inherited, you prefix your overriding definition with the `override` keyword. Doing so clarifies that you intend to provide an override and have not provided a matching definition by mistake. Overriding by accident can cause unexpected behavior, and any overrides without the `override` keyword are diagnosed as an error when your code is compiled. -Overriding -重写 -A subclass can provide its own custom implementation of an instance method, class method, instance property, or subscript that it would otherwise inherit from a superclass. This is known as overriding. -子类可以为继承过来的实例方法,类方法,实例属性或脚本提供它自己的实现,这个行为被称作重写。 +如果要重写某个属性,你需要在重写的定义前加上`override`关键字。这么做是为了表明你是为了提供一个重写的版本而不是错误地提供了一个同样的定义。意外地重写会引起不可预知的错误,没有加关键字`override`的重写都会在编译时被诊断为错误。 -To override a characteristic that would otherwise be inherited, you prefix your overriding definition with the override keyword. Doing so clarifies that you intend to provide an override and have not provided a matching definition by mistake. Overriding by accident can cause unexpected behavior, and any overrides without the override keyword are diagnosed as an error when your code is compiled. -如果要重写某个属性,你需要在重写的定义前加上override关键字。这么做是为了表明你是为了提供一个重写的版本而不是错误地提供了一个同样的定义。意外地重写会引起不可预知的错误,没有加关键字override的重写都会在编译时被诊断为错误。 +The `override` keyword also prompts the Swift compiler to check that your overriding class’s superclass (or one of its parents) has a declaration that matches the one you provided for the override. This check ensures that your overriding definition is correct. -The override keyword also prompts the Swift compiler to check that your overriding class’s superclass (or one of its parents) has a declaration that matches the one you provided for the override. This check ensures that your overriding definition is correct. -Override关键字也会提醒Swift编译器去校验被继承的父类(或其中中一个父类)中是否有匹配的声明用于被重写。这个检查可以确保你的重写定义是正确的。 -Accessing Superclass Methods, Properties, and Subscripts -访问父类的方法,属性和脚本 +`Override`关键字也会提醒Swift编译器去校验被继承的父类(或其中中一个父类)中是否有匹配的声明用于被重写。这个检查可以确保你的重写定义是正确的。 + +##Accessing Superclass Methods, Properties, and Subscripts +##访问父类的方法,属性和脚本 When you provide a method, property, or subscript override for a subclass, it is sometimes useful to use the existing superclass implementation as part of your override. For example, you can refine the behavior of that existing implementation or store a modified value in an existing inherited variable. 当你访问父类的方法,属性或脚本时,有时在你的重写版本中使用已存在的父类实现会很有作用。比如你可以优化一个已有的实现或者在一个继承来的变量重储存一个修改过的值。 -Where this is appropriate, you access the superclass version of a method, property, or subscript by using the super prefix: -在适当的地方,你可以通过super前缀来访问父类版本的方法,属性或脚本: - An overridden method named someMethod can call the superclass version of someMethod by callingsuper.someMethod() within the overriding method implementation. -一个重写的方法someMethod可以在方法实现中通过super.someMethod()来调用父类版本的someMethod。 - An overridden property called someProperty can access the superclass version of someProperty assuper.someProperty within the overriding getter or setter implementation. -一个重写的属性someProperty可以在getter和setter方法的重写实现中通过super.someProperty来访问父类版本的someProperty。 - An overridden subscript for someIndex can access the superclass version of the same subscript as super[someIndex] from within the overriding subscript implementation. -一个重写的脚本someIndex可以在脚本实现中通过super[someIndex]来调用父类版本的someIndex。 - -Overriding Methods -重写方法 +Where this is appropriate, you access the superclass version of a method, property, or subscript by using the `super` prefix: + +在适当的地方,你可以通过`super`前缀来访问父类版本的方法,属性或脚本: + +* An overridden method named `someMethod` can call the superclass version of `someMethod` by calling `super.someMethod()` within the overriding method implementation. +* An overridden property called `someProperty` can access the superclass version of `someProperty` as `super.someProperty` within the overriding getter or setter implementation. +* An overridden subscript for `someIndex` can access the superclass version of the same subscript as `super[someIndex]` from within the overriding subscript implementation. + +* 一个重写的方法`someMethod`可以在方法实现中通过`super.someMethod()`来调用父类版本的`someMethod`。 +* 一个重写的属性`someProperty`可以在getter和setter方法的重写实现中通过`super.someProperty`来访问父类版本的`someProperty`。 +* 一个重写的脚本`someIndex`可以在脚本实现中通过`super[someIndex]`来调用父类版本的`someIndex`。 + +##Overriding Methods +##重写方法 You can override an inherited instance or class method to provide a tailored or alternative implementation of the method within your subclass. + 在子类中你可以通过提供一个定制或替代的实现来重写一个继承过来的实例方法或类方法。 -The following example defines a new subclass of Vehicle called Car, which overrides the description method it inherits from Vehicle: -下面的例子定义了Vehicle类的一个新子类Car, 子类中重写了从父类中继承过来的方法description: -1 class Car: Vehicle { -2 var speed: Double = 0.0 -3 init() { -4 super.init() -5 maxPassengers = 5 -6 numberOfWheels = 4 -7 } -8 override func description() -> String { -9 return super.description() + "; " -10 + "traveling at \(speed) mph" -11 } -12 } - -Car declares a new stored Double property called speed. This property defaults to 0.0, meaning “zero miles per hour”. Car also has a custom initializer, which sets the maximum number of passengers to 5, and the default number of wheels to 4. -Car类中声明了一个新的Double类存储型属性speed,默认值是0.0,代表”时速为每小时0英里”。Car类还有自定义构造器,构造器中设置最大乘客量为5,默认车轮数为4。 - -Car overrides its inherited description method by providing a method with the same declaration as the description method from Vehicle. The overriding method definition is prefixed with the override keyword. -Car类重写了继承来的description方法,它的声明和父类Vehicle中一致。被重写的方法定义前加上了override关键字。 - -Rather than providing a completely custom implementation of description, the overriding method actually starts by calling super.description to retrieve the description provided by Vehicle. It then appends some additional information about the car’s current speed. -重写的方法并没有完全自定义方法description的实现,它在开始时通过调用super.description来使用父类Vehicle中的方法实现,之后再为车辆的当前速度追加了一些额外信息。 - -If you create a new instance of Car, and print the output of its description method, you can see that the description has indeed changed: -如果你创建一个Car类的实例,并打印description方法的输出,你会发现描述的信息已经发生了改变。 -1 let car = Car() -2 println("Car: \(car.description())") -3 // Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph - -Overriding Properties -重写属性 + +The following example defines a new subclass of `Vehicle` called `Car`, which overrides the `description` method it inherits from `Vehicle`: + +下面的例子定义了`Vehicle`类的一个新子类`Car`, 子类中重写了从父类中继承过来的方法`description`: + +``` +class Car: Vehicle { + var speed: Double = 0.0 + init() { + super.init() + maxPassengers = 5 + numberOfWheels = 4 + } + override func description() -> String { + return super.description() + "; " + + "traveling at \(speed) mph" + } +} +``` + +`Car` declares a new stored `Double` property called `speed`. This property defaults to `0.0`, meaning “zero miles per hour”. `Car` also has a custom initializer, which sets the maximum number of passengers to `5`, and the default number of wheels to `4`. + +`Car`类中声明了一个新的`Double`类存储型属性`speed`,默认值是`0.0`,代表”时速为每小时0英里”。Car类还有自定义构造器,构造器中设置最大乘客量为`5`,默认车轮数为`4`。 + +`Car` overrides its inherited `description` method by providing a method with the same declaration as the `description` method from `Vehicle`. The overriding method definition is prefixed with the `override` keyword. + +`Car`类重写了继承来的`description`方法,它的声明和父类`Vehicle`中一致。被重写的方法定义前加上了`override`关键字。 + +Rather than providing a completely custom implementation of `description`, the overriding method actually starts by calling `super.description` to retrieve the description provided by `Vehicle`. It then appends some additional information about the car’s current speed. + +重写的方法并没有完全自定义方法`description`的实现,它在开始时通过调用`super.description`来使用父类`Vehicle`中的方法实现,之后再为车辆的当前速度追加了一些额外信息。 + +If you create a new instance of `Car`, and print the output of its `description` method, you can see that the description has indeed changed: + +如果你创建一个`Car`类的实例,并打印`description`方法的输出,你会发现描述的信息已经发生了改变。 + +``` +let car = Car() +println("Car: \(car.description())") +// Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph +``` + +##Overriding Properties +##重写属性 + You can override an inherited instance or class property to provide your own custom getter and setter for that property, or to add property observers to enable the overriding property to observe when the underlying property value changes. + 你可以重写继承来的实例属性或类属性来提供自定义的getter和setter方法,或添加属性观察器来使被重写的属性观察属性值什么时候发生改变。 -Overriding Property Getters and Setters -重写属性的Getters和Setters +##Overriding Property Getters and Setters +##重写属性的Getters和Setters + You can provide a custom getter (and setter, if appropriate) to override any inherited property, regardless of whether the inherited property is implemented as a stored or computed property at its source. The stored or computed nature of an inherited property is not known by a subclass—it only knows that the inherited property has a certain name and type. You must always state both the name and the type of the property you are overriding, to enable the compiler to check that your override matches a superclass property with the same name and type. + 你可以提供自定义的getter(或setter,如适用)来重写任何被继承的属性,无论被继承的属性是存储型的还是计算型的。子类并不知道继承来的属性是存储型的还是计算型的,它只知道继承来的属性有名字和类型。在你重写一个属性时,必须声明它的名字和类型。这是为了让编译器检测你重写的属性在父类中有相同的名字和类型。 You can present an inherited read-only property as a read-write property by providing both a getter and a setter in your subclass property override. You cannot, however, present an inherited read-write property as a read-only property. + 你可以通过提供getter和setter来将继承来的一个只读属性重写为一个读写属性。但是你无法将一个继承来的读写属性重写成一个只读属性。 -N OT E -If you provide a setter as part of a property override, you must also provide a getter for that override. If you don’t want to modify the inherited property’s value within the overriding getter, you can simply pass through the inherited value by returning super.someProperty from the getter, as in the SpeedLimitedCar example below. +``` +NOTE +If you provide a setter as part of a property override, you must also provide a getter for that override. If you don’t want to modify the inherited property’s value within the overriding getter, you can simply pass through the inherited value by returning `super.someProperty` from the getter, as in the `SpeedLimitedCar` example below. +``` + +``` 注意 -如果你在重写时为一个属性提供了setter,那么你必须同时要提供一个getter。如果你不想在重写版本的getter中修改继承来的属性值,你可以直接返回super.someProperty,正如下面SpeedLimitedCar的例子所示。 - -The following example defines a new class called SpeedLimitedCar, which is a subclass of Car. The SpeedLimitedCar class represents a car that has been fitted with a speed-limiting device, which prevents the car from traveling faster than 40mph. You implement this limitation by overriding the inherited speed property: -下面的例子定义了一个新的类SpeedLimitedCar,这个类是Car类的子类。SpeedLimitedCar类表示安装了限速装置的车来防止车的时速超过40英里。你需要通过重写speed属性来实现这个速度限制: -1 class SpeedLimitedCar: Car { -2 override var speed: Double { -3 get { -4 return super.speed -5 } -6 set { -7 super.speed = min(newValue, 40.0) -8 } -9 } -10 } - -Whenever you set the speed property of a SpeedLimitedCar instance, the property’s setter implementation checks the new value and limits it to 40mph. It does this by setting the underlying speed property of its superclass to be the smaller of newValue and 40.0. The smaller of these two values is determined by passing them to the min function, which is a global function provided by the Swift standard library. The min function takes two or more values and returns the smallest one of those values. -当你设置一个SpeedLimitedCar实例的speed属性时,属性的setter方法会检验新设置的值并把它限制在时速40英里以内,这是通过选择新设置的值和40之间最小的值来实现的。这个比较会通过调用min函数实现,它是Swift标准库中的一个方法。min函数接受两个或更多的参数并返回其中最小的一个。 - -If you try to set the speed property of a SpeedLimitedCar instance to more than 40mph, and then print the output of its description method, you see that the speed has been limited: -如果你尝试将SpeedLimitedCar实例中的speed属性设置成时速40英里以上,然后打印description方法的输出,你会看到车速已经被限制了: -1 let limitedCar = SpeedLimitedCar() -2 limitedCar.speed = 60.0 -3 println("SpeedLimitedCar: \(limitedCar.description())") -4 // SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph - -Overriding Property Observers -覆盖属性观察器 -You can use property overriding to add property observers to an inherited property. This enables you to be notified when the value of the inherited property changes, regardless of how that property was originally implemented. For more information on property observers, see Property Observers. -你可以在属性重写时为一个继承来的属性添加属性观察器。当继承来的属性被修改时,你就会被通知到,无论那个属性原来是如何被实现的。关于属性观察器的更多内容,请参考属属性观察器。 - -N OT E -You cannot add property observers to inherited constant stored properties or inherited read-only computed properties. The value of these properties cannot be set, and so it is not appropriate to provide a willSet or didSet implementation as part of an override. +如果你在重写时为一个属性提供了setter,那么你必须同时要提供一个getter。如果你不想在重写版本的getter中修改继承来的属性值,你可以直接返回`super.someProperty`,正如下面`SpeedLimitedCar`的例子所示。 +``` + +The following example defines a new class called `SpeedLimitedCar`, which is a subclass of `Car`. The `SpeedLimitedCar` class represents a car that has been fitted with a speed-limiting device, which prevents the car from traveling faster than 40mph. You implement this limitation by overriding the inherited `speed` property: + +下面的例子定义了一个新的类`SpeedLimitedCar`,这个类是`Car`类的子类。`SpeedLimitedCar`类表示安装了限速装置的车来防止车的时速超过40英里。你需要通过重写`speed`属性来实现这个速度限制: + +``` +class SpeedLimitedCar: Car { + override var speed: Double { + get { + return super.speed + } + set { + super.speed = min(newValue, 40.0) + } + } +} +``` + +Whenever you set the `speed` property of a `SpeedLimitedCar` instance, the property’s setter implementation checks the new value and limits it to 40mph. It does this by setting the underlying `speed` property of its superclass to be the smaller of `newValue` and `40.0`. The smaller of these two values is determined by passing them to the `min` function, which is a global function provided by the Swift standard library. The `min` function takes two or more values and returns the smallest one of those values. + +当你设置一个`SpeedLimitedCar`实例的`speed`属性时,属性的`setter`方法会检验新设置的值并把它限制在时速40英里以内,这是通过选择新设置的值和40之间最小的值来实现的。这个比较会通过调用`min`函数实现,它是Swift标准库中的一个方法。`min`函数接受两个或更多的参数并返回其中最小的一个。 + +If you try to set the `speed` property of a `SpeedLimitedCar` instance to more than 40mph, and then print the output of its `description` method, you see that the speed has been limited: + +如果你尝试将`SpeedLimitedCar`实例中的`speed`属性设置成时速40英里以上,然后打印`description`方法的输出,你会看到车速已经被限制了: + +``` +let limitedCar = SpeedLimitedCar() +limitedCar.speed = 60.0 +println("SpeedLimitedCar: \(limitedCar.description())") +// SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph +``` + +##Overriding Property Observers +##覆盖属性观察器 + +You can use property overriding to add property observers to an inherited property. This enables you to be notified when the value of the inherited property changes, regardless of how that property was originally implemented. For more information on property observers, see [Property Observers](). + +你可以在属性重写时为一个继承来的属性添加属性观察器。当继承来的属性被修改时,你就会被通知到,无论那个属性原来是如何被实现的。关于属性观察器的更多内容,请参考属[属性观察器]()。 + +``` +NOTE +You cannot add property observers to inherited constant stored properties or inherited read-only computed properties. The value of these properties cannot be set, and so it is not appropriate to provide a `willSet` or `didSet` implementation as part of an override. Note also that you cannot provide both an overriding setter and an overriding property observer. If you want to observe changes to a property’s value, and you are already providing a custom setter for that property, you can simply observe any value changes from within the custom setter. +``` + +``` 注意 -你不可以为继承来的常量存储型属性或只读计算型属性添加属性观察器。这些属性的值是不可以被修改的,所以在重写时为它们提供willSet和didSet的实现是不恰当的。 +你不可以为继承来的常量存储型属性或只读计算型属性添加属性观察器。这些属性的值是不可以被修改的,所以在重写时为它们提供`willSet`和`didSet`的实现是不恰当的。 注意你也不能同事提供重写的setter方法和属性观察期。如果你想要观察属性值的变化,并且你已经给那个属性提供了定制的setter方法,在setter方法中你就已经可以观察到任何属性值的变化了。 +``` + +The following example defines a new class called `AutomaticCar`, which is a subclass of `Car`. The `AutomaticCar` class represents a car with an automatic gearbox, which automatically selects an appropriate gear to use based on the current speed. `AutomaticCar` also provides a custom `description` method to print the current gear. + +下面的例子定义了一个新类`AutomaticCar`,它是`Car`类的子类。`AutomaticCar`类表示自动档汽车,它会根据当前的车速选择一个合适的档位。`AutomaticCar`提供了一个定制的`description`方法来输出当前的档位。 + +``` +class AutomaticCar: Car { + var gear = 1 + override var speed: Double { + didSet { + gear = Int(speed / 10.0) + 1 + } + } + override func description() -> String { + return super.description() + " in gear \(gear)" + } +} +``` -The following example defines a new class called AutomaticCar, which is a subclass of Car. The AutomaticCar class represents a car with an automatic gearbox, which automatically selects an appropriate gear to use based on the current speed. AutomaticCar also provides a custom description method to print the current gear. -下面的例子定义了一个新类AutomaticCar,它是Car类的子类。AutomaticCar类表示自动档汽车,它会根据当前的车速选择一个合适的档位。AutomaticCar提供了一个定制的description方法来输出当前的档位。 -1 class AutomaticCar: Car { -2 var gear = 1 -3 override var speed: Double { -4 didSet { -5 gear = Int(speed / 10.0) + 1 -6 } -7 } -8 override func description() -> String { -9 return super.description() + " in gear \(gear)" -10 } -11 } - -Whenever you set the speed property of an AutomaticCar instance, the property’s didSet observer automatically sets the gear property to an appropriate choice of gear for the new speed. Specifically, the property observer chooses a gear which is the new speed value divided by 10, rounded down to the nearest integer, plus 1. A speed of 10.0 produces a gear of 1, and a speed of 35.0 produces a gear of 4: -当你为一个AutomaticCar实例设置speed属性时,属性的didSet观察器会自动设置gear属性到一个合适的档位。具体的计算方法是,属性观察者将新设置的速度值除以10,向下取整之后再加1。例如速度是10的时候档位是1,速度是35.0的时候档位是4。 - -1 let automatic = AutomaticCar() -2 automatic.speed = 35.0 -3 println("AutomaticCar: \(automatic.description())") -4 // AutomaticCar: 4 wheels; up to 5 passengers; traveling at 35.0 mph in gear 4 - -Preventing Overrides -防止重写 -You can prevent a method, property, or subscript from being overridden by marking it as final. Do this by writing the @final attribute before its introducer keyword (such as @final var, @final func, @final class func, and @final subscript). -你可以通过标记一个属性,方法或附属脚本为final来防止它们被重写。具体方法是在声明它们的关键字前加上@final (例如@final var, @final func, @final class func, @final subscript)。 +Whenever you set the `speed` property of an `AutomaticCar` instance, the property’s `didSet` observer automatically sets the `gear` property to an appropriate choice of gear for the new speed. Specifically, the property observer chooses a gear which is the new `speed` value divided by `10`, rounded down to the nearest integer, plus `1`. A speed of `10.0` produces a gear of `1`, and a speed of `35.0` produces a gear of `4`: + +当你为一个`AutomaticCar`实例设置`speed`属性时,属性的`didSet`观察器会自动设置`gear`属性到一个合适的档位。具体的计算方法是,属性观察者将新设置的速度值除以`10`,向下取整之后再加`1`。例如速度是`10`的时候档位是`1`,速度是`35.0`的时候档位是`4`。 + +``` +let automatic = AutomaticCar() +automatic.speed = 35.0 +println("AutomaticCar: \(automatic.description())") +// AutomaticCar: 4 wheels; up to 5 passengers; traveling at 35.0 mph in gear 4 +``` + +##Preventing Overrides +##防止重写 +You can prevent a method, property, or subscript from being overridden by marking it as *final*. Do this by writing the `@final` attribute before its introducer keyword (such as `@final var`, `@final func`, `@final class func`, and `@final subscript`). +你可以通过标记一个属性,方法或附属脚本为*final*来防止它们被重写。具体方法是在声明它们的关键字前加上`@final` (例如`@final var`, `@final func`, `@final class func`及`@final subscript`)。 Any attempts to override a final method, property, or subscript in a subclass are reported as a compile-time error. Methods, properties or subscripts that you add to a class in an extension can also be marked as final within the extension’s definition. + 如果被标记为final的方法,属性或附属脚本在子类中被尝试重写,在编译时便会报错。在扩展时被添加到类中的方法,属性或附属脚本也可以在扩展的定义中标记为final。 -You can mark an entire class as final by writing the @final attribute before the class keyword in its class definition (@final class). Any attempts to subclass a final class will be reported as a compile-time error. -你也可以通过在关键字class前添加@final属性(@final class)来把整个类标记为final。如此以来这个类就不可以被继承,否则在编译时会报错。 + +You can mark an entire class as final by writing the `@final` attribute before the `class` keyword in its class definition (`@final class`). Any attempts to subclass a final class will be reported as a compile-time error. + +你也可以通过在关键字class前添加`@final`属性(`@final class`)来把整个类标记为final。如此以来这个类就不可以被继承,否则在编译时会报错。 From 723d40f08b8f86a76bb9a1ae1b158dcacbed451e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Sun, 15 Jun 2014 17:29:35 +0800 Subject: [PATCH 057/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index e93bfda..127060e 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -107,26 +107,25 @@ A constant or variable of a certain class type may actually refer to an instance Because downcasting can fail, the type cast operator comes in two different forms. The optional form, as?, returns an optional value of the type you are trying to downcast to. The forced form, as, attempts the downcast and force-unwraps the result as a single compound action. ## 向下转型 +有时候,一些实例的类型是它父类的类型,这个时候你就需要使用`as`操作符进行向下转型。 -某一类类型的常量或变量可能实际上是指在幕后一个子类的实例。在那里你认为是这样的话,你可以尝试向下转换与类型转换运算符(如)的子类型。 - -因为向下转换可能会失败,类型转换运算符有两种不同的形式。可选的形式,?,返回你试图向下转换到该类型的可选值。强制的形式,如,试图丧气和强制解开的结果作为一个单一的复合动作。 +因为向下转型可能会失败,类型转换操作符带有两种不同形式。可选形式( optional form)` as? `返回一个你试图下转成的类型的可选值(optional value)。强制形式 `as` 把试图向下转型和强制解包(force-unwraps)结果作为一个混合动作。 Use the optional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast. Use the forced form of the type cast operator (as) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type. -使用类型转换运算符的可选形式(as?)时,你是不知道,如果向下转换会成功。这种形式的运算符将始终返回一个可选值,该值将为零,如果向下转换是不可能的。这使您可以检查是否有成功的垂头丧气。 +当你不确定向下转型能否成功时,使用`as?`,当转化失败时,他会返回`nil `,这样你就能判断是否转换成功。 -使用类型转换运算符的强制形式(如)只有当你确定低垂将始终成功。如果您尝试向下转换到一个不正确的类类型这种形式的操作会触发一个运行时错误。 +当你对类型确定的对象进行向下转型时,使用`as`,当转化失败时,他会抛出一个错误。 The example below iterates over each MediaItem in library, and prints an appropriate description for each item. To do this, it needs to access each item as a true Movie or Song, and not just as a MediaItem. This is necessary in order for it to be able to access the director or artist property of a Movie or Song for use in the description. In this example, each item in the array might be a Movie, or it might be a Song. You don’t know in advance which actual class to use for each item, and so it is appropriate to use the optional form of the type cast operator (as?) to check the downcast each time through the loop: -下面遍历每个MediaItem库,并打印每个项目的适当描述的例子。要做到这一点,它需要访问每个项目作为一个真正的电影或歌曲,而不是仅仅作为一个MediaItem。这是必要的,以便它能够访问一个电影或歌曲的导演或艺人属性在描述中使用。 +下面的例子,迭代了`library`里的每一个` MediaItem` ,并打印出适当的描述。要这样做,`item`需要真正作为`Movie` 或 `Song`的类型来使用。不仅仅是作为 `MediaItem`。为了能够使用`Movie` 或 `Song`的 `director` 或 `artist`属性,这是必要的。 -在这个例子中,数组中的每个项目可能是电影,也可能是一首乐曲。你不事先知道哪一个实际的类使用的每个项目,所以它是适合使用类型转换运算符的可选形式(如?)通过每次循环检查垂头丧气: +在这个示例中,数组中的每一个`item`可能是 `Movie` 或 `Song`。 事前你不知道每个`item`的真实类型,所以这里使用可选形式的类型转换 (`as?`)去检查循环里的每次下转。 for item in library { if let movie = item as? Movie { @@ -143,7 +142,7 @@ In this example, each item in the array might be a Movie, or it might be a Song. // Song: 'Never Gonna Give You Up', by Rick Astley The example starts by trying to downcast the current item as a Movie. Because item is a MediaItem instance, it’s possible that it might be a Movie; equally, it’s also possible that it might a Song, or even just a base MediaItem. Because of this uncertainty, the as? form of the type cast operator returns an optional value when attempting to downcast to a subclass type. The result of item as Movie is of type Movie?, or “optional Movie”. -这个例子开始试图通过向下转换当前项目作为电影。因为项目是一个MediaItem例如,它是可能的,它可能是一个电影;同样,它也有可能是它可能的乐曲,甚至只是一个基础MediaItem。由于这种不确定性,将作为?试图向下转换到子类类型时,类型转换运算符的形式返回一个可选值。项目作为电影的结果是类型的电影?,或“可选的电影”。 +示例首先试图将 `item` 下转为 `Movie`。因为 `item` 是一个 `MediaItem` 类型的实例,它可能是一个`Movie`;同样,它可能是一个 `Song`,或者仅仅是基类 `MediaItem`。因为不确定,`as?`形式试图下转时返还一个可选值。 `item as Movie` 的返回值是`Movie?`类型或 “optional Movie”。 Downcasting to Movie fails when applied to the two Song instances in the library array. To cope with this, the example above uses optional binding to check whether the optional Movie actually contains a value (that is, to find out whether the downcast succeeded.) This optional binding is written “if let movie = item as? Movie”, which can be read as: From a620dc53789b4cf40e606a94a070c800d878dfa6 Mon Sep 17 00:00:00 2001 From: Henry Ge Date: Sun, 15 Jun 2014 17:30:54 +0800 Subject: [PATCH 058/261] =?UTF-8?q?=E7=BB=A7=E6=89=BF=E5=B7=B2=E5=AE=8C?= =?UTF-8?q?=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 946f88b..b915b34 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ The Swift Programming Language 中文化项目 * 属性 [认领 by 周源] * 方法 [认领 by 米尔] * 下标 [已完成 by 递归] - * 继承 [认领 by 晗光] + * 继承 [已完成 by 晗光] * 构造过程 [认领 by 刘康] * 析构过程 [认领 by 许诺] * 自动引用计数 [认领 by 韩国兴/MK] From f5016bf5a228d6251c50cfbd147c5dbc0aa5cec2 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Sun, 15 Jun 2014 19:36:03 +0800 Subject: [PATCH 059/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 148 ++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index e69de29..f0aa6ff 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -0,0 +1,148 @@ +# 声明 +A declaration introduces a new name or construct into your program. For example, you use declarations to introduce functions and methods, variables and constants, and to define new, named enumeration, structure, class, and protocol types. You can also use a declaration to extend the the behavior of an existing named type and to import symbols into your program that are declared elsewhere. + +声明将新的名字或者结构引入到程序中。例如,使用声明可以引入函数、方法、变量和常量;可以定义新的,命名的枚举类型,接口,类和原型类型。也可以使用声明来扩展已存在命名类型的行为,在程序中引入在其它地方声明的符号。 + +In Swift, most declarations are also definitions in the sense that they are implemented or initialized at the same time they are declared. That said, because protocols don’t implement their members, most protocol members are declarations only. For convenience and because the distinction isn’t that important in Swift, the term declaration covers both declarations and definitions. + +在Swift中,大多数声明在某种意义上也是定义,可以在声明的同时实现和初始化他们。。也就是说,因为协议不会实现他们的成员,大多数协议成员仅仅是声明。为了方便,因为这个不同在Swift里不是那么重要,因此这个术语declaration同时包含了声明和定义。 + +>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 + +## 模块范围 + +The module scope defines the code that’s visible to other code in Swift source files that are part of the same module. The top-level code in a Swift source file consists of zero or more statements, declarations, and expressions. Variables, constants, and other named declarations that are declared at the top-level of a source file are visible to code in every source file that is part of the same module。 + +>GRAMMAR OF A TOP-LEVEL DECLARATION + +>top-level-declaration → statements­opt + +Code Blocks + +代码块 + +A code block is used by a variety of declarations and control structures to group statements together. It has the following form: + +大量不同的声明和控制结构通过代码块来把语句分组。有如下的形式: + + { + `statements` + } + +The statements inside a code block include declarations, expressions, and other kinds of statements and are executed in order of their appearance in source code. + +在代码块里的语句包括声明,表达式,和其它类型的语句,按照在源代码里出现的顺序只习惯。 + +>GRAMMAR OF A CODE BLOCK +>code-block → {­statements­opt­} + +##Import Declaration + +## Import 声明 + +An import declaration lets you access symbols that are declared outside the current file. The basic form imports the entire module; it consists of the import keyword followed by a module name: + + +import声明可以让你访问到当前文件之外的符号。基本的形式是引入整个模块。由import关键字后面跟着一个模块名。 + + + import module + +Providing more detail limits which symbols are imported—you can specify a specific submodule or a specific declaration within a module or submodule. When this detailed form is used, only the imported symbol (and not the module that declares it) is made available in the current scope. + +如果提供更多的细节,你还可以明确限制引入一个具体的子模块或者子模块里的一个具体的声明。如果采用这种形式的声明,只有被引入的符号(而不是声明它的模块)可以在当前范围里访问到。 + + 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 + +##Constant Declaration + +##常量声明 + +A constant declaration introduces a constant named value into your program. Constant declarations are declared using the keyword let and have the following form: + +常量声明会在你的程序里引入一个不变的命名值。常量声明使用关键字let,采用如下的形式: + + let constant name: type = expression + +A constant declaration defines an immutable binding between the constant name and the value of the initializer expression; after the value of a constant is set, it cannot be changed. That said, if a constant is initialized with a class object, the object itself can change, but the binding between the constant name and the object it refers to can’t. + +常量声明在常量名和初始化表达式的值之间定义了一个不可变的绑定;在值被设置之后,它就不能改变了。也就是说,如果常量用一个class对象实例化,对象本身可以改变,但是在常量名和对象之间的绑定时不会改变的。 + +When a constant is declared at global scope, it must be initialized with a value. When a constant declaration occurs in the context of a class or structure declaration, it is considered a constant property. Constant declarations are not computed properties and therefore do not have getters or setters. + +如果一个常量在全局范围里声明,它就必须有一个初始值。当一个常量在类或者结构声明中声明的,它会被认为是一个常量属性。常量声明不是i可计算的属性,因此没有getters和setters方法。 + +If the constant name of a constant declaration is a tuple pattern, the name of each item in the tuple is bound to the corresponding value in the initializer expression. + +如果一个常量的声明的名字是一个元组模式,在元组中的没一项在初始化表达式里都会绑定到响应的值。 + + let (firstNumber, secondNumber) = (10, 42) + +In this example, firstNumber is a named constant for the value 10, and secondNumber is a named constant for the value 42. Both constants can now be used independently: + +在这个例子,firstNumer是一个命令常量,值是10.secondNumber是一个命令的常量,值是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." + +The type annotation (: type) is optional in a constant declaration when the type of the constant name can be inferred, as described in Type Inference. + +在常量声明中,如果常量名的类型可以被推断出来,type是可选的,正如在Type Inference里描述的。 + +To declare a static constant property, mark the declaration with the static keyword. Static properties are discussed in Type Properties. + +为了声明一个静态的常量属性,使用static关键字 来标记声明。静态属性在TypeProerties里讨论。 + +For more information about constants and for guidance about when to use them, see Constants and Variables and Stored Properties +想获得更多关于常量的信息或者想在使用中获得帮助,请查看常量和变量和存储属性(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 From f4a7e308da9a5af49af7b5fbf242759511bf8916 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Sun, 15 Jun 2014 20:02:31 +0800 Subject: [PATCH 060/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 185 ++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index f0aa6ff..07b0266 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -146,3 +146,188 @@ For more information about constants and for guidance about when to use them, se >pattern-initializer-list → pattern-initializer­ | pattern-initializer­ , pattern-initializer-list­ >pattern-initializer → pattern ­initializer ­opt­ >initializer → =­expression + + +##Variable Declaration + +##变量声明 + +A variable declaration introduces a variable named value into your program and is declared using the keyword var. + +变量声明会引入一个可变的命令值到你的程序中,使用关键字var进行声明。 + +Variable declarations have several forms that declare different kinds of named, mutable values, including stored and computed variables and properties, stored variable and property observers, and static variable properties. The appropriate form to use depends on the scope at which the variable is declared and the kind of variable you intend to declare. + +变量声明有好几种不同的形式来声明命令的,可变的值,包括可存储的可计算的变量和属性,可存储的变量和属性观察者。还有静态的变量属性。要使用哪种具体的形式取决于变量声明的范围和你打算声明的变量种类。 + +>注意: +>你也可以在协议声明的上下文声明属性,详情参见类型属性声明。 + +You can override a property in a subclass by prefixing the subclass’s property declaration with the override keyword, as described in Overriding. + +你可以在子类中重写一个属性通过在子类中的属性声明的前面使用override。 + + +##Stored Variables and Stored Variable Properties + +##存储型变量和存储型变量属性 + +The following form declares a stored variable or stored variable property: + +下面的形式声明了一可存储的变量或可存储的变量属性 + + var variable name: type = expression + +You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class or structure declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, it is referred to as a stored variable. When it is declared in the context of a class or structure declaration, it is referred to as a stored variable property. + +你可以在全局范围、函数的局部范围或者类或结构声明的环境里定义变量声明。如果这种形式的变量声明在全局或者函数局部范围里声明,它指的就是可存储的变量。如果是在类或者结构声明的环境里声明的,它就是指的可存储变量属性。 + +The initializer expression can’t be present in a protocol declaration, but in all other contexts, the initializer expression is optional. That said, if no initializer expression is present, the variable declaration must include an explicit type annotation (: type). + +初始化表达式不能在协议声明里出现,但是可以出现在其它所有的环境里。初始化表达式是可选的。也就是说,如果没有初始化表达式存在,变量声明必须包括一个现实的类型表示。 + +As with constant declarations, if the variable name is a tuple pattern, the name of each item in the tuple is bound to the corresponding value in the initializer expression. + +和常量声明一样,如果变量名字是一个元组模式,元组中每一项的名字都会被绑定到初始化表达式的对应的值里 + + +As their names suggest, the value of a stored variable or a stored variable property is stored in memory. + +顾名思义,存储变量的或者存储属性的值是存储在内存中的。 + +##Computed Variables and Computed Properties + +##计算型变量和计算型属性 + +The following form declares a computed variable or computed property: + +下面的形式声明了一个可计算的变量或者可计算的属性 + + var variable name: type { + get { + statements + } + set(setter name) { + statements + } + } +You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class, structure, enumeration, or extension declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, it is referred to as a computed variable. When it is declared in the context of a class, structure, or extension declaration, it is referred to as a computed property. + +可以在全局范围,局部范围,或者类、结构、枚举或者可扩展的声明。如果这类型是的变量声明在全局或者函数的局部返回声明,指的是可计算的变量。如果它在一个雷,结构或者扩展声明里,它就是指的可计算的属性。 + + +The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly, as described in Read-Only Computed Properties. But if you provide a setter clause, you must also provide a getter clause. + +getter用于读取值,setter用于写入值。setter语句是可选的,仅仅getter方法是需要的,你可以把两者都忽略,只是简单的返回请求的值,正如在Read-Only Comuted Properties.但是如果你提供一个setter y语句,你不想页提供一个getter语句。 + +The setter name and enclosing parentheses is optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is newValue, as described in Shorthand Setter Declaration. + +setter名字和封闭的大括号是可选的。如果你i供一个setter名字。如果你提供一个setter名字,它会被作为setter的参数的名称。如果你不提供setter名称,setter缺省的参数名是newvalue,正如在Shorthand Setter Declaration. + +Unlike stored named values and stored variable properties, the value of a computed named value or a computed property is not stored in memory. + +不像存储的名字值和存储的变量属性,可计算名字的值或者计算属性的值不会存储到内存中。 + +For more information and to see examples of computed properties, see Computed Properties. + +获得更多信息,查看如何使用属性监视器的例子,请查看属性监视器(prpperty observers)一节。 + +##Stored Variable Observers and Property Observers + +##存储型变量监视器和属性监视器 + +You can also declare a stored variable or property with willSet and didSet observers. A stored variable or property declared with observers has the following form: + +你也可以声明一个存储变量或者属性使用willset和didset 观察者。一个存储变量或者声明的属性有以下的形式: + +var variable name: type = expression { +willSet(setter name) { + statements +} +didSet(setter name { + statements +} +} +You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class or structure declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, the observers are referred to as stored variable observers. When it is declared in the context of a class or structure declaration, the observers are referred to as property observers. + +你可以i在全局范围,函数的局部返回,或者类,结构环境里声明这种形式的变量。当这类型是的变量声明在全局范围或者函数的局部范围里声明的时候,观察者会被作为可存储的变量观察者。当在类或者结构声明中声明的时候,观察者会被作为属性的观察者。 + +You can add property observers to any stored property. You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass, as described in Overriding Property Observers. + +可以为任何存储属性增加观察器。你可以可以为继承的属性增加属性观察器(无论是存储的或是计算的)通过使用子类覆盖,就像Overriding PropertyOververs里描述的一样。 + +The initializer expression is optional in the context of a class or structure declaration, but required elsewhere. The type annotation is required in all variable declarations that include observers, regardless of the context in which they are declared. + +在类或者结构声明里,初始化表达式是可选的。但是在其他所有地方时必须的。类型保险在所有变量声明里是必须的,包括观测器,无论他们声明的环境。 + +The willSet and didSet observers provide a way to observe (and to respond appropriately) when the value of a variable or property is being set. The observers are not called when the variable or property is first initialized. Instead, they are called only when the value is set outside of an initialization context. + +willset 和 didset 观察器提供了方式来观察好合适的响应在一个变量或者属性的值被设置的时候。观察器仅仅在初始化环境的外边可以被调用。 + +A willSet observer is called just before the value of the variable or property is set. The new value is passed to the willSet observer as a constant, and therefore it can’t be changed in the implementation of the willSet clause. The didSet observer is called immediately after the new value is set. In contrast to the willSet observer, the old value of the variable or property is passed to the didSet observer in case you still need access to it. That said, if you assign a value to a variable or property within its own didSet observer clause, that new value that you assign will replace the one that was just set and passed to the willSet observer. + +willset观察器只是在变量或是属性被设置的时候被调用。新值会被作为常量传递给willset语句。didSet观察期在新值被设置的时候被调用。与willset相比,变量或属性的旧值。 + +The setter name and enclosing parentheses in the willSet and didSet clauses are optional. If you provide setter names, they are used as the parameter names to the willSet and didSet observers. If you do not provide setter names, the default parameter name to the willSet observer is newValue and the default parameter name to the didSet observer is oldValue. + +在willset和didset语句里 setter名字和括号是可选的。如果你提供你不提供setter名字,willset 缺省的参数名是newValue好缺省的参数名是oldValue. + +The didSet clause is optional when you provide a willSet clause. Likewise, the willSet clause is optional when you provide a didSet clause. + +如果你提供一个willset语句,didset语句是可选的。同样的,如果你提供一个didset 语句,willset语句是可选的 + +For more information and to see an example of how to use property observers, see Property Observers. + +获得更多信息,查看如何使用属性监视器的例子,请查看属性监视器(prpperty observers)一节。 + +##Class and Static Variable Properties + +##类和静态变量属性 + +To declare a class computed property, mark the declaration with the class keyword. To declare a static variable property, mark the declaration with the static keyword. Class and static properties are discussed in 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-bloc + + + + From 70df64f4bd765a33b4eb8c16461560130a2ad4b5 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Sun, 15 Jun 2014 21:27:59 +0800 Subject: [PATCH 061/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 1100 +++++++++++++++++++++++++++++++ 1 file changed, 1100 insertions(+) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 07b0266..f029b4a 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -329,5 +329,1105 @@ To declare a class computed property, mark the declaration with the class keywor >didSet-clause → attributes ­opt ­didSet ­setter-name ­opt­ code-bloc +##Type Alias Declaration +##类型的别名声明 +A type alias declaration introduces a named alias of an existing type into your program. Type alias declarations begin with the keyword typealias and have the following form: + +类型alias声明引入了一个存在类型的名字到你的程序当中。类型alias声明以关键字typelias开头,使用一下的形式: + + typealias name = existing type + +After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. The existing type can be a named type or a compound type. Type aliases do not create new types; they simply allow a name to refer to an existing type. + +在一个类型alias声明后,声明的名字可以使用在你的程序的的任何地方使用了。存在的类型可能是一个命令类型或是计算类型。类型 alias不能创造新类型,他们只是简单的把名字指向一个存在的类型。 + +See also Protocol Associated Type Declaration. + +也可以参看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 + +##Function Declaration + +##函数声明 + +A :newTerm`function declaration` introduces a function or method into your program. A function declared in the context of class, structure, enumeration, or protocol is referred to as a method. Function declarations are declared using the keyword func and have the following form: + +一个新术语”函数声明“引入了一个函数或者方法到程序中。在类,结构,枚举或者协议韩经理声明的函数会被挡住函数。番薯声明使用关键字func声明,采用以下的形式。 + + func function name(parameters) -> return type { + statements + } +If the function has a return type of Void, the return type can be omitted as follows: + +如果函数有void的返回类型,返回类型可像下面这样忽略: + +func function name(parameters) { + statements +} +The type of each parameter must be included—it can’t be inferred. By default, the parameters to a function are constants. Write var in front of a parameter’s name to make it a variable, scoping any changes made to the variable just to the function body, or write inout to make those changes also apply to the argument that was passed in the caller’s scope. For a discussion of in-out parameters, see In-Out Parameters. + +每个参数的类型必须包含-不能通过推断。默认情况下,函数的参数是常量。在参数名的前面写一个var会让他成为一个变量,对变量的做的任何变化只会在函数体力有效,或者写入input使这些改变也会应用唉调用者范围的参数。 + +Functions can return multiple values using a tuple type as the return type of the function. + +函数可以使用元组类型作为函数的返回类型来返回多个值 + +A function definition can appear inside another function declaration. This kind of function is known as a nested function. For a discussion of nested functions, see Nested Functions. + +函数定义可以出现在另一个函数声明之内。这种函数叫做嵌入函数。对于嵌入函数的讨论,请参见Nested Function。 + +Parameter Names + +Function parameters are a comma separated list where each parameter has one of several forms. The order of arguments in a function call must match the order of parameters in the function’s declaration. The simplest entry in a parameter list has the following form: + +函数参数是一个逗号分隔的列表,每个参数可以有好几种形式。函数调用的时候参数的顺序必须匹配函数声明的参数顺序。在参数列表里最简单的输入形式: + + + * parameter name: parameter type + + + +For function parameters, the parameter name is used within the function body, but is not used when calling the function. For method parameters, the parameter name is used as within the function body, and is also used as a label for the argument when calling the method. The name of a method’s first parameter is used only within the function body, like the parameter of a function. For example: + +对于函数参数,参数名字在函数体内部使用,但是在调用函数的时候不会使用。对于方法参数,参数名可以在函数体使用,也在调用方法时可以作为参数的标签使用。函数的一个参数名字仅仅在函数体力使用,就像函数的参数。例如 + + + * func f(x: Int, y: String) -> String { + * return y + String(x) + * } + * f(7, "hello") // x and y have no name + * class C { + * func f(x: Int, y: String) -> String { + * return y + String(x) + * } + * } + * let c = C() + * c.f(7, y: "hello") // x has no name, y has a name + + +You can override the default behavior for how parameter names are used with one of the following forms: + +你可以重写参数名字使用的默认行为,采用如下的形式: + + + * external parameter name local parameter name: parameter type + + * +#parameter name: parameter type + + * _ local parameter name: parameter type + + + +A second name before the local parameter name gives the parameter an external name, which can be different than the local parameter name. The external parameter name must be used when the function is called. The corresponding argument must have the external name in function or method calls. + +本地参数名的在第二个名字给参数了一个外部的名字,这个不同于本地的参数名。外部的参数名必须在函数调用的时候调用。相应的参数必须在函数或者方法调用时有外部名字。 + +A hash symbol (#) before a parameter name indicates that the name should be used as both an external and a local parameter name. It has the same meaning as writing the local parameter name twice. The corresponding argument must have this name in function or method calls. + +参数名前的#显示了名字应该被作为外部和本地参数只哟个。它和写入本地参数名两次有同样的意义。嘴硬的参数在函数或者参数调用时必须有这个名字。 + +An underscore (_) before a local parameter name gives that parameter no name to be used in function calls. The corresponding argument must have no name in function or method calls. + +本次参数名的下划线在函数调用的时候让参数没有使用名字。对应的参在函数或者方法调用的时候不可以有名字。 + +Special Kinds of Parameters + +Parameters can be ignored, take a variable number of values, and provide default values using the following forms: +参数可以忽略,可以是可变数量的值,使用如下的形式提供默认值 + + + * _ : <#parameter type#. + + + * parameter name: parameter type... + + + * parameter name: parameter type = default argument value + + + +A parameter named with an underscore (_) is explicitly ignored an can’t be accessed within the body of the function. +带有下划线的参数会显式的被忽略,在函数体内部不能被访问到。 + +A parameter with a base type name followed immediately by three dots (...) is understood as a variadic parameter. A function can have at most one variadic parameter, which must be its last parameter. A variadic parameter is treated as an array that contains elements of the base type name. For instance, the variadic parameter Int... is treated as Int[]. For an example that uses a variadic parameter, see Variadic Parameters. +带有基本类型后面接着3个点的参数。 +A parameter with an equals sign (=) and an expression after its type is understood to have a default value of the given expression. If the parameter is omitted when calling the function, the default value is used instead. If the parameter is not omitted, it must have its name in the function call. For example, f() and f(x: 7) are both valid calls to a function with a single default parameter named x, but f(7) is invalid because it provides a value without a name. + +带有等号(=)的参数和它类型后面的表达式会被仿作给定表达式的默认类型。如果参数在调用函数的时候被忽略,默认值会被使用。例如,f()和f(x:7)都是有效的调用对于带有单个默认的的参数名x的函数,但是f(7)是有效的,因为它提供了没有名字的值。 + +Special Kinds of MethodsMethods on an enumeration or a structure that modify self must be marked with the mutating keyword at the start of the function declaration. +枚举类型或者结构上的方法,会修改self的必须在函数声明的开始标记为mutating关键字 +Methods that override a superclass method must be marked with the override keyword at the start of the function declaration. It is an error to override a method without the override keyword or to use the overridekeyword on a method that doesn’t override a superclass method. +重写超类方法的方法必须在函数声明的开头override关键词标记。不适用override就重写方法会产生错误或者使用override在没有override超类的方法 + +Methods associated with a type rather than an instance of a type must be marked with the static attribute for enumerations and structures or the class attribute for classes. + +与type相关而不是类型实例相关的方法必须使用使用static属性来标记枚举、结构或者类的class属性 + +Curried Functions and Methods + +Curried functions and methods have the following form: +当前的函数和方法有以下的形式: + + + * func function name(parameters)(parameters) -> return type { + + + * + statements + + * +} + + + func addTwoNumbers(a: Int)(b: Int) -> Int { + return a + b + } + func addTwoNumbers(a: Int) -> (Int -> Int) { + func addTheSecondNumber(b: Int) -> Int { + return a + b + } + return addTheSecondNumber + } + + addTwoNumbers(4)(5) // Returns 9 + +多级柯里化应用如下 + +>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­: + +A function declared this way is understood as a function whose return type is another function. For example, the following two declarations are equivalent: +用这种方式声明的函数会被当做一个函数,这个函数的返回类型是另外一个函数。例如,下面2个声明是一样的: + + +Enumeration Declaration + +An enumeration declaration introduces a named enumeration type into your program. +枚举声明引入一个个名叫枚举的类型到你的程序中。 + + +Enumeration declarations have two basic forms and are declared using the keyword enum. The body of an enumeration declared using either form contains zero or more values—called enumeration cases—and any number of declarations, including computed properties, instance methods, static methods, initializers, type aliases, and even other enumeration, structure, and class declarations. Enumeration declarations can’t contain destructor or protocol declarations. + +枚举声明有2中基本的形式,使用关键字enum声明。一个枚举类型的的主题使用2中形式之一,包含0或者蒙多的值-被称作枚举类型还有任何数量的声明,包括可计算的属性,实例方法,静态方法,初始化,类型aliase,和其它的枚举、结构和类声明。枚举声明不能包含析构或者协议声明。 + +Unlike classes and structures, enumeration types do not have an implicitly provided default initializer; all initializers must be declared explicitly. Initializers can delegate to other initializers in the enumeration, but the initialization process is complete only after an initializer assigns one of the enumeration cases to self. +不像类或者结构,枚举类型没有一个默认的初始化,但是初始化过程仅仅在初始化赋值给枚举类型的一个给self的时候。 + +Like structures but unlike classes, enumerations are value types; instances of an enumeration are copied when assigned to variables or constants, or when passed as arguments to a function call. For information about value types, see Structures and Enumerations Are Value Types. + +类似结构但是不像类,枚举累心是值类型;一个枚举实例在赋值给变量或者常量的时候会被复制,或者在传递参数给函数调用的的时候。 + +You can extend the behavior of an enumeration type with an extension declaration, as discussed inExtension Declaration. + +Enumerations with Cases of Any Type + +The following form declares an enumeration type that contains enumeration cases of any type: +下面的形式声明了一个枚举类型,包含了所有类型的枚举。 + + + * enum enumeration name { + + + * + case enumeration case 1 + + * + case enumeration case 2(associated value types) + + + * +} + + + + +Enumerations declared in this form are sometimes called discriminated unions in other programming languages. +用这种形式声明的枚举在其他语言里有时候被叫做discriminated unions + +In this form, each case block consists of the keyword case followed by one or more enumeration cases, separated by commas. The name of each case must be unique. Each case can also specify that it stores values of a given type. These types are specified in the associated value types tuple, immediately following the name of the case. For more information and to see examples of cases with associated value types, seeAssociated Values. +用这种方式,每个cast块由关键字case组成,case后跟着一个或者多个逗号分隔的枚举情况。每个case的名字必须是唯一的。每个case页能够确定他存储一个给定类型的值。这些类型用关联只类型元组来设置,后面紧梗着case的名字。获取更多信息,看下关联至类型的的例子,请看Assiciated Values +Enumerations with Raw Cases Values + +The following form declares an enumeration type that contains enumeration cases of the same basic type: +下面的形式声明了一种枚举类型,保护同样基本类型的枚举case + + + * enum enumeration name: raw value type { + + + * + case enumeration case 1 = raw value 1 + + * + case enumeration case 2 = raw value 2 + + * +} + + + + +In this form, each case block consists of the keyword case, followed by one or more enumeration cases, separated by commas. Unlike the cases in the first form, each case has an underlying value, called a raw value, of the same basic type. The type of these values is specified in the raw value type and must represent a literal integer, floating-point number, character, or string. +通过这种形式,每种caes块是由关键字case后面跟着一个或者多个由多个逗号分隔的枚举case。不像第一种形式的case,每个case有一个underlying值,叫做原生值。这些值的类型在rsw值的类型设置,必须表示一个字面量整数,浮点数,字符和字符串。 + +Each case must have a unique name and be assigned a unique raw value. If the raw value type is specified as Int and you don’t assign a value to the cases explicitly, they are implicitly assigned the values 0, 1, 2, and so on. Each unassigned case of type Int is implicitly assigned a raw value that is automatically incremented from the raw value of the previous case. + +每个case必须有一个唯一的名字,然后被赋值为一个单独的原生值。如果原生值用Int设置,你不需要要显式的赋值,他们可以默认的赋值1,1,2等等。每个没有赋值的Int类型会被赋值为原生类型,可以自动的从之前的case的原生值增加。 + + + * enum ExampleEnum: Int { + * case A, B, C = 5, D + * } + + +In the above example, the value of ExampleEnum.A is 0 and the value of ExampleEnum.B is 1. And because the value of ExampleEnum.C is explicitly set to 5, the value of ExampleEnum.D is automatically incremented from 5 and is therefore 6. + +在上面的例子中,ExampleEnum。A的值是o.ExampleEnum.B值是1。因为ExampleEnum.C是显式的设置为5,ExampleEnumd.D的值会从5自动的增加,所以是6. + +The raw value of an enumeration case can be accessed by calling its toRaw method, as inExampleEnum.B.toRaw(). You can also use a raw value to find a corresponding case, if there is one, by calling the fromRaw method, which returns an optional case. For more information and to see examples of cases with raw value types, see Raw Values. + +枚举类型的原生值可以通过toRaw方法访问,比如ExampleEnum.B.toRaw()。你也可以使用一个原生值来找到对应的case通过调用fromRaw方法。 +Accessing Enumeration Cases + +To reference the case of an enumeration type, use dot (.) syntax, as in EnumerationType.EnumerationCase. When the enumeration type can be inferred from context, you can omit it (the dot is still required), as described inEnumeration Syntax and Implicit Member Expression. +正如EnumerationType.EnumerationCase,可以使用。来引用一个enumeration类型的case,正如inEnumeration Syntax and Implicit Member Expression.描述的。 +To check the values of enumeration cases, use a switch statement, as shown in Matching Enumeration Values with a Switch Statement. The enumeration type is pattern-matched against the enumeration case patterns in the case blocks of the switch statement, as described in 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­ + +Structure Declaration + +A structure declaration introduces a named structure type into your program. Structure declarations are declared using the keyword struct and have the following form: +一个结构声明引入了一个命名的类型到你的程序。结构声明使用struct声明,采用以下的形式: + + + * struct structure name: adopted protocols { + + + * + declarations + + * +} + + + + +The body of a structure contains zero or more declarations. These declarations can include both stored and computed properties, static properties, instance methods, static methods, initializers, type aliases, and even other structure, class, and enumeration declarations. Structure declarations can’t contain destructor or protocol declarations. For a discussion and several examples of structures that include various kinds of declarations, see Classes and Structures. + +结构体包含0或者更多的声明。这个声明能包括可存储和计算的属性,静态属性,示例方法,静态方法,实例化,type aliases,甚至其他结构,类和枚举声明。结构声明不能包含析构或者协议声明。在Classes and Structures里,包括好几种了类型的声明的桃花好几个结构例子。 + +Structure types can adopt any number of protocols, but can’t inherit from classes, enumerations, or other structures. + +结构类型可以采用任何数量的协议,但是从classes继承,枚举或者其他结构。 + +There are three ways create an instance of a previously declared structure: + +有3种方式创建过去声明过的示例结构的示例。 + + + * +Call one of the initializers declared within the structure, as described in Initializers. +就像Initializers描述的,调用结构里的一个初始器之一。 + + * +If no initializers are declared, call the structure’s memberwise initializer, as described in Memberwise Initializers for Structure Types. +如果没有初始器被声明,就可以调用结构区的成员 + + * +If no initializers are declared, and all properties of the structure declaration were given initial values, call the structure’s default initializer, as described in Default Initializers. +如果没有初始化器被声明,结构所有其他声明的属性就会被给予初始化的值,调用结构的某人初始化器,正如Default Initializers.描述的那样。 + + + +The process of initializing a structure’s declared properties is described in Initialization. + +初始化结构的声明的属性的过程在Initialization里描述的一样。 + +Properties of a structure instance can be accessed using dot (.) syntax, as described in Accessing Properties. + +一个结构实例的属性使用通过。语法来访问。 + +Structures are value types; instances of a structure are copied when assigned to variables or constants, or when passed as arguments to a function call. For information about value types, see Structures and Enumerations Are Value Types. + +结构是值类型;一个结构的实例复制在赋值给变量或者常量或者在传递参数给函数调用的时候。关于值类型的信息,请参看Structures and Enumerations Are Value Types. + +You can extend the behavior of a structure type with an extension declaration, as discussed in Extension Declaration. +你可以用一个扩展声明来扩展一个结构类型的行为,正如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­} + + + +Class Declaration + +A class declaration introduces a named class type into your program. Class declarations are declared using the keyword class and have the following form: + +类型声明映入了一个命令的类型到你的程序中。类声明使用关键字class声明,采用下面的形式: + + + + * class class name: superclass, adopted protocols { + + + * + declarations + + * +} + + + + +The body of a class contains zero or more declarations. These declarations can include both stored and computed properties, instance methods, class methods, initializers, a single destructor method, type aliases, and even other class, structure, and enumeration declarations. Class declarations can’t contain protocol declarations. For a discussion and several examples of classes that include various kinds of declarations, see Classes and Structures. + +一个class的主题会包含0或多个声明。这些声明可以包括可存储的和可计算的属性,实例方法,类方法,初始化器,一个析构函数,type aliases ,和甚至其他的class,结构,枚举声明。类声明不能包括是协议声明。 + +A class type can inherit from only one parent class, its superclass, but can adopt any number of protocols. The superclass appears first in the type-inheritance-clause, followed by any adopted protocols. +一个class类只能从一个父类中继承,但是可以有多个洗衣。超类首先出现在类型继承语句中,后面跟着采用的协议。 + +As discussed in Initializer Declaration, classes can have designated and convenience initializers. When you declare either kind of initializer, you can require any subclass to override it by marking the initializer with therequired attribute. The designated initializer of a class must initialize all of the class’s declared properties and it must do so before calling any of its superclass’s designated initializers. + +正如在初始化声明讨论的一样,类的初始化很特别很便利。当你声明不同种类的初始化器时,你可以使用required属性要求任何子类重写他。这个特定的初始化器必须初始化类的所有声明的属性。在调用任何自雷的特定的初始化器时都必须这么做。 + +A class can override properties, methods, and initializers of its superclass. Overridden methods and properties must be marked with the override keyword. + +类可以重写他的超类的属性,方法和初始化器。重写的方法和属性必须都使用overrid来标记。 + +Although properties and methods declared in the superclass are inherited by the current class, designated initializers declared in the superclass are not. That said, if the current class overrides all of the superclass’s designated initializers, it inherits the superclass’s convenience initializers. Swift classes do not inherit from a universal base class. + +尽管在子类中声明的属性和方法可以被当前的类继承,但是在超类中指定的初始化器却不行。也就是说,如果当前类重写了超类的所有指定的初始化器,它就会继续超类的便利的初始化器。Swift类不会从通用的基类中继承。 + +There are two ways create an instance of a previously declared class: + +有两种方式创建过去声明的类的实例: + + + * +Call one of the initializers declared within the class, as described in Initializers. +在类的内部调用声明的初始化器。 + + * +If no initializers are declared, and all properties of the class declaration were given initial values, call the class’s default initializer, as described in Default Initializers. + +如果没有声明的初始化器,类声明的素有属性会有一个初始化值,是通过调用类的默认的初始化器来完成的。正如Default Initializers描述的。 + + + +Access properties of a class instance with dot (.) syntax, as described in Accessing Properties. + +访问类的属性使用,如Accessing Properties的一样。 + + +Classes are reference types; instances of a class are referred to, rather than copied, when assigned to variables or constants, or when passed as arguments to a function call. For information about reference types, see Structures and Enumerations Are Value Types. + +类是引用类型;在被赋值给变量货常量的时候,类的实例会被引用而不是被赋值,当被作为参数传递给函数调用的时候。更多信息,参考 + Structures and Enumerations Are Value Types.。 + + +You can extend the behavior of a class type with an extension declaration, as discussed in Extension Declaration. + +你可以使用extension声明来扩展类的行为,正如Extension Desclaration. + +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­}­ +Protocol Declaration +A protocol declaration introduces a named protocol type into your program. Protocol declarations are declared using the keyword protocol and have the following form: +一个协议声明引入了一命令协议类型到你的程序中。协议声明可以使用protoco来声明,有如下的形式: + + + * protocol protocol name: inherited protocols { + + + * + protocol member declarations + + * +} + + + +Protocol Method Declaration + +Protocols declare that conforming types must implement a method by including a protocol method declaration in the body of the protocol declaration. Protocol method declarations have the same form as function declarations, with two exceptions: They don’t include a function body, and you can’t provide any default parameter values as part of the function declaration. For examples of conforming types that implement the method requirements of a protocol, see Method Requirements. + +协议表明,conforming类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 + + +To declare a class or static method requirement in a protocol declaration, mark the method declaration with the class keyword. Classes that implement this method also declare the method with the class keyword. Structures that implement it must declare the method with the static keyword instead. If you’re implementing the method in an extension, use the class keyword if you’re extending a class and the static keyword if you’re extending a structure. + +在协议声明里,为了声明一个类或者静态方法要求,使用class关键字来标记方法声明。实现这个方法的类也用class来声明方法。实现它的结构必须用static进行声明。如果你在extension里实现,如果你扩展class使用class,如果是结构使用static +See also Function Declaration. +GRAMMAR OF A PROTOCOL METHOD DECLARATION +protocol-method-declaration → function-head­function-name­generic-parameter-clause­opt­function-signature­ +Protocol Initializer DeclarationProtocols declare that conforming types must implement an initializer by including a protocol initializer declaration in the body of the protocol declaration. Protocol initializer declarations have the same form as initializer declarations, except they don’t include the initializer’s body. +See also Initializer Declaration. +GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION +protocol-initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­ +Protocol Subscript Declaration + +Protocols declare that conforming types must implement a subscript by including a protocol subscript declaration in the body of the protocol declaration. Protocol property declarations have a special form of a subscript declaration: + + + + + * subscript (parameters) -> return type { get set } + + + +Subscript declarations only declare the minimum getter and setter implementation requirements for types that conform to the protocol. If the subscript declaration includes both the get and set keywords, a conforming type must implement both a getter and a setter clause. If the subscript declaration includes only the get keyword, a conforming type must implement at least a getter clause and optionally can implement a setter clause. +See also Subscript Declaration. +GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION +protocol-subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ +Protocol Associated Type Declaration + +Protocols declare associated types using the keyword typealias. An associated type provides an alias for a type that is used as part of a protocol’s declaration. Accosiated types are similiar to type paramters in generic parameter clauses, but they’re associated with Self in the protocol in which they’re declared. In that context, Self refers to the eventual type that conforms to the protocol. For more information and examples, see Associated Types. + +协议用关键字typealias声明关联类型。关联类型为类型提供了一个alias,这个被用作协议声明的一部分。关联类型与在通用参数预计的类型参数相似,但是他们与声明他们的协议中的self相似。在那个环境下,self指的是时间类型。 +See also Type Alias Declaration. +GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION +protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­opt­ +Initializer Declaration + +An initializer declaration introduces an initializer for a class, structure, or enumeration into your program. Initializer declarations are declared using the keyword init and have two basic forms. + +实例化声明引入了类的初始化器到程序里。初始化声明使用关键字init声明,有两种基本形式: + +Structure, enumeration, and class types can have any number of initializers, but the rules and associated behavior for class initializers are different. Unlike structures and enumerations, classes have two kinds of initializers: designated initializers and convenience initializers, as described in Initialization. + +结构,枚举和类类型可以有很多初始器,但是class初始化器的规则和关联行为是不同的。不像结构和枚举类型。类有两种初始化器:制定的和便利的初始化器。 +The following form declares initializers for structures, enumerations, and designated initializers of classes: + + * init(parameters) { + + + * + statements + + * +} + + + +A designated initializer of a class initializes all of the class’s properties directly. It can’t call any other initializers of the same class, and if the class has a superclass, it must call one of the superclass’s designated initializers. If the class inherits any properties from its superclass, one of the superclass’s designated initializers must be called before any of these properties can be set or modified in the current class. +Designated initializers can be declared in the context of a class declaration only and therefore can’t be added to a class using an extension declaration. +Initializers in structures and enumerations can call other declared initializers to delegate part or all of the initialization process. +To declare convenience initializers for a class, prefix the initializer declaration with the context-sensitive keyword convenience. + + * convenience init(parameters) { + + + * + statements + + * +} + + + +Convenience initializers can delegate the initialization process to another convenience initializer or to one of the class’s designated initializers. That said, the initialization processes must end with a call to a designated initializer that ultimately initializes the class’s properties. Convenience initializers can’t call a superclass’s initializers. +You can mark designated and convenience initializers with the required attribute to require that every subclass implement the initializer. Because designated initializers are not inherited by subclasses, they must be implemented directly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or overrides the designated initializers with convenience initializers). Unlike methods, properties, and subscripts, you don’t need to mark overridden initializers with the override keyword. +To see examples of initializers in various type declarations, see Initialization. +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­ +Deinitializer Declaration + +A deinitializer declaration declares a deinitializer for a class type. Deinitializers take no parameters and have the following form: + +析构声明在类中声明了一个析构器。析构器不需要参数,遵循如下的格式: + + + * deinit { + + + * + statements + + * +} + + + + +A deinitializer is called automatically when there are no longer any references to a class object, just before the class object is deallocated. A deinitializer can be declared only in the body of a class declaration—but not in an extension of a class—and each class can have at most one. + +当类中没有对任何其它对象的引用时,在类对象释放之前,析构器会自动的被调用。析构器只能在类的声明体内、声明——但是不能在 类的扩展声明内,每个类最多只能有一个析构器声明。 + +A subclass inherits its superclass’s deinitializer, which is implicitly called just before the subclass object is deallocated. The subclass object is not deallocated until all deinitializers in its inheritance chain have finished executing. + + +Deinitializers are not called directly. + +子类继承了它的超类的析构器,在子类帝乡将要被释放时会被隐式的调用。子类在所有析构器被执行完毕前不会被释放。 +析构器不会被直接调用。 +For an example of how to use a deinitializer in a class declaration, see Deinitialization. +GRAMMAR OF A DEINITIALIZER DECLARATION +deinitializer-declaration → attributes­opt­deinit­code-block­ +Extension Declaration + +An extension declaration allows you to extend the behavior of existing class, structure, and enumeration types. Extension declarations begin with the keyword extension and have the following form: + +扩展声明用于扩展一个已存在的类,结构体,枚举的行为。扩展声明以关键字extension开始,遵循如下的规则: + + + * extension type: adopted protocols { + + + * + declarations + + * +} + + + + +The body of an extension declaration contains zero or more declarations. These declarations can include computed properties, computed static properties, instance methods, static and class methods, initializers, subscript declarations, and even class, structure, and enumeration declarations. Extension declarations can’t contain destructor or protocol declarations, store properties, property observers, or other extension declarations. For a discussion and several examples of extensions that include various kinds of declarations, see Extensions. +一个扩展声明体包括零个或多个声明。这些声明可以包括计算型属性,计算型静态属性,实例方法,静态和类方法,构造器, 附属脚本声明,甚至其他类,结构和枚举声明。扩展声明不能包含析构器,协议声明,存储型属性,属性监测器或其他 的扩展属性。详细讨论和查看包含多种扩展声明的实例,参见扩展一节。 + +Extension declarations can add protocol conformance to an existing class, structure, and enumeration type in the adopted protocols. Extension declarations can’t add class inheritance to an existing class, and therefore the type-inheritance-clause in an extension declaration contains only a list of protocols. + +扩展声明可以向现存的类,结构体,枚举内添加一致的协议。扩展声明不能向一个类中添加继承的类,因此 type-inheritance-clause只包含协议列表。 + + +Properties, methods, and initializers of an existing type can’t be overridden in an extension of that type. +属性,方法,现存类型的构造器不能被它们类型的扩展所重写。 + +Extension declarations can contain initializer declarations. That said, if the type you’re extending is defined in another module, an initializer declaration must delegate to an initializer already defined in that module to ensure members of that type are properly initialized. +扩展声明可以包含构造器声明,这意味着,如果你扩展的类型在其他模块中定义,构造器声明必须委托另一个在 那个模块里声明的构造器来恰当的初始化。 + +GRAMMAR OF AN EXTENSION DECLARATION +extension-declaration → extension­type-identifier­type-inheritance-clause­opt­extension-body­ +extension-body → {­declarations­opt­}­ +Subscript Declaration + +A subscript declaration allows you to add subscripting support for objects of a particular type and are typically used to provide a convenient syntax for accessing the elements in a collection, list, or sequence. Subscript declarations are declared using the keyword subscript and have the following form: +附属脚本用于向特定类型的对象添加附属脚本支持,通常为访问集合,列表和序列的元素时提供便利的语法。附属脚本声明使用关键字subscript,声明形式如下: + + + * subscript (parameters) -> return type { + + + * + get { + + + * + statements + + * + } + + + * + set(setter name) { + + + * + statements + + * + } + + + * +} + + + + +Subscript declarations can appear only in the context of a class, structure, enumeration, extension, or protocol declaration. + + +The parameters specify one or more indexes used to access elements of the corresponding type in a subscript expression (for example, the i in the expression object[i]). Although the indexes used to access the elements can be of any type, each parameter must include a type annotation to specify the type of each index. The return type specifies the type of the element being accessed. + +变量(parameters)指定一个或多个用于在相应类型的附属脚本中访问元素的索引(例如,表达式object[i]中的i)。尽管用于元素访问的索引可以是任意类型的,但是每个变量必须包含一个用于指定每种索引类型的类型标注。返回类型(return type)指定被访问的元素的类型。 + + +As with computed properties, subscript declarations support reading and writing the value of the accessed elements. The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly. That said, if you provide a setter clause, you must also provide a getter clause. +和计算性属性一样,附属脚本声明支持对访问元素的读写操作。getter用于读取值,setter用于写入值。setter子句是可选的,当仅需要一个getter子句时,可以将二者都忽略且直接返回请求的值即可。也就是说,如果使用了setter子句,就必须使用getter子句。 + +The setter name and enclosing parentheses are optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is value. That type of the setter name must be the same as the return type. +setter的名字和封闭的括号是可选的。如果使用了setter名称,它会被当做传给setter的变量的名称。如果不使用setter名称,那么传给setter的变量的名称默认是value。setter名称的类型必须与返回类型(return type)的类型相同。 + +You can overload a subscript declaration in the type in which it is declared, as long as the parameters or thereturn type differ from the one you’re overloading. You can also override a subscript declaration inherited from a superclass. When you do so, you must mark the overridden subscript declaration with the overridekeyword. +可以在附属脚本声明的类型中,可以重载附属脚本,只要变量(parameters)或返回类型(return type)与先前的不同即可。此时,必须使用override关键字声明那个被覆盖的附属脚本。(注:好乱啊!到底是重载还是覆盖?!) + +You can also declare subscripts in the context of a protocol declaration, as described in Protocol Subscript Declaration. +同样可以在协议声明的上下文中声明附属脚本,Protocol Subscript Declaration中有所描述。 +For more information about subscripting and to see examples of subscript declarations, see Subscripts. +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­ +Operator Declaration + +An operator declaration introduces a new infix, prefix, or postfix operator into your program and is declared using the contextual keyword operator. + + +You can declare operators of three different fixities: infix, prefix, and postfix. The fixity of an operator specifies the relative position of an operator to its operands. + + +There are three basic forms of an operator declaration, one for each fixity. The fixity of the operator is specified by including the contextual keyword infix, prefix, or postfix between operator and the name of the operator. In each form, the name of the operator can contain only the operator characters defined inOperators. +运算符声明会向程序中引入中缀、前缀或后缀运算符,它使用上下文关键字operator声明。 可以声明三种不同的缀性:中缀、前缀和后缀。操作符的缀性描述了操作符与它的操作数的相对位置。 运算符声明有三种基本形式,每种缀性各一种。运算符的缀性通过在operator和运算符之间添加上下文关键字infix,prefix或postfix来指定。每种形式中,运算符的名字只能包含Operators中定义的运算符字符。 +The following form declares a new infix operator: + + * operator infix operator name { + + + * + precedence precedence level + + * + associativity associativity + + * +} + + + + +An infix operator is a binary operator that is written between its two operands, such as the familiar addition operator (+) in the expression 1 + 2. +中缀运算符是二元运算符,它可以被置于两个操作数之间,比如表达式1 + 2 中的加法运算符(+)。 + +Infix operators can optionally specify a precedence, associativity, or both. +中缀运算符可以可选地指定优先级,结合性,或两者同时指定。 + +The precedence of an operator specifies how tightly an operator binds to its operands in the absence of grouping parentheses. You specify the precedence of an operator by writing the contextual keywordprecedence followed by the precedence level. The precedence level can be any whole number (decimal integer) from 0 to 255; unlike decimal integer literals, it can’t contain any underscore characters. Although the precedence level is a specific number, it is significant only relative to another operator. That is, when two operators compete with each other for their operands, such as in the expression 2 + 3 * 5, the operator with the higher precedence level binds more tightly to its operands. +运算符的优先级可以指定在没有括号包围的情况下,运算符与它的操作数如何紧密绑定的。可以使用上下文关键字precedence并优先级(precedence level)一起来指定一个运算符的优先级。优先级可以是0到255之间的任何一个数字(十进制整数);与十进制整数字面量不同的是,它不可以包含任何下划线字符。尽管优先级是一个特定的数字,但它仅用作与另一个运算符比较(大小)。也就是说,一个操作数可以同时被两个运算符使用时,例如2 + 3 * 5,优先级更高的运算符将优先与操作数绑定。 + +The associativity of an operator specifies how a sequence of operators with the same precedence level are grouped together in the absence of grouping parentheses. You specify the associativity of an operator by writing the contextual keyword associativity followed by the associativity, which is one of the contextual keywords left, right, or none. Operators that are left-associative group left-to-right. For example, the subtraction operator (-) is left-associative, and therefore the expression 4 - 5 - 6 is grouped as (4 - 5) - 6and evaluates to -7. Operators that are right-associative group right-to-left, and operators that are specified with an associativity of none don’t associate at all. Nonassociative operators of the same precedence level can’t appear adjacent to each to other. For example, 1 < 2 < 3 is not a valid expression. +运算符的结合性可以指定在没有括号包围的情况下,优先级相同的运算符以何种顺序被分组的。可以使用上下文关键字associativity并结合性(associativity)一起来指定一个运算符的结合性,其中结合性可以说是上下文关键字left,right或none中的任何一个。左结合运算符以从左到右的形式分组。例如,减法运算符(-)具有左结合性,因此4 - 5 - 6被以(4 - 5) - 6的形式分组,其结果为-7。 右结合运算符以从右到左的形式分组,对于设置为none的非结合运算符,它们不以任何形式分组。具有相同优先级的非结合运算符,不可以互相邻接。例如,表达式1 < 2 < 3非法的。 + +Infix operators that are declared without specifying a precedence or associativity are initialized with a precedence level of 100 and an associativity of none. +声明时不指定任何优先级或结合性的中缀运算符,它们的优先级会被初始化为100,结合性被初始化为none。 +The following form declares a new prefix operator: + + * operator prefix operator name {} + + + + +A prefix operator is a unary operator that is written immediately before its operand, such as the prefix increment operator (++) is in the expression ++i. +缀运算符的声明中不指定优先级。前缀运算符是非结合的。 +Prefix operators declarations don’t specify a precedence level. Prefix operators are nonassociative. +The following form declares a new postfix operator: + + * operator postfix operator name {} + + + +A postfix operator is a unary operator that is written immediately after its operand, such as the postfix increment operator (++) is in the expression i++. +As with prefix operators, postfix operator declarations don’t specify a precedence level. Postfix operators are nonassociative. +After declaring a new operator, you implement it by declaring a function that has the same name as the operator. To see an example of how to create and implement a new operator, see Custom Operators. +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­ + +The body of a protocol contains zero or more protocol member declarations, which describe the conformance requirements that any type adopting the protocol must fulfill. In particular, a protocol can declare that conforming types must implement certain properties, methods, initializers, and subscripts. Protocols can also declare special kinds of type aliases, called associated types, that can specify relationships among the various declarations of the protocol. The protocol member declarations are discussed in detail below. +协议的主体包含洗衣成员声明,它描述了comformance要求,任何实现它的协议都必须满足的要求。特别是,协议可以声明comformin类型,必须实现某个属性,方法,初始化,和子脚本。协议页能声明特殊种类的type aliase,被称作关联类型,可以设置协议里的不同声明的关系。协议成员声明下面会做详细的讨论。 + +Protocol types can inherit from any number of other protocols. When a protocol type inherits from other protocols, the set of requirements from those other protocols are aggregated, and any type that inherits from the current protocol must conform to all those requirements. For an example of how to use protocol inheritance, see Protocol Inheritance. + +协议类型可以从任何数量的其它协议。当一个协议类型从其它洗衣继承时,从那些协议中的要求会被集合,任何从当前协议继承的类型都必须和那些要求一致。 + + + +NOTE +You can also aggregate the conformance requirements of multiple protocols using protocol composition types, as described in Protocol Composition Type and Protocol Composition. + +You can add protocol conformance to a previously declared type by adopting the protocol in an extension declaration of that type. In the extension, you must implement all of the adopted protocol’s requirements. If the type already implements all of the requirements, you can leave the body of the extension declaration empty. + +你可以增加协议conformance到任何一个过去声明的类型通过在那个类型的extendsion中声明。在这个扩展力,你必须实现所有使用的协议的需求。如果那个类型已经实现了所有的要求,扩展声明的主题可以是空的。 + +By default, types that conform to a protocol must implement all properties, methods, and subscripts declared in the protocol. That said, you can mark these protocol member declarations with the optional attribute to specify that their implementation by a conforming type is optional. The optional attribute can be applied only to protocols that are marked with the objc attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. For more information about how to use the optionalattribute and for guidance about how to access optional protocol members—for example, when you’re not sure whether a conforming type implements them—see Optional Protocol Requirements. + +默认情况下,与协议一致的类型必须实现所有的属性,方法,和声明的subscripts。也就是说,你可以用opaional属性来标记协议成员,表示他们的实现是可选的。option属性仅仅能被应用到用objc标记的属性。结构,仅仅class类型能采纳和玉包含可选的成员变量的协议一致。对于如何访问可选的协议成员-例如,如果你不确定一个confroming类型是否要实现他们-看见 Optional Protocol Requirements. + +To restrict the adoption of a protocol to class types only, mark the entire protocol declaration with theclass_protocol attribute. Any protocol that inherits from a protocol marked with the class_protocol attribute can likewise be adopted only by a class type. + +为了限制协议的的只应用到某个class type,用class_protocol属性标记整个协议声明。任何从标记class_protocol协议继承的协议可以只被class 类型采纳。 + +NOTE +If a protocol is already marked with the objc attribute, the class_protocol attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the class_protocol attribute explicitly. + +Protocols are named types, and thus they can appear in all the same places in your code as other named types, as discussed in Protocols as Types. However, you can’t construct an instance of a protocol, because protocols do not actually provide the implementations for the requirements they specify. + + +You can use protocols to declare which methods a delegate of a class or structure should implement, as described in Delegation. +你可以使用协议来声明类或者结构应该实现那个方法,如Delegation.描述。 + +GRAMMAR OF A PROTOCOL DECLARATION +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 Property Declaration + +Protocols declare that conforming types must implement a property by including a protocol property declaration in the body of the protocol declaration. Protocol property declarations have a special form of a variable declaration: + +协议声明conforming类型必须通过在协议声明体里包括协议属性声明实现属性。协议属性声明有一个特殊形式的变量声明。 + + + * var property name: type { get set } + + + + +As with other protocol member declarations, these property declarations declare only the getter and setter requirements for types that conform to the protocol. As a result, you don’t implement the getter or setter directly in the protocol in which it is declared. +与其他成员声明一样,这些属性声明仅仅声明getter和setter要求。结果,你不需要在声明的协议里直接实现getter或setter +The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can’t be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property. For examples of conforming types that implement the property requirements of a protocol, see Property Requirements. +See also Variable Declaration. +GRAMMAR OF A PROTOCOL PROPERTY DECLARATION +protocol-property-declaration → variable-declaration-head­variable-name­type-annotation­getter-setter-keyword-block­ + +Protocol Method Declaration + +Protocols declare that conforming types must implement a method by including a protocol method declaration in the body of the protocol declaration. Protocol method declarations have the same form as function declarations, with two exceptions: They don’t include a function body, and you can’t provide any default parameter values as part of the function declaration. For examples of conforming types that implement the method requirements of a protocol, see Method Requirements. + +协议表明,conforming类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 + + +To declare a class or static method requirement in a protocol declaration, mark the method declaration with the class keyword. Classes that implement this method also declare the method with the class keyword. Structures that implement it must declare the method with the static keyword instead. If you’re implementing the method in an extension, use the class keyword if you’re extending a class and the static keyword if you’re extending a structure. + +在协议声明里,为了声明一个类或者静态方法要求,使用class关键字来标记方法声明。实现这个方法的类也用class来声明方法。实现它的结构必须用static进行声明。如果你在extension里实现,如果你扩展class使用class,如果是结构使用static +See also Function Declaration. +GRAMMAR OF A PROTOCOL METHOD DECLARATION +protocol-method-declaration → function-head­function-name­generic-parameter-clause­opt­function-signature­ +Protocol Initializer DeclarationProtocols declare that conforming types must implement an initializer by including a protocol initializer declaration in the body of the protocol declaration. Protocol initializer declarations have the same form as initializer declarations, except they don’t include the initializer’s body. +See also Initializer Declaration. +GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION +protocol-initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­ +Protocol Subscript Declaration + +Protocols declare that conforming types must implement a subscript by including a protocol subscript declaration in the body of the protocol declaration. Protocol property declarations have a special form of a subscript declaration: + + + + + * subscript (parameters) -> return type { get set } + + + +Subscript declarations only declare the minimum getter and setter implementation requirements for types that conform to the protocol. If the subscript declaration includes both the get and set keywords, a conforming type must implement both a getter and a setter clause. If the subscript declaration includes only the get keyword, a conforming type must implement at least a getter clause and optionally can implement a setter clause. +See also Subscript Declaration. +GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION +protocol-subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ +Protocol Associated Type Declaration + +Protocols declare associated types using the keyword typealias. An associated type provides an alias for a type that is used as part of a protocol’s declaration. Accosiated types are similiar to type paramters in generic parameter clauses, but they’re associated with Self in the protocol in which they’re declared. In that context, Self refers to the eventual type that conforms to the protocol. For more information and examples, see Associated Types. + +协议用关键字typealias声明关联类型。关联类型为类型提供了一个alias,这个被用作协议声明的一部分。关联类型与在通用参数预计的类型参数相似,但是他们与声明他们的协议中的self相似。在那个环境下,self指的是时间类型。 +See also Type Alias Declaration. +GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION +protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­opt­ +Initializer Declaration + +An initializer declaration introduces an initializer for a class, structure, or enumeration into your program. Initializer declarations are declared using the keyword init and have two basic forms. + +实例化声明引入了类的初始化器到程序里。初始化声明使用关键字init声明,有两种基本形式: + +Structure, enumeration, and class types can have any number of initializers, but the rules and associated behavior for class initializers are different. Unlike structures and enumerations, classes have two kinds of initializers: designated initializers and convenience initializers, as described in Initialization. + +结构,枚举和类类型可以有很多初始器,但是class初始化器的规则和关联行为是不同的。不像结构和枚举类型。类有两种初始化器:制定的和便利的初始化器。 +The following form declares initializers for structures, enumerations, and designated initializers of classes: + + * init(parameters) { + + + * + statements + + * +} + + + +A designated initializer of a class initializes all of the class’s properties directly. It can’t call any other initializers of the same class, and if the class has a superclass, it must call one of the superclass’s designated initializers. If the class inherits any properties from its superclass, one of the superclass’s designated initializers must be called before any of these properties can be set or modified in the current class. +Designated initializers can be declared in the context of a class declaration only and therefore can’t be added to a class using an extension declaration. +Initializers in structures and enumerations can call other declared initializers to delegate part or all of the initialization process. +To declare convenience initializers for a class, prefix the initializer declaration with the context-sensitive keyword convenience. + + * convenience init(parameters) { + + + * + statements + + * +} + + + +Convenience initializers can delegate the initialization process to another convenience initializer or to one of the class’s designated initializers. That said, the initialization processes must end with a call to a designated initializer that ultimately initializes the class’s properties. Convenience initializers can’t call a superclass’s initializers. +You can mark designated and convenience initializers with the required attribute to require that every subclass implement the initializer. Because designated initializers are not inherited by subclasses, they must be implemented directly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or overrides the designated initializers with convenience initializers). Unlike methods, properties, and subscripts, you don’t need to mark overridden initializers with the override keyword. +To see examples of initializers in various type declarations, see Initialization. +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­ +Deinitializer Declaration + +A deinitializer declaration declares a deinitializer for a class type. Deinitializers take no parameters and have the following form: + +析构声明在类中声明了一个析构器。析构器不需要参数,遵循如下的格式: + + + * deinit { + + + * + statements + + * +} + + + + +A deinitializer is called automatically when there are no longer any references to a class object, just before the class object is deallocated. A deinitializer can be declared only in the body of a class declaration—but not in an extension of a class—and each class can have at most one. + +当类中没有对任何其它对象的引用时,在类对象释放之前,析构器会自动的被调用。析构器只能在类的声明体内、声明——但是不能在 类的扩展声明内,每个类最多只能有一个析构器声明。 + +A subclass inherits its superclass’s deinitializer, which is implicitly called just before the subclass object is deallocated. The subclass object is not deallocated until all deinitializers in its inheritance chain have finished executing. + + +Deinitializers are not called directly. + +子类继承了它的超类的析构器,在子类帝乡将要被释放时会被隐式的调用。子类在所有析构器被执行完毕前不会被释放。 +析构器不会被直接调用。 +For an example of how to use a deinitializer in a class declaration, see Deinitialization. +GRAMMAR OF A DEINITIALIZER DECLARATION +deinitializer-declaration → attributes­opt­deinit­code-block­ +Extension Declaration + +An extension declaration allows you to extend the behavior of existing class, structure, and enumeration types. Extension declarations begin with the keyword extension and have the following form: + +扩展声明用于扩展一个已存在的类,结构体,枚举的行为。扩展声明以关键字extension开始,遵循如下的规则: + + + * extension type: adopted protocols { + + + * + declarations + + * +} + + + + +The body of an extension declaration contains zero or more declarations. These declarations can include computed properties, computed static properties, instance methods, static and class methods, initializers, subscript declarations, and even class, structure, and enumeration declarations. Extension declarations can’t contain destructor or protocol declarations, store properties, property observers, or other extension declarations. For a discussion and several examples of extensions that include various kinds of declarations, see Extensions. +一个扩展声明体包括零个或多个声明。这些声明可以包括计算型属性,计算型静态属性,实例方法,静态和类方法,构造器, 附属脚本声明,甚至其他类,结构和枚举声明。扩展声明不能包含析构器,协议声明,存储型属性,属性监测器或其他 的扩展属性。详细讨论和查看包含多种扩展声明的实例,参见扩展一节。 + +Extension declarations can add protocol conformance to an existing class, structure, and enumeration type in the adopted protocols. Extension declarations can’t add class inheritance to an existing class, and therefore the type-inheritance-clause in an extension declaration contains only a list of protocols. + +扩展声明可以向现存的类,结构体,枚举内添加一致的协议。扩展声明不能向一个类中添加继承的类,因此 type-inheritance-clause只包含协议列表。 + + +Properties, methods, and initializers of an existing type can’t be overridden in an extension of that type. +属性,方法,现存类型的构造器不能被它们类型的扩展所重写。 + +Extension declarations can contain initializer declarations. That said, if the type you’re extending is defined in another module, an initializer declaration must delegate to an initializer already defined in that module to ensure members of that type are properly initialized. +扩展声明可以包含构造器声明,这意味着,如果你扩展的类型在其他模块中定义,构造器声明必须委托另一个在 那个模块里声明的构造器来恰当的初始化。 + +GRAMMAR OF AN EXTENSION DECLARATION +extension-declaration → extension­type-identifier­type-inheritance-clause­opt­extension-body­ +extension-body → {­declarations­opt­}­ +Subscript Declaration + +A subscript declaration allows you to add subscripting support for objects of a particular type and are typically used to provide a convenient syntax for accessing the elements in a collection, list, or sequence. Subscript declarations are declared using the keyword subscript and have the following form: +附属脚本用于向特定类型的对象添加附属脚本支持,通常为访问集合,列表和序列的元素时提供便利的语法。附属脚本声明使用关键字subscript,声明形式如下: + + + * subscript (parameters) -> return type { + + + * + get { + + + * + statements + + * + } + + + * + set(setter name) { + + + * + statements + + * + } + + + * +} + + + + +Subscript declarations can appear only in the context of a class, structure, enumeration, extension, or protocol declaration. + + +The parameters specify one or more indexes used to access elements of the corresponding type in a subscript expression (for example, the i in the expression object[i]). Although the indexes used to access the elements can be of any type, each parameter must include a type annotation to specify the type of each index. The return type specifies the type of the element being accessed. + +变量(parameters)指定一个或多个用于在相应类型的附属脚本中访问元素的索引(例如,表达式object[i]中的i)。尽管用于元素访问的索引可以是任意类型的,但是每个变量必须包含一个用于指定每种索引类型的类型标注。返回类型(return type)指定被访问的元素的类型。 + + +As with computed properties, subscript declarations support reading and writing the value of the accessed elements. The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly. That said, if you provide a setter clause, you must also provide a getter clause. +和计算性属性一样,附属脚本声明支持对访问元素的读写操作。getter用于读取值,setter用于写入值。setter子句是可选的,当仅需要一个getter子句时,可以将二者都忽略且直接返回请求的值即可。也就是说,如果使用了setter子句,就必须使用getter子句。 + +The setter name and enclosing parentheses are optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is value. That type of the setter name must be the same as the return type. +setter的名字和封闭的括号是可选的。如果使用了setter名称,它会被当做传给setter的变量的名称。如果不使用setter名称,那么传给setter的变量的名称默认是value。setter名称的类型必须与返回类型(return type)的类型相同。 + +You can overload a subscript declaration in the type in which it is declared, as long as the parameters or thereturn type differ from the one you’re overloading. You can also override a subscript declaration inherited from a superclass. When you do so, you must mark the overridden subscript declaration with the overridekeyword. +可以在附属脚本声明的类型中,可以重载附属脚本,只要变量(parameters)或返回类型(return type)与先前的不同即可。此时,必须使用override关键字声明那个被覆盖的附属脚本。(注:好乱啊!到底是重载还是覆盖?!) + +You can also declare subscripts in the context of a protocol declaration, as described in Protocol Subscript Declaration. +同样可以在协议声明的上下文中声明附属脚本,Protocol Subscript Declaration中有所描述。 +For more information about subscripting and to see examples of subscript declarations, see Subscripts. +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­ +Operator Declaration + +An operator declaration introduces a new infix, prefix, or postfix operator into your program and is declared using the contextual keyword operator. + + +You can declare operators of three different fixities: infix, prefix, and postfix. The fixity of an operator specifies the relative position of an operator to its operands. + + +There are three basic forms of an operator declaration, one for each fixity. The fixity of the operator is specified by including the contextual keyword infix, prefix, or postfix between operator and the name of the operator. In each form, the name of the operator can contain only the operator characters defined inOperators. +运算符声明会向程序中引入中缀、前缀或后缀运算符,它使用上下文关键字operator声明。 可以声明三种不同的缀性:中缀、前缀和后缀。操作符的缀性描述了操作符与它的操作数的相对位置。 运算符声明有三种基本形式,每种缀性各一种。运算符的缀性通过在operator和运算符之间添加上下文关键字infix,prefix或postfix来指定。每种形式中,运算符的名字只能包含Operators中定义的运算符字符。 +The following form declares a new infix operator: + + * operator infix operator name { + + + * + precedence precedence level + + * + associativity associativity + + * +} + + + + +An infix operator is a binary operator that is written between its two operands, such as the familiar addition operator (+) in the expression 1 + 2. +中缀运算符是二元运算符,它可以被置于两个操作数之间,比如表达式1 + 2 中的加法运算符(+)。 + +Infix operators can optionally specify a precedence, associativity, or both. +中缀运算符可以可选地指定优先级,结合性,或两者同时指定。 + +The precedence of an operator specifies how tightly an operator binds to its operands in the absence of grouping parentheses. You specify the precedence of an operator by writing the contextual keywordprecedence followed by the precedence level. The precedence level can be any whole number (decimal integer) from 0 to 255; unlike decimal integer literals, it can’t contain any underscore characters. Although the precedence level is a specific number, it is significant only relative to another operator. That is, when two operators compete with each other for their operands, such as in the expression 2 + 3 * 5, the operator with the higher precedence level binds more tightly to its operands. +运算符的优先级可以指定在没有括号包围的情况下,运算符与它的操作数如何紧密绑定的。可以使用上下文关键字precedence并优先级(precedence level)一起来指定一个运算符的优先级。优先级可以是0到255之间的任何一个数字(十进制整数);与十进制整数字面量不同的是,它不可以包含任何下划线字符。尽管优先级是一个特定的数字,但它仅用作与另一个运算符比较(大小)。也就是说,一个操作数可以同时被两个运算符使用时,例如2 + 3 * 5,优先级更高的运算符将优先与操作数绑定。 + +The associativity of an operator specifies how a sequence of operators with the same precedence level are grouped together in the absence of grouping parentheses. You specify the associativity of an operator by writing the contextual keyword associativity followed by the associativity, which is one of the contextual keywords left, right, or none. Operators that are left-associative group left-to-right. For example, the subtraction operator (-) is left-associative, and therefore the expression 4 - 5 - 6 is grouped as (4 - 5) - 6and evaluates to -7. Operators that are right-associative group right-to-left, and operators that are specified with an associativity of none don’t associate at all. Nonassociative operators of the same precedence level can’t appear adjacent to each to other. For example, 1 < 2 < 3 is not a valid expression. +运算符的结合性可以指定在没有括号包围的情况下,优先级相同的运算符以何种顺序被分组的。可以使用上下文关键字associativity并结合性(associativity)一起来指定一个运算符的结合性,其中结合性可以说是上下文关键字left,right或none中的任何一个。左结合运算符以从左到右的形式分组。例如,减法运算符(-)具有左结合性,因此4 - 5 - 6被以(4 - 5) - 6的形式分组,其结果为-7。 右结合运算符以从右到左的形式分组,对于设置为none的非结合运算符,它们不以任何形式分组。具有相同优先级的非结合运算符,不可以互相邻接。例如,表达式1 < 2 < 3非法的。 + +Infix operators that are declared without specifying a precedence or associativity are initialized with a precedence level of 100 and an associativity of none. +声明时不指定任何优先级或结合性的中缀运算符,它们的优先级会被初始化为100,结合性被初始化为none。 +The following form declares a new prefix operator: + + * operator prefix operator name {} + + + + +A prefix operator is a unary operator that is written immediately before its operand, such as the prefix increment operator (++) is in the expression ++i. +缀运算符的声明中不指定优先级。前缀运算符是非结合的。 +Prefix operators declarations don’t specify a precedence level. Prefix operators are nonassociative. +The following form declares a new postfix operator: + + * operator postfix operator name {} + + + +A postfix operator is a unary operator that is written immediately after its operand, such as the postfix increment operator (++) is in the expression i++. +As with prefix operators, postfix operator declarations don’t specify a precedence level. Postfix operators are nonassociative. +After declaring a new operator, you implement it by declaring a function that has the same name as the operator. To see an example of how to create and implement a new operator, see Custom Operators. +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­ From eadbfd88ada79b7a37eddbf1e3b6e7f7c068c26a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B1=B3=E5=B0=94?= Date: Sun, 15 Jun 2014 21:41:00 +0800 Subject: [PATCH 062/261] update --- src/chapter2/11_Methods.md | 438 +++++++++++++++++++++++++++++++++++++ 1 file changed, 438 insertions(+) diff --git a/src/chapter2/11_Methods.md b/src/chapter2/11_Methods.md index e69de29..639298e 100644 --- a/src/chapter2/11_Methods.md +++ b/src/chapter2/11_Methods.md @@ -0,0 +1,438 @@ +# 方法 (Methods) + +Methods are functions that are associated with a particular type. Classes, structures, and enumerations can all define instance methods, which encapsulate specific tasks and functionality for working with an instance of a given type. Classes, structures, and enumerations can also define type methods, which are associated with the type itself. Type methods are similar to class methods in Objective-C. + +方法是指和某些特定类型相关联的函数。类、结构体、枚举都可以定义实例方法, 这些实例方法可以将特定任务和功能封装到一个指定的类型实例中。类、结构体、美剧也可以定义类型方法, 这些类型方法仅和类型本身有关联。 类型方法和 Objective-C 中的类方法(class methods)很相似。 + +The fact that structures and enumerations can define methods in Swift is a major difference from C and Objective-C. In Objective-C, classes are the only types that can define methods. In Swift, you can choose whether to define a class, structure, or enumeration, and still have the flexibility to define methods on the type you create. + +事实上,结构体和枚举可以在 Swift 中定义方法, 成为了和 C、Objective-C 之间一个主要区别。在 Objective-C 中,只有类(Class)才能定义方法。在 Swift 中,你可以选择在类、结构体、枚举、甚至是你自己定义的类型中,去定义方法。 + +## 实例方法(Instance Methods) + +Instance methods are functions that belong to instances of a particular class, structure, or enumeration. They support the functionality of those instances, either by providing ways to access and modify instance properties, or by providing functionality related to the instance’s purpose. Instance methods have exactly the same syntax as functions, as described in Functions. + +实例方法是属于某个特定类、结构体、枚举实例的函数。实例方法提供获取和修改实例变量的途径,又或是提供与实例用途相关的功能,以满足这些实例的功能需要。实例方法的语法和函数一样,参考`函数`这一章节。 + +You write an instance method within the opening and closing braces of the type it belongs to. An instance method has implicit access to all other instance methods and properties of that type. An instance method can be called only on a specific instance of the type it belongs to. It cannot be called in isolation without an existing instance. + +实例类型要写在类型的括号中。实例方法可以隐式地访问这个类型的所有实例方法和属性。实例方法只能被它所属类型的实例调用,不能在实例之外被独立调用。 + +Here’s an example that defines a simple `Counter` class, which can be used to count the number of times an action occurs: + +这里有一个例子,定义了一个可以用来记录动作发生次数的计数器 Counter 类 + +``` + +class Counter { + var count = 0 + func increment() { + count++ + } + func incrementBy(amount: Int) { + count += amount + } + func reset() { + count = 0 + } +} + +``` + +The Counter class defines three instance methods: + +`Counter` 类定义了三个实例方法: + +* `increment` increments the counter by 1. + +* `increment` * 计数器每次递增 +1。 + +* `incrementBy(amount: Int)` increments the counter by an specified integer amount. + +* `incrementBy(amount: Int)` 计数器根据给定的 amount 值增量 + +* `reset` resets the counter to zero. + +* `reset` 重置计数器归零。 + +The `Counter` class also declares a variable property, count, to keep track of the current counter value. + +`Counter` 类也声明了一个变量属性 count,用来记录当前的计数器的值。 + +You call instance methods with the same dot syntax as properties: + +你可以像调用属性一样,通过相同的点语法 (dot syntax) 来调用实例方法: + +``` + +let counter = Counter() +// the initial counter value is 0 +// 计数器初始值为0 +counter.increment() +// the counter's value is now 1 +// 计数器的值现在是1 +counter.incrementBy(5) +// the counter's value is now 6 +// 计数器的值现在是6 +counter.reset() +// the counter's value is now 0 +// 计数器的值现在是0 + +``` + +## 方法的内部参数和外部参数(Local and External Parameter Names for Methods) + +Function parameters can have both a local name (for use within the function’s body) and an external name (for use when calling the function), as described in External Parameter Names. The same is true for method parameters, because methods are just functions that are associated with a type. However, the default behavior of local names and external names is different for functions and methods. + +函数参数可以有一个内部名称(用于函数内部)和一个外部名称(用于函数调用),正如`函数`章节里`外部参数名`描述的那样。方法参数和函数参数一样,因为方法只不过是和类型相关联的函数罢了。然而,内部名称和外部名称在函数和方法内部的默认行为却是不一样的。 + +Methods in Swift are very similar to their counterparts in Objective-C. As in Objective-C, the name of a method in Swift typically refers to the method’s first parameter using a preposition such as with, for, or by, as seen in the incrementBy method from the preceding Counter class example. The use of a preposition enables the method to be read as a sentence when it is called. Swift makes this established method naming convention easy to write by using a different default approach for method parameters than it uses for function parameters. + +Swift 里的方法和 Objective-C 里的方法是非常相似的。和 Objective-C 中一样, Swift 里的方法通常使用 with、for、by 之类的介词来指向第一个参数,比如计数器例子里的 `incrementBy`。介词的使用可以使这个方法的调用如同阅读一个句子。与函数参数不同的是,对于方法参数,Swift 使用了一套不同的默认处理规则,使得方法的命名规则写起来更加简单。 + +Specifically, Swift gives the first parameter name in a method a local parameter name by default, and gives the second and subsequent parameter names both local and external parameter names by default. This convention matches the typical naming and calling convention you will be familiar with from writing Objective-C methods, and makes for expressive method calls without the need to qualify your parameter names. + + +具体来说,Swift 默认第一个参数名仅作为内部名称,第二个和之后的参数名作为内部名称和外部名称。这个约定和典型的命名和调用方法的约定相匹配,你会觉得和写 Objective-C 方法十分相似,而且这个约定不需要限制你的参数名。 + +Consider this alternative version of the Counter class, which defines a more complex form of the incrementBy method: + +我们来看看计数器 `Counter` 的另外一个版本,这个版本定义了更加复杂的 `incrementBy` 方法: + +``` + +class Counter { + var count: Int = 0 + func incrementBy(amount: Int, numberOfTimes: Int) { + count += amount * numberOfTimes + } +} + +``` + +This `incrementBy` method has two parameters—`amount` and `numberOfTimes`. By default, Swift treats `amount` as a local name only, but treats `numberOfTimes` as both a local and an external name. You call the method as follows: + +这个 `incrementBy` 方法有两个参数 -- `amount` 和 `numberOfTimes`。根据默认约定,Swift 只把 `amount` 看做内部变量,但是把 `numberOfTimes` 同时作为内部名称和外部名称。你可以这样调用: + +``` + +let counter = Counter() +counter.incrementBy(5, numberOfTimes: 3) +// counter value is now 15 +// 计数器的值现在是15 + +``` + +You don’t need to define an external parameter name for the first argument value, because its purpose is clear from the function name `incrementBy`. The second argument, however, is qualified by an external parameter name to make its purpose clear when the method is called. + +你不需要为第一个参数值定义一个外部参数名称,因为这个参数值的意图已经被函数名 `incrementBy` 表达得很清楚了。但是第二个参数被外部参数名限制了,这是为了在方法调用的时候,表达出更清晰的意图。 + +This default behavior effectively treats the method as if you had written a hash symbol (`#`) before the `numberOfTimes` parameter: + +这种默认行为使方法处理变得高效,就好像你在 `numberOfTimes` 前加了一个 `#` 号: + +``` + +func incrementBy(amount: Int, #numberOfTimes: Int) { + count += amount * numberOfTimes +} + +``` + +The default behavior described above mean that method definitions in Swift are written with the same grammatical style as Objective-C, and are called in a natural, expressive way. + +以上描述的默认行为表,Swift 中的方法定义和 Objective-C 有着同样的语法风格,都使用了自然的表达手法。 + +## 修改方法的外部参数名称行为(Modifying External Parameter Name Behavior for Methods) + +Sometimes it’s useful to provide an external parameter name for a method’s first parameter, even though this is not the default behavior. You can either add an explicit external name yourself, or you can prefix the first parameter’s name with a hash symbol to use the local name as an external name too. + +有时候,提供为方法的第一个参数提供一个外部参数名称是有用的,即使这不是个默认行为。你可以自己增加一个明确的外部名称,也可以给第一个参数增加一个 # 的前缀,使得内部名称可以作为外部名称使用。 + +Conversely, if you do not want to provide an external name for the second or subsequent parameter of a method, override the default behavior by using an underscore character (`_`) as an explicit external parameter name for that parameter. + +相反地,如果你不想为方法里的第二个及后续参数提供外部名称,可以使用 `_` 作为显式的外部参数名称来重写这个规则。 + +### The self Property + +Every instance of a type has an implicit property called `self`, which is exactly equivalent to the instance itself. You use this implicit self property to refer to the current instance within its own instance methods. + +每个类型的实例都有一个隐式的属性,叫做 `self`,这个变量和实例自身等价。你可以使用 self 来指代当前实例。 + +The `increment` method in the example above could have been written like this: + +例子中的 `increment` 可以写成这样: + +``` + +func increment() { + self.count++ +} + +``` + +In practice, you don’t need to write `self` in your code very often. If you don’t explicitly write `self`, Swift assumes that you are referring to a property or method of the current instance whenever you use a known property or method name within a method. This assumption is demonstrated by the use of `count` (rather than `self.count`) inside the three instance methods for `Counter`. + +事实上,你不需要经常在代码里写 `self`。如果你没有明确写 `self`,无论你调用了已知属性或是方法,Swift 会假设你调用的是当前实例的属性或者方法。这个假设已经在第一个例子里证实了, `Counter` 里直接调用了 `count` 而不是通过 `self.count`。 + +The main exception to this rule occurs when a parameter name for an instance method has the same name as a property of that instance. In this situation, the parameter name takes precedence, and it becomes necessary to refer to the property in a more qualified way. You use the implicit `self` property to distinguish between the parameter name and the property name. + +当一个实例方法的参数名和这个实例里的属性名重复时,这个规则怎么处理呢?在这种情况下,参数名拥有更高的优先级,同时属性名的引用需要使用更清晰明确的方法。可以使用隐式的 `self` 来区分参数名和属性名。 + +Here, `self` disambiguates between a method parameter called `x` and an instance property that is also called `x`: + +这里的 `self` 避免了方法参数名为 `x` 和实例属性名为 `x` 的混淆冲突: + +``` + +struct Point { + var x = 0.0, y = 0.0 + func isToTheRightOfX(x: Double) -> Bool { + return self.x > x + } +} +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") +} +// prints "This point is to the right of the line where x == 1.0 + +``` + +Without the `self` prefix, Swift would assume that both uses of `x` referred to the method parameter called `x`. + +如果没有 `self` 这个前缀,Swift 会假设这两个 `x` 都指代参数 `x`。 + +### 修改实例方法中的值类型 (Modifying Value Types from Within Instance Methods) + +Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods. + +结构体和枚举都是值类型。值类型的属性默认不能在实例方法中被修改。 + +However, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to `mutating` behavior for that method. The method can then mutate (that is, change) its properties from within the method, and any changes that it makes are written back to the original structure when the method ends. The method can also assign a completely new instance to its implicit `self` property, and this new instance will replace the existing one when the method ends. + +然而,如果你需要通过特殊方法来修改结构体或枚举的属性,你得为那个方法使用 `变异` 这个用法。这个方法可以在方法内部改变它的属性,并且在这个方法结束时,它产生的任何改变都会保留在原来的结构体实例中。方法也可以指定一个完整全新的实例替换隐式的 `self` 属性,从而在方法结束的时候,会替换原来的实例。 + +You can opt in to this behavior by placing the `mutating` keyword before the `func` keyword for that method: + +你可以通过在 `func` 前增加 `mutating` 来调用 `变异` + +``` + +struct Point { + var x = 0.0, y = 0.0 + mutating func moveByX(deltaX: Double, y deltaY: Double) { + x += deltaX + y += deltaY + } +} +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))") +// prints "The point is now at (3.0, 4.0) + +``` + +The `Point` structure above defines a mutating `moveByX` method, which moves a `Point` instance by a certain amount. Instead of returning a new point, this method actually modifies the point on which it is called. The `mutating` keyword is added to its definition to enable it to modify its properties. + +上面这个 `Point` 结构体定义了一个变异的 `moveByX` 方法,这个方法可以将 `Point` 实例按照某个数值移动。这个方法在调用的时候修改了这个实例的坐标数据,而不是替换了这个实例。为了可以修改它的属性,在这个方法定义前增加了 `mutating` 。 + +Note that you cannot call a mutating method on a constant of structure type, because its properties cannot be changed, even if they are variable properties, as described in Stored Properties of Constant Structure Instances: + +注意,你不能在一个作为常量的结构体实例上使用编译方法。因为它的属性已经无法更改,即使它们是可变属性。正如 `属性` 这个章节中的 `常量结构体实例的属性`中描述的那样。 + +``` + +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) + +Mutating methods can assign an entirely new instance to the implicit `self` property. The `Point` example shown above could have been written in the following way instead: + +变异方法可以将一个全新的实例赋值给 `self`。上面的 `Point` 例子可以被重写为如下: + +``` + +struct Point { + var x = 0.0, y = 0.0 + mutating func moveByX(deltaX: Double, y deltaY: Double) { + self = Point(x: x + deltaX, y: y + deltaY) + } +} + +``` + +This version of the mutating `moveByX` method creates a brand new structure whose `x` and `y` values are set to the target location. The end result of calling this alternative version of the method will be exactly the same as for calling the earlier version. + +这个版本的变异 `moveByX` 重新创造了一个指向新坐标 `x` 和 `y` 的实例。调用这个版本的方法,执行结果和上一个版本相同。 + +Mutating methods for enumerations can set the implicit `self` parameter to be a different member from the same enumeration: + +枚举类型的变异方法可以将 `self` 赋值为相同枚举类型中的另外一个成员。 + +``` + +enum TriStateSwitch { + case Off, Low, High + mutating func next() { + switch self { + case Off: + self = Low + case Low: + self = High + case High: + self = Off + } + } +} +var ovenLight = TriStateSwitch.Low +ovenLight.next() +// ovenLight is now equal to .High +ovenLight.next() +// ovenLight is now equal to .Off + +``` + +This example defines an enumeration for a three-state switch. The switch cycles between three different power states (`Off`, `Low` and `High`) every time its `next` method is called. + +这个例子定义了一个有三种状态的枚举类型。每次调用 `next` 方法都会在这三种状态中切换一次。 + +## 类型方法 (Type Methods) + +Instance methods, as described above, are methods that are called on an instance of a particular type. You can also define methods that are called on the type itself. These kinds of methods are called type methods. You indicate type methods for classes by writing the keyword `class` before the method’s `func` keyword, and type methods for structures and enumerations by writing the keyword `static` before the method’s `func` keyword. + +上面描述的实例方法,都是在一个指定类型的实例中调用的。你也可以定义可以被类型自身调用的方法。这些类型的方法被称为类型方法。在类中,你可以通过在 `func` 关键词前增加 `class` 前缀来指定这个方法为类型方法。在结构体和枚举中,你可以通过在 `func` 关键词前增加 `static` 前缀来指定这个方法为类型方法 + +> NOTE 提示 + +> In Objective-C, you can define type-level methods only for Objective-C classes. In Swift, you can define type-level methods for all classes, structures, and enumerations. Each type method is explicitly scoped to the type it supports. + +> 在 Objective-C 中,你可以给 Objective-C 类指定一个类型级别的方法。在 Swift 中,你可以为所有类、结构体、枚举指定类型级别的方法。每个类型方法仅显式包含在它支持的类中 + +Type methods are called with dot syntax, like instance methods. However, you call type methods on the type, not on an instance of that type. Here’s how you call a type method on a class called `SomeClass`: + +和实例方法一样,类型方法也通过点语法 (dot syntax) 被调用。然后你可以直接在类型上调用这个方法,而不是在一个类型的实例上。下面的 `SomeClass` 会表明如何调用类型方法: + +``` + +class SomeClass { + class func someTypeMethod() { + // type method implementation goes here + } +} +SomeClass.someTypeMethod() + +``` + +Within the body of a type method, the implicit self property refers to the type itself, rather than an instance of that type. For structures and enumerations, this means that you can use self to disambiguate between static properties and static method parameters, just as you do for instance properties and instance method parameters. + +在类型方法体中,隐式 self 属性指代类型本身,而不是某个类型的实例。对于结构体和枚举来说,这意味着你可以使用 self 来解除静态属性和静态方法参数之间的混淆,就如同实例属性和实例方法参数那样。 + +More generally, any unqualified method and property names that you use within the body of a type method will refer to other type-level methods and properties. A type method can call another type method with the other method’s name, without needing to prefix it with the type name. Similarly, type methods on structures and enumerations can access static properties by using the static property’s name without a type name prefix. + +更广泛的说,在类型方法体内,没有显式调用的方法和属性都会被指代为其他类型级别的方法和属性。类型方法可以通过其他方法名来调用其他类型方法,而不需要在方法名前增加类型名称。同样的,结构体和枚举的类型方法也可以通过静态属性名直接获取静态属性,而不需要在属性名前增加类型名称。 + +The example below defines a structure called `LevelTracker`, which tracks a player’s progress through the different levels or stages of a game. It is a single-player game, but can store information for multiple players on a single device. + +下面这个例子指定了 `LevelTracker` 结构体。它可以跟踪一个游戏中成员的不同关卡过程。这是一个单玩家游戏,但是可以在单个设备中存储多个玩家的游戏数据。 + +All of the game’s levels (apart from level one) are locked when the game is first played. Every time a player finishes a level, that level is unlocked for all players on the device. The `LevelTracker` structure uses static properties and methods to keep track of which levels of the game have been unlocked. It also tracks the current level for an individual player. + +游戏刚开始的时候,所有游戏关卡(除了第一关)都被锁定。每次一个玩家结束了一个关卡,这个关卡会为这个设备上的所有玩家解锁。`LevelTracker` 结构体使用了静态属性和方法来记录哪个游戏关卡被解锁,同时记录为每个成员玩家当前所在关卡。 + +``` + +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 + } + } +} + +``` + +The `LevelTracker` structure keeps track of the highest level that any player has unlocked. This value is stored in a static property called `highestUnlockedLevel`. + +`LevelTracker` 结构体持续记录被任何一个玩家解锁的最高关卡。这个值被保存在静态属性 `highestUnlockedLevel` 中。 + +`LevelTracker` also defines two type functions to work with the `highestUnlockedLevel` property. The first is a type function called `unlockLevel`, which updates the value of `highestUnlockedLevel` whenever a new level is unlocked. The second is a convenience type function called `levelIsUnlocked`, which returns `true` if a particular level number is already unlocked. (Note that these type methods can access the `highestUnlockedLevel` static property without your needing to write it as `LevelTracker.highestUnlockedLevel`.) + +`LevelTracker` 也指定了两个与 `highestUnlockedLevel` 一起工作的类型函数。第一个类型函数 `unlockLevel` ,当新关卡解锁时,用来更新 `highestUnlockedLevel` 。第二个是 `levelIsUnlocked`,如果某个关卡编号已经解锁,返回 `true`。(注意,这些类型方法在获取 `highestUnlockedLevel` 属性时,不需要写成 `LevelTracker.highestUnlockedLevel` 也能直接获取 `highestUnlockedLevel` 这个静态属性。) + +In addition to its static property and type methods, `LevelTracker` tracks an individual player’s progress through the game. It uses an instance property called `currentLevel` to track the level that a player is currently playing. + +除了静态属性和类型方法之外,`LevelTracker` 也跟踪每个独立玩家在游戏中的进程。通过一个实例属性 `currentLevel` 来记录玩家当前的关卡。 + +To help manage the `currentLevel` property, `LevelTracker` defines an instance method called `advanceToLevel`. Before updating `currentLevel`, this method checks whether the requested new level is already unlocked. The `advanceToLevel` method returns a Boolean value to indicate whether or not it was actually able to set `currentLevel`. + +为了帮助管理 `currentLevel` 属性,`LevelTracker` 指定了一个实例方法 `advanceToLevel`。在更新 `currentLevel` 之前,这个方法会检测请求的下一关已经解锁。`advanceToLevel` 方法返回一个布尔值,表示是否可以前进到某个关卡。 + +The `LevelTracker` structure is used with the `Player` class, shown below, to track and update the progress of an individual player: + +`LevelTracker` 结构体可以和 `Player` 类结合使用,来跟踪和更新每个玩家的游戏进程: + +``` + +class Player { + var tracker = LevelTracker() + let playerName: String + func completedLevel(level: Int) { + LevelTracker.unlockLevel(level + 1) + tracker.advanceToLevel(level + 1) + } + init(name: String) { + playerName = name + } +} + +``` + +The `Player` class creates a new instance of `LevelTracker` to track that player’s progress. It also provides a method called `completedLevel`, which is called whenever a player completes a particular level. This method unlocks the next level for all players and updates the player’s progress to move them to the next level. (The Boolean return value of `advanceToLevel` is ignored, because the level is known to have been unlocked by the call to `LevelTracker.unlockLevel` on the previous line.) + +`Player` 实例化了一个 `LevelTracker` 来追踪玩家的游戏进程。它也提供了 `completedLevel` 方法,当一个玩家完成某个特定关卡时将会被调用。这个方法为所有玩家解锁下一个关卡,并且更新玩家的进程到下一个关卡。(`advanceToLevel` 的布尔返回值被忽略了, 因为 `LevelTracker.unlockLevel` 已经在这个方法之前解锁了下一个关。) + +You can create a instance of the `Player` class for a new player, and see what happens when the player completes level one: + +你可以为一个新玩家实例化一个 `Player` 类,然后看看当玩家完成第一关的时候会发生什么: + +``` + +var player = Player(name: "Argyrios") +player.completedLevel(1) +println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)") +// prints "highest unlocked level is now 2 + +``` + +If you create a second player, whom you try to move to a level that is not yet unlocked by any player in the game, the attempt to set the player’s current level fails: + +如果你实例化了第二个玩家,并试图让他进入一个尚未解锁的关卡,这会导致失败: + +``` + +player = Player(name: "Beto") +if player.tracker.advanceToLevel(6) { + println("player is now on level 6") +} else { + println("level 6 has not yet been unlocked") +} +// prints "level 6 has not yet been unlocked + +``` \ No newline at end of file From e6960404c1d9694cfbe2ef1a1ddae9dfe1b15146 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Sun, 15 Jun 2014 22:19:20 +0800 Subject: [PATCH 063/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 176 ++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 68 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index f029b4a..775e8f3 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -285,6 +285,7 @@ For more information and to see an example of how to use property observers, see ##类和静态变量属性 To declare a class computed property, mark the declaration with the class keyword. To declare a static variable property, mark the declaration with the static keyword. Class and static properties are discussed in Type Properties. +要声明一个类计算属性,要用class关键字标记声明。声明静态的变量属性,用关键字static标记声明。类和静态属性在Type属性里讨论。 >GRAMMAR OF A VARIABLE DECLARATION @@ -460,14 +461,19 @@ A parameter named with an underscore (_) is explicitly ignored an can’t be acc 带有下划线的参数会显式的被忽略,在函数体内部不能被访问到。 A parameter with a base type name followed immediately by three dots (...) is understood as a variadic parameter. A function can have at most one variadic parameter, which must be its last parameter. A variadic parameter is treated as an array that contains elements of the base type name. For instance, the variadic parameter Int... is treated as Int[]. For an example that uses a variadic parameter, see Variadic Parameters. + 带有基本类型后面接着3个点的参数。 + A parameter with an equals sign (=) and an expression after its type is understood to have a default value of the given expression. If the parameter is omitted when calling the function, the default value is used instead. If the parameter is not omitted, it must have its name in the function call. For example, f() and f(x: 7) are both valid calls to a function with a single default parameter named x, but f(7) is invalid because it provides a value without a name. 带有等号(=)的参数和它类型后面的表达式会被仿作给定表达式的默认类型。如果参数在调用函数的时候被忽略,默认值会被使用。例如,f()和f(x:7)都是有效的调用对于带有单个默认的的参数名x的函数,但是f(7)是有效的,因为它提供了没有名字的值。 Special Kinds of MethodsMethods on an enumeration or a structure that modify self must be marked with the mutating keyword at the start of the function declaration. + 枚举类型或者结构上的方法,会修改self的必须在函数声明的开始标记为mutating关键字 + Methods that override a superclass method must be marked with the override keyword at the start of the function declaration. It is an error to override a method without the override keyword or to use the overridekeyword on a method that doesn’t override a superclass method. + 重写超类方法的方法必须在函数声明的开头override关键词标记。不适用override就重写方法会产生错误或者使用override在没有override超类的方法 Methods associated with a type rather than an instance of a type must be marked with the static attribute for enumerations and structures or the class attribute for classes. @@ -477,6 +483,7 @@ Methods associated with a type rather than an instance of a type must be marked Curried Functions and Methods Curried functions and methods have the following form: + 当前的函数和方法有以下的形式: @@ -523,12 +530,14 @@ Curried functions and methods have the following form: > default-argument-clause → =­expression­: A function declared this way is understood as a function whose return type is another function. For example, the following two declarations are equivalent: + 用这种方式声明的函数会被当做一个函数,这个函数的返回类型是另外一个函数。例如,下面2个声明是一样的: Enumeration Declaration An enumeration declaration introduces a named enumeration type into your program. + 枚举声明引入一个个名叫枚举的类型到你的程序中。 @@ -537,6 +546,7 @@ Enumeration declarations have two basic forms and are declared using the keyword 枚举声明有2中基本的形式,使用关键字enum声明。一个枚举类型的的主题使用2中形式之一,包含0或者蒙多的值-被称作枚举类型还有任何数量的声明,包括可计算的属性,实例方法,静态方法,初始化,类型aliase,和其它的枚举、结构和类声明。枚举声明不能包含析构或者协议声明。 Unlike classes and structures, enumeration types do not have an implicitly provided default initializer; all initializers must be declared explicitly. Initializers can delegate to other initializers in the enumeration, but the initialization process is complete only after an initializer assigns one of the enumeration cases to self. + 不像类或者结构,枚举类型没有一个默认的初始化,但是初始化过程仅仅在初始化赋值给枚举类型的一个给self的时候。 Like structures but unlike classes, enumerations are value types; instances of an enumeration are copied when assigned to variables or constants, or when passed as arguments to a function call. For information about value types, see Structures and Enumerations Are Value Types. @@ -548,6 +558,7 @@ You can extend the behavior of an enumeration type with an extension declaration Enumerations with Cases of Any Type The following form declares an enumeration type that contains enumeration cases of any type: + 下面的形式声明了一个枚举类型,包含了所有类型的枚举。 @@ -568,32 +579,29 @@ The following form declares an enumeration type that contains enumeration cases Enumerations declared in this form are sometimes called discriminated unions in other programming languages. + 用这种形式声明的枚举在其他语言里有时候被叫做discriminated unions In this form, each case block consists of the keyword case followed by one or more enumeration cases, separated by commas. The name of each case must be unique. Each case can also specify that it stores values of a given type. These types are specified in the associated value types tuple, immediately following the name of the case. For more information and to see examples of cases with associated value types, seeAssociated Values. -用这种方式,每个cast块由关键字case组成,case后跟着一个或者多个逗号分隔的枚举情况。每个case的名字必须是唯一的。每个case页能够确定他存储一个给定类型的值。这些类型用关联只类型元组来设置,后面紧梗着case的名字。获取更多信息,看下关联至类型的的例子,请看Assiciated Values -Enumerations with Raw Cases Values - -The following form declares an enumeration type that contains enumeration cases of the same basic type: -下面的形式声明了一种枚举类型,保护同样基本类型的枚举case +用这种方式,每个cast块由关键字case组成,case后跟着一个或者多个逗号分隔的枚举情况。每个case的名字必须是唯一的。每个case页能够确定他存储一个给定类型的值。这些类型用关联只类型元组来设置,后面紧梗着case的名字。获取更多信息,看下关联至类型的的例子,请看Assiciated Values Enumerations with Raw Cases Values - * enum enumeration name: raw value type { +The following form declares an enumeration type that contains enumeration cases of the same basic type: +下面的形式声明了一种枚举类型,包含同样基本类型的枚举case - * - case enumeration case 1 = raw value 1 - * - case enumeration case 2 = raw value 2 + enum enumeration name: raw value type { - * -} + case enumeration case 1 = raw value 1 + case enumeration case 2 = raw value 2 + } In this form, each case block consists of the keyword case, followed by one or more enumeration cases, separated by commas. Unlike the cases in the first form, each case has an underlying value, called a raw value, of the same basic type. The type of these values is specified in the raw value type and must represent a literal integer, floating-point number, character, or string. + 通过这种形式,每种caes块是由关键字case后面跟着一个或者多个由多个逗号分隔的枚举case。不像第一种形式的case,每个case有一个underlying值,叫做原生值。这些值的类型在rsw值的类型设置,必须表示一个字面量整数,浮点数,字符和字符串。 Each case must have a unique name and be assigned a unique raw value. If the raw value type is specified as Int and you don’t assign a value to the cases explicitly, they are implicitly assigned the values 0, 1, 2, and so on. Each unassigned case of type Int is implicitly assigned a raw value that is automatically incremented from the raw value of the previous case. @@ -601,9 +609,9 @@ Each case must have a unique name and be assigned a unique raw value. If the raw 每个case必须有一个唯一的名字,然后被赋值为一个单独的原生值。如果原生值用Int设置,你不需要要显式的赋值,他们可以默认的赋值1,1,2等等。每个没有赋值的Int类型会被赋值为原生类型,可以自动的从之前的case的原生值增加。 - * enum ExampleEnum: Int { - * case A, B, C = 5, D - * } + enum ExampleEnum: Int { + case A, B, C = 5, D + } In the above example, the value of ExampleEnum.A is 0 and the value of ExampleEnum.B is 1. And because the value of ExampleEnum.C is explicitly set to 5, the value of ExampleEnum.D is automatically incremented from 5 and is therefore 6. @@ -613,10 +621,15 @@ In the above example, the value of ExampleEnum.A is 0 and the value of ExampleEn The raw value of an enumeration case can be accessed by calling its toRaw method, as inExampleEnum.B.toRaw(). You can also use a raw value to find a corresponding case, if there is one, by calling the fromRaw method, which returns an optional case. For more information and to see examples of cases with raw value types, see Raw Values. 枚举类型的原生值可以通过toRaw方法访问,比如ExampleEnum.B.toRaw()。你也可以使用一个原生值来找到对应的case通过调用fromRaw方法。 -Accessing Enumeration Cases + +##Accessing Enumeration Cases + +##访问枚举case To reference the case of an enumeration type, use dot (.) syntax, as in EnumerationType.EnumerationCase. When the enumeration type can be inferred from context, you can omit it (the dot is still required), as described inEnumeration Syntax and Implicit Member Expression. + 正如EnumerationType.EnumerationCase,可以使用。来引用一个enumeration类型的case,正如inEnumeration Syntax and Implicit Member Expression.描述的。 + To check the values of enumeration cases, use a switch statement, as shown in Matching Enumeration Values with a Switch Statement. The enumeration type is pattern-matched against the enumeration case patterns in the case blocks of the switch statement, as described in Enumeration Case Pattern. >GRAMMAR OF AN ENUMERATION DECLARATION @@ -641,19 +654,12 @@ To check the values of enumeration cases, use a switch statement, as shown in Ma Structure Declaration A structure declaration introduces a named structure type into your program. Structure declarations are declared using the keyword struct and have the following form: -一个结构声明引入了一个命名的类型到你的程序。结构声明使用struct声明,采用以下的形式: - - - * struct structure name: adopted protocols { - - - * - declarations - - * -} +一个结构声明引入了一个命名的类型到你的程序。结构声明使用struct声明,采用以下的形式: + struct structure name: adopted protocols { + declarations + } The body of a structure contains zero or more declarations. These declarations can include both stored and computed properties, static properties, instance methods, static methods, initializers, type aliases, and even other structure, class, and enumeration declarations. Structure declarations can’t contain destructor or protocol declarations. For a discussion and several examples of structures that include various kinds of declarations, see Classes and Structures. @@ -669,17 +675,14 @@ There are three ways create an instance of a previously declared structure: 有3种方式创建过去声明过的示例结构的示例。 - * -Call one of the initializers declared within the structure, as described in Initializers. -就像Initializers描述的,调用结构里的一个初始器之一。 + * Call one of the initializers declared within the structure, as described in Initializers. + 就像Initializers描述的,调用结构里的一个初始器之一。 - * -If no initializers are declared, call the structure’s memberwise initializer, as described in Memberwise Initializers for Structure Types. -如果没有初始器被声明,就可以调用结构区的成员 + * If no initializers are declared, call the structure’s memberwise initializer, as described in Memberwise Initializers for Structure Types. + 如果没有初始器被声明,就可以调用结构区的成员 - * -If no initializers are declared, and all properties of the structure declaration were given initial values, call the structure’s default initializer, as described in Default Initializers. -如果没有初始化器被声明,结构所有其他声明的属性就会被给予初始化的值,调用结构的某人初始化器,正如Default Initializers.描述的那样。 + * If no initializers are declared, and all properties of the structure declaration were given initial values, call the structure’s default initializer, as described in Default Initializers. + 如果没有初始化器被声明,结构所有其他声明的属性就会被给予初始化的值,调用结构的某人初始化器,正如Default Initializers .描述的那样。 @@ -697,31 +700,26 @@ Structures are value types; instances of a structure are copied when assigned to You can extend the behavior of a structure type with an extension declaration, as discussed in Extension Declaration. 你可以用一个扩展声明来扩展一个结构类型的行为,正如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­} +>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­} -Class Declaration - -A class declaration introduces a named class type into your program. Class declarations are declared using the keyword class and have the following form: - -类型声明映入了一个命令的类型到你的程序中。类声明使用关键字class声明,采用下面的形式: +##Class Declaration +##类声明 - * class class name: superclass, adopted protocols { - - - * - declarations +A class declaration introduces a named class type into your program. Class declarations are declared using the keyword class and have the following form: - * -} +类型声明映入了一个命令的类型到你的程序中。类声明使用关键字class声明,采用下面的形式: + class class name: superclass, adopted protocols { + declarations + } The body of a class contains zero or more declarations. These declarations can include both stored and computed properties, instance methods, class methods, initializers, a single destructor method, type aliases, and even other class, structure, and enumeration declarations. Class declarations can’t contain protocol declarations. For a discussion and several examples of classes that include various kinds of declarations, see Classes and Structures. @@ -748,14 +746,12 @@ There are two ways create an instance of a previously declared class: 有两种方式创建过去声明的类的实例: - * -Call one of the initializers declared within the class, as described in Initializers. -在类的内部调用声明的初始化器。 + * Call one of the initializers declared within the class, as described in Initializers. + 在类的内部调用声明的初始化器。 - * -If no initializers are declared, and all properties of the class declaration were given initial values, call the class’s default initializer, as described in Default Initializers. + * If no initializers are declared, and all properties of the class declaration were given initial values, call the class’s default initializer, as described in Default Initializers. -如果没有声明的初始化器,类声明的素有属性会有一个初始化值,是通过调用类的默认的初始化器来完成的。正如Default Initializers描述的。 + 如果没有声明的初始化器,类声明的素有属性会有一个初始化值,是通过调用类的默认的初始化器来完成的。正如Default Initializers描述的。 @@ -774,24 +770,68 @@ You can extend the behavior of a class type with an extension declaration, as di 你可以使用extension声明来扩展类的行为,正如Extension Desclaration. -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­}­ -Protocol 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­} + +##Protocol Declaration + +##协议声明 + A protocol declaration introduces a named protocol type into your program. Protocol declarations are declared using the keyword protocol and have the following form: + 一个协议声明引入了一命令协议类型到你的程序中。协议声明可以使用protoco来声明,有如下的形式: - * protocol protocol name: inherited protocols { + protocol protocol name: inherited protocols { + protocol member declarations + } +The body of a protocol contains zero or more protocol member declarations, which describe the conformance requirements that any type adopting the protocol must fulfill. In particular, a protocol can declare that conforming types must implement certain properties, methods, initializers, and subscripts. Protocols can also declare special kinds of type aliases, called associated types, that can specify relationships among the various declarations of the protocol. The protocol member declarations are discussed in detail below. - * - protocol member declarations +协议的主体包含洗衣成员声明,它描述了comformance要求,任何实现它的协议都必须满足的要求。特别是,协议可以声明comformin类型,必须实现某个属性,方法,初始化,和子脚本。协议页能声明特殊种类的typealiase,被称作关联类型,可以设置协议里的不同声明的关系。协议成员声明下面会做详细的讨论。 - * -} +Protocol types can inherit from any number of other protocols. When a protocol type inherits from other protocols, the set of requirements from those other protocols are aggregated, and any type that inherits from the current protocol must conform to all those requirements. For an example of how to use protocol inheritance, see Protocol Inheritance. + +协议类型可以从任何数量的其它协议。当一个协议类型从其它洗衣继承时,从那些协议中的要求会被集合,任何从当前协议继承的类型都必须和那些要求一致。 + + +NOTE +You can also aggregate the conformance requirements of multiple protocols using protocol composition types, as described in Protocol Composition Type and Protocol Composition. + +You can add protocol conformance to a previously declared type by adopting the protocol in an extension declaration of that type. In the extension, you must implement all of the adopted protocol’s requirements. If the type already implements all of the requirements, you can leave the body of the extension declaration empty. + +你可以增加协议conformance到任何一个过去声明的类型通过在那个类型的extendsion中声明。在这个扩展力,你必须实现所有使用的协议的需求。如果那个类型已经实现了所有的要求,扩展声明的主题可以是空的。 + +By default, types that conform to a protocol must implement all properties, methods, and subscripts declared in the protocol. That said, you can mark these protocol member declarations with the optional attribute to specify that their implementation by a conforming type is optional. The optional attribute can be applied only to protocols that are marked with the objc attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. For more information about how to use the optionalattribute and for guidance about how to access optional protocol members—for example, when you’re not sure whether a conforming type implements them—see Optional Protocol Requirements. +默认情况下,与协议一致的类型必须实现所有的属性,方法,和声明的subscripts。也就是说,你可以用opaional属性来标记协议成员,表示他们的实现是可选的。option属性仅仅能被应用到用objc标记的属性。结构,仅仅class类型能采纳和玉包含可选的成员变量的协议一致。对于如何访问可选的协议成员-例如,如果你不确定一个confroming类型是否要实现他们-看见 Optional Protocol Requirements. + +To restrict the adoption of a protocol to class types only, mark the entire protocol declaration with theclass_protocol attribute. Any protocol that inherits from a protocol marked with the class_protocol attribute can likewise be adopted only by a class type. + +为了限制协议的的只应用到某个class type,用class_protocol属性标记整个协议声明。任何从标记class_protocol协议继承的协议可以只被class 类型采纳。 + +NOTE +If a protocol is already marked with the objc attribute, the class_protocol attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the class_protocol attribute explicitly. + +Protocols are named types, and thus they can appear in all the same places in your code as other named types, as discussed in Protocols as Types. However, you can’t construct an instance of a protocol, because protocols do not actually provide the implementations for the requirements they specify. + + +You can use protocols to declare which methods a delegate of a class or structure should implement, as described in Delegation. +你可以使用协议来声明类或者结构应该实现那个方法,如Delegation.描述。 + +GRAMMAR OF A PROTOCOL DECLARATION +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 Method Declaration From 3f9af7bd6bd49b40e293bf0dc10d07a5e2f2819d Mon Sep 17 00:00:00 2001 From: mofengfly Date: Sun, 15 Jun 2014 23:06:37 +0800 Subject: [PATCH 064/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 673 ++++++++------------------------ 1 file changed, 157 insertions(+), 516 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 775e8f3..c9d6fac 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -248,6 +248,7 @@ didSet(setter name { statements } } + You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class or structure declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, the observers are referred to as stored variable observers. When it is declared in the context of a class or structure declaration, the observers are referred to as property observers. 你可以i在全局范围,函数的局部返回,或者类,结构环境里声明这种形式的变量。当这类型是的变量声明在全局范围或者函数的局部范围里声明的时候,观察者会被作为可存储的变量观察者。当在类或者结构声明中声明的时候,观察者会被作为属性的观察者。 @@ -392,9 +393,7 @@ Function parameters are a comma separated list where each parameter has one of s 函数参数是一个逗号分隔的列表,每个参数可以有好几种形式。函数调用的时候参数的顺序必须匹配函数声明的参数顺序。在参数列表里最简单的输入形式: - - * parameter name: parameter type - + parameter name: parameter type For function parameters, the parameter name is used within the function body, but is not used when calling the function. For method parameters, the parameter name is used as within the function body, and is also used as a label for the argument when calling the method. The name of a method’s first parameter is used only within the function body, like the parameter of a function. For example: @@ -402,17 +401,18 @@ For function parameters, the parameter name is used within the function body, bu 对于函数参数,参数名字在函数体内部使用,但是在调用函数的时候不会使用。对于方法参数,参数名可以在函数体使用,也在调用方法时可以作为参数的标签使用。函数的一个参数名字仅仅在函数体力使用,就像函数的参数。例如 - * func f(x: Int, y: String) -> String { - * return y + String(x) - * } - * f(7, "hello") // x and y have no name - * class C { - * func f(x: Int, y: String) -> String { - * return y + String(x) - * } - * } - * let c = C() - * c.f(7, y: "hello") // x has no name, y has a name +func f(x: Int, y: String) -> String { + return y + String(x) + } + f(7, "hello") // x and y have no name + + class C { + func f(x: Int, y: String) -> String { + return y + String(x) + } + } + let c = C() + c.f(7, y: "hello") // x没有名称,y有名称 You can override the default behavior for how parameter names are used with one of the following forms: @@ -420,13 +420,9 @@ You can override the default behavior for how parameter names are used with one 你可以重写参数名字使用的默认行为,采用如下的形式: - * external parameter name local parameter name: parameter type - - * -#parameter name: parameter type - - * _ local parameter name: parameter type - + external parameter name local parameter name: parameter type + #parameter name: parameter type + _ local parameter name: parameter type A second name before the local parameter name gives the parameter an external name, which can be different than the local parameter name. The external parameter name must be used when the function is called. The corresponding argument must have the external name in function or method calls. @@ -441,23 +437,21 @@ An underscore (_) before a local parameter name gives that parameter no name to 本次参数名的下划线在函数调用的时候让参数没有使用名字。对应的参在函数或者方法调用的时候不可以有名字。 -Special Kinds of Parameters +##Special Kinds of Parameters + +##特殊类型的参数 Parameters can be ignored, take a variable number of values, and provide default values using the following forms: 参数可以忽略,可以是可变数量的值,使用如下的形式提供默认值 - * _ : <#parameter type#. - - - * parameter name: parameter type... - - - * parameter name: parameter type = default argument value - + _ : <#parameter type#. + parameter name: parameter type... + parameter name: parameter type = default argument value A parameter named with an underscore (_) is explicitly ignored an can’t be accessed within the body of the function. + 带有下划线的参数会显式的被忽略,在函数体内部不能被访问到。 A parameter with a base type name followed immediately by three dots (...) is understood as a variadic parameter. A function can have at most one variadic parameter, which must be its last parameter. A variadic parameter is treated as an array that contains elements of the base type name. For instance, the variadic parameter Int... is treated as Int[]. For an example that uses a variadic parameter, see Variadic Parameters. @@ -480,22 +474,20 @@ Methods associated with a type rather than an instance of a type must be marked 与type相关而不是类型实例相关的方法必须使用使用static属性来标记枚举、结构或者类的class属性 -Curried Functions and Methods - -Curried functions and methods have the following form: - -当前的函数和方法有以下的形式: +##Curried Functions and Methods +##科里化函数和方法 - * func function name(parameters)(parameters) -> return type { +Curried functions and methods have the following form: +科里化函数和方法有以下的形式: - * - statements - * -} + func function name(parameters)(parameters) -> return type { + statements + } +以这种形式定义的函数的返回值是另一个函数。举例来说,下面的两个声明时等价的: func addTwoNumbers(a: Int)(b: Int) -> Int { return a + b @@ -534,7 +526,9 @@ A function declared this way is understood as a function whose return type is an 用这种方式声明的函数会被当做一个函数,这个函数的返回类型是另外一个函数。例如,下面2个声明是一样的: -Enumeration Declaration +##Enumeration Declaration + +##枚举声明 An enumeration declaration introduces a named enumeration type into your program. @@ -562,19 +556,10 @@ The following form declares an enumeration type that contains enumeration cases 下面的形式声明了一个枚举类型,包含了所有类型的枚举。 - * enum enumeration name { - - - * - case enumeration case 1 - - * - case enumeration case 2(associated value types) - - - * -} - + enum enumeration name { + case enumeration case 1 + case enumeration case 2(associated value types) + } @@ -591,13 +576,11 @@ The following form declares an enumeration type that contains enumeration cases 下面的形式声明了一种枚举类型,包含同样基本类型的枚举case - enum enumeration name: raw value type { - - case enumeration case 1 = raw value 1 - - case enumeration case 2 = raw value 2 + enum enumeration name: raw value type { + case enumeration case 1 = raw value 1 + case enumeration case 2 = raw value 2 + } - } In this form, each case block consists of the keyword case, followed by one or more enumeration cases, separated by commas. Unlike the cases in the first form, each case has an underlying value, called a raw value, of the same basic type. The type of these values is specified in the raw value type and must represent a literal integer, floating-point number, character, or string. @@ -822,7 +805,8 @@ Protocols are named types, and thus they can appear in all the same places in yo You can use protocols to declare which methods a delegate of a class or structure should implement, as described in Delegation. 你可以使用协议来声明类或者结构应该实现那个方法,如Delegation.描述。 -GRAMMAR OF A PROTOCOL DECLARATION + +>协议声明的语法 protocol-declaration → attributes­opt­protocol­protocol-name­type-inheritance-clause­opt­protocol-body­ protocol-name → identifier­ protocol-body → {­protocol-member-declarations­opt­}­ @@ -833,398 +817,82 @@ protocol-member-declaration → protocol-subscript-declaration­ protocol-member-declaration → protocol-associated-type-declaration­ protocol-member-declarations → protocol-member-declaration­protocol-member-declarations­opt­ +##Protocol Property Declaration -Protocol Method Declaration - -Protocols declare that conforming types must implement a method by including a protocol method declaration in the body of the protocol declaration. Protocol method declarations have the same form as function declarations, with two exceptions: They don’t include a function body, and you can’t provide any default parameter values as part of the function declaration. For examples of conforming types that implement the method requirements of a protocol, see Method Requirements. - -协议表明,conforming类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 - - -To declare a class or static method requirement in a protocol declaration, mark the method declaration with the class keyword. Classes that implement this method also declare the method with the class keyword. Structures that implement it must declare the method with the static keyword instead. If you’re implementing the method in an extension, use the class keyword if you’re extending a class and the static keyword if you’re extending a structure. - -在协议声明里,为了声明一个类或者静态方法要求,使用class关键字来标记方法声明。实现这个方法的类也用class来声明方法。实现它的结构必须用static进行声明。如果你在extension里实现,如果你扩展class使用class,如果是结构使用static -See also Function Declaration. -GRAMMAR OF A PROTOCOL METHOD DECLARATION -protocol-method-declaration → function-head­function-name­generic-parameter-clause­opt­function-signature­ -Protocol Initializer DeclarationProtocols declare that conforming types must implement an initializer by including a protocol initializer declaration in the body of the protocol declaration. Protocol initializer declarations have the same form as initializer declarations, except they don’t include the initializer’s body. -See also Initializer Declaration. -GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION -protocol-initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­ -Protocol Subscript Declaration - -Protocols declare that conforming types must implement a subscript by including a protocol subscript declaration in the body of the protocol declaration. Protocol property declarations have a special form of a subscript declaration: - - - - - * subscript (parameters) -> return type { get set } - - - -Subscript declarations only declare the minimum getter and setter implementation requirements for types that conform to the protocol. If the subscript declaration includes both the get and set keywords, a conforming type must implement both a getter and a setter clause. If the subscript declaration includes only the get keyword, a conforming type must implement at least a getter clause and optionally can implement a setter clause. -See also Subscript Declaration. -GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION -protocol-subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ -Protocol Associated Type Declaration - -Protocols declare associated types using the keyword typealias. An associated type provides an alias for a type that is used as part of a protocol’s declaration. Accosiated types are similiar to type paramters in generic parameter clauses, but they’re associated with Self in the protocol in which they’re declared. In that context, Self refers to the eventual type that conforms to the protocol. For more information and examples, see Associated Types. - -协议用关键字typealias声明关联类型。关联类型为类型提供了一个alias,这个被用作协议声明的一部分。关联类型与在通用参数预计的类型参数相似,但是他们与声明他们的协议中的self相似。在那个环境下,self指的是时间类型。 -See also Type Alias Declaration. -GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION -protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­opt­ -Initializer Declaration - -An initializer declaration introduces an initializer for a class, structure, or enumeration into your program. Initializer declarations are declared using the keyword init and have two basic forms. - -实例化声明引入了类的初始化器到程序里。初始化声明使用关键字init声明,有两种基本形式: - -Structure, enumeration, and class types can have any number of initializers, but the rules and associated behavior for class initializers are different. Unlike structures and enumerations, classes have two kinds of initializers: designated initializers and convenience initializers, as described in Initialization. - -结构,枚举和类类型可以有很多初始器,但是class初始化器的规则和关联行为是不同的。不像结构和枚举类型。类有两种初始化器:制定的和便利的初始化器。 -The following form declares initializers for structures, enumerations, and designated initializers of classes: - - * init(parameters) { - - - * - statements - - * -} - - - -A designated initializer of a class initializes all of the class’s properties directly. It can’t call any other initializers of the same class, and if the class has a superclass, it must call one of the superclass’s designated initializers. If the class inherits any properties from its superclass, one of the superclass’s designated initializers must be called before any of these properties can be set or modified in the current class. -Designated initializers can be declared in the context of a class declaration only and therefore can’t be added to a class using an extension declaration. -Initializers in structures and enumerations can call other declared initializers to delegate part or all of the initialization process. -To declare convenience initializers for a class, prefix the initializer declaration with the context-sensitive keyword convenience. - - * convenience init(parameters) { - - - * - statements - - * -} - - - -Convenience initializers can delegate the initialization process to another convenience initializer or to one of the class’s designated initializers. That said, the initialization processes must end with a call to a designated initializer that ultimately initializes the class’s properties. Convenience initializers can’t call a superclass’s initializers. -You can mark designated and convenience initializers with the required attribute to require that every subclass implement the initializer. Because designated initializers are not inherited by subclasses, they must be implemented directly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or overrides the designated initializers with convenience initializers). Unlike methods, properties, and subscripts, you don’t need to mark overridden initializers with the override keyword. -To see examples of initializers in various type declarations, see Initialization. -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­ -Deinitializer Declaration - -A deinitializer declaration declares a deinitializer for a class type. Deinitializers take no parameters and have the following form: - -析构声明在类中声明了一个析构器。析构器不需要参数,遵循如下的格式: - - - * deinit { - - - * - statements - - * -} - - - - -A deinitializer is called automatically when there are no longer any references to a class object, just before the class object is deallocated. A deinitializer can be declared only in the body of a class declaration—but not in an extension of a class—and each class can have at most one. - -当类中没有对任何其它对象的引用时,在类对象释放之前,析构器会自动的被调用。析构器只能在类的声明体内、声明——但是不能在 类的扩展声明内,每个类最多只能有一个析构器声明。 - -A subclass inherits its superclass’s deinitializer, which is implicitly called just before the subclass object is deallocated. The subclass object is not deallocated until all deinitializers in its inheritance chain have finished executing. - - -Deinitializers are not called directly. - -子类继承了它的超类的析构器,在子类帝乡将要被释放时会被隐式的调用。子类在所有析构器被执行完毕前不会被释放。 -析构器不会被直接调用。 -For an example of how to use a deinitializer in a class declaration, see Deinitialization. -GRAMMAR OF A DEINITIALIZER DECLARATION -deinitializer-declaration → attributes­opt­deinit­code-block­ -Extension Declaration - -An extension declaration allows you to extend the behavior of existing class, structure, and enumeration types. Extension declarations begin with the keyword extension and have the following form: - -扩展声明用于扩展一个已存在的类,结构体,枚举的行为。扩展声明以关键字extension开始,遵循如下的规则: - - - * extension type: adopted protocols { - - - * - declarations - - * -} - - - - -The body of an extension declaration contains zero or more declarations. These declarations can include computed properties, computed static properties, instance methods, static and class methods, initializers, subscript declarations, and even class, structure, and enumeration declarations. Extension declarations can’t contain destructor or protocol declarations, store properties, property observers, or other extension declarations. For a discussion and several examples of extensions that include various kinds of declarations, see Extensions. -一个扩展声明体包括零个或多个声明。这些声明可以包括计算型属性,计算型静态属性,实例方法,静态和类方法,构造器, 附属脚本声明,甚至其他类,结构和枚举声明。扩展声明不能包含析构器,协议声明,存储型属性,属性监测器或其他 的扩展属性。详细讨论和查看包含多种扩展声明的实例,参见扩展一节。 - -Extension declarations can add protocol conformance to an existing class, structure, and enumeration type in the adopted protocols. Extension declarations can’t add class inheritance to an existing class, and therefore the type-inheritance-clause in an extension declaration contains only a list of protocols. +##协议属性声明 -扩展声明可以向现存的类,结构体,枚举内添加一致的协议。扩展声明不能向一个类中添加继承的类,因此 type-inheritance-clause只包含协议列表。 - - -Properties, methods, and initializers of an existing type can’t be overridden in an extension of that type. -属性,方法,现存类型的构造器不能被它们类型的扩展所重写。 - -Extension declarations can contain initializer declarations. That said, if the type you’re extending is defined in another module, an initializer declaration must delegate to an initializer already defined in that module to ensure members of that type are properly initialized. -扩展声明可以包含构造器声明,这意味着,如果你扩展的类型在其他模块中定义,构造器声明必须委托另一个在 那个模块里声明的构造器来恰当的初始化。 - -GRAMMAR OF AN EXTENSION DECLARATION -extension-declaration → extension­type-identifier­type-inheritance-clause­opt­extension-body­ -extension-body → {­declarations­opt­}­ -Subscript Declaration - -A subscript declaration allows you to add subscripting support for objects of a particular type and are typically used to provide a convenient syntax for accessing the elements in a collection, list, or sequence. Subscript declarations are declared using the keyword subscript and have the following form: -附属脚本用于向特定类型的对象添加附属脚本支持,通常为访问集合,列表和序列的元素时提供便利的语法。附属脚本声明使用关键字subscript,声明形式如下: - - - * subscript (parameters) -> return type { - - - * - get { - - - * - statements - - * - } - - - * - set(setter name) { - - - * - statements - - * - } - - - * -} - - - - -Subscript declarations can appear only in the context of a class, structure, enumeration, extension, or protocol declaration. - - -The parameters specify one or more indexes used to access elements of the corresponding type in a subscript expression (for example, the i in the expression object[i]). Although the indexes used to access the elements can be of any type, each parameter must include a type annotation to specify the type of each index. The return type specifies the type of the element being accessed. - -变量(parameters)指定一个或多个用于在相应类型的附属脚本中访问元素的索引(例如,表达式object[i]中的i)。尽管用于元素访问的索引可以是任意类型的,但是每个变量必须包含一个用于指定每种索引类型的类型标注。返回类型(return type)指定被访问的元素的类型。 - - -As with computed properties, subscript declarations support reading and writing the value of the accessed elements. The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly. That said, if you provide a setter clause, you must also provide a getter clause. -和计算性属性一样,附属脚本声明支持对访问元素的读写操作。getter用于读取值,setter用于写入值。setter子句是可选的,当仅需要一个getter子句时,可以将二者都忽略且直接返回请求的值即可。也就是说,如果使用了setter子句,就必须使用getter子句。 - -The setter name and enclosing parentheses are optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is value. That type of the setter name must be the same as the return type. -setter的名字和封闭的括号是可选的。如果使用了setter名称,它会被当做传给setter的变量的名称。如果不使用setter名称,那么传给setter的变量的名称默认是value。setter名称的类型必须与返回类型(return type)的类型相同。 - -You can overload a subscript declaration in the type in which it is declared, as long as the parameters or thereturn type differ from the one you’re overloading. You can also override a subscript declaration inherited from a superclass. When you do so, you must mark the overridden subscript declaration with the overridekeyword. -可以在附属脚本声明的类型中,可以重载附属脚本,只要变量(parameters)或返回类型(return type)与先前的不同即可。此时,必须使用override关键字声明那个被覆盖的附属脚本。(注:好乱啊!到底是重载还是覆盖?!) - -You can also declare subscripts in the context of a protocol declaration, as described in Protocol Subscript Declaration. -同样可以在协议声明的上下文中声明附属脚本,Protocol Subscript Declaration中有所描述。 -For more information about subscripting and to see examples of subscript declarations, see Subscripts. -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­ -Operator Declaration - -An operator declaration introduces a new infix, prefix, or postfix operator into your program and is declared using the contextual keyword operator. - - -You can declare operators of three different fixities: infix, prefix, and postfix. The fixity of an operator specifies the relative position of an operator to its operands. - - -There are three basic forms of an operator declaration, one for each fixity. The fixity of the operator is specified by including the contextual keyword infix, prefix, or postfix between operator and the name of the operator. In each form, the name of the operator can contain only the operator characters defined inOperators. -运算符声明会向程序中引入中缀、前缀或后缀运算符,它使用上下文关键字operator声明。 可以声明三种不同的缀性:中缀、前缀和后缀。操作符的缀性描述了操作符与它的操作数的相对位置。 运算符声明有三种基本形式,每种缀性各一种。运算符的缀性通过在operator和运算符之间添加上下文关键字infix,prefix或postfix来指定。每种形式中,运算符的名字只能包含Operators中定义的运算符字符。 -The following form declares a new infix operator: - - * operator infix operator name { - - - * - precedence precedence level - - * - associativity associativity - - * -} - - - - -An infix operator is a binary operator that is written between its two operands, such as the familiar addition operator (+) in the expression 1 + 2. -中缀运算符是二元运算符,它可以被置于两个操作数之间,比如表达式1 + 2 中的加法运算符(+)。 - -Infix operators can optionally specify a precedence, associativity, or both. -中缀运算符可以可选地指定优先级,结合性,或两者同时指定。 - -The precedence of an operator specifies how tightly an operator binds to its operands in the absence of grouping parentheses. You specify the precedence of an operator by writing the contextual keywordprecedence followed by the precedence level. The precedence level can be any whole number (decimal integer) from 0 to 255; unlike decimal integer literals, it can’t contain any underscore characters. Although the precedence level is a specific number, it is significant only relative to another operator. That is, when two operators compete with each other for their operands, such as in the expression 2 + 3 * 5, the operator with the higher precedence level binds more tightly to its operands. -运算符的优先级可以指定在没有括号包围的情况下,运算符与它的操作数如何紧密绑定的。可以使用上下文关键字precedence并优先级(precedence level)一起来指定一个运算符的优先级。优先级可以是0到255之间的任何一个数字(十进制整数);与十进制整数字面量不同的是,它不可以包含任何下划线字符。尽管优先级是一个特定的数字,但它仅用作与另一个运算符比较(大小)。也就是说,一个操作数可以同时被两个运算符使用时,例如2 + 3 * 5,优先级更高的运算符将优先与操作数绑定。 - -The associativity of an operator specifies how a sequence of operators with the same precedence level are grouped together in the absence of grouping parentheses. You specify the associativity of an operator by writing the contextual keyword associativity followed by the associativity, which is one of the contextual keywords left, right, or none. Operators that are left-associative group left-to-right. For example, the subtraction operator (-) is left-associative, and therefore the expression 4 - 5 - 6 is grouped as (4 - 5) - 6and evaluates to -7. Operators that are right-associative group right-to-left, and operators that are specified with an associativity of none don’t associate at all. Nonassociative operators of the same precedence level can’t appear adjacent to each to other. For example, 1 < 2 < 3 is not a valid expression. -运算符的结合性可以指定在没有括号包围的情况下,优先级相同的运算符以何种顺序被分组的。可以使用上下文关键字associativity并结合性(associativity)一起来指定一个运算符的结合性,其中结合性可以说是上下文关键字left,right或none中的任何一个。左结合运算符以从左到右的形式分组。例如,减法运算符(-)具有左结合性,因此4 - 5 - 6被以(4 - 5) - 6的形式分组,其结果为-7。 右结合运算符以从右到左的形式分组,对于设置为none的非结合运算符,它们不以任何形式分组。具有相同优先级的非结合运算符,不可以互相邻接。例如,表达式1 < 2 < 3非法的。 - -Infix operators that are declared without specifying a precedence or associativity are initialized with a precedence level of 100 and an associativity of none. -声明时不指定任何优先级或结合性的中缀运算符,它们的优先级会被初始化为100,结合性被初始化为none。 -The following form declares a new prefix operator: - - * operator prefix operator name {} - - - - -A prefix operator is a unary operator that is written immediately before its operand, such as the prefix increment operator (++) is in the expression ++i. -缀运算符的声明中不指定优先级。前缀运算符是非结合的。 -Prefix operators declarations don’t specify a precedence level. Prefix operators are nonassociative. -The following form declares a new postfix operator: - - * operator postfix operator name {} - - - -A postfix operator is a unary operator that is written immediately after its operand, such as the postfix increment operator (++) is in the expression i++. -As with prefix operators, postfix operator declarations don’t specify a precedence level. Postfix operators are nonassociative. -After declaring a new operator, you implement it by declaring a function that has the same name as the operator. To see an example of how to create and implement a new operator, see Custom Operators. -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­ - -The body of a protocol contains zero or more protocol member declarations, which describe the conformance requirements that any type adopting the protocol must fulfill. In particular, a protocol can declare that conforming types must implement certain properties, methods, initializers, and subscripts. Protocols can also declare special kinds of type aliases, called associated types, that can specify relationships among the various declarations of the protocol. The protocol member declarations are discussed in detail below. -协议的主体包含洗衣成员声明,它描述了comformance要求,任何实现它的协议都必须满足的要求。特别是,协议可以声明comformin类型,必须实现某个属性,方法,初始化,和子脚本。协议页能声明特殊种类的type aliase,被称作关联类型,可以设置协议里的不同声明的关系。协议成员声明下面会做详细的讨论。 - -Protocol types can inherit from any number of other protocols. When a protocol type inherits from other protocols, the set of requirements from those other protocols are aggregated, and any type that inherits from the current protocol must conform to all those requirements. For an example of how to use protocol inheritance, see Protocol Inheritance. - -协议类型可以从任何数量的其它协议。当一个协议类型从其它洗衣继承时,从那些协议中的要求会被集合,任何从当前协议继承的类型都必须和那些要求一致。 - - - -NOTE -You can also aggregate the conformance requirements of multiple protocols using protocol composition types, as described in Protocol Composition Type and Protocol Composition. - -You can add protocol conformance to a previously declared type by adopting the protocol in an extension declaration of that type. In the extension, you must implement all of the adopted protocol’s requirements. If the type already implements all of the requirements, you can leave the body of the extension declaration empty. - -你可以增加协议conformance到任何一个过去声明的类型通过在那个类型的extendsion中声明。在这个扩展力,你必须实现所有使用的协议的需求。如果那个类型已经实现了所有的要求,扩展声明的主题可以是空的。 +Protocols declare that conforming types must implement a property by including a protocol property declaration in the body of the protocol declaration. Protocol property declarations have a special form of a variable declaration: -By default, types that conform to a protocol must implement all properties, methods, and subscripts declared in the protocol. That said, you can mark these protocol member declarations with the optional attribute to specify that their implementation by a conforming type is optional. The optional attribute can be applied only to protocols that are marked with the objc attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. For more information about how to use the optionalattribute and for guidance about how to access optional protocol members—for example, when you’re not sure whether a conforming type implements them—see Optional Protocol Requirements. +var property name: type { get set } +As with other protocol member declarations, these property declarations declare only the getter and setter requirements for types that conform to the protocol. As a result, you don’t implement the getter or setter directly in the protocol in which it is declared. -默认情况下,与协议一致的类型必须实现所有的属性,方法,和声明的subscripts。也就是说,你可以用opaional属性来标记协议成员,表示他们的实现是可选的。option属性仅仅能被应用到用objc标记的属性。结构,仅仅class类型能采纳和玉包含可选的成员变量的协议一致。对于如何访问可选的协议成员-例如,如果你不确定一个confroming类型是否要实现他们-看见 Optional Protocol Requirements. +The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can’t be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property. For examples of conforming types that implement the property requirements of a protocol, see Property Requirements. -To restrict the adoption of a protocol to class types only, mark the entire protocol declaration with theclass_protocol attribute. Any protocol that inherits from a protocol marked with the class_protocol attribute can likewise be adopted only by a class type. +See also Variable Declaration. -为了限制协议的的只应用到某个class type,用class_protocol属性标记整个协议声明。任何从标记class_protocol协议继承的协议可以只被class 类型采纳。 +GRAMMAR OF A PROTOCOL PROPERTY DECLARATION -NOTE -If a protocol is already marked with the objc attribute, the class_protocol attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the class_protocol attribute explicitly. +protocol-property-declaration → variable-declaration-head­variable-name­type-annotation­getter-setter-keyword-block­ -Protocols are named types, and thus they can appear in all the same places in your code as other named types, as discussed in Protocols as Types. However, you can’t construct an instance of a protocol, because protocols do not actually provide the implementations for the requirements they specify. +##Protocol Method Declaration -You can use protocols to declare which methods a delegate of a class or structure should implement, as described in Delegation. -你可以使用协议来声明类或者结构应该实现那个方法,如Delegation.描述。 +##协议方法声明 -GRAMMAR OF A PROTOCOL DECLARATION -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 Property Declaration +Protocols declare that conforming types must implement a method by including a protocol method declaration in the body of the protocol declaration. Protocol method declarations have the same form as function declarations, with two exceptions: They don’t include a function body, and you can’t provide any default parameter values as part of the function declaration. For examples of conforming types that implement the method requirements of a protocol, see Method Requirements. -Protocols declare that conforming types must implement a property by including a protocol property declaration in the body of the protocol declaration. Protocol property declarations have a special form of a variable declaration: +协议表明,conforming类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 -协议声明conforming类型必须通过在协议声明体里包括协议属性声明实现属性。协议属性声明有一个特殊形式的变量声明。 +To declare a class or static method requirement in a protocol declaration, mark the method declaration with the class keyword. Classes that implement this method also declare the method with the class keyword. Structures that implement it must declare the method with the static keyword instead. If you’re implementing the method in an extension, use the class keyword if you’re extending a class and the static keyword if you’re extending a structure. - * var property name: type { get set } +在协议声明里,为了声明一个类或者静态方法要求,使用class关键字来标记方法声明。实现这个方法的类也用class来声明方法。实现它的结构必须用static进行声明。如果你在extension里实现,如果你扩展class使用class,如果是结构使用static +>GRAMMAR OF A PROTOCOL METHOD DECLARATION +>protocol-method-declaration → function-head­function-name­generic-parameter-clause­opt­function-signature­ -As with other protocol member declarations, these property declarations declare only the getter and setter requirements for types that conform to the protocol. As a result, you don’t implement the getter or setter directly in the protocol in which it is declared. -与其他成员声明一样,这些属性声明仅仅声明getter和setter要求。结果,你不需要在声明的协议里直接实现getter或setter -The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can’t be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property. For examples of conforming types that implement the property requirements of a protocol, see Property Requirements. -See also Variable Declaration. -GRAMMAR OF A PROTOCOL PROPERTY DECLARATION -protocol-property-declaration → variable-declaration-head­variable-name­type-annotation­getter-setter-keyword-block­ +##Protocol Initializer Declaration +##协议构造器声明 -Protocol Method Declaration +Protocols declare that conforming types must implement an initializer by including a protocol initializer declaration in the body of the protocol declaration. Protocol initializer declarations have the same form as initializer declarations, except they don’t include the initializer’s body. -Protocols declare that conforming types must implement a method by including a protocol method declaration in the body of the protocol declaration. Protocol method declarations have the same form as function declarations, with two exceptions: They don’t include a function body, and you can’t provide any default parameter values as part of the function declaration. For examples of conforming types that implement the method requirements of a protocol, see Method Requirements. +See also Initializer Declaration. -协议表明,conforming类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 +>GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION +>protocol-initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­ -To declare a class or static method requirement in a protocol declaration, mark the method declaration with the class keyword. Classes that implement this method also declare the method with the class keyword. Structures that implement it must declare the method with the static keyword instead. If you’re implementing the method in an extension, use the class keyword if you’re extending a class and the static keyword if you’re extending a structure. -在协议声明里,为了声明一个类或者静态方法要求,使用class关键字来标记方法声明。实现这个方法的类也用class来声明方法。实现它的结构必须用static进行声明。如果你在extension里实现,如果你扩展class使用class,如果是结构使用static -See also Function Declaration. -GRAMMAR OF A PROTOCOL METHOD DECLARATION -protocol-method-declaration → function-head­function-name­generic-parameter-clause­opt­function-signature­ -Protocol Initializer DeclarationProtocols declare that conforming types must implement an initializer by including a protocol initializer declaration in the body of the protocol declaration. Protocol initializer declarations have the same form as initializer declarations, except they don’t include the initializer’s body. -See also Initializer Declaration. -GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION -protocol-initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­ -Protocol Subscript Declaration +##Protocol Subscript Declaration Protocols declare that conforming types must implement a subscript by including a protocol subscript declaration in the body of the protocol declaration. Protocol property declarations have a special form of a subscript declaration: +>subscript (parameters) -> return type { get set } + +Subscript declarations only declare the minimum getter and setter implementation requirements for types that conform to the protocol. If the subscript declaration includes both the get and set keywords, a conforming type must implement both a getter and a setter clause. If the subscript declaration includes only the get keyword, a conforming type must implement at least a getter clause and optionally can implement a setter clause. +See also Subscript Declaration. - * subscript (parameters) -> return type { get set } +>GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION +>protocol-subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ +##Protocol Associated Type Declaration -Subscript declarations only declare the minimum getter and setter implementation requirements for types that conform to the protocol. If the subscript declaration includes both the get and set keywords, a conforming type must implement both a getter and a setter clause. If the subscript declaration includes only the get keyword, a conforming type must implement at least a getter clause and optionally can implement a setter clause. -See also Subscript Declaration. -GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION -protocol-subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ -Protocol Associated Type Declaration +##协议关联类型声明 Protocols declare associated types using the keyword typealias. An associated type provides an alias for a type that is used as part of a protocol’s declaration. Accosiated types are similiar to type paramters in generic parameter clauses, but they’re associated with Self in the protocol in which they’re declared. In that context, Self refers to the eventual type that conforms to the protocol. For more information and examples, see Associated Types. 协议用关键字typealias声明关联类型。关联类型为类型提供了一个alias,这个被用作协议声明的一部分。关联类型与在通用参数预计的类型参数相似,但是他们与声明他们的协议中的self相似。在那个环境下,self指的是时间类型。 + See also Type Alias Declaration. -GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION -protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­opt­ -Initializer Declaration + +>GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION + +>protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­op An initializer declaration introduces an initializer for a class, structure, or enumeration into your program. Initializer declarations are declared using the keyword init and have two basic forms. @@ -1235,15 +903,10 @@ Structure, enumeration, and class types can have any number of initializers, but 结构,枚举和类类型可以有很多初始器,但是class初始化器的规则和关联行为是不同的。不像结构和枚举类型。类有两种初始化器:制定的和便利的初始化器。 The following form declares initializers for structures, enumerations, and designated initializers of classes: - * init(parameters) { - - - * - statements - - * -} + init(parameters) { + statements + } A designated initializer of a class initializes all of the class’s properties directly. It can’t call any other initializers of the same class, and if the class has a superclass, it must call one of the superclass’s designated initializers. If the class inherits any properties from its superclass, one of the superclass’s designated initializers must be called before any of these properties can be set or modified in the current class. @@ -1251,41 +914,31 @@ Designated initializers can be declared in the context of a class declaration on Initializers in structures and enumerations can call other declared initializers to delegate part or all of the initialization process. To declare convenience initializers for a class, prefix the initializer declaration with the context-sensitive keyword convenience. - * convenience init(parameters) { - - - * - statements - - * -} + convenience init(parameters) { + statements + } Convenience initializers can delegate the initialization process to another convenience initializer or to one of the class’s designated initializers. That said, the initialization processes must end with a call to a designated initializer that ultimately initializes the class’s properties. Convenience initializers can’t call a superclass’s initializers. You can mark designated and convenience initializers with the required attribute to require that every subclass implement the initializer. Because designated initializers are not inherited by subclasses, they must be implemented directly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or overrides the designated initializers with convenience initializers). Unlike methods, properties, and subscripts, you don’t need to mark overridden initializers with the override keyword. -To see examples of initializers in various type declarations, see Initialization. -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­ -Deinitializer Declaration - -A deinitializer declaration declares a deinitializer for a class type. Deinitializers take no parameters and have the following form: -析构声明在类中声明了一个析构器。析构器不需要参数,遵循如下的格式: +To see examples of initializers in various type declarations, see Initialization. - * deinit { +>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­ - * - statements - - * -} +A deinitializer declaration declares a deinitializer for a class type. Deinitializers take no parameters and have the following form: +析构声明在类中声明了一个析构器。析构器不需要参数,遵循如下的格式: + deinit { + statements + } A deinitializer is called automatically when there are no longer any references to a class object, just before the class object is deallocated. A deinitializer can be declared only in the body of a class declaration—but not in an extension of a class—and each class can have at most one. @@ -1299,29 +952,29 @@ Deinitializers are not called directly. 子类继承了它的超类的析构器,在子类帝乡将要被释放时会被隐式的调用。子类在所有析构器被执行完毕前不会被释放。 析构器不会被直接调用。 -For an example of how to use a deinitializer in a class declaration, see Deinitialization. -GRAMMAR OF A DEINITIALIZER DECLARATION -deinitializer-declaration → attributes­opt­deinit­code-block­ -Extension Declaration -An extension declaration allows you to extend the behavior of existing class, structure, and enumeration types. Extension declarations begin with the keyword extension and have the following form: +For an example of how to use a deinitializer in a class declaration, see Deinitialization. +>GRAMMAR OF A DEINITIALIZER DECLARATION -扩展声明用于扩展一个已存在的类,结构体,枚举的行为。扩展声明以关键字extension开始,遵循如下的规则: +>deinitializer-declaration → attributes­opt­deinit­code-block +##Extension Declaration +##扩展声明 - * extension type: adopted protocols { +An extension declaration allows you to extend the behavior of existing class, structure, and enumeration types. Extension declarations begin with the keyword extension and have the following form: +扩展声明用于扩展一个已存在的类,结构体,枚举的行为。扩展声明以关键字extension开始,遵循如下的规则: - * - declarations - * -} + extension type: adopted protocols { + declarations + } The body of an extension declaration contains zero or more declarations. These declarations can include computed properties, computed static properties, instance methods, static and class methods, initializers, subscript declarations, and even class, structure, and enumeration declarations. Extension declarations can’t contain destructor or protocol declarations, store properties, property observers, or other extension declarations. For a discussion and several examples of extensions that include various kinds of declarations, see Extensions. + 一个扩展声明体包括零个或多个声明。这些声明可以包括计算型属性,计算型静态属性,实例方法,静态和类方法,构造器, 附属脚本声明,甚至其他类,结构和枚举声明。扩展声明不能包含析构器,协议声明,存储型属性,属性监测器或其他 的扩展属性。详细讨论和查看包含多种扩展声明的实例,参见扩展一节。 Extension declarations can add protocol conformance to an existing class, structure, and enumeration type in the adopted protocols. Extension declarations can’t add class inheritance to an existing class, and therefore the type-inheritance-clause in an extension declaration contains only a list of protocols. @@ -1335,46 +988,30 @@ Properties, methods, and initializers of an existing type can’t be overridden Extension declarations can contain initializer declarations. That said, if the type you’re extending is defined in another module, an initializer declaration must delegate to an initializer already defined in that module to ensure members of that type are properly initialized. 扩展声明可以包含构造器声明,这意味着,如果你扩展的类型在其他模块中定义,构造器声明必须委托另一个在 那个模块里声明的构造器来恰当的初始化。 -GRAMMAR OF AN EXTENSION DECLARATION -extension-declaration → extension­type-identifier­type-inheritance-clause­opt­extension-body­ -extension-body → {­declarations­opt­}­ -Subscript Declaration - -A subscript declaration allows you to add subscripting support for objects of a particular type and are typically used to provide a convenient syntax for accessing the elements in a collection, list, or sequence. Subscript declarations are declared using the keyword subscript and have the following form: -附属脚本用于向特定类型的对象添加附属脚本支持,通常为访问集合,列表和序列的元素时提供便利的语法。附属脚本声明使用关键字subscript,声明形式如下: +>GRAMMAR OF AN EXTENSION DECLARATION +>extension-declaration → extension­type-identifier­type-inheritance-clause­opt­extension-body­ +>extension-body → {­declarations­opt­}­ - * subscript (parameters) -> return type { +##Subscript Declaration +##附属脚本声明 - * - get { - +A subscript declaration allows you to add subscripting support for objects of a particular type and are typically used to provide a convenient syntax for accessing the elements in a collection, list, or sequence. Subscript declarations are declared using the keyword subscript and have the following form: +附属脚本用于向特定类型的对象添加附属脚本支持,通常为访问集合,列表和序列的元素时提供便利的语法。附属脚本声明使用关键字subscript,声明形式如下: - * - statements - * +> subscript (`parameter`) -> (return type){ + get{ + `statements` } - - - * - set(setter name) { - - - * - statements - - * + set(`setter name`){ + `statements` } - - - * } - Subscript declarations can appear only in the context of a class, structure, enumeration, extension, or protocol declaration. @@ -1384,24 +1021,30 @@ The parameters specify one or more indexes used to access elements of the corres As with computed properties, subscript declarations support reading and writing the value of the accessed elements. The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly. That said, if you provide a setter clause, you must also provide a getter clause. + 和计算性属性一样,附属脚本声明支持对访问元素的读写操作。getter用于读取值,setter用于写入值。setter子句是可选的,当仅需要一个getter子句时,可以将二者都忽略且直接返回请求的值即可。也就是说,如果使用了setter子句,就必须使用getter子句。 The setter name and enclosing parentheses are optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is value. That type of the setter name must be the same as the return type. + setter的名字和封闭的括号是可选的。如果使用了setter名称,它会被当做传给setter的变量的名称。如果不使用setter名称,那么传给setter的变量的名称默认是value。setter名称的类型必须与返回类型(return type)的类型相同。 You can overload a subscript declaration in the type in which it is declared, as long as the parameters or thereturn type differ from the one you’re overloading. You can also override a subscript declaration inherited from a superclass. When you do so, you must mark the overridden subscript declaration with the overridekeyword. + 可以在附属脚本声明的类型中,可以重载附属脚本,只要变量(parameters)或返回类型(return type)与先前的不同即可。此时,必须使用override关键字声明那个被覆盖的附属脚本。(注:好乱啊!到底是重载还是覆盖?!) You can also declare subscripts in the context of a protocol declaration, as described in Protocol Subscript Declaration. 同样可以在协议声明的上下文中声明附属脚本,Protocol Subscript Declaration中有所描述。 For more information about subscripting and to see examples of subscript declarations, see Subscripts. -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­ -Operator Declaration + +>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­ + +#Operator Declaration An operator declaration introduces a new infix, prefix, or postfix operator into your program and is declared using the contextual keyword operator. @@ -1410,20 +1053,14 @@ You can declare operators of three different fixities: infix, prefix, and postfi There are three basic forms of an operator declaration, one for each fixity. The fixity of the operator is specified by including the contextual keyword infix, prefix, or postfix between operator and the name of the operator. In each form, the name of the operator can contain only the operator characters defined inOperators. + 运算符声明会向程序中引入中缀、前缀或后缀运算符,它使用上下文关键字operator声明。 可以声明三种不同的缀性:中缀、前缀和后缀。操作符的缀性描述了操作符与它的操作数的相对位置。 运算符声明有三种基本形式,每种缀性各一种。运算符的缀性通过在operator和运算符之间添加上下文关键字infix,prefix或postfix来指定。每种形式中,运算符的名字只能包含Operators中定义的运算符字符。 The following form declares a new infix operator: - * operator infix operator name { - - - * - precedence precedence level - - * - associativity associativity - - * -} +> operator infix `operator name`{ + precedence `precedence level` + associativity `associativity` + } @@ -1435,18 +1072,18 @@ Infix operators can optionally specify a precedence, associativity, or both. 中缀运算符可以可选地指定优先级,结合性,或两者同时指定。 The precedence of an operator specifies how tightly an operator binds to its operands in the absence of grouping parentheses. You specify the precedence of an operator by writing the contextual keywordprecedence followed by the precedence level. The precedence level can be any whole number (decimal integer) from 0 to 255; unlike decimal integer literals, it can’t contain any underscore characters. Although the precedence level is a specific number, it is significant only relative to another operator. That is, when two operators compete with each other for their operands, such as in the expression 2 + 3 * 5, the operator with the higher precedence level binds more tightly to its operands. + 运算符的优先级可以指定在没有括号包围的情况下,运算符与它的操作数如何紧密绑定的。可以使用上下文关键字precedence并优先级(precedence level)一起来指定一个运算符的优先级。优先级可以是0到255之间的任何一个数字(十进制整数);与十进制整数字面量不同的是,它不可以包含任何下划线字符。尽管优先级是一个特定的数字,但它仅用作与另一个运算符比较(大小)。也就是说,一个操作数可以同时被两个运算符使用时,例如2 + 3 * 5,优先级更高的运算符将优先与操作数绑定。 The associativity of an operator specifies how a sequence of operators with the same precedence level are grouped together in the absence of grouping parentheses. You specify the associativity of an operator by writing the contextual keyword associativity followed by the associativity, which is one of the contextual keywords left, right, or none. Operators that are left-associative group left-to-right. For example, the subtraction operator (-) is left-associative, and therefore the expression 4 - 5 - 6 is grouped as (4 - 5) - 6and evaluates to -7. Operators that are right-associative group right-to-left, and operators that are specified with an associativity of none don’t associate at all. Nonassociative operators of the same precedence level can’t appear adjacent to each to other. For example, 1 < 2 < 3 is not a valid expression. + 运算符的结合性可以指定在没有括号包围的情况下,优先级相同的运算符以何种顺序被分组的。可以使用上下文关键字associativity并结合性(associativity)一起来指定一个运算符的结合性,其中结合性可以说是上下文关键字left,right或none中的任何一个。左结合运算符以从左到右的形式分组。例如,减法运算符(-)具有左结合性,因此4 - 5 - 6被以(4 - 5) - 6的形式分组,其结果为-7。 右结合运算符以从右到左的形式分组,对于设置为none的非结合运算符,它们不以任何形式分组。具有相同优先级的非结合运算符,不可以互相邻接。例如,表达式1 < 2 < 3非法的。 Infix operators that are declared without specifying a precedence or associativity are initialized with a precedence level of 100 and an associativity of none. 声明时不指定任何优先级或结合性的中缀运算符,它们的优先级会被初始化为100,结合性被初始化为none。 The following form declares a new prefix operator: - * operator prefix operator name {} - - +> operator prefix `operator name`{} A prefix operator is a unary operator that is written immediately before its operand, such as the prefix increment operator (++) is in the expression ++i. @@ -1454,20 +1091,24 @@ A prefix operator is a unary operator that is written immediately before its ope Prefix operators declarations don’t specify a precedence level. Prefix operators are nonassociative. The following form declares a new postfix operator: - * operator postfix operator name {} +> operator postfix `operator name`{} A postfix operator is a unary operator that is written immediately after its operand, such as the postfix increment operator (++) is in the expression i++. As with prefix operators, postfix operator declarations don’t specify a precedence level. Postfix operators are nonassociative. After declaring a new operator, you implement it by declaring a function that has the same name as the operator. To see an example of how to create and implement a new operator, see Custom Operators. -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­ + + +>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 + From 81c955706dcf96334c1137c60ffb1aa161d724e6 Mon Sep 17 00:00:00 2001 From: Xiao Du Date: Sun, 15 Jun 2014 23:31:54 +0800 Subject: [PATCH 065/261] update to 293 --- src/chapter2/09_Classes_and_Structures.md | 64 ++++++++++++++++++++--- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index f944696..ef40eb7 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -237,21 +237,71 @@ var cinema = hd This example declares a constant called `hd` and sets it to a `Resolution` instance initialized with the width and height of full HD video (`1920` pixels wide by `1080` pixels high). -例子中声明了一个名叫`hd`的常量,它的值是一个初始化成全高清视频分辨率(宽`1920`长`1080`)的`Resolution`实例。 +例子中声明了一个名叫`hd`的常量,并将它初始化为全高清视频分辨率(宽`1920`长`1080`)的`Resolution`实例。 -It then declares a variable called cinema and sets it to the current value of hd. Because Resolution is a structure, a copy of the existing instance is made, and this new copy is assigned to cinema. Even though hd and cinema now have the same width and height, they are two completely different instances behind the scenes. +It then declares a variable called `cinema` and sets it to the current value of `hd`. Because `Resolution` is a structure, a copy of the existing instance is made, and this new copy is assigned to `cinema`. Even though `hd` and `cinema` now have the same width and height, they are two completely different instances behind the scenes. +然后例子中声明了一个变量`cinema`,将`hd`的当前值赋给了它。由于`Resolution`是结构体,赋值操作会生成一个新的实例并传递给`cinema`。因此虽然`hd`和`cinema`有相同的宽高,但它们实际上仍是完全不同的实例。 +Next, the `width` property of `cinema` is amended to be the width of the slightly-wider 2K standard used for digital cinema projection (`2048` pixels wide and `1080` pixels high): +接下来,将`cinema`的`width`属性改为数字电影中2K宽屏的标准宽度(宽`2048`像素高`1080`像素): -Next, the width property of cinema is amended to be the width of the slightly-wider 2K standard used for digital cinema projection (2048 pixels wide and 1080 pixels high): - +``` cinema.width = 2048 -Checking the width property of cinema shows that it has indeed changed to be 2048: +``` +Checking the `width` property of `cinema` shows that it has indeed changed to be `2048`: + +检查一下`cinema`的`width`属性的确改成了`2048`: + +``` println("cinema is now \(cinema.width) pixels wide") // prints "cinema is now 2048 pixels wide" -However, the width property of the original hd instance still has the old value of 1920: +``` + +However, the `width` property of the original `hd` instance still has the old value of `1920`: +不过,原来的`hd`实例的`width`属性还是旧值`1920`: +``` println("hd is still \(hd.width) pixels wide") // prints "hd is still 1920 pixels wide" -When cinema was given the current value of hd, the values stored in \ No newline at end of file +``` + +When `cinema` was given the current value of `hd`, the *values* stored in `hd` were copied into the new `cinema` instance. The end result is two completely separate instances, which just happened to contain the same numeric values. Because they are separate instances, setting the width of `cinema` to `2048` doesn’t affect the width stored in `hd`. + +当使用`hd`给`cinema`赋值时,`hd`存储的*值*被复制了一份并传递给`cinema`实例。结果`hd`和`cinema`成为了仅仅是属性值相同的两个完全无关的实例。所以将`cinema`的`width`属性改为`2048`不会影响`hd`中的`width`值。 + +The same behavior applies to enumerations: +枚举也有相同的特性: + +``` +enum CompassPoint { + case North, South, East, West +} +var currentDirection = CompassPoint.West +let rememberedDirection = currentDirection +currentDirection = .East +if rememberedDirection == .West { + println("The remembered direction is still .West") +} +// prints "The remembered direction is still .West" +``` + +When `rememberedDirection` is assigned the value of `currentDirection`, it is actually set to a copy of that value. + +当`rememberedDirection`赋值为`currentDirection`时,实际上只是赋值了值拷贝而已。 + +Changing the value of `currentDirection` thereafter does not affect the copy of the original value that was stored in `rememberedDirection`. +改变`currentDirection` +‌ +Classes Are Reference Types +Unlike value types, reference types are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used instead. + +Here’s an example, using the VideoMode class defined above: + +let tenEighty = VideoMode() +tenEighty.resolution = hd +tenEighty.interlaced = true +tenEighty.name = "1080i" +tenEighty.frameRate = 25.0 +This example declares a new constant called tenEighty and sets it to refer to a new instance of the VideoMode class. The video mode is assigned a copy of the HD resolution of 1920 by 1080 from before. It is set to be interlaced, and is given a name of "1080i". Finally, it is set to a frame rate of 25.0 frames per second. \ No newline at end of file From a854a466576831f5d0ba3918b786ef14ff693d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B1=B3=E5=B0=94?= Date: Mon, 16 Jun 2014 10:15:12 +0800 Subject: [PATCH 066/261] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71b5223..1fd7685 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ The Swift Programming Language 中文化项目 * 枚举 [认领 by 灵吾] * 类和结构体 [认领 by 晓毒] * 属性 [认领 by 周源] - * 方法 [认领 by 米尔] + * 方法 [已完成 by 米尔] * 下标 [已完成 by 递归] * 继承 [认领 by 晗光] * 构造过程 [认领 by 刘康] From 1e6e7225e12502a6d4464e2ad293c20cc550e5f2 Mon Sep 17 00:00:00 2001 From: Henry Ge Date: Mon, 16 Jun 2014 11:22:11 +0800 Subject: [PATCH 067/261] Update 13_Inheritance.md --- src/chapter2/13_Inheritance.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chapter2/13_Inheritance.md b/src/chapter2/13_Inheritance.md index 43126f7..3cfffac 100644 --- a/src/chapter2/13_Inheritance.md +++ b/src/chapter2/13_Inheritance.md @@ -209,6 +209,7 @@ The `override` keyword also prompts the Swift compiler to check that your overri ##访问父类的方法,属性和脚本 When you provide a method, property, or subscript override for a subclass, it is sometimes useful to use the existing superclass implementation as part of your override. For example, you can refine the behavior of that existing implementation or store a modified value in an existing inherited variable. + 当你访问父类的方法,属性或脚本时,有时在你的重写版本中使用已存在的父类实现会很有作用。比如你可以优化一个已有的实现或者在一个继承来的变量重储存一个修改过的值。 Where this is appropriate, you access the superclass version of a method, property, or subscript by using the `super` prefix: From e4582b94d1b037bc9998d28ea8d71e5481f91381 Mon Sep 17 00:00:00 2001 From: yozomk Date: Mon, 16 Jun 2014 12:48:16 +0800 Subject: [PATCH 068/261] MK translate ARC --- .../16_Automatic_Reference_Counting.md | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index e69de29..f964029 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -0,0 +1,36 @@ +# 自动引用计数 + +Swift uses Automatic Reference Counting (ARC) to track and manage your app’s memory usage. In most cases, this means that memory management “just works” in Swift, and you do not need to think about memory management yourself. ARC automatically frees up the memory used by class instances when those instances are no longer needed. + +However, in a few cases ARC requires more information about the relationships between parts of your code in order to manage memory for you. This chapter describes those situations and shows how you enable ARC to manage all of your app’s memory. + +Swift 使用自动引用计数(ARC)机制跟踪和管理APP的内存使用,大部分情况下,此机制是自动工作的,你没有必要考虑内存管理的事情。当一个类实例不在需要的时候,ARC会自动释放其占用的内存。 + +但少数情况下,ARC需要更多关于你代码之间的关系信息来帮你管理内存。本章介绍了这些情况,并向你示范如何启用ARC来管理你的APP的全部内存。 + +> NOTE +> +> Reference counting only applies to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference. + +> 注意 +> +> 引用计数仅适用于类实例。结构体和枚举类型是值类型而非引用类型, 也不是按照引用的方式存储和传递的,所以不适用引用计数机制。 + +## ARC是如何工作的 +Every time you create a new instance of a class, ARC allocates a chunk of memory to store information about that instance. This memory holds information about the type of the instance, together with the values of any stored properties associated with that instance. + +Additionally, when an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purposes instead. This ensures that class instances do not take up space in memory when they are no longer needed. + +当你创建一个类实例的时候,ARC会为之分配一块内存来存储该实例的相关信息。这些信息包括:该实例的类型及其相关的属性和值。当该实例不再需要的时候,ARC会释放其占用的内存留作他用。这种机制保证了不需要的类实例不会一直占用内存空间。 + +However, if ARC were to deallocate an instance that was still in use, it would no longer be possible to access that instance’s properties, or call that instance’s methods. Indeed, if you tried to access the instance, your app would most likely crash. + +To make sure that instances don’t disappear while they are still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists. + +然而,如果ARC释放了一个正在使用的类实例的内存,那就会导致该实例的方法和属性都不能访问。而且,如果你试图访问已被ARC释放的实例,你的APP很可能会崩溃。 + +为了确保使用中的类实例不会无端消失(被ARC回收),ARC会跟踪和统计每个类实例被多少属性,常量,变量所引用。即使只有一个活动引用存在,该类实例也不会被ARC回收。 + +To make this possible, whenever you assign a class instance to a property, constant, or variable, that property, constant, or variable makes a strong reference to the instance. The reference is called a “strong“ reference because it keeps a firm hold on that instance, and does not allow it to be deallocated for as long as that strong reference remains. + +为了保证ARC机制的有效运行,无论何时你将一个类实例分配给一个属性、常量或一个变量,那么这个属性、常量或变量与类实例之间将建立起一种强引用关系。之所以称为“强引用”,是它会牢牢保持与类实例的引用关系,只要指向类实例的强引用存在,该实例就是不允许被销毁的。 From ce2c83ca97779966949899789527f5a90f306202 Mon Sep 17 00:00:00 2001 From: yozomk Date: Mon, 16 Jun 2014 12:55:42 +0800 Subject: [PATCH 069/261] MK translate ARC fix mistakes --- src/chapter2/16_Automatic_Reference_Counting.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index f964029..cb7f3d7 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -4,7 +4,7 @@ Swift uses Automatic Reference Counting (ARC) to track and manage your app’s m However, in a few cases ARC requires more information about the relationships between parts of your code in order to manage memory for you. This chapter describes those situations and shows how you enable ARC to manage all of your app’s memory. -Swift 使用自动引用计数(ARC)机制跟踪和管理APP的内存使用,大部分情况下,此机制是自动工作的,你没有必要考虑内存管理的事情。当一个类实例不在需要的时候,ARC会自动释放其占用的内存。 +Swift 使用自动引用计数(ARC)机制跟踪和管理APP的内存使用,大部分情况下,此机制是自动工作的,你没有必要考虑内存管理的事情。当一个类实例不再需要的时候,ARC会自动释放其占用的内存。 但少数情况下,ARC需要更多关于你代码之间的关系信息来帮你管理内存。本章介绍了这些情况,并向你示范如何启用ARC来管理你的APP的全部内存。 @@ -21,13 +21,13 @@ Every time you create a new instance of a class, ARC allocates a chunk of memory Additionally, when an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purposes instead. This ensures that class instances do not take up space in memory when they are no longer needed. -当你创建一个类实例的时候,ARC会为之分配一块内存来存储该实例的相关信息。这些信息包括:该实例的类型及其相关的属性和值。当该实例不再需要的时候,ARC会释放其占用的内存留作他用。这种机制保证了不需要的类实例不会一直占用内存空间。 +当你创建一个类实例的时候,ARC会为之分配一块内存来存储该实例的相关信息。这些信息包括:该实例的类型及其相关的属性和值。当该实例不再需要的时候,ARC会释放其占用的内存留作他用。这种机制保证了不需要的类实例占用内存会及时得到释放。 However, if ARC were to deallocate an instance that was still in use, it would no longer be possible to access that instance’s properties, or call that instance’s methods. Indeed, if you tried to access the instance, your app would most likely crash. To make sure that instances don’t disappear while they are still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists. -然而,如果ARC释放了一个正在使用的类实例的内存,那就会导致该实例的方法和属性都不能访问。而且,如果你试图访问已被ARC释放的实例,你的APP很可能会崩溃。 +然而,如果ARC释放了一个正在使用的类实例的内存,那会导致该实例的方法和属性都不能访问。而且,如果你试图访问已被ARC释放的实例,你的APP很可能会崩溃。 为了确保使用中的类实例不会无端消失(被ARC回收),ARC会跟踪和统计每个类实例被多少属性,常量,变量所引用。即使只有一个活动引用存在,该类实例也不会被ARC回收。 From adb7c129eda10f644ef7550665534cdb090222e1 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Mon, 16 Jun 2014 14:36:45 +0800 Subject: [PATCH 070/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 55 ++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index c9d6fac..372c65a 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -995,6 +995,7 @@ Extension declarations can contain initializer declarations. That said, if the t ##Subscript Declaration + ##附属脚本声明 A subscript declaration allows you to add subscripting support for objects of a particular type and are typically used to provide a convenient syntax for accessing the elements in a collection, list, or sequence. Subscript declarations are declared using the keyword subscript and have the following form: @@ -1011,7 +1012,6 @@ A subscript declaration allows you to add subscripting support for objects of a } - Subscript declarations can appear only in the context of a class, structure, enumeration, extension, or protocol declaration. @@ -1044,61 +1044,88 @@ For more information about subscripting and to see examples of subscript declara >subscript-head → attributes­opt­subscript­parameter-clause­ >subscript-result → ->­attributes­opt­type­ -#Operator Declaration +##Operator Declaration + +##运算符声明 An operator declaration introduces a new infix, prefix, or postfix operator into your program and is declared using the contextual keyword operator. +运算符声明引入了新的中缀,前缀或后缀运算到程序中,使用上下文关键字operator声明。 You can declare operators of three different fixities: infix, prefix, and postfix. The fixity of an operator specifies the relative position of an operator to its operands. +可以声明3种不同的缀:中缀、前缀和后缀。一个运算符的缀规定了一个它相对于它的操作数的相对位置。 -There are three basic forms of an operator declaration, one for each fixity. The fixity of the operator is specified by including the contextual keyword infix, prefix, or postfix between operator and the name of the operator. In each form, the name of the operator can contain only the operator characters defined inOperators. +There are three basic forms of an operator declaration, one for each fixity. The fixity of the operator is specified by including the contextual keyword infix, prefix, or postfix between operator and the name of the operator. In each form, the name of the operator can contain only the operator characters defined in Operators. + +运算符声明有三种基本形式,每种缀性各一种。运算符的缀性通过在operator和运算符之间添加上下文关键字infix,prefix或postfix来指定。对于每种形式,运算符的名字只能包含Operators中定义的运算符字符。 -运算符声明会向程序中引入中缀、前缀或后缀运算符,它使用上下文关键字operator声明。 可以声明三种不同的缀性:中缀、前缀和后缀。操作符的缀性描述了操作符与它的操作数的相对位置。 运算符声明有三种基本形式,每种缀性各一种。运算符的缀性通过在operator和运算符之间添加上下文关键字infix,prefix或postfix来指定。每种形式中,运算符的名字只能包含Operators中定义的运算符字符。 The following form declares a new infix operator: +下面这种形式声明了一个新的中缀运算符: + > operator infix `operator name`{ precedence `precedence level` associativity `associativity` } - - An infix operator is a binary operator that is written between its two operands, such as the familiar addition operator (+) in the expression 1 + 2. -中缀运算符是二元运算符,它可以被置于两个操作数之间,比如表达式1 + 2 中的加法运算符(+)。 + +中缀运算符是二元运算符,置于两个操作数之间,比如我们熟悉的表达式1 + 2 中的加法运算符(+)。 Infix operators can optionally specify a precedence, associativity, or both. -中缀运算符可以可选地指定优先级,结合性,或两者同时指定。 -The precedence of an operator specifies how tightly an operator binds to its operands in the absence of grouping parentheses. You specify the precedence of an operator by writing the contextual keywordprecedence followed by the precedence level. The precedence level can be any whole number (decimal integer) from 0 to 255; unlike decimal integer literals, it can’t contain any underscore characters. Although the precedence level is a specific number, it is significant only relative to another operator. That is, when two operators compete with each other for their operands, such as in the expression 2 + 3 * 5, the operator with the higher precedence level binds more tightly to its operands. +中缀运算符可以指定优先级,结合性,或两者同时指定。 + +The precedence of an operator specifies how tightly an operator binds to its operands in the absence of grouping parentheses. You specify the precedence of an operator by writing the contextual keyword precedence followed by the precedence level. The precedence level can be any whole number (decimal integer) from 0 to 255; unlike decimal integer literals, it can’t contain any underscore characters. Although the precedence level is a specific number, it is significant only relative to another operator. That is, when two operators compete with each other for their operands, such as in the expression 2 + 3 * 5, the operator with the higher precedence level binds more tightly to its operands. -运算符的优先级可以指定在没有括号包围的情况下,运算符与它的操作数如何紧密绑定的。可以使用上下文关键字precedence并优先级(precedence level)一起来指定一个运算符的优先级。优先级可以是0到255之间的任何一个数字(十进制整数);与十进制整数字面量不同的是,它不可以包含任何下划线字符。尽管优先级是一个特定的数字,但它仅用作与另一个运算符比较(大小)。也就是说,一个操作数可以同时被两个运算符使用时,例如2 + 3 * 5,优先级更高的运算符将优先与操作数绑定。 +运算符的优先级指定了在没有分组括号的情况下,运算符与它的操作数绑定的紧密程度。可以使用上下文关键字precedence和优先等级一起来指定一个运算符的优先级。优先级可以是0到255之间的任何一个数字(十进制整数);与十进制整数字面量不同的是,它不可以包含任何下划线字符。尽管优先级是一个特定的数字,但它仅用作与另一个运算符比较(大小)。也就是说,一个操作数可以同时被两个运算符使用时,例如2 + 3 * 5,优先级更高的运算符将优先与操作数绑定。 -The associativity of an operator specifies how a sequence of operators with the same precedence level are grouped together in the absence of grouping parentheses. You specify the associativity of an operator by writing the contextual keyword associativity followed by the associativity, which is one of the contextual keywords left, right, or none. Operators that are left-associative group left-to-right. For example, the subtraction operator (-) is left-associative, and therefore the expression 4 - 5 - 6 is grouped as (4 - 5) - 6and evaluates to -7. Operators that are right-associative group right-to-left, and operators that are specified with an associativity of none don’t associate at all. Nonassociative operators of the same precedence level can’t appear adjacent to each to other. For example, 1 < 2 < 3 is not a valid expression. +The associativity of an operator specifies how a sequence of operators with the same precedence level are grouped together in the absence of grouping parentheses. You specify the associativity of an operator by writing the contextual keyword associativity followed by the associativity, which is one of the contextual keywords left, right, or none. Operators that are left-associative group left-to-right. For example, the subtraction operator (-) is left-associative, and therefore the expression 4 - 5 - 6 is grouped as (4 - 5) - 6 and evaluates to -7. Operators that are right-associative group right-to-left, and operators that are specified with an associativity of none don’t associate at all. Nonassociative operators of the same precedence level can’t appear adjacent to each to other. For example, 1 < 2 < 3 is not a valid expression. -运算符的结合性可以指定在没有括号包围的情况下,优先级相同的运算符以何种顺序被分组的。可以使用上下文关键字associativity并结合性(associativity)一起来指定一个运算符的结合性,其中结合性可以说是上下文关键字left,right或none中的任何一个。左结合运算符以从左到右的形式分组。例如,减法运算符(-)具有左结合性,因此4 - 5 - 6被以(4 - 5) - 6的形式分组,其结果为-7。 右结合运算符以从右到左的形式分组,对于设置为none的非结合运算符,它们不以任何形式分组。具有相同优先级的非结合运算符,不可以互相邻接。例如,表达式1 < 2 < 3非法的。 +运算符的结合性明确了,没有分组的括号包围的情况下,优先级相同的运算符以何种顺序被分组的。使用上下文关键字associativity和结合性(associativity)一起来指定一个运算符的结合性,其中结合性的值是上下文关键字left,right或none之一。左结合运算符以从左到右的形式分组。例如,减法运算符(-)具有左结合性,因此表达式4 - 5 - 6以(4 - 5) - 6的形式分组,其结果为-7。 右结合运算符以从右到左的形式分组,对于设置为none的非结合运算符,它们不以任何形式分组。具有相同优先级的非结合运算符,不可以互相邻接。例如,1 < 2 < 3 就是一个无效的表达式 Infix operators that are declared without specifying a precedence or associativity are initialized with a precedence level of 100 and an associativity of none. -声明时不指定任何优先级或结合性的中缀运算符,它们的优先级会被初始化为100,结合性被初始化为none。 + +如果再声明时不指定任何优先级或结合性,中缀运算符的优先级会被初始化为100,结合性被初始化为none。 + The following form declares a new prefix operator: +下面的形式声明了一个新的前缀运算符: + > operator prefix `operator name`{} A prefix operator is a unary operator that is written immediately before its operand, such as the prefix increment operator (++) is in the expression ++i. -缀运算符的声明中不指定优先级。前缀运算符是非结合的。 + +前缀运算符一元运算符,紧跟在操作数之前,比如表达式 ++i 中的前缀递增运算符(++)。 + Prefix operators declarations don’t specify a precedence level. Prefix operators are nonassociative. + +前缀缀运算符的声明中不指定优先级。前缀运算符是非结合的。 + The following form declares a new postfix operator: +下面的形式声明了一个新的后缀运算符: + + > operator postfix `operator name`{} A postfix operator is a unary operator that is written immediately after its operand, such as the postfix increment operator (++) is in the expression i++. + +后缀运算符一元运算符,紧跟在操作数之前,比如表达式 i++ 中的前后缀递增运算符(++)。 + As with prefix operators, postfix operator declarations don’t specify a precedence level. Postfix operators are nonassociative. +与前缀运算符一样,后缀运算符声明不会指定优先级。后缀运算符也是非结合性的。 + After declaring a new operator, you implement it by declaring a function that has the same name as the operator. To see an example of how to create and implement a new operator, see Custom Operators. +在声明了一个新的运算符止呕,要声明一个和运算符同名的函数来实现它。如何创建和实现新的操作符,请看Custom Operators。 + + >GRAMMAR OF AN OPERATOR DECLARATION > From ba36c8f2577eb6da65c77ed656123dd97cab57b7 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Mon, 16 Jun 2014 15:02:39 +0800 Subject: [PATCH 071/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 372c65a..5bf5a67 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -963,7 +963,7 @@ For an example of how to use a deinitializer in a class declaration, see Deiniti An extension declaration allows you to extend the behavior of existing class, structure, and enumeration types. Extension declarations begin with the keyword extension and have the following form: -扩展声明用于扩展一个已存在的类,结构体,枚举的行为。扩展声明以关键字extension开始,遵循如下的规则: +扩展声明用于扩展一个已存在的类,结构体,枚举的行为。扩展声明以关键字extension开始,有如下的形式: @@ -975,15 +975,15 @@ An extension declaration allows you to extend the behavior of existing class, st The body of an extension declaration contains zero or more declarations. These declarations can include computed properties, computed static properties, instance methods, static and class methods, initializers, subscript declarations, and even class, structure, and enumeration declarations. Extension declarations can’t contain destructor or protocol declarations, store properties, property observers, or other extension declarations. For a discussion and several examples of extensions that include various kinds of declarations, see Extensions. -一个扩展声明体包括零个或多个声明。这些声明可以包括计算型属性,计算型静态属性,实例方法,静态和类方法,构造器, 附属脚本声明,甚至其他类,结构和枚举声明。扩展声明不能包含析构器,协议声明,存储型属性,属性监测器或其他 的扩展属性。详细讨论和查看包含多种扩展声明的实例,参见扩展一节。 +扩展声明体包括零个或多个声明。这些声明可以包括计算型属性,计算型静态属性,实例方法,静态和类方法,构造器,附属脚本声明,甚至其它类,结构和枚举声明。扩展声明不能包含析构器,协议声明,存储型属性,属性监测器或其它的扩展属性。详细讨论和查看包含多种扩展声明的实例,参见Extensions一节。 Extension declarations can add protocol conformance to an existing class, structure, and enumeration type in the adopted protocols. Extension declarations can’t add class inheritance to an existing class, and therefore the type-inheritance-clause in an extension declaration contains only a list of protocols. -扩展声明可以向现存的类,结构体,枚举内添加一致的协议。扩展声明不能向一个类中添加继承的类,因此 type-inheritance-clause只包含协议列表。 +扩展声明可以向存在的类,结构体,枚举添加一致的协议。扩展声明不能向一个类中添加类的继承,因此type-inheritance-clause只包含协议的列表。 Properties, methods, and initializers of an existing type can’t be overridden in an extension of that type. -属性,方法,现存类型的构造器不能被它们类型的扩展所重写。 +现存类型的属性,方法,构造器不能被它们的扩展重写。 Extension declarations can contain initializer declarations. That said, if the type you’re extending is defined in another module, an initializer declaration must delegate to an initializer already defined in that module to ensure members of that type are properly initialized. 扩展声明可以包含构造器声明,这意味着,如果你扩展的类型在其他模块中定义,构造器声明必须委托另一个在 那个模块里声明的构造器来恰当的初始化。 @@ -999,7 +999,8 @@ Extension declarations can contain initializer declarations. That said, if the t ##附属脚本声明 A subscript declaration allows you to add subscripting support for objects of a particular type and are typically used to provide a convenient syntax for accessing the elements in a collection, list, or sequence. Subscript declarations are declared using the keyword subscript and have the following form: -附属脚本用于向特定类型的对象添加附属脚本支持,通常为访问集合,列表和序列的元素时提供便利的语法。附属脚本声明使用关键字subscript,声明形式如下: + +附属脚本声明用于向特定类型的对象添加附属脚本支持,通常为访问集合,列表和序列的元素提供便利的语法。使用关键字subscript,声明形式如下: > subscript (`parameter`) -> (return type){ @@ -1014,27 +1015,31 @@ A subscript declaration allows you to add subscripting support for objects of a Subscript declarations can appear only in the context of a class, structure, enumeration, extension, or protocol declaration. +附属脚本声明只能出现在类,结构,枚举类型,扩展或协议声明的上下文中。 The parameters specify one or more indexes used to access elements of the corresponding type in a subscript expression (for example, the i in the expression object[i]). Although the indexes used to access the elements can be of any type, each parameter must include a type annotation to specify the type of each index. The return type specifies the type of the element being accessed. -变量(parameters)指定一个或多个用于在相应类型的附属脚本中访问元素的索引(例如,表达式object[i]中的i)。尽管用于元素访问的索引可以是任意类型的,但是每个变量必须包含一个用于指定每种索引类型的类型标注。返回类型(return type)指定被访问的元素的类型。 +参数(parameters)指定了一个或多个用于在相应类型的附属脚本表达式中访问元素的索引(例如,表达式object[i]中的i)。尽管用于访问元素的索引可以是任意类型,但是每个参数必须包含一个类型标注来指定每种索引的类型。返回类型(return type)指定被访问的元素的类型。 As with computed properties, subscript declarations support reading and writing the value of the accessed elements. The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly. That said, if you provide a setter clause, you must also provide a getter clause. -和计算性属性一样,附属脚本声明支持对访问元素的读写操作。getter用于读取值,setter用于写入值。setter子句是可选的,当仅需要一个getter子句时,可以将二者都忽略且直接返回请求的值即可。也就是说,如果使用了setter子句,就必须使用getter子句。 +和计算型属性一样,附属脚本声明支持对访问元素的读写。getter用于读取,setter用于写入。setter子句是可选的,当仅需要一个getter子句时,可以将二者都忽略,直接返回请求的值即可。也就是说,如果提供了setter子句,getter子句也必须要有。 The setter name and enclosing parentheses are optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is value. That type of the setter name must be the same as the return type. -setter的名字和封闭的括号是可选的。如果使用了setter名称,它会被当做传给setter的变量的名称。如果不使用setter名称,那么传给setter的变量的名称默认是value。setter名称的类型必须与返回类型(return type)的类型相同。 +setter的名字和封闭的括号是可选的。如果提供了setter名称,它会被setter的参数名。如果没有提供setter名称,那么传给setter的参数的名称默认是value。setter名称的类型必须与返回类型(return type)的类型相同。 -You can overload a subscript declaration in the type in which it is declared, as long as the parameters or thereturn type differ from the one you’re overloading. You can also override a subscript declaration inherited from a superclass. When you do so, you must mark the overridden subscript declaration with the overridekeyword. +You can overload a subscript declaration in the type in which it is declared, as long as the parameters or the return type differ from the one you’re overloading. You can also override a subscript declaration inherited from a superclass. When you do so, you must mark the overridden subscript declaration with the override keyword. -可以在附属脚本声明的类型中,可以重载附属脚本,只要变量(parameters)或返回类型(return type)与先前的不同即可。此时,必须使用override关键字声明那个被覆盖的附属脚本。(注:好乱啊!到底是重载还是覆盖?!) +在附属脚本声明的类型中,可以重载附属脚本,只要参数(parameters)或返回类型(return type) 与先前的不同即可。如果这样做的话,必须使用override关键字声明那个被覆盖的附属脚本。 You can also declare subscripts in the context of a protocol declaration, as described in Protocol Subscript Declaration. -同样可以在协议声明的上下文中声明附属脚本,Protocol Subscript Declaration中有所描述。 -For more information about subscripting and to see examples of subscript declarations, see Subscripts. +在协议声明的上下文中,也声明附属脚本,正如Protocol Subscript Declaration描述的一样。 + +For more information about subscripting and to see examples of subscript declarations, see Subscripts。. + +获取更多关于附属脚本的信息和例子,请参看Subscripts。 >GRAMMAR OF A SUBSCRIPT DECLARATION From 0844031824e0751c77f771faea9928f724d6dee9 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Mon, 16 Jun 2014 15:14:41 +0800 Subject: [PATCH 072/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 5bf5a67..af55c43 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -765,7 +765,7 @@ You can extend the behavior of a class type with an extension declaration, as di A protocol declaration introduces a named protocol type into your program. Protocol declarations are declared using the keyword protocol and have the following form: -一个协议声明引入了一命令协议类型到你的程序中。协议声明可以使用protoco来声明,有如下的形式: +协议声明引入命名的协议类型到程序中,以使用protoco来声明,有如下的形式: protocol protocol name: inherited protocols { @@ -774,16 +774,20 @@ A protocol declaration introduces a named protocol type into your program. Proto The body of a protocol contains zero or more protocol member declarations, which describe the conformance requirements that any type adopting the protocol must fulfill. In particular, a protocol can declare that conforming types must implement certain properties, methods, initializers, and subscripts. Protocols can also declare special kinds of type aliases, called associated types, that can specify relationships among the various declarations of the protocol. The protocol member declarations are discussed in detail below. -协议的主体包含洗衣成员声明,它描述了comformance要求,任何实现它的协议都必须满足的要求。特别是,协议可以声明comformin类型,必须实现某个属性,方法,初始化,和子脚本。协议页能声明特殊种类的typealiase,被称作关联类型,可以设置协议里的不同声明的关系。协议成员声明下面会做详细的讨论。 +协议的主体包含0或多个协议成员声明,它描述了任何实现它的协议都必须满足的一致性要求。特别是,一致性的协议必须实现某个属性,方法,构造器,和附属脚本。协议也能声明特殊种类的类型别名,被、称作关联类型,设置协议里的不同声明的关系。下面会对协议成员声明会做详细的讨论 Protocol types can inherit from any number of other protocols. When a protocol type inherits from other protocols, the set of requirements from those other protocols are aggregated, and any type that inherits from the current protocol must conform to all those requirements. For an example of how to use protocol inheritance, see Protocol Inheritance. -协议类型可以从任何数量的其它协议。当一个协议类型从其它洗衣继承时,从那些协议中的要求会被集合,任何从当前协议继承的类型都必须和那些要求一致。 +协议类型可以继承任意数量的其它协议。如果一个协议类型从其它协议继承时任何从当前协议继承的类型都必须和从那些协议中的要求集合一致。如何使用协议继承,请查看Protocol Inheritance. NOTE +注意 + You can also aggregate the conformance requirements of multiple protocols using protocol composition types, as described in Protocol Composition Type and Protocol Composition. +你也可以使用协议符合类型聚合多个协议的一致性要求。 + You can add protocol conformance to a previously declared type by adopting the protocol in an extension declaration of that type. In the extension, you must implement all of the adopted protocol’s requirements. If the type already implements all of the requirements, you can leave the body of the extension declaration empty. 你可以增加协议conformance到任何一个过去声明的类型通过在那个类型的extendsion中声明。在这个扩展力,你必须实现所有使用的协议的需求。如果那个类型已经实现了所有的要求,扩展声明的主题可以是空的。 From cb853bf041afd243591a715b59a7cab25abe9785 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Mon, 16 Jun 2014 15:38:01 +0800 Subject: [PATCH 073/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 45 ++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index af55c43..8bb94bd 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -827,13 +827,22 @@ protocol-member-declarations → protocol-member-declaration­protocol-member-de Protocols declare that conforming types must implement a property by including a protocol property declaration in the body of the protocol declaration. Protocol property declarations have a special form of a variable declaration: -var property name: type { get set } +协议声明一致性类型必须通过在协议声明体里包括一个协议属性声明来实现属性。协议属性声明有一个特殊形式的变量声明: + + var property name: type { get set } + As with other protocol member declarations, these property declarations declare only the getter and setter requirements for types that conform to the protocol. As a result, you don’t implement the getter or setter directly in the protocol in which it is declared. +与其它协议成员声明一样,这些属性声明只声明了与协议一致的类型的getter和setter要求。结果,你不能在它声明的协议里实现getter货setter + The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can’t be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property. For examples of conforming types that implement the property requirements of a protocol, see Property Requirements. +getter和setter要求可以通过一致性类型以各种方式满足。如果属性声明包含get和set关键词,一致性类型就可以用可读写(实现了getter和setter)的存储型变量属性或计算型属性,但是属性不能以常量属性或只读计算型属性实现。如果属性声明仅仅包含get关键词的话,它可以作为任意类型的属性被实现。比如说实现了协议的属性要求的一致性类型,参见属性要求。 + See also Variable Declaration. +更多参见变量声明 + GRAMMAR OF A PROTOCOL PROPERTY DECLARATION protocol-property-declaration → variable-declaration-head­variable-name­type-annotation­getter-setter-keyword-block­ @@ -845,7 +854,7 @@ protocol-property-declaration → variable-declaration-head­variable-name­type Protocols declare that conforming types must implement a method by including a protocol method declaration in the body of the protocol declaration. Protocol method declarations have the same form as function declarations, with two exceptions: They don’t include a function body, and you can’t provide any default parameter values as part of the function declaration. For examples of conforming types that implement the method requirements of a protocol, see Method Requirements. -协议表明,conforming类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 +协议声明conforming类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 To declare a class or static method requirement in a protocol declaration, mark the method declaration with the class keyword. Classes that implement this method also declare the method with the class keyword. Structures that implement it must declare the method with the static keyword instead. If you’re implementing the method in an extension, use the class keyword if you’re extending a class and the static keyword if you’re extending a structure. @@ -858,12 +867,17 @@ To declare a class or static method requirement in a protocol declaration, mark >protocol-method-declaration → function-head­function-name­generic-parameter-clause­opt­function-signature­ ##Protocol Initializer Declaration + ##协议构造器声明 Protocols declare that conforming types must implement an initializer by including a protocol initializer declaration in the body of the protocol declaration. Protocol initializer declarations have the same form as initializer declarations, except they don’t include the initializer’s body. +协议声明了一致性类型必须在协议声明的主体里通过引入一个协议构造器声明来实现一个构造器。协议构造器声明 除了不包含构造器体外,和构造器声明有着相同的形式. + See also Initializer Declaration. +更多请参阅构造器声明。 + >GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION >protocol-initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­ @@ -873,6 +887,7 @@ See also Initializer Declaration. Protocols declare that conforming types must implement a subscript by including a protocol subscript declaration in the body of the protocol declaration. Protocol property declarations have a special form of a subscript declaration: +协议声明了一致性类型必须在协议声明的主体里通过引入一个协议附属脚本声明来实现一个附属脚本。协议属性声明 对附属脚本声明有一个特殊的形式: >subscript (parameters) -> return type { get set } @@ -880,6 +895,8 @@ Protocols declare that conforming types must implement a subscript by including Subscript declarations only declare the minimum getter and setter implementation requirements for types that conform to the protocol. If the subscript declaration includes both the get and set keywords, a conforming type must implement both a getter and a setter clause. If the subscript declaration includes only the get keyword, a conforming type must implement at least a getter clause and optionally can implement a setter clause. See also Subscript Declaration. +附属脚本声明只为和协议一致的类型声明了必需的最小数量的的getter和setter。如果附属脚本申明包含get和set关键字, 一致的类型也必须有一个getter和setter语句。如果附属脚本声明值包含get关键字,一致的类型必须至少包含一个 getter语句,可以选择是否包含setter语句。 + >GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION >protocol-subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ @@ -898,13 +915,19 @@ See also Type Alias Declaration. >protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­op + +##Initializer Declaration + +##构造器声明 + An initializer declaration introduces an initializer for a class, structure, or enumeration into your program. Initializer declarations are declared using the keyword init and have two basic forms. -实例化声明引入了类的初始化器到程序里。初始化声明使用关键字init声明,有两种基本形式: +构造器声明引入了类的初始化器到程序里。初始化声明使用关键字init声明,有两种基本形式: Structure, enumeration, and class types can have any number of initializers, but the rules and associated behavior for class initializers are different. Unlike structures and enumerations, classes have two kinds of initializers: designated initializers and convenience initializers, as described in Initialization. 结构,枚举和类类型可以有很多初始器,但是class初始化器的规则和关联行为是不同的。不像结构和枚举类型。类有两种初始化器:制定的和便利的初始化器。 + The following form declares initializers for structures, enumerations, and designated initializers of classes: @@ -914,10 +937,20 @@ The following form declares initializers for structures, enumerations, and desig A designated initializer of a class initializes all of the class’s properties directly. It can’t call any other initializers of the same class, and if the class has a superclass, it must call one of the superclass’s designated initializers. If the class inherits any properties from its superclass, one of the superclass’s designated initializers must be called before any of these properties can be set or modified in the current class. + +类的指定构造器将类的所有属性直接初始化。如果类有超类,它不能调用该类的其他构造器,它只能调用超类的一个 指定构造器。如果该类从它的超类处继承了任何属性,这些属性在当前类内被赋值或修饰时,必须带哦用一个超类的 指定构造器。 + Designated initializers can be declared in the context of a class declaration only and therefore can’t be added to a class using an extension declaration. + +指定构造器可以在类声明的上下文中声明,因此它不能用扩展声明的方法加入一个类中。 + Initializers in structures and enumerations can call other declared initializers to delegate part or all of the initialization process. + +结构体和枚举的构造器可以带哦用其他的已声明的构造器,来委托其中一个火全部进行初始化过程。 + To declare convenience initializers for a class, prefix the initializer declaration with the context-sensitive keyword convenience. +以关键字convenience来声明一个类的便利构造器: convenience init(parameters) { statements @@ -925,10 +958,16 @@ To declare convenience initializers for a class, prefix the initializer declarat Convenience initializers can delegate the initialization process to another convenience initializer or to one of the class’s designated initializers. That said, the initialization processes must end with a call to a designated initializer that ultimately initializes the class’s properties. Convenience initializers can’t call a superclass’s initializers. + +便利构造器可以将初始化过程委托给另一个便利构造器或类的一个指定构造器。这意味着,类的初始化过程必须 以一个将所有类属性完全初始化的指定构造器的调用作为结束。便利构造器不能调用超类的构造器。 + You can mark designated and convenience initializers with the required attribute to require that every subclass implement the initializer. Because designated initializers are not inherited by subclasses, they must be implemented directly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or overrides the designated initializers with convenience initializers). Unlike methods, properties, and subscripts, you don’t need to mark overridden initializers with the override keyword. +你可以使用requierd关键字,将便利构造器和指定构造器标记为每个子类的构造器都必须拥有的。因为指定构造器 不被子类继承,他们必须被立即执行。当子类直接执行所有超类的指定构造器(或使用便利构造器重写指定构造器)时, 必需的便利构造器可以被隐式的执行,亦可以被继承。不像方法,附属脚本那样,你不需要为这些重写的构造器标注 overrride关键字。 + To see examples of initializers in various type declarations, see Initialization. +查看更多关于不同声明方法的构造器的例子,参阅构造过程一节。 >GRAMMAR OF AN INITIALIZER DECLARATION From 4df0cdd7eb337c37823a19121bc1f9c5ff8ba204 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Mon, 16 Jun 2014 16:51:56 +0800 Subject: [PATCH 074/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 40 ++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 8bb94bd..b73baee 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -634,11 +634,11 @@ To check the values of enumeration cases, use a switch statement, as shown in Ma raw-value-style-enum-case → enum-case-name­raw-value-assignment­opt­ raw-value-assignment → =­literal­ -Structure Declaration - +##Structure Declaration +##结构声明 A structure declaration introduces a named structure type into your program. Structure declarations are declared using the keyword struct and have the following form: -一个结构声明引入了一个命名的类型到你的程序。结构声明使用struct声明,采用以下的形式: +结构声明引入了命名的类型到程序中。结构声明使用struct声明,采用以下的形式: struct structure name: adopted protocols { declarations @@ -671,11 +671,11 @@ There are three ways create an instance of a previously declared structure: The process of initializing a structure’s declared properties is described in Initialization. -初始化结构的声明的属性的过程在Initialization里描述的一样。 +初始化一个结构的声明的属性的过程在Initialization里描述的一样。 Properties of a structure instance can be accessed using dot (.) syntax, as described in Accessing Properties. -一个结构实例的属性使用通过。语法来访问。 +一个结构实例的属性使用通过.法来访问。 Structures are value types; instances of a structure are copied when assigned to variables or constants, or when passed as arguments to a function call. For information about value types, see Structures and Enumerations Are Value Types. @@ -697,7 +697,7 @@ You can extend the behavior of a structure type with an extension declaration, a A class declaration introduces a named class type into your program. Class declarations are declared using the keyword class and have the following form: -类型声明映入了一个命令的类型到你的程序中。类声明使用关键字class声明,采用下面的形式: +类型声明引入了命名的类型到程序中。类声明使用关键字class声明,采用下面的形式: class class name: superclass, adopted protocols { @@ -707,7 +707,7 @@ A class declaration introduces a named class type into your program. Class decla The body of a class contains zero or more declarations. These declarations can include both stored and computed properties, instance methods, class methods, initializers, a single destructor method, type aliases, and even other class, structure, and enumeration declarations. Class declarations can’t contain protocol declarations. For a discussion and several examples of classes that include various kinds of declarations, see Classes and Structures. -一个class的主题会包含0或多个声明。这些声明可以包括可存储的和可计算的属性,实例方法,类方法,初始化器,一个析构函数,type aliases ,和甚至其他的class,结构,枚举声明。类声明不能包括是协议声明。 +一个class的主题会包含0或多个声明。这些声明可以包括可存储的和可计算的属性,实例方法,类方法,初始化器,一个析构函数,类型 别名,和甚至其它的class,结构,枚举声明。类声明不能包括是协议声明。 A class type can inherit from only one parent class, its superclass, but can adopt any number of protocols. The superclass appears first in the type-inheritance-clause, followed by any adopted protocols. 一个class类只能从一个父类中继承,但是可以有多个洗衣。超类首先出现在类型继承语句中,后面跟着采用的协议。 @@ -718,11 +718,11 @@ As discussed in Initializer Declaration, classes can have designated and conveni A class can override properties, methods, and initializers of its superclass. Overridden methods and properties must be marked with the override keyword. -类可以重写他的超类的属性,方法和初始化器。重写的方法和属性必须都使用overrid来标记。 +类可以重写它超类的属性,方法和构造器。重写的方法和属性必须都使用override来标记。 Although properties and methods declared in the superclass are inherited by the current class, designated initializers declared in the superclass are not. That said, if the current class overrides all of the superclass’s designated initializers, it inherits the superclass’s convenience initializers. Swift classes do not inherit from a universal base class. -尽管在子类中声明的属性和方法可以被当前的类继承,但是在超类中指定的初始化器却不行。也就是说,如果当前类重写了超类的所有指定的初始化器,它就会继续超类的便利的初始化器。Swift类不会从通用的基类中继承。 +尽管在子类中声明的属性和方法可以被当前的类继承,但是在超类中指定的构造器却不行。也就是说,如果当前类重写了超类的所有指定的构造器,它就会继续超类的便利构造器。Swift类不会从通用的基类中继承。 There are two ways create an instance of a previously declared class: @@ -734,24 +734,23 @@ There are two ways create an instance of a previously declared class: * If no initializers are declared, and all properties of the class declaration were given initial values, call the class’s default initializer, as described in Default Initializers. - 如果没有声明的初始化器,类声明的素有属性会有一个初始化值,是通过调用类的默认的初始化器来完成的。正如Default Initializers描述的。 + 如果没有声明的初始化器,类声明的素有属性会有一个初始化值,是通过调用类的默认的初始化器来完成的。正如Default Initializers描述的。 Access properties of a class instance with dot (.) syntax, as described in Accessing Properties. -访问类的属性使用,如Accessing Properties的一样。 +使用.语法访问类的属性,如Accessing Properties描述的一样。 Classes are reference types; instances of a class are referred to, rather than copied, when assigned to variables or constants, or when passed as arguments to a function call. For information about reference types, see Structures and Enumerations Are Value Types. -类是引用类型;在被赋值给变量货常量的时候,类的实例会被引用而不是被赋值,当被作为参数传递给函数调用的时候。更多信息,参考 - Structures and Enumerations Are Value Types.。 +类是引用类型;在被赋值给变量或常量的时候,或者当被作为参数传递给函数调用的时候,类的实例会被引用而不是被复制。更多信息,参考Structures and Enumerations Are Value Types.。 You can extend the behavior of a class type with an extension declaration, as discussed in Extension Declaration. -你可以使用extension声明来扩展类的行为,正如Extension Desclaration. +可以使用extension声明来扩展类的行为,如Extension Desclaration描述的那样. > GRAMMAR OF A CLASS DECLARATION @@ -765,7 +764,7 @@ You can extend the behavior of a class type with an extension declaration, as di A protocol declaration introduces a named protocol type into your program. Protocol declarations are declared using the keyword protocol and have the following form: -协议声明引入命名的协议类型到程序中,以使用protoco来声明,有如下的形式: +协议声明引入命名的协议类型到程序中,用关键字protocol来声明,有如下的形式: protocol protocol name: inherited protocols { @@ -790,21 +789,26 @@ You can also aggregate the conformance requirements of multiple protocols using You can add protocol conformance to a previously declared type by adopting the protocol in an extension declaration of that type. In the extension, you must implement all of the adopted protocol’s requirements. If the type already implements all of the requirements, you can leave the body of the extension declaration empty. -你可以增加协议conformance到任何一个过去声明的类型通过在那个类型的extendsion中声明。在这个扩展力,你必须实现所有使用的协议的需求。如果那个类型已经实现了所有的要求,扩展声明的主题可以是空的。 +你可以增加协议conformance到任何一个过去声明的类型通过在那个类型的extendsion中声明。在这个扩展里,你必须实现所有使用的协议的需求。如果那个类型已经实现了所有的要求,扩展声明的主题可以是空的。 By default, types that conform to a protocol must implement all properties, methods, and subscripts declared in the protocol. That said, you can mark these protocol member declarations with the optional attribute to specify that their implementation by a conforming type is optional. The optional attribute can be applied only to protocols that are marked with the objc attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. For more information about how to use the optionalattribute and for guidance about how to access optional protocol members—for example, when you’re not sure whether a conforming type implements them—see Optional Protocol Requirements. -默认情况下,与协议一致的类型必须实现所有的属性,方法,和声明的subscripts。也就是说,你可以用opaional属性来标记协议成员,表示他们的实现是可选的。option属性仅仅能被应用到用objc标记的属性。结构,仅仅class类型能采纳和玉包含可选的成员变量的协议一致。对于如何访问可选的协议成员-例如,如果你不确定一个confroming类型是否要实现他们-看见 Optional Protocol Requirements. +默认情况下,与协议一致的类型必须实现所有的属性,方法,和声明的附属脚本。也就是说,你可以用opaional属性来标记协议成员,表示他们的实现是可选的。option属性仅仅能被应用到objc标记的属性。结构,仅仅class类型能采纳和玉包含可选的成员变量的协议一致。对于如何访问可选的协议成员-例如,如果你不确定一个一致性类型是否要实现-查看一下 Optional Protocol Requirements. To restrict the adoption of a protocol to class types only, mark the entire protocol declaration with theclass_protocol attribute. Any protocol that inherits from a protocol marked with the class_protocol attribute can likewise be adopted only by a class type. -为了限制协议的的只应用到某个class type,用class_protocol属性标记整个协议声明。任何从标记class_protocol协议继承的协议可以只被class 类型采纳。 +为了限制协议的的只应用到某个class type,用 class_protocol属性标记整个协议声明。任何从标记class_protocol 协议继承的协议可以只被class类型采纳。 NOTE +注意 + If a protocol is already marked with the objc attribute, the class_protocol attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the class_protocol attribute explicitly. +如果协议已经用objc标记过了,class_protocol会隐式的应用到那个协议;没有必要显式的用class_protocol标记协议。 + Protocols are named types, and thus they can appear in all the same places in your code as other named types, as discussed in Protocols as Types. However, you can’t construct an instance of a protocol, because protocols do not actually provide the implementations for the requirements they specify. +协议是命名类型,因此在你的代码里它们可以像其它命名类型一样出现在左右同样的地方,如在协议里的类型一样。不管怎么样,你不能构造协议的实例,因为协议实际上不能提供它们 You can use protocols to declare which methods a delegate of a class or structure should implement, as described in Delegation. 你可以使用协议来声明类或者结构应该实现那个方法,如Delegation.描述。 From 451d5f61fc99542aa028f7c9a7a8e407e4e1200f Mon Sep 17 00:00:00 2001 From: mofengfly Date: Mon, 16 Jun 2014 18:07:28 +0800 Subject: [PATCH 075/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 76 +++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index b73baee..991e0a8 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -47,6 +47,8 @@ In Swift, most declarations are also definitions in the sense that they are impl The module scope defines the code that’s visible to other code in Swift source files that are part of the same module. The top-level code in a Swift source file consists of zero or more statements, declarations, and expressions. Variables, constants, and other named declarations that are declared at the top-level of a source file are visible to code in every source file that is part of the same module。 +模块范围定义了在模块中对Swift源文件可见的代码。在Swift源文件中顶层的代码由0或多个语句、声明和表达式组成。在源文件的最上层声明的变量、常量和其它命名的声明对于同一模块的其它源文件代码都是可见的。 + >GRAMMAR OF A TOP-LEVEL DECLARATION >top-level-declaration → statements­opt @@ -213,7 +215,7 @@ The following form declares a computed variable or computed property: } You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class, structure, enumeration, or extension declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, it is referred to as a computed variable. When it is declared in the context of a class, structure, or extension declaration, it is referred to as a computed property. -可以在全局范围,局部范围,或者类、结构、枚举或者可扩展的声明。如果这类型是的变量声明在全局或者函数的局部返回声明,指的是可计算的变量。如果它在一个雷,结构或者扩展声明里,它就是指的可计算的属性。 +可以在全局范围,局部范围,或者类、结构、枚举或者定义可扩展的声明。如果这类型是的变量声明在全局或者函数的局部返回声明,指的是计算型变量。如果它在一个雷,结构或者扩展声明里,它就是指的是计算型属性。 The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly, as described in Read-Only Computed Properties. But if you provide a setter clause, you must also provide a getter clause. @@ -427,22 +429,22 @@ You can override the default behavior for how parameter names are used with one A second name before the local parameter name gives the parameter an external name, which can be different than the local parameter name. The external parameter name must be used when the function is called. The corresponding argument must have the external name in function or method calls. -本地参数名的在第二个名字给参数了一个外部的名字,这个不同于本地的参数名。外部的参数名必须在函数调用的时候调用。相应的参数必须在函数或者方法调用时有外部名字。 +本地参数名前的第二个名字给参数了一个外部的名字,这个不同于本地的参数名。外部的参数名必须在函数调用的时候调用。相应的参数必须在函数或者方法调用时有外部名字。 A hash symbol (#) before a parameter name indicates that the name should be used as both an external and a local parameter name. It has the same meaning as writing the local parameter name twice. The corresponding argument must have this name in function or method calls. -参数名前的#显示了名字应该被作为外部和本地参数只哟个。它和写入本地参数名两次有同样的意义。嘴硬的参数在函数或者参数调用时必须有这个名字。 +参数名前的#显示了名字应该同时被作为外部和本地参数使用。它和写入本地参数名两次有同样的意义。相应的参数在函数或者参数调用时必须有这个名字。 An underscore (_) before a local parameter name gives that parameter no name to be used in function calls. The corresponding argument must have no name in function or method calls. -本次参数名的下划线在函数调用的时候让参数没有使用名字。对应的参在函数或者方法调用的时候不可以有名字。 +本地参数名前面的下划线在函数调用的时候让参数可以没有名字。相应的参数在函数或者方法调用的时候没有名字。 ##Special Kinds of Parameters ##特殊类型的参数 Parameters can be ignored, take a variable number of values, and provide default values using the following forms: -参数可以忽略,可以是可变数量的值,使用如下的形式提供默认值 +参数可以忽略,需要不同数量的值,会提供默认值。使用如下的形式: _ : <#parameter type#. @@ -460,19 +462,19 @@ A parameter with a base type name followed immediately by three dots (...) is un A parameter with an equals sign (=) and an expression after its type is understood to have a default value of the given expression. If the parameter is omitted when calling the function, the default value is used instead. If the parameter is not omitted, it must have its name in the function call. For example, f() and f(x: 7) are both valid calls to a function with a single default parameter named x, but f(7) is invalid because it provides a value without a name. -带有等号(=)的参数和它类型后面的表达式会被仿作给定表达式的默认类型。如果参数在调用函数的时候被忽略,默认值会被使用。例如,f()和f(x:7)都是有效的调用对于带有单个默认的的参数名x的函数,但是f(7)是有效的,因为它提供了没有名字的值。 +带有等号(=)的参数和它的类型后面的表达式会被当作给定表达式的默认类型。如果参数在调用函数的时候被忽略,默认值会被使用。例如,对于带有单个默认的的参数名x的函数,f()和f(x:7)都是有效的调用,但是f(7)是有效的,因为它提供了没有名字的值。 -Special Kinds of MethodsMethods on an enumeration or a structure that modify self must be marked with the mutating keyword at the start of the function declaration. +Special Kinds of Methods on an enumeration or a structure that modify self must be marked with the mutating keyword at the start of the function declaration. -枚举类型或者结构上的方法,会修改self的必须在函数声明的开始标记为mutating关键字 +会修改self的枚举类型或者结构上的方法,必须在函数声明的开始标记为mutating关键字 Methods that override a superclass method must be marked with the override keyword at the start of the function declaration. It is an error to override a method without the override keyword or to use the overridekeyword on a method that doesn’t override a superclass method. -重写超类方法的方法必须在函数声明的开头override关键词标记。不适用override就重写方法会产生错误或者使用override在没有override超类的方法 +重写超类方法的方法必须在函数声明的开头override关键词标记。没有override就重写方法会产生错误或者使用override在没有重载超类的方法 Methods associated with a type rather than an instance of a type must be marked with the static attribute for enumerations and structures or the class attribute for classes. -与type相关而不是类型实例相关的方法必须使用使用static属性来标记枚举、结构或者类的class属性 +与type相关而不是类型实例相关的方法必须使用使用static属性来标记枚举、结构或者类的class属性。 ##Curried Functions and Methods @@ -523,7 +525,7 @@ Curried functions and methods have the following form: A function declared this way is understood as a function whose return type is another function. For example, the following two declarations are equivalent: -用这种方式声明的函数会被当做一个函数,这个函数的返回类型是另外一个函数。例如,下面2个声明是一样的: +用这种方式声明的函数会被当做一个函数,它的返回类型是另外一个函数。例如,下面2个声明是一样的: ##Enumeration Declaration @@ -532,12 +534,12 @@ A function declared this way is understood as a function whose return type is an An enumeration declaration introduces a named enumeration type into your program. -枚举声明引入一个个名叫枚举的类型到你的程序中。 +枚举声明引入了名叫枚举的类型程序中。 Enumeration declarations have two basic forms and are declared using the keyword enum. The body of an enumeration declared using either form contains zero or more values—called enumeration cases—and any number of declarations, including computed properties, instance methods, static methods, initializers, type aliases, and even other enumeration, structure, and class declarations. Enumeration declarations can’t contain destructor or protocol declarations. -枚举声明有2中基本的形式,使用关键字enum声明。一个枚举类型的的主题使用2中形式之一,包含0或者蒙多的值-被称作枚举类型还有任何数量的声明,包括可计算的属性,实例方法,静态方法,初始化,类型aliase,和其它的枚举、结构和类声明。枚举声明不能包含析构或者协议声明。 +枚举声明有2种基本的形式,使用关键字enum声明。一个枚举类型的的主体会使用这2种形式之一,包含0或多个值-被称作枚举类型。还有任何数量的声明,包括计算型的属性,实例方法,静态方法,初始化,类型别名,和其它的枚举、结构和类声明。枚举声明不能包含析构或者协议声明。 Unlike classes and structures, enumeration types do not have an implicitly provided default initializer; all initializers must be declared explicitly. Initializers can delegate to other initializers in the enumeration, but the initialization process is complete only after an initializer assigns one of the enumeration cases to self. @@ -545,11 +547,13 @@ Unlike classes and structures, enumeration types do not have an implicitly provi Like structures but unlike classes, enumerations are value types; instances of an enumeration are copied when assigned to variables or constants, or when passed as arguments to a function call. For information about value types, see Structures and Enumerations Are Value Types. -类似结构但是不像类,枚举累心是值类型;一个枚举实例在赋值给变量或者常量的时候会被复制,或者在传递参数给函数调用的的时候。 +类似结构但是不像类,枚举是值类型;一个枚举实例在赋值给变量或者常量的时候会被复制,或者在传递参数给函数调用的的时候。 + +You can extend the behavior of an enumeration type with an extension declaration, as discussed in Extension Declaration. + -You can extend the behavior of an enumeration type with an extension declaration, as discussed inExtension Declaration. -Enumerations with Cases of Any Type +可以使用extension声明扩展枚举类型的行为,如果Extension Declaration Enumerations with Cases of Any Type描述的那样。 The following form declares an enumeration type that contains enumeration cases of any type: @@ -565,11 +569,11 @@ The following form declares an enumeration type that contains enumeration cases Enumerations declared in this form are sometimes called discriminated unions in other programming languages. -用这种形式声明的枚举在其他语言里有时候被叫做discriminated unions +用这种形式声明的枚举在其它语言里有时候被叫做discriminated unions In this form, each case block consists of the keyword case followed by one or more enumeration cases, separated by commas. The name of each case must be unique. Each case can also specify that it stores values of a given type. These types are specified in the associated value types tuple, immediately following the name of the case. For more information and to see examples of cases with associated value types, seeAssociated Values. -用这种方式,每个cast块由关键字case组成,case后跟着一个或者多个逗号分隔的枚举情况。每个case的名字必须是唯一的。每个case页能够确定他存储一个给定类型的值。这些类型用关联只类型元组来设置,后面紧梗着case的名字。获取更多信息,看下关联至类型的的例子,请看Assiciated Values Enumerations with Raw Cases Values +用这种方式,每个cast块由关键字case组成,case后跟着一个或者多个逗号分隔的枚举case。每个case的名字必须是唯一的。每个case也能够确定它存储一个给定类型的值。这些类型用关联值类型元组来设置,后面紧跟着case的名字。获取更多信息,或关联值类型的的例子,请看Assiciated Values Enumerations with Raw Cases Values The following form declares an enumeration type that contains enumeration cases of the same basic type: @@ -589,7 +593,7 @@ In this form, each case block consists of the keyword case, followed by one or m Each case must have a unique name and be assigned a unique raw value. If the raw value type is specified as Int and you don’t assign a value to the cases explicitly, they are implicitly assigned the values 0, 1, 2, and so on. Each unassigned case of type Int is implicitly assigned a raw value that is automatically incremented from the raw value of the previous case. -每个case必须有一个唯一的名字,然后被赋值为一个单独的原生值。如果原生值用Int设置,你不需要要显式的赋值,他们可以默认的赋值1,1,2等等。每个没有赋值的Int类型会被赋值为原生类型,可以自动的从之前的case的原生值增加。 +每个case必须有一个唯一的名字,然后被赋值为一个单独的原生值。如果原生值用Int设置,你不需要要显式的赋值,他们可以默认的赋值1,1,2等等。每个没有赋值的Int类型会被赋值为原生类型,可以自动的从之前的case的原生值递增。 enum ExampleEnum: Int { @@ -611,10 +615,12 @@ The raw value of an enumeration case can be accessed by calling its toRaw method To reference the case of an enumeration type, use dot (.) syntax, as in EnumerationType.EnumerationCase. When the enumeration type can be inferred from context, you can omit it (the dot is still required), as described inEnumeration Syntax and Implicit Member Expression. -正如EnumerationType.EnumerationCase,可以使用。来引用一个enumeration类型的case,正如inEnumeration Syntax and Implicit Member Expression.描述的。 +正如EnumerationType.EnumerationCase,可以使用语法.来引用一个enumeration类型的case,正如inEnumeration Syntax and Implicit Member Expression所描述的。 To check the values of enumeration cases, use a switch statement, as shown in Matching Enumeration Values with a Switch Statement. The enumeration type is pattern-matched against the enumeration case patterns in the case blocks of the switch statement, as described in Enumeration Case Pattern. +使用switch语句来检验枚举事件的值,正如使用switch语句匹配枚举值(Matching Enumeration Values with a Switch Statement)一节描述的那样。 + >GRAMMAR OF AN ENUMERATION DECLARATION > enum-declaration → attributes­opt­union-style-enum­ attributes­opt­raw-value-style-enum­ @@ -638,7 +644,7 @@ To check the values of enumeration cases, use a switch statement, as shown in Ma ##结构声明 A structure declaration introduces a named structure type into your program. Structure declarations are declared using the keyword struct and have the following form: -结构声明引入了命名的类型到程序中。结构声明使用struct声明,采用以下的形式: +结构声明引入了命名的类型到程序中。结构声明使用struct声明,采用如下的形式: struct structure name: adopted protocols { declarations @@ -876,7 +882,7 @@ To declare a class or static method requirement in a protocol declaration, mark Protocols declare that conforming types must implement an initializer by including a protocol initializer declaration in the body of the protocol declaration. Protocol initializer declarations have the same form as initializer declarations, except they don’t include the initializer’s body. -协议声明了一致性类型必须在协议声明的主体里通过引入一个协议构造器声明来实现一个构造器。协议构造器声明 除了不包含构造器体外,和构造器声明有着相同的形式. +协议声明了一致性类型必须在协议声明的主体里通过引入一个协议构造器声明来实现一个构造器。协议构造器声明除了不包含构造器体外,和构造器声明有着相同的形式. See also Initializer Declaration. @@ -891,7 +897,7 @@ See also Initializer Declaration. Protocols declare that conforming types must implement a subscript by including a protocol subscript declaration in the body of the protocol declaration. Protocol property declarations have a special form of a subscript declaration: -协议声明了一致性类型必须在协议声明的主体里通过引入一个协议附属脚本声明来实现一个附属脚本。协议属性声明 对附属脚本声明有一个特殊的形式: +协议声明了一致性类型必须在协议声明的主体里通过引入一个协议附属脚本声明来实现一个附属脚本。协议属性声明对附属脚本声明有一个特殊附属脚本声明形式: >subscript (parameters) -> return type { get set } @@ -899,7 +905,7 @@ Protocols declare that conforming types must implement a subscript by including Subscript declarations only declare the minimum getter and setter implementation requirements for types that conform to the protocol. If the subscript declaration includes both the get and set keywords, a conforming type must implement both a getter and a setter clause. If the subscript declaration includes only the get keyword, a conforming type must implement at least a getter clause and optionally can implement a setter clause. See also Subscript Declaration. -附属脚本声明只为和协议一致的类型声明了必需的最小数量的的getter和setter。如果附属脚本申明包含get和set关键字, 一致的类型也必须有一个getter和setter语句。如果附属脚本声明值包含get关键字,一致的类型必须至少包含一个 getter语句,可以选择是否包含setter语句。 +附属脚本声明只为和协议一致的类型声明了必需的最小数量的的getter和setter。如果附属脚本声明包含get和set关键字, 一致的类型也必须有一个getter和setter语句。如果附属脚本声明值包含get关键字,一致的类型必须至少包含一个 getter语句,可以选择是否包含setter语句。 >GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION @@ -911,10 +917,12 @@ See also Subscript Declaration. Protocols declare associated types using the keyword typealias. An associated type provides an alias for a type that is used as part of a protocol’s declaration. Accosiated types are similiar to type paramters in generic parameter clauses, but they’re associated with Self in the protocol in which they’re declared. In that context, Self refers to the eventual type that conforms to the protocol. For more information and examples, see Associated Types. -协议用关键字typealias声明关联类型。关联类型为类型提供了一个alias,这个被用作协议声明的一部分。关联类型与在通用参数预计的类型参数相似,但是他们与声明他们的协议中的self相似。在那个环境下,self指的是时间类型。 +协议用关键字typealias声明关联类型。关联类型为类型提供了一个别名,这个被用作协议声明的一部分。关联类型与在通用参数子句的类型参数相似,但是他们与声明他们的协议中的self相似。在那个环境下,self指的是时间类型。 See also Type Alias Declaration. +也可以参看 Type Alias Declaration. + >GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION >protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­op @@ -926,14 +934,15 @@ See also Type Alias Declaration. An initializer declaration introduces an initializer for a class, structure, or enumeration into your program. Initializer declarations are declared using the keyword init and have two basic forms. -构造器声明引入了类的初始化器到程序里。初始化声明使用关键字init声明,有两种基本形式: +构造器声明引入了类的构造器器到程序中。初始化声明使用关键字init声明,有两种基本形式: Structure, enumeration, and class types can have any number of initializers, but the rules and associated behavior for class initializers are different. Unlike structures and enumerations, classes have two kinds of initializers: designated initializers and convenience initializers, as described in Initialization. -结构,枚举和类类型可以有很多初始器,但是class初始化器的规则和关联行为是不同的。不像结构和枚举类型。类有两种初始化器:制定的和便利的初始化器。 +结构,枚举和类类型可以有很多构造器,但是类构造器的规则和关联行为是不同的。不像结构和枚举类型。类有两种构造器:指定的和便利的构造器器。 The following form declares initializers for structures, enumerations, and designated initializers of classes: +下面的形式声明了结构,枚举和类指定的构造器 init(parameters) { statements @@ -942,15 +951,15 @@ The following form declares initializers for structures, enumerations, and desig A designated initializer of a class initializes all of the class’s properties directly. It can’t call any other initializers of the same class, and if the class has a superclass, it must call one of the superclass’s designated initializers. If the class inherits any properties from its superclass, one of the superclass’s designated initializers must be called before any of these properties can be set or modified in the current class. -类的指定构造器将类的所有属性直接初始化。如果类有超类,它不能调用该类的其他构造器,它只能调用超类的一个 指定构造器。如果该类从它的超类处继承了任何属性,这些属性在当前类内被赋值或修饰时,必须带哦用一个超类的 指定构造器。 +类的指定构造器将类的所有属性直接初始化。如果类有超类,它不能调用该类的其它构造器,它只能调用超类的一个 指定构造器。如果该类从它的超类处继承了任何属性,这些属性在当前类内被赋值或修饰时,必须带调用一个超类的 指定构造器。 Designated initializers can be declared in the context of a class declaration only and therefore can’t be added to a class using an extension declaration. -指定构造器可以在类声明的上下文中声明,因此它不能用扩展声明的方法加入一个类中。 +指定构造器可以在类声明的上下文中声明,因此它不能用扩展声明的方法被加入到一个类中。 Initializers in structures and enumerations can call other declared initializers to delegate part or all of the initialization process. -结构体和枚举的构造器可以带哦用其他的已声明的构造器,来委托其中一个火全部进行初始化过程。 +结构体和枚举的构造器可以调用其它的已声明的构造器,来委托部分或全部初始化过程。 To declare convenience initializers for a class, prefix the initializer declaration with the context-sensitive keyword convenience. @@ -990,17 +999,19 @@ A deinitializer declaration declares a deinitializer for a class type. Deinitial A deinitializer is called automatically when there are no longer any references to a class object, just before the class object is deallocated. A deinitializer can be declared only in the body of a class declaration—but not in an extension of a class—and each class can have at most one. -当类中没有对任何其它对象的引用时,在类对象释放之前,析构器会自动的被调用。析构器只能在类的声明体内、声明——但是不能在 类的扩展声明内,每个类最多只能有一个析构器声明。 +当类中没有对任何其它对象的引用时,在类对象释放之前,析构器会自动的被调用。析构器只能在类的声明体内、而不能在 类的扩展内声明,每个类最多只能有一个析构器声明。 A subclass inherits its superclass’s deinitializer, which is implicitly called just before the subclass object is deallocated. The subclass object is not deallocated until all deinitializers in its inheritance chain have finished executing. +子类继承了它的超类的析构器,在子类帝乡将要被释放时会被隐式的调用。子类在所有析构器被执行完毕前不会被释放。 Deinitializers are not called directly. -子类继承了它的超类的析构器,在子类帝乡将要被释放时会被隐式的调用。子类在所有析构器被执行完毕前不会被释放。 析构器不会被直接调用。 For an example of how to use a deinitializer in a class declaration, see Deinitialization. +如何使用类声明中的析构器,请查看Deinitialization + >GRAMMAR OF A DEINITIALIZER DECLARATION >deinitializer-declaration → attributes­opt­deinit­code-block @@ -1013,7 +1024,6 @@ An extension declaration allows you to extend the behavior of existing class, st 扩展声明用于扩展一个已存在的类,结构体,枚举的行为。扩展声明以关键字extension开始,有如下的形式: - extension type: adopted protocols { declarations } From 674a17f9335f4e9ef739b464f8efcab458277657 Mon Sep 17 00:00:00 2001 From: Joven Pan Date: Mon, 16 Jun 2014 20:31:36 +0800 Subject: [PATCH 076/261] Update 23_Advanced_Operators.md --- src/chapter2/23_Advanced_Operators.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index e69de29..b789adc 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -0,0 +1,9 @@ +# 高级操作符 + +除了《基础操作符》里讲到的操作符,Swift还提供了一些高级操作符,用以完成更复杂的数值运算。比如位运算和移位操作符,其语法同C和Objective-C类似。 + +和C语言的算术操作符不同,Swift默认不支持溢出运算。数值溢出会被捕获并报错。但是,Swift提供了另一套支持溢出运算的操作符,比如可溢出加操作符(&+),可溢出操作符都以&作为前缀。 + +在自定义结构体、类或者枚举类型中,可以重载Swift操作符。通过操作符重载,可以简单地实现操作符的重定义。 + +Swift允许用户自定义操作符,并且可定制这些操作符的优先级和结合性。 From 6b3f29e922e600d7966800e5a2da39a233a31654 Mon Sep 17 00:00:00 2001 From: Joven Pan Date: Mon, 16 Jun 2014 20:37:43 +0800 Subject: [PATCH 077/261] Update 23_Advanced_Operators.md --- src/chapter2/23_Advanced_Operators.md | 64 +++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index b789adc..1dcb497 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -7,3 +7,67 @@ 在自定义结构体、类或者枚举类型中,可以重载Swift操作符。通过操作符重载,可以简单地实现操作符的重定义。 Swift允许用户自定义操作符,并且可定制这些操作符的优先级和结合性。 + + +## 位操作符 + +位操作符可以处理数据结构中的比特位,通常在图像处理和设备驱动等底层开发程序中使用。通过位操作符,还可以有效地处理外部数据源,比如使用自定义协议进行通信时用来编解码数据。 + +Swift支持C语言里所有的位操作符,如下所述: + +### 按位非 + +按位非操作符(~)对操作数每一位取反: + +按位非是前置操作符,紧置于操作数之前,不带空格: + +``` +let initialBits: UInt8 = 0b00001111 +let invertedBits = ~initialBits // 等于 11110000 +``` + +UInt8 是8位无符号整型,可以存储0-255之间的任意数。这个例子先初始化了一个UInt8 整型变量initialBits,二进制值为00001111,前四位为0,后四位为1,换算成十进制等于15。 + + +接着将这个变量initialBits进行按位非操作得到常量invertedBits,0变成1,1变成0,得到的二进制值为11110000,换算成十进制等于240。 + +### 按位与 + +按位与操作符(&)有两个操作数。按位与操作就是将两个操作数的每一位对齐,当对应位都是1时返回1,其他情况都返回0。 + +以下代码,firstSixBits 和lastSixBits 中间4个位都等于1,将它们按位与操作后得到二进制数00111100,换算成十进制为60: + +``` +let firstSixBits: UInt8 = 0b11111100 +let lastSixBits: UInt8 = 0b00111111 +let middleFourBits = firstSixBits & lastSixBits // 等于 00111100 +``` + +### 按位或 + +按位或操作符(|)也有两个操作数。按位或操作就是将两个操作数的每一位对齐,当对应位有一个是1时就返回1,而只有两个位都是0的情况才返回0。 + +以下代码,someBits 和moreBits 在不同位上有1,将它们按位或操作后得到二进制数11111110,换算成十进制为254: + +``` +let someBits: UInt8 = 0b10110010 +let moreBits: UInt8 = 0b01011110 +let combinedbits = someBits | moreBits // 等于 11111110 +``` + +### 按位异或 + +按位异或操作符(^)比较两个操作数的对应位,当两个位不同时返回1,相同时返回0。 + +以下代码,firstBits 和otherBits 对应位相同的情况返回0,不同的情况返回1: + +``` +let firstBits: UInt8 = 0b00010100 +let otherBits: UInt8 = 0b00000101 +let outputBits = firstBits ^ otherBits // 等于 00010001 +``` + + + + + From c03f9a97fa00d30a63d2621d733b6faaf7cc03d3 Mon Sep 17 00:00:00 2001 From: Joven Pan Date: Mon, 16 Jun 2014 20:44:23 +0800 Subject: [PATCH 078/261] Update 23_Advanced_Operators.md --- src/chapter2/23_Advanced_Operators.md | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index 1dcb497..69cfb5e 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -67,6 +67,55 @@ let otherBits: UInt8 = 0b00000101 let outputBits = firstBits ^ otherBits // 等于 00010001 ``` +## 按位左移、右移操作符 + +左移操作符(<<)和右移操作符()将操作数的所有位向左或向右移动指定的位数。 + +按位左移和右移的效果等同于将操作数乘以或除以2的倍数。向左移动一位相当于将操作数乘以2,向右移动一位相当于将操作数除以2。 + + +### 无符号移位操作 + +无符号移位的规则如下: + +1. 已有的位向左或向右移动指定的位数。 +2. 舍弃超出边界的位。. +3. 移动后产生的空位用0填充。 + +这种方法称为逻辑移位。 + +下图展示了11111111 << 1(11111111 左移一位)和11111111 >> 1(11111111 右移一位)的结果。蓝色数字表示被移动位,灰色表示被丢弃位,空位用橙色的0填充。 + +Swift移位操作代码: + +``` +let shiftBits: UInt8 = 4 // 即二进制的00000100 +shiftBits << 1 // 00001000 +shiftBits << 2 // 00010000 +shiftBits << 5 // 10000000 +shiftBits << 6 // 00000000 +shiftBits >> 2 // 00000001 +``` + +移位操作可以对其他数据类型实现编码和解码: + +``` +let pink: UInt32 = 0xCC6699 +let redComponent = (pink & 0xFF0000) >> 16 // redComponent是0xCC, 即204 +let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent是0x66, 即102 +let blueComponent = pink & 0x0000FF // blueComponent是0x99, 即153 +``` + +这个例子中用一个UInt32 常量pink 来存储css中粉色的颜色值。CSS中颜色#CC6699在Swift用十六进制0xCC6699来表示。这个颜色值经过按位与(&)和按位右移操作后可分解出它的红色成分(CC)、绿色成分(66)和蓝色成分(99)。 + +对0xCC6699 和0xFF0000进行按位与操作就可以得到红色成分。0xFF0000 里的0类似于遮罩,将0xCC6699的第二和第三字节过滤掉后返回0xCC0000 。 + +然后,将0xCC0000 向右移动16位。因为十六进制中每两个字符占8个比特位,所以移动16位的结果是把0xCC0000 变成0x0000CC,等同于0xCC,换算成十进制是204。 + +同理,对0xCC6699 和0x00FF00进行按位与操作可以得到绿色成分。将结果值0x006600再向右移动8位得到0x66,换算成十进制是102。 + +最后,对0xCC6699 和0x0000FF进行按位与操作可以得到蓝色成分。结果值0x000099不需要再做移位操作,因为0x000099 等价于0x99,换算成十进制是153。 + From fa4d9fab2a6f32972a14e0730b25c5d84cc4d294 Mon Sep 17 00:00:00 2001 From: Joven Pan Date: Mon, 16 Jun 2014 20:56:30 +0800 Subject: [PATCH 079/261] Update 23_Advanced_Operators.md --- src/chapter2/23_Advanced_Operators.md | 161 ++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index 69cfb5e..f3a997c 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -116,6 +116,167 @@ let blueComponent = pink & 0x0000FF // blueComponent是0x99, 即153 最后,对0xCC6699 和0x0000FF进行按位与操作可以得到蓝色成分。结果值0x000099不需要再做移位操作,因为0x000099 等价于0x99,换算成十进制是153。 +### 有符号移位操作 + +有符号的移位操作相对复杂得多,因为正负号也是用二进制位表示的。(下面举的例子虽然都是8位的,但原理是通用的。) + +有符号整型的第一位为符号位,0代表正数,1代表负数,其余的为数值位。有符号和无符号正整数的存储结构是相同的,比如数值4的二进制结构图: + +符号位为0,代表正数,其余7个数值位用二进制表示十进制的4。 + +负数的存储不太一样,它存储的是2的n次方减去它的绝对值,n为数值位的位数。比如一个8位的数有7个数值位,所以是2的7次方,即128。我们来看下数值-4的二进制结构图: + +这里符号位为1,代表负数,其余7个数值位的值是124(即128-4): + +负数的编码方式称为二进制补码表示。这种表示方式看起来很奇怪,但它有几个优点。 + +首先,对全部8个比特位(包括符号位)做标准的二进制加法就可以完成-1 加 -4 的操作,加法过程中丢弃超出的比特位。 + +第二,使用二进制补码表示方式,我们可以和正数一样对负数进行按位左移或右移,同样也是左移1位时乘于2,右移1位时除于2。但是,对有符号整型的右移有一个特别的要求: + ++ 有符号和无符号整型按位右移时规则相同,但有符号整型移位后出现的空位使用符号位来填充,而不是0。 + +这就确保了按位右移后,有符号整型的符号不会发生变化。这称为算术移位。 + +因为正数和负数特殊的存储方式,向右移位都会使它们更接近于0。移位过程中保持符号位不变,所以负数向右移位时值虽然接近于0但始终是负数。 + +## 溢出操作符 + +当给整型常量或变量赋值溢出时,Swift默认会报错,这就保证了操作过大或过小数据时的安全性。 + +举个例子,Int16整型能表示-32768 到 32767之间任意的有符号整数,但如果给它 赋值超出该范围则会导致错误: + +``` +var potentialOverflow = Int16.max +// potentialOverflow 等于 32767, 即Int16能表示的最大值 +potentialOverflow += 1 +// 噢,出错了 +``` + +值溢出时提供错误处理机制可以使编程更灵活。 + +然而,需要判断溢出条件时,你可以采用溢出运算,而不是触发错误。Swfit为整型计算提供了5个以&符号开头的溢出操作符。 + ++ 溢出加法(&+) ++ 溢出减法(&-) ++ 溢出乘法(&*) ++ 溢出除法(&/) ++ 溢出取余(&%) + +### 上溢出 + +下面的例子展示了溢出加法(&+)的用法: + +``` +var willOverflow = UInt8.max +// willOverflow 等于 255, 即UInt8 能表示的最大值 +willOverflow = willOverflow &+ 1 +// 现在willOverflow 等于 0 +``` + +willOverflow 等于UInt8 所能表示的最大值255(二进制11111111),使用溢出加法&+加1,如下图所示因为上溢出UInt8 无法表示出这个新值了。溢出后,有效位为00000000,也就是0。 + +### 下溢出 + +数值也有可能因为太小而越界。举个例子: + +UInt8能表示的最小值是0(二进制为00000000)。对00000000使用溢出减法&-减1,就会得到二进制数11111111,即十进制的255。 + +代码如下: + +``` +var willUnderflow = UInt8.min +// willUnderflow 等于 0, 即UInt8能表示的最小值 +willUnderflow = willUnderflow &- 1 +// 现在willUnderflow 等于255 +``` + +有符号整型也有类似的下溢出,它所有的减法都是对包括符号位在内的二进制数进行二进制减法,这在 "按位左移、右移操作符" 一节提到过。Int8 能表示的最小整数是-128,即二进制的10000000。用溢出减法减去1后,变成了01111111,即Int8 能表示的最大整数127。 + +代码如下: + +``` +var signedUnderflow = Int8.min +// signedUnderflow 等于 -128, 即Int8 能表示的最小值 +signedUnderflow = signedUnderflow &- 1 +// 现在signedUnderflow 等于 127 +``` + +有符号和无符号整型的上溢出总是从最大有效值变成最小值,下溢出总是从最小有效值变成最大值。 + +### 除零溢出 + +将一个数除以0或者对0取余都会导致错误: + +``` +let x = 1 +let y = x / 0 +``` + +但是使用可溢出版本的操作符&/和&%会返回0值。 + +``` +let x = 1 +let y = x &/ 0 +// y 等于 0 +``` + +## 优先级和结合性 + +操作符的优先级有高低之分,高优先级的操作符会先被计算。 + +结合性规定了具有相同优先级的操作符如何分组——向左还是向右。意思就是,到底是和左边的表达式结合,还是和右边的表达式结合。 + +在复合表达式中,操作符的优先级和结合性是非常重要的。举个例子,为什么下列表达式的结果为4? + +``` +2 + 3 * 4 % 5 +// 结果等于 4 +``` + +如果严格地从左到右计算,计算过程会是这样: + ++ 2 + 3 = 5; ++ t 5 * 4 = 20; ++ 20 %5 = 0 + +但是正确答案是4而不是0。优先级高的操作符要先计算,在Swift和C语言中,都是先乘除后加减的。所以,执行完乘法和取余运算才能执行加法运算。 + +乘法和取余拥有相同的优先级,在运算过程中,我们还需要考虑结合性。乘法和取余运算都是左结合的。这相当于在表达式中有隐藏的括号让运算从左开始: + +``` +2 + ((3 * 4) % 5) +``` + +(3 * 4)等于 12,相当于 + +``` +2 + (12 % 5) +``` + +(12 % 5) 等于 2,相当于 + +``` +2 + 2 +``` + +最后计算结果为 4。 + +Swift操作符的优先级和结合性的完整规则,请看表达式。 + +> 注意: +> +> Swift操作符的优先级和结合性的规则跟C系语言不太一样,相对于C语言和Objective-C更加简单且保守。所以在移植已有代码到Swift时,注意确认操作数的计算顺序。 + +## 操作符函数 + +类和结构体重新自定义已有操作符的功能,这称为操作符重载。 + + + + + + From ee3b3bc36178a34a5e0c839f8b1d2de1e735ea8c Mon Sep 17 00:00:00 2001 From: Neekey Date: Mon, 16 Jun 2014 22:48:23 +0800 Subject: [PATCH 080/261] Update 07_Attributes.md --- src/chapter3/07_Attributes.md | 41 +++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/chapter3/07_Attributes.md b/src/chapter3/07_Attributes.md index 5abc873..57ed087 100644 --- a/src/chapter3/07_Attributes.md +++ b/src/chapter3/07_Attributes.md @@ -4,41 +4,78 @@ *Attributes* provide more information about a declaration or type. There are two kinds of attributes in Swift, those that apply to declarations and those that apply to types. For instance, the `required` attribute—when applied to a designated or convenience initializer declaration of a class—indicates that every subclass must implement that initializer. And the `noreturn` attribute—when applied to a function or method type—indicates that the function or method doesn’t return to its caller. +*属性* 为声明和类型提供了更多的信息。在Swift中有两种类型的属性,一种应用在声明中,另一种应用于类型。比如,`required`属性——当被应用在一个类的预设初构造函数或者便利构造函数中时——表明了其所有的子类都必须实现这个构造函数。`noreturn`属性——当被应用在函数或者方法类型中时——表明这个函数或者方法不会返回任何值给调用者。 + You specify an attribute by writing the `@` symbol followed by the attribute’s name and any arguments that the attribute accepts: ``` @attribute name @attribute name(attribute arguments) -``` +``` + +你可以通过`@`符号以及紧随其后的属性名称和该属性接受的参数来指定属性。 + +``` + @属性名称 + @属性名称(属性参数) +``` Some declaration attributes accept arguments that specify more information about the attribute and how it applies to a particular declaration. These *attribute arguments* are enclosed in parentheses, and their format is defined by the attribute they belong to. +有些声明属性可以通过给定参数来指定该属性相关的更多信息,以及描述该属性如何应用于这个声明中。 + ## Declaration Attributes +## 声明属性 + You can apply a declaration attribute to declarations only. However, you can also apply the `noreturn` attribute to a function or method *type*. +你只能将声明属性应用在声明中。不过你还是可以将`noreturn`属性应用在函数或者方法*类型*中。 + `assignment` -> Apply this attribute to functions that overload a compound assignment operator. Functions that overload a compound assignment operator must mark their initial input parameter as inout. For an example of how to use the assignment attribute, see [Compound Assignment Operators](#). +> Apply this attribute to functions that overload a compound assignment operator. Functions that overload a compound assignment operator must mark their initial input parameter as `inout`. For an example of how to use the assignment attribute, see [Compound Assignment Operators](#). + +`assignment` +> 这个属性应用于那些重载了复合赋值运算符的函数上。 一个重载了复合赋值运算符必须将它的初始化输入参数标记为`inout`.查看[符合赋值运算符]中关于如何使用assigment属性的一个例子。 `class_protocol` > Apply this attribute to a protocol to indicate that the protocol can be adopted by class types only. > If you apply the `objc` attribute to a protocol, the `class_protocol` attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the `class_protocol` attribute explicitly. +`class_protocol` +> 当这个属性被应用在协议上时,它表明这个协议只能被类使用。 + +> 如果一个协议被应用了`objc`属性,那么`class_protocol`属性就被隐形地添加在这个协议上了,不需要再显性地添加一次。 + `exported` > Apply this attribute to an import declaration to export the imported module, submodule, or declaration from the current module. If another module imports the current module, that other module can access the items exported by the current module. +`exported` +> 通过将这个属性应用给一个导入声明,使得当前模块中被导入进来的模块,子模块或者声明可以被导出。如果另一个模块导入了这个模块,那么这个模块可以访问所有被这个模块导出的项。 + `final` > Apply this attribute to a class or to a property, method, or subscript member of a class. It’s applied to a class to indicate that the class can’t be subclassed. It’s applied to a property, method, or subscript of a class to indicate that that class member can’t be overridden in any subclass. +`final` +> 这个属性被应用在一个类或者一个类的属性、方法、或者子脚本上。如果应用在类上,则表明这个类不能被继承。如果被应用在一个类的属性、方法或者子脚本上,则表明这个类的成员不能被任何子类覆盖。 + `lazy` > Apply this attribute to a stored variable property of a class or structure to indicate that the property’s initial value is calculated and stored at most once, when the property is first accessed. For an example of how to use the `lazy` attribute, see [Lazy Stored Properties](#). +`lazy` +> 通过将这个属性应用在一个类或者结构体的存储变量属性上,来指定这个属性的初始值只在第一次被读取时才进行一次计算。查看[懒惰存储属性](#)中给出的关于如何使用`lazy`的例子。 + `noreturn` > Apply this attribute to a function or method declaration to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. You can mark a function or method type with this attribute to indicate that the function or method doesn’t return to its caller. > You can override a function or method that is not marked with the `noreturn` attribute with a function or method that is. That said, you can’t override a function or method that is marked with the `noreturn` attribute with a function or method that is not. Similar rules apply when you implement a protocol method in a conforming type. +`noreturn` +> 将这个属性应用在函数或者方法声明中来指定这个函数或者方法,`T`,是`@noreturn T`类型。你可以通过使用这个关键词来标记函数或者方法来表明这个函数或者方法不返回任何值给它的调用者。 + +> 你可以使用一个标记了这个属性的函数或者方法来覆盖一个没有标记过这个属性的函数或者方法,但是反过来不行。同样的,当你要实现一个协议方法时,也需要遵循这个规则。 + `NSCopying` > Apply this attribute to a stored variable property of a class. This attribute causes the property’s setter to be synthesized with a *copy* of the property’s value—returned by the `copyWithZone` method—instead of the value of the property itself. The type of the property must conform to the `NSCopying` protocol. From 13fe37adb6cf8ccf633612e425dafe0475a8583a Mon Sep 17 00:00:00 2001 From: liuyunclouder Date: Mon, 16 Jun 2014 23:44:04 +0800 Subject: [PATCH 081/261] ss --- src/chapter2/08_Enumerations.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/chapter2/08_Enumerations.md b/src/chapter2/08_Enumerations.md index e69de29..3624a7b 100644 --- a/src/chapter2/08_Enumerations.md +++ b/src/chapter2/08_Enumerations.md @@ -0,0 +1,21 @@ +# 枚举 (Enumerations) +枚举为一组相关值定义了一个通用的类型,使你能够在代码中使用这些值的同时保持类型安全。 + +如果你熟悉C语言,你就知道C语言里的枚举是给相关名称赋予一系列整型值。相比C语言,Swift中的枚举更灵活,并且不需要为每一个枚举成员指定一个值。如果枚举成员被赋予了值(也就是“原始值”),这个值可以是字符串、字符、任一整型值或者浮点类型的值。 + +或者,枚举成员也可以成员值指定任一类型的关联值,就像其他语言的联合类型或者变体类型。你可以在一个枚举变量里定义一系列通用的相关成员,每一个成员都有一个相应类型的值与其关联。 + +枚举作为Swift语言中的“一等公民”,采用了许多一贯只被类支持的特性,比如计算属性,以提供关于枚举变量当前值的额外信息,以及实例方法,以提供关于枚举变量所代表值的功能。枚举类型也支持为枚举成员定义初始化值,还有在原有实现上扩展以增加其功能,以及遵循协议提供标准功能。 + +关于这些特性的更多信息,请参考属性,方法,初始化,扩展,以及协议。 + +## 枚举语法 +你可以用enum关键字引入枚举类型,并把完整的定义用一对大括号包裹起来: + +``` +enum SomeEnumeration { + // enumeration definition goes here +} +``` + +以指南针的四个方位为例: From 4aabd52daeaf06181bdc78930f571794259df820 Mon Sep 17 00:00:00 2001 From: liuyunclouder Date: Tue, 17 Jun 2014 00:06:10 +0800 Subject: [PATCH 082/261] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=9E=9A=E4=B8=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/08_Enumerations.md | 263 +++++++++++++++++++++++++++++++- 1 file changed, 262 insertions(+), 1 deletion(-) diff --git a/src/chapter2/08_Enumerations.md b/src/chapter2/08_Enumerations.md index 3624a7b..0731799 100644 --- a/src/chapter2/08_Enumerations.md +++ b/src/chapter2/08_Enumerations.md @@ -1,4 +1,5 @@ # 枚举 (Enumerations) + 枚举为一组相关值定义了一个通用的类型,使你能够在代码中使用这些值的同时保持类型安全。 如果你熟悉C语言,你就知道C语言里的枚举是给相关名称赋予一系列整型值。相比C语言,Swift中的枚举更灵活,并且不需要为每一个枚举成员指定一个值。如果枚举成员被赋予了值(也就是“原始值”),这个值可以是字符串、字符、任一整型值或者浮点类型的值。 @@ -9,13 +10,273 @@ 关于这些特性的更多信息,请参考属性,方法,初始化,扩展,以及协议。 + ## 枚举语法 + 你可以用enum关键字引入枚举类型,并把完整的定义用一对大括号包裹起来: ``` enum SomeEnumeration { - // enumeration definition goes here + // 枚举定义 } ``` 以指南针的四个方位为例: + +``` +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作为其类型。 + +多个成员值可以用逗号分隔在同一行出现: + +``` +enum Planet { + case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune +} +``` + +每一个枚举变量都定义了一个全新的类型。和Swift中的其他类型一样,枚举变量的命名(比如CompassPoint和Planet)都需要以大写字母开头,并采用单数而不是复数形式,这样阅读时就一目了然了。 + +``` +var directionToHead = CompassPoint.West +``` + +当以CompassPoint其中一个值初始化时, 编译器将推断directionToHead的类型。而一旦把directionToHead以CompassPoint类型完成声明后,在设置它为CompassPoint其他值的时候,你就可以使用更为简短便捷的点语法了: + +``` +directionToHead = .East +``` + +directionToHead的类型已知了,因此你可以在赋值时省略类型。当遇到显式声明的枚举变量时,借助点语法可以使你的代码更具可读性。 + + +## 用Switch语句匹配枚举值 + +你可以通过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" +``` + +这段代码可以这样理解: + +“考虑directionToHead的值:当它等于.North时,打印 “Lots of planets have a north” ;当它等于.South时,打印 “Watch out for penguins” ”,后续省略。 + +就像在流程控制里所描述的那样,switch语句在确定枚举变量的值的时候要全面完备。如果删掉.West对应的情况,这段代码将不能通过编译,因为它没有考虑到完整的CompassPoint 成员列表。要求全面完备确保了枚举变量不会被意外忽略。 + +当不能为每一个枚举变量都提供case关键字时,可以为 那些没有一一提到的枚举成员设置一个default关键字: + +``` +let somePlanet = Planet.Earth +switch somePlanet { +case .Earth: + println("Mostly harmless") +default: + println("Not a safe place for humans") +} +// 输出 "Mostly harmless" +``` + + +## 相关值 + +上一节内容的例子展示了枚举成员是具有独立定义和独立类型的值。你可以为Planet.Earth设置一个常量或变量,以及后续做检验。但有时为枚举成员关联其他类型的值将会很有用。这让你能为枚举成员添加额外的配置信息,并允许其在每次使用时改变其信息内容。 + +你能为Swift中的枚举变量定义任意给定类型的关联值,并且如果需要,这些关联值的类型可以根据枚举成员而不同。这样的枚举变量在其他编程语言中被称为可区分联合类型、带标签的联合类型或者变异类型。 + +例如,假设一个存货清单跟踪系统需要跟踪两种带有不同条形码的产品。一种产品被打上UPC-A格式的一维条形码,这一格式使用0到9的数字。每个条形码包含一个“号码系统”数字,紧跟着十个“标识符”数字,最后还有一个“校验位”数字以验证该条形码是否被正确扫描了。 + +![](http://gtms04.alicdn.com/tps/i4/TB1y.hbFFXXXXXibFXX.wCCNpXX-366-175.png) + +另一种产品被打上QR格式的二维码,这一格式使用ISO 8859-1的任意字符,并且可以编码长达2953个字符的字符串。 + +![](http://gtms01.alicdn.com/tps/i1/TB11AE1FFXXXXaSXXXX39VBMpXX-257-257.png) + +如果我们的存货清单跟踪系统能分别以长度为三的整型数组的形式保存UPC-A格式,并以任意长度的字符串格式保存QR格式就好了。 + +``` +enum Barcode { + case UPCA(Int, Int, Int) + case QRCode(String) +} +``` + +在Swift中,可以这样定义这两种产品条纹码的枚举变量: + +``` +enum Barcode { + case UPCA(Int, Int, Int) + case QRCode(String) +} +``` + +这段代码可以这样理解: + +“定义一个叫Barcode的枚举类型,可包含关联长度为三的整型数组的UPCA 以及关联字符串的QRCode”。 + +这一定义不包含任何确切整型值或者字符串,它只定义Barcode.UPCA和Barcode.QRCode对应Barcode枚举变量和常量可以存储的关联值的类型。 + +现在条纹码可以使用任一类型创建: + +``` +var productBarcode = Barcode.UPCA(8, 85909_51226, 3) +``` + +这个例子创建了一个叫productBarcode的新变量,赋予它一个关联了(8, 8590951226, 3)数组的Barcode.UPCA。上面的“标识符”值中包含了一个下划线:85909_51226,让它作为条纹码更具可读性。 + +我们也可以赋予这个产品另外一个条纹码: + +``` +productBarcode = .QRCode("ABCDEFGHIJKLMNOP") +``` + +这时,原有的Barcode.UPCA和它的整型值被替换成新的Barcode.QRCode和字符串。类型为Barcode的常量和变量可以保存.UPCA或者.QRCode(以及它们的关联值),并且在任一给定时间内只能保存其中一个。 + +和之前一样,我们可以使用switch语句来检验不同类型的条纹码。然而这次,可以把关联值抽取出来作为switch语句的一部分。你可以抽取关联值作为一个常量(带有前缀let)或者变量(带有前缀var)以在switch语句的case主体内使用: + +``` +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." +``` + +如果一个枚举成员所有的都能被抽取为常量,或者都能被抽取为变量,你可以在枚举成员名称前放一个let或者var作为注解,简单来说就是这样: + +``` +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." +``` + + + ## 原始值 + + 上面关联值小节里的条纹码的例子展示了枚举成员是如何声明其和不同类型的值相关联。作为关联值的替代,枚举成员也可以在初始化时预先设置默认值(也叫原始值),并且其类型保持相同。 + + 以下是一个例子展示命名的枚举成员和原始的ASCII码相关联: + + ``` + enum ASCIIControlCharacter: Character { + case Tab = "\t" + case LineFeed = "\n" + case CarriageReturn = "\r" +} +``` + +这里,一个名为ASCIIControlCharacter的枚举类型的原始值被定义为字符类型,并且被设置为一些更为常见的ASCII控制字符。关于字符可参考“字符串与字符”一章。 + +注意原始值和关联值并不一样。像这个例子中的三个ASCII码一样,原始值是你在代码中第一次定义枚举类型时就已设置的值,并且一个特定枚举成员的原始值始终不会改变。而关联值是你根据某一枚举成员创建一个常量或变量时才设置的值,并且每次创建时都可以不同。 + +原始值可以是字符串、字符,或者任一整型和浮点数类型。每个原始值在其枚举类型声明时都必须保持唯一。当整型被用作原始值时,如果一些枚举成员没有设置特定值,它们的原始值会自增。 + +下面的枚举类型是对之前Planet枚举类型的一个改良,使用整型的原始值代表每个星球离太阳距离大小的顺序。 + +``` +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 +``` + +你也可以通过枚举类型的fromRaw方法去试图查找带有某一特定原始值的枚举成员。这个例子通过其原始值为7找到了Uranus: + +``` +let possiblePlanet = Planet.fromRaw(7) +// possiblePlanet类型为Planet?并等于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" +``` + +这个例子使用可选绑定试图访问原始值为9的星球。如果可以取回,if let somePlanet = Planet.fromRaw(9)这一语句将取回一个可选Planet并把它赋予somePlanet。而这种情况下是不可能取回一个位置为9的星球,因此,else分支就被执行了。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 306e4134dbc7dfc76193ca4ee4d03850014b9877 Mon Sep 17 00:00:00 2001 From: liuyunclouder Date: Tue, 17 Jun 2014 00:10:10 +0800 Subject: [PATCH 083/261] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=9E=9A=E4=B8=BEmar?= =?UTF-8?q?kdown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/08_Enumerations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chapter2/08_Enumerations.md b/src/chapter2/08_Enumerations.md index 0731799..9728ab4 100644 --- a/src/chapter2/08_Enumerations.md +++ b/src/chapter2/08_Enumerations.md @@ -211,14 +211,14 @@ enum Planet: Int { ``` let earthsOrder = Planet.Earth.toRaw() -// earthsOrder is 3 +// earthsOrder 为 3 ``` 你也可以通过枚举类型的fromRaw方法去试图查找带有某一特定原始值的枚举成员。这个例子通过其原始值为7找到了Uranus: ``` let possiblePlanet = Planet.fromRaw(7) -// possiblePlanet类型为Planet?并等于Planet.Uranus +// possiblePlanet类型为Planet?并且值等于Planet.Uranus ``` 然而,不是所有的int值都能匹配到一个星球。因此,fromRaw方法返回一个可选的枚举成员。以上的例子中,possiblePlanet的类型是”Planet?”或者”可选Planet”。 From 7fe764cb9ec658a420bc0c3d3065bce4b98283e0 Mon Sep 17 00:00:00 2001 From: liuyunclouder Date: Tue, 17 Jun 2014 00:13:40 +0800 Subject: [PATCH 084/261] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=9E=9A=E4=B8=BEmar?= =?UTF-8?q?kdown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/08_Enumerations.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chapter2/08_Enumerations.md b/src/chapter2/08_Enumerations.md index 9728ab4..37ab965 100644 --- a/src/chapter2/08_Enumerations.md +++ b/src/chapter2/08_Enumerations.md @@ -177,13 +177,13 @@ case let .QRCode(productCode): ``` - ## 原始值 +## 原始值 - 上面关联值小节里的条纹码的例子展示了枚举成员是如何声明其和不同类型的值相关联。作为关联值的替代,枚举成员也可以在初始化时预先设置默认值(也叫原始值),并且其类型保持相同。 +上面关联值小节里的条纹码的例子展示了枚举成员是如何声明其和不同类型的值相关联。作为关联值的替代,枚举成员也可以在初始化时预先设置默认值(也叫原始值),并且其类型保持相同。 - 以下是一个例子展示命名的枚举成员和原始的ASCII码相关联: +以下是一个例子展示命名的枚举成员和原始的ASCII码相关联: - ``` +``` enum ASCIIControlCharacter: Character { case Tab = "\t" case LineFeed = "\n" From 6ab217c4467c956f076a6bd0fc2d8c47bfa0acd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=90=BC=E9=9B=AA?= Date: Tue, 17 Jun 2014 01:48:08 +0800 Subject: [PATCH 085/261] update 01_The_Basics - Page 50. --- src/chapter2/01_The_Basics.md | 155 ++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index e69de29..890722b 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -0,0 +1,155 @@ +# The Basics +# 基础部分 + +Swift is a new programming language for iOS and OS X app development. Nonetheless, many parts of Swift will be familiar from your experience of developing in C and Objective-C. + +Swift是一个用于iOS和OS X平台开发的新的编程语言。尽管如此,Swift在很多地方都会和你以往用C语言和Objective-C开发的经验类似。 + +Swift provides its own versions of all fundamental C and Objective-C types, including Int for integers; Double and Float for floating-point values; Bool for Boolean values; and String for textual data. Swift also provides powerful versions of the two primary collection types, Array and Dictionary, as described in Collection Types. + +Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值Int,浮点值Double和Float,布尔值Bool,以及文本值String。Swift还提供了两个强大的常见集合类型,数组和字典,见[集合类型](link to 集合类型)。 + +Like C, Swift uses variables to store and refer to values by an identifying name. Swift also makes extensive use of variables whose values cannot be changed. These are known as constants, and are much more powerful than constants in C. Constants are used throughout Swift to make code safer and clearer in intent when you work with values that do not need to change. + +和C一样,Swift使用具有唯一名称的变量(variables)来储存和指向特定值。Swift还对那些值不能改变的变量进行了扩展,他们也被称为常量(Constants),Swift中的常量比C中的常量更加强大。在Swift中当你需要处理一些恒定不变的值的时候,使用常量(Constants)可以让代码更加安全和整洁。 + +In addition to familiar types, Swift introduces advanced types not found in Objective-C. These include tuples, which enable you to create and pass around groupings of values. Tuples can return multiple values from a function as a single compound value. + +除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,包括:元组(tuples),你可以创建和传递一组数值。元组(tuples)可以在函数中以一个复合值的形式返回多个数值。 + +Swift also introduces optional types, which handle the absence of a value. Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”. Optionals are similar to using nil with pointers in Objective-C, but they work for any type, not just classes. Optionals are safer and more expressive than nil pointers in Objective-C and are at the heart of many of Swift’s most powerful features. + +Swift还有可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用nil,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的nil,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大的特性的核心。 + +Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This enables you to catch and fix errors as early as possible in the development prObjective Cess. + +可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(String),类型安全性会阻止你错误的给它赋一个整型(Int)的值。这让你在开发的过程中尽早的发现问题。 + +# Constants and Variables +# 常量和变量 + +**Constants and variables associate a name (such as maximumNumberOfLoginAttempts or welcomeMessage) with a value of a particular type (such as the number 10 or the string "Hello"). The value of a constant cannot be changed once it is set, whereas a variable can be set to a different value in the future. + +常量和变量对应一个变量名(如maximumNumberOfLoginAttempts或welcomeMessage)以及对应类型的值(如数字10或字符串"Hello")。常量的值一旦设定旧不能改变,变量的值可以改变。 + +# Declaring Constants and Variables +# 声明常量和变量 + +Constants and variables must be declared before they are used. You declare constants with the let keyword and variables with the var keyword. Here’s an example of how constants and variables can be used to track the number of login attempts a user has made: + +常量和变量必须在使用前声明。用`let`来声明常量,用`var`来声明变量。下面是一个用常量和变量来记录用户尝试登录次数的例子: + + let maximumNumberOfLoginAttempts = 10 + var currentLoginAttempt = 0 + +This code can be read as: + +这段代码可以解读为: + +“Declare a new constant called maximumNumberOfLoginAttempts, and give it a value of 10. Then, declare a new variable called currentLoginAttempt, and give it an initial value of 0.” + +声明一个新的常量,叫做“登录尝试次数的最大值”,值为10。声明一个新的变量,叫“当前尝试次数”,初始值设为0。 + +In this example, the maximum number of allowed login attempts is declared as a constant, because the maximum value never changes. The current login attempt counter is declared as a variable, because this value must be incremented after each failed login attempt. + +在这个例子中,登录尝试次数的最大值被声明为常量,因为这个最大值不会改变,当前尝试次数被声明为变量,因为这个值在每次失败的登录尝试之后都要增加。 + +You can declare multiple constants or multiple variables on a single line, separated by commas: + +你可以在同一行内声明多个常量或变量,用逗号分割: + + var x = 0.0, y = 0.0, z = 0.0 + +> NOTE + +> If a stored value in your code is not going to change, always declare it as a constant with the let keyword. Use variables only for storing values that need to be able to change. + +> 注意 + +> 当值不会改变时,永远用`let`声明常量。只在值需要改变的时候用变量。 + +# Type Annotations +# 类型批注 + +You can provide a type annotation when you declare a constant or variable, to be clear about the kind of values the constant or variable can store. Write a type annotation by placing a colon after the constant or variable name, followed by a space, followed by the name of the type to use. + +在声明常量和变量时,你可以提供一个类型批注,来表明这个常量或变量可以储存的值的类型。类型批注的格式是在常量或变量名后加一个冒号,接着是一个空格,接着是要用的类型的名称。 + +This example provides a type annotation for a variable called welcomeMessage, to indicate that the variable can store String values: + +下面是一个叫`welcomeMessage`的变量的类型批注的例子,来说明这个变量可以储存字符串类型的值: + +``` +var welcomeMessage: String +``` + +The colon in the declaration means “…of type…,” so the code above can be read as: + +这个表达式中冒号表示:“类型是”,所以这段代码的可以解读为: + +“Declare a variable called welcomeMessage that is of type String.” + +“声明一个叫welcomeMessage的变量,类型是字符串。” + +The phrase “of type String” means “can store any String value.” Think of it as meaning “the type of thing” (or “the kind of thing”) that can be stored. + +“类型是”表示“可以储存任意的字符串类型的值”。可以把它想作是“一个事物的类型”它可以储存的。(Think of it as meaning “the type of thing” (or “the kind of thing”) that can be stored. 妈蛋这句真心不会翻啊……) + +The welcomeMessage variable can now be set to any string value without error: + +变量`welcomeMessage`可以被赋值为任意字符串类型的值,而不会报错: + + welcomeMessage = "Hello" + +> NOTE + +> It is rare that you need to write type annotations in practice. If you provide an initial value for a constant or variable at the point that it is defined, Swift can almost always infer the type to be used for that constant or variable, as described in Type Safety and Type Inference. In the welcomeMessage example above, no initial value is provided, and so the type of the welcomeMessage variable is specified with a type annotation rather than being inferred from an initial value. + +> 注意 + +> 在实践中你需要写类型批注的很少见。如果你在定义一个常量或变量的时候给了它一个初始值,Swift几乎总是可以推断出这个常量或变量使用的类型,参见类型安全(Type Safety)和类型推断(Type Inference)。在上面这个welcomeMessage的例子里,没有提供初始值,所以welcomeMessage这个变量的类型是通过类型批注的形式来指定,而不是通过初始值推断而来。 + +# Naming Constants and Variables +# 命名常量和变量 + +You can use almost any character you like for constant and variable names, including Unicode characters: +你可以使用几乎所有你喜欢的符号来命名常量和变量,包括unicode字符: + +``` +let π = 3.14159 +let 你好 = "你好世界" +let 🐶🐮 = "dogcow" +``` + +Constant and variable names cannot contain mathematical symbols, arrows, private-use (or invalid) Unicode code points, or line- and box-drawing characters. Nor can they begin with a number, although numbers may be included elsewhere within the name. + +常量和变量的命名不能包括数学运算符,箭头, 私有(或无效)的unicode码位, 或者线条(line-),以及制表符(box-drawing)字符。也不能以数字开头,尽管数字可以出现在变量名的其他位置。 + +Once you’ve declared a constant or variable of a certain type, you can’t redeclare it again with the same name, or change it to store values of a different type. Nor can you change a constant into a variable or a variable into a constant. + +一旦你声明了常量或变量的特定类型,你不能用同样的名称重新声明,也不能改变它的储值类型,亦不能把常量改为变量或变量改为常量。 + +> NOTE + +> If you need to give a constant or variable the same name as a reserved Swift keyword, you can do so by surrounding the keyword with back ticks (`) when using it as a name. However, you should avoid using keywords as names unless you have absolutely no choice. + +> 注意 + +> 如果你需要给一个常量或变量一个相同的名字作为swift的关键字,你可以在使用这个名字的时候用重音符(`)把关键字包围起来。然而,除非你没有别的选择,你应该避免使用关键字的方式来命名。 + +You can change the value of an existing variable to another value of a compatible type. In this example, the value of friendlyWelcome is changed from "Hello!" to "Bonjour!": + +你可以改变一个已经存在的变量的值,变成另一个适配类型的值。在下面的例子里,变量`friendlyWelcome`的值从"Hello!"变成了"Bonjour!": + + var friendlyWelcome = "Hello!" + friendlyWelcome = "Bonjour!" + // friendlyWelcome is now "Bonjour!" + // friendlyWelcome的值现在是"Bonjour!"了。 + +Unlike a variable, the value of a constant cannot be changed once it is set. Attempting to do so is reported as an error when your code is compiled: + +和变量不同,常量的值一旦设定就不能更改。尝试这样做会导致代码编译时报错。 + + let languageName = "Swift" + languageName = "Swift++" + // this is a compile-time error - languageName cannot be changed From 9cf9b19b2a1402a304f109c2af2fb55e77b5ac75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=8E=89=E6=9E=97=28=E9=A3=9E=E9=95=BF=29?= Date: Tue, 17 Jun 2014 09:39:11 +0800 Subject: [PATCH 086/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d34f08c..c4ee7de 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The Swift Programming Language 中文化项目 * 控制流 [认领 by 墨昕] * 函数 [认领 by 紫溪] * 闭包 [认领 by 闻西] - * 枚举 [认领 by 灵吾] + * 枚举 [已完成 by 灵吾] * 类和结构体 [认领 by 晓毒] * 属性 [认领 by 周源] * 方法 [已完成 by 米尔] From 17d66ebc07d754e4a9ea5815425cfa97d56dc528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=96=E9=82=80?= Date: Tue, 17 Jun 2014 10:19:19 +0800 Subject: [PATCH 087/261] translate the patterns --- src/chapter3/08_Patterns.md | 369 ++++++++++++++++++++++++++++++++++++ 1 file changed, 369 insertions(+) diff --git a/src/chapter3/08_Patterns.md b/src/chapter3/08_Patterns.md index e69de29..19d2752 100644 --- a/src/chapter3/08_Patterns.md +++ b/src/chapter3/08_Patterns.md @@ -0,0 +1,369 @@ +# Patterns +# 模式 + +A pattern represents the structure of a single value or a composite value. For example, the structure of a tuple ```(1, 2)``` is a comma-separated list of two elements. Because patterns represent the structure of a value rather than any one particular value, you can match them with a variety of values. For instance, the pattern (x, y) matches the tuple (1, 2) and any other two-element tuple. In addition matching a pattern with a value, you can extract part or all of a composite value and bind each part to a constant or variable name. + +模式代表了单个值或者复合值的结构。例如,元组```(1, 2)```的结构是逗号分隔的两个元素的列表。因为模式代表一种值的结构,而不是特定的某个值,你可以把模式和各种同类型的值进行匹配。比如,模式```(x, y)```可以匹配元组```(1, 2)```,以及任何含两个元素的元组。除了将模式与一个值匹配外,你可以从合成值中提取部分或全部,然后分别把各部分和一个常量或变量进行绑定。 + +In Swift, patterns occur in variable and constant declarations (on their left-hand side), in ```for-in``` statements, and in ```switch``` statements (in their case labels). Although any pattern can occur in the case labels of a ```switch``` statement, in the other contexts, only wildcard patterns, identifier patterns, and patterns containing those two patterns can occur. + +在Swift中,模式出现在变量和常量的声明(放在它们的左侧),```for-in```语句及```switch```语句(放在其case标签内)中。尽管任何模式都可以出现在```switch```语句的case标签中,但在其他情况下,只有通配符模式,标识符模式和包含这两种模式的模式才能出现。 + +You can specify a type annotation for a wildcard pattern, an identifier pattern, and a tuple pattern to constraint the pattern to match only values of a certain type. + +你可以为通配符模式,标识符模式和元组模式指定类型注释,用来限制这种模式只匹配某种类型的值。 + +> GRAMMAR OF A PATTERN +> +> pattern → wildcard-pattern­ type-annotation­ opt +> +> pattern → identifier-pattern­ type-annotation­ opt +> +> pattern → value-binding-pattern­ +> +> pattern → tuple-pattern­ type-annotation ­opt­ +> +> pattern → enum-case-pattern­ +> +> pattern → type-casting-pattern­ +> +> pattern → expression-pattern­ + +  + +> 模式语法 +> +> 模式 → 通配符模式 类型注解 可选 +> +> 模式 → 标识符模式 类型注解 可选 +> +> 模式 → 值绑定模式 +> +> 模式 → 元组模式 类型注解 可选 +> +> 模式 → 枚举用例模式 +> +> 模式 → 类型转换模式 +> +> 模式 → 表达式模式 + + +## Wildcard Pattern +## 通配符模式 + +A wildcard pattern matches and ignores any value and consists of an underscore (_). Use a wildcard pattern when you don’t care about the values being matched against. For example, the following code iterates through the closed range ```1...3```, ignoring the current value of the range on each iteration of the loop: + +通配符模式由一个下划线(_)组成,它会匹配并忽略任何值。当你不关心被匹配的值时,可以使用此模式。例如,下面这段代码对闭区间```1...3```进行了循环,并忽略了每次循环的区间当前值: + +``` +for _ in 1...3 { + // Do something three times. +} +``` + +``` +for _ in 1...3 { + // 执行某操作3次. +} +``` + +> GRAMMAR OF A WILDCARD PATTERN +> +> wildcard-pattern → _­ + +  + +> 通配符模式语法 +> +> 通配符模式 → _ + +## Identifier Pattern +## 标识符模式 + +An identifier pattern matches any value and binds the matched value to a variable or constant name. For example, in the following constant declaration, ```someValue``` is an identifier pattern that matches the value ```42``` of type ```Int```: + +标识符模式匹配任何值,并将匹配的值绑定到一个变量或常量。例如,在下面的常量声明中,```someValue```是一个标识符模式,其匹配了类型是```Int```的值```42```。 + +``` +let someValue = 42 +``` + +``` +let someValue = 42 +``` + +When the match succeeds, the value ```42``` is bound (assigned) to the constant name ```someValue```. + +当匹配成功时,值```42```被绑定(赋值)给了常量```someValue``` + +When the pattern on the left-hand side of a variable or constant declaration is an identifier pattern, the identifier pattern is implicitly a subpattern of a value-binding pattern. + +当一个变量或常量声明的左边是标识符模式时,标识符模式是隐式的值绑定模式。 + +> GRAMMAR OF AN IDENTIFIER PATTERN +> +> identifier-pattern → identifier­ + +  + +> 标识符模式语法 +> +> 标识符模式 → 标识符 + +## Value-Binding Pattern +## 值绑定模式 + +A value-binding pattern binds matched values to variable or constant names. Value-binding patterns that bind a matched value to the name of a constant begin with the keyword ```let```; those that bind to the name of variable begin with the keyword ```var```. + +值绑定模式绑定匹配的值到一个变量或常量。绑定匹配值给常量时,以关键字```let```开头;绑定给变量时,则使用关键字```var```。 + +Identifiers patterns within a value-binding pattern bind new named variables or constants to their matching values. For example, you can decompose the elements of a tuple and bind the value of each element to a corresponding identifier pattern. + +包含在值绑定模式中的标识符模式,会绑定新的变量或常量到其匹配的值。例如,你可以分解一个元组的元素,并把每个元素绑定到相应的标识符模式中。 + +``` +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 { + // 将x,y分别绑定到常量point的元素3,2。 +case let (x, y): + println("The point is at (\(x), \(y)).") +} +// prints "The point is at (3, 2)." +``` + +In the example above, ```let``` distributes to each identifier pattern in the tuple pattern ```(x, y)```. Because of this behavior, the ```switch``` cases ```case let (x, y):``` and ```case (let x, let y):``` match the same values. + +在上面的例子中,```let```将元组模式```(x, y)```分配到各个标识符模式。因为这种行为,```switch```语句中的```case let (x, y):```和```case (let x, let y):```匹配的值是一样的。 + +> GRAMMAR OF A VALUE-BINDING PATTERN +> +> value-binding-pattern → var­ pattern­ let ­pattern­ + +  + +> 值绑定模式语法 +> +> 值绑定模式 → var 模式 | let 模式 + +## Tuple Pattern +## 元组模式 + +A tuple pattern is a comma-separated list of zero or more patterns, enclosed in parentheses. Tuple patterns match values of corresponding tuple types. + +元组模式是被一对圆括号包围、并以逗号分隔的列表,列表中可以包含零或多个模式。元组模式会匹配相应元组类型的值。 + +You can constrain a tuple pattern to match certain kinds of tuple types by using type annotations. For example, the tuple pattern ```(x, y): (Int, Int)``` in the constant declaration ``` let (x, y): (Int, Int) = (1, 2)``` matches only tuple types in which both elements are of type ``` Int``` . To constrain only some elements of a tuple pattern, provide type annotations directly to those individual elements. For example, the tuple pattern in ``` let (x: String, y)``` matches any two-element tuple type, as long as the first element is of type ``` String``` . + +你可以使用类型注释来限制一个元组模式仅匹配某种类型的元组。例如,在常量申明```let (x, y): (Int, Int) = (1, 2)```中的元组模式```(x, y): (Int, Int)```只匹配两个元素都是```Int```这种类型的元组。如果仅需要限制元组模式中的某几个元素,直接对这几个元素提供类型注释即可。例如,在```let (x: String, y)```中的元组模式,将匹配包含两个元素且第一个元素类型是```String```的任意元组。 + +When a tuple pattern is used as the pattern in a ```for-in``` statement or in a variable or constant declaration, it can contain only wildcard patterns, identifier patterns, or other tuple patterns that contain those. For example, the following code isn’t valid because the element ```0``` in the tuple pattern ```(x, 0)``` is an expression pattern: + +当元组模式被用在```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)] +// 下面的代码是不正确的. +for (x, 0) in points { + /* ... */ +} +``` + +The parentheses around a tuple pattern that contains a single element have no effect. The pattern matches values of that single element’s type. For example, the following are equivalent: + +对于只包含一个元素的元组,包围元组的圆括号是不起作用的。模式会匹配该单个元素的类型。例如,下面的不同写法是等效的: + +``` +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 +``` + +> GRAMMAR OF A TUPLE PATTERN +> +> 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­ + +  + +> 元组模式语法 +> +> 元组模式 → ( 元组模式元素列表 可选 ) +> +> 元组模式元素列表 → 元组模式元素 | 元组模式元素 , 元组模式元素列表 +> +> 元组模式元素 → 模式 + +## Enumeration Case Pattern +## 枚举用例模式 + +An enumeration case pattern matches a case of an existing enumeration type. Enumeration case patterns appear only in ```switch``` statement case labels. + +枚举用例模式匹配现有枚举类型的某种用例。枚举用例模式仅在```switch```语句的case标签中出现。 + +If the enumeration case you’re trying to match has any associated values, the corresponding enumeration case pattern must specify a tuple pattern that contains one element for each associated value. For an example that uses a ```switch``` statement to match enumeration cases containing associated values, see [Associated Values](). + +如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。使用```switch```语句来匹配包含关联值的枚举用例的例子,请参阅[关联值](). + +> GRAMMAR OF AN ENUMERATION CASE PATTERN +> +> enum-case-pattern → type-identifier ­opt­ .­ enum-case-name­ tuple-pattern­ opt­ + +  + +> 枚举用例模式语法 +> +> 枚举用例模式 → 类型标识 可选 . 枚举的case名 元组模式 可选 + +## Type-Casting Patterns +## 类型转换模式 + +There are two type-casting patterns, the ```is``` pattern and the ```as``` pattern. Both type-casting patterns appear only in ```switch``` statement case labels. The ```is``` and ```as``` patterns have the following form: + +有两种类型转换模式,分别是```is```模式和```as```模式。这两种模式均只出现在```switch```语句的case标签中。```is```模式和```as```模式有以下形式: + +> is type +> +> pattern as type + +  + +> ```is``` type +> +> pattern ```as``` type + +The ```is``` pattern matches a value if the type of that value at runtime is the same as the type specified in the right-hand side of the ```is``` pattern—or a subclass of that type. The ```is``` pattern behaves like the ```is``` operator in that they both perform a type cast but discard the returned type. + +如果一个值的类型在运行时(runtime)和```is```模式右边所指定的类型(或者那个类型的子类型)一致,```is```模式将会匹配这个值。```is```模式类似```is```操作符,它们都进行类型转换,但是抛弃了返回的类型。 + +The ```as``` pattern matches a value if the type of that value at runtime is the same as the type specified in the right-hand side of the ```as``` pattern—or a subclass of that type. If the match succeeds, the type of the matched value is cast to the pattern specified in the left-hand side of the ```as``` pattern. + +如果一个值的类型在运行时(runtime)和```as```模式右边所指定的类型(或者那个类型的子类型)一致,```as```模式将会匹配这个值。一旦匹配成功,匹配值的类型被转换成```as```模式左边所指定的模式。 + +For an example that uses a ```switch``` statement to match values with ```is``` and ```as``` patterns, see [Type Casting for Any and AnyObject](). + +关于使用```switch```语句来匹配```is```模式和```as```模式值的例子,请参阅[Type Casting for Any and AnyObject]()。 + +> GRAMMAR OF A TYPE CASTING PATTERN +> +> type-casting-pattern → is-pattern­ as-pattern­ +> is-pattern → is­ type­ +> as-pattern → pattern­ as ­type­ + +  + +> 类型转换模式语法 +> +> 类型转换模式 → is模式 | as模式 +> is模式 → is 类型 +> as模式 → 模式 as 类型 + +## Expression Pattern +## 表达式模式 + +An expression pattern represents the value of an expression. Expression patterns appear only in ```switch``` statement case labels. + +表达式模式代表了一个表达式的值。该模式只出现在```switch```语句的case标签中。 + +The expression represented by the expression pattern is compared with the value of an input expression using the Swift standard library ```~=``` operator. The matches succeeds if the ```~=``` operator returns ```true```. By default, the ```~=``` operator compares two values of the same type using the ```==``` operator. It can also match an integer value with a range of integers in an ```Range``` object, as the following example shows: + +由表达式模式所代表的表达式会使用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." +``` + +You can overload the ```~=``` operator to provide custom expression matching behavior. For example, you can rewrite the above example to compare the point expression with a string representations of points. + +你可以重载```~=```操作符来提供自定义的表达式匹配行为。例如,你可以重写上面的例子来比较使用字符串所表达的点。 + +``` +// 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." +``` + +``` +// 重载 ~= 操作符让整数能匹配字符串 +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." +``` + +> GRAMMAR OF AN EXPRESSION PATTERN +> +> expression-pattern → expression­ + +  + +> 表达式模式语法 +> +> 表达式模式 → 表达式 + From 76bca8c56160c5973dda1831e2fa0020edebfa94 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Tue, 17 Jun 2014 12:11:10 +0800 Subject: [PATCH 088/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 94 +++++++++++++++++---------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 991e0a8..2c3b71e 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -1,11 +1,11 @@ # 声明 A declaration introduces a new name or construct into your program. For example, you use declarations to introduce functions and methods, variables and constants, and to define new, named enumeration, structure, class, and protocol types. You can also use a declaration to extend the the behavior of an existing named type and to import symbols into your program that are declared elsewhere. -声明将新的名字或者结构引入到程序中。例如,使用声明可以引入函数、方法、变量和常量;可以定义新的,命名的枚举类型,接口,类和原型类型。也可以使用声明来扩展已存在命名类型的行为,在程序中引入在其它地方声明的符号。 +声明将新的名字或者结构引入到程序中。例如,使用声明可以引入函数、方法、变量和常量;可以定义新的,命名的枚举类型,结构,类和协议类型。也可以使用声明来扩展已存在命名类型的行为,在程序中引入在其它地方声明的符号。 In Swift, most declarations are also definitions in the sense that they are implemented or initialized at the same time they are declared. That said, because protocols don’t implement their members, most protocol members are declarations only. For convenience and because the distinction isn’t that important in Swift, the term declaration covers both declarations and definitions. -在Swift中,大多数声明在某种意义上也是定义,可以在声明的同时实现和初始化他们。。也就是说,因为协议不会实现他们的成员,大多数协议成员仅仅是声明。为了方便,因为这个不同在Swift里不是那么重要,因此这个术语declaration同时包含了声明和定义。 +在Swift中,大多数声明在某种意义上也是定义,可以在声明的同时实现和初始化他们。也就是说,因为协议并不会实现他们的成员,所以大多数协议成员仅仅是声明。为了方便,由于这个不同在Swift里不是那么重要,因此术语declaration同时包含了声明和定义。 >GRAMMAR OF A DECLARATION @@ -47,7 +47,7 @@ In Swift, most declarations are also definitions in the sense that they are impl The module scope defines the code that’s visible to other code in Swift source files that are part of the same module. The top-level code in a Swift source file consists of zero or more statements, declarations, and expressions. Variables, constants, and other named declarations that are declared at the top-level of a source file are visible to code in every source file that is part of the same module。 -模块范围定义了在模块中对Swift源文件可见的代码。在Swift源文件中顶层的代码由0或多个语句、声明和表达式组成。在源文件的最上层声明的变量、常量和其它命名的声明对于同一模块的其它源文件代码都是可见的。 +模块范围定义了对模块中其它Swift源文件可见的代码。在Swift源文件中顶层的代码由0或多个语句、声明和表达式组成。在源文件的顶层声明的变量、常量和其它命名的声明对同一模块的其它源文件代码都是可见的。 >GRAMMAR OF A TOP-LEVEL DECLARATION @@ -59,7 +59,7 @@ Code Blocks A code block is used by a variety of declarations and control structures to group statements together. It has the following form: -大量不同的声明和控制结构通过代码块来把语句分组。有如下的形式: +通过代码块把不同的声明和控制结构语句分组,有如下的形式: { `statements` @@ -67,7 +67,7 @@ A code block is used by a variety of declarations and control structures to grou The statements inside a code block include declarations, expressions, and other kinds of statements and are executed in order of their appearance in source code. -在代码块里的语句包括声明,表达式,和其它类型的语句,按照在源代码里出现的顺序只习惯。 +在代码块里的语句包括声明,表达式,和其它类型的语句,按照在源代码里出现的顺序执行。 >GRAMMAR OF A CODE BLOCK >code-block → {­statements­opt­} @@ -79,14 +79,14 @@ The statements inside a code block include declarations, expressions, and other An import declaration lets you access symbols that are declared outside the current file. The basic form imports the entire module; it consists of the import keyword followed by a module name: -import声明可以让你访问到当前文件之外的符号。基本的形式是引入整个模块。由import关键字后面跟着一个模块名。 +import声明可以让你访问当前文件之外声明的符号。基本的形式是引入整个模块。由import关键字后面跟着一个模块名进行声明。 import module Providing more detail limits which symbols are imported—you can specify a specific submodule or a specific declaration within a module or submodule. When this detailed form is used, only the imported symbol (and not the module that declares it) is made available in the current scope. -如果提供更多的细节,你还可以明确限制引入一个具体的子模块或者子模块里的一个具体的声明。如果采用这种形式的声明,只有被引入的符号(而不是声明它的模块)可以在当前范围里访问到。 +如果提供更多的细节限制,还可以明确限制引入一个具体的子模块或者模块子模块里的一个具体的声明。如果采用这种形式的声明,只有被引入的符号(而不是声明它的模块)可以在当前范围里被访问到。 import import kind module.symbol name import module.submodule @@ -104,42 +104,43 @@ Providing more detail limits which symbols are imported—you can specify a spec A constant declaration introduces a constant named value into your program. Constant declarations are declared using the keyword let and have the following form: -常量声明会在你的程序里引入一个不变的命名值。常量声明使用关键字let,采用如下的形式: +常量声明引入一个不变的命名值到程序中。常量声明使用关键字let,采用如下的形式: let constant name: type = expression A constant declaration defines an immutable binding between the constant name and the value of the initializer expression; after the value of a constant is set, it cannot be changed. That said, if a constant is initialized with a class object, the object itself can change, but the binding between the constant name and the object it refers to can’t. -常量声明在常量名和初始化表达式的值之间定义了一个不可变的绑定;在值被设置之后,它就不能改变了。也就是说,如果常量用一个class对象实例化,对象本身可以改变,但是在常量名和对象之间的绑定时不会改变的。 +常量声明在常量名和初始化表达式的值之间定义了一个不可变的绑定;在值被设置之后,它就不能改变了。也就是说,如果常量用一个class对象实例化,对象本身可以改变,但是在常量名和对象之间的绑定是不会改变的。 When a constant is declared at global scope, it must be initialized with a value. When a constant declaration occurs in the context of a class or structure declaration, it is considered a constant property. Constant declarations are not computed properties and therefore do not have getters or setters. -如果一个常量在全局范围里声明,它就必须有一个初始值。当一个常量在类或者结构声明中声明的,它会被认为是一个常量属性。常量声明不是i可计算的属性,因此没有getters和setters方法。 +如果一个常量在全局范围里声明,它就必须有一个初始值。当一个常量在类或者结构声明中声明,它会被认为是一个常量属性。常量声明不是计算型属性,因此没有getters和setters方法。 If the constant name of a constant declaration is a tuple pattern, the name of each item in the tuple is bound to the corresponding value in the initializer expression. -如果一个常量的声明的名字是一个元组模式,在元组中的没一项在初始化表达式里都会绑定到响应的值。 +如果一个常量声明的名字是一个元组,元组中的每一项在初始化表达式里都会绑定到相应的值。 let (firstNumber, secondNumber) = (10, 42) In this example, firstNumber is a named constant for the value 10, and secondNumber is a named constant for the value 42. Both constants can now be used independently: -在这个例子,firstNumer是一个命令常量,值是10.secondNumber是一个命令的常量,值是42.这两个常量现在都可以独立的使用。 +在这个例子,firstNumer是一个命名常量,值是10。secondNumber是一个命命名常量,值是4。.这两个常量现在都可以独立的使用。 - 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." The type annotation (: type) is optional in a constant declaration when the type of the constant name can be inferred, as described in Type Inference. -在常量声明中,如果常量名的类型可以被推断出来,type是可选的,正如在Type Inference里描述的。 +如Type Inference里描述的一样,如果常量名的类型可以被推断出来,类型标识(:type)是可选的。 To declare a static constant property, mark the declaration with the static keyword. Static properties are discussed in Type Properties. -为了声明一个静态的常量属性,使用static关键字 来标记声明。静态属性在TypeProerties里讨论。 +为了声明一个静态的常量属性,使用关键字static来标记声明。静态属性会在Type Proerties里讨论。 For more information about constants and for guidance about when to use them, see Constants and Variables and Stored Properties + 想获得更多关于常量的信息或者想在使用中获得帮助,请查看常量和变量和存储属性(stored properties)等节。 >GRAMMAR OF A CONSTANT DECLARATION @@ -156,18 +157,18 @@ For more information about constants and for guidance about when to use them, se A variable declaration introduces a variable named value into your program and is declared using the keyword var. -变量声明会引入一个可变的命令值到你的程序中,使用关键字var进行声明。 +变量声明会引入一个可变的命名值到程序中,使用关键字var进行声明。 Variable declarations have several forms that declare different kinds of named, mutable values, including stored and computed variables and properties, stored variable and property observers, and static variable properties. The appropriate form to use depends on the scope at which the variable is declared and the kind of variable you intend to declare. -变量声明有好几种不同的形式来声明命令的,可变的值,包括可存储的可计算的变量和属性,可存储的变量和属性观察者。还有静态的变量属性。要使用哪种具体的形式取决于变量声明的范围和你打算声明的变量种类。 +变量声明有好几种不同的形式来声明不同类型的命名的,可变的值,包括存储型和计算型的变量和属性,存储型变量和属性观察者,还有静态的变量属性。要使用哪种适合的形式取决于变量声明的范围和你打算声明的变量种类。 >注意: ->你也可以在协议声明的上下文声明属性,详情参见类型属性声明。 + You can override a property in a subclass by prefixing the subclass’s property declaration with the override keyword, as described in Overriding. -你可以在子类中重写一个属性通过在子类中的属性声明的前面使用override。 +通过在子类中的属性声明的前面使用override,可以在子类中重写一个属性。 ##Stored Variables and Stored Variable Properties @@ -176,26 +177,26 @@ You can override a property in a subclass by prefixing the subclass’s property The following form declares a stored variable or stored variable property: -下面的形式声明了一可存储的变量或可存储的变量属性 +下面的形式声明了一个存储型变量或存储型的变量属性 var variable name: type = expression You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class or structure declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, it is referred to as a stored variable. When it is declared in the context of a class or structure declaration, it is referred to as a stored variable property. -你可以在全局范围、函数的局部范围或者类或结构声明的环境里定义变量声明。如果这种形式的变量声明在全局或者函数局部范围里声明,它指的就是可存储的变量。如果是在类或者结构声明的环境里声明的,它就是指的可存储变量属性。 +你可以在全局范围、函数的局部范围或者类或结构声明的上下文环境里定义变量声明。如果这种形式的变量声明在全局范围或者函数局部范围里声明,它指的就是存储型变量。如果是在类或者结构声明的环境里声明的,它就是指的存储型变量属性。 The initializer expression can’t be present in a protocol declaration, but in all other contexts, the initializer expression is optional. That said, if no initializer expression is present, the variable declaration must include an explicit type annotation (: type). -初始化表达式不能在协议声明里出现,但是可以出现在其它所有的环境里。初始化表达式是可选的。也就是说,如果没有初始化表达式存在,变量声明必须包括一个现实的类型表示。 +初始化表达式不能在协议声明里出现,但是可以出现在其它所有的上下文环境里。初始化表达式是可选的。也就是说,如果没有初始化表达式存在,变量声明必须包括一个显式的类型表示(:type)。 As with constant declarations, if the variable name is a tuple pattern, the name of each item in the tuple is bound to the corresponding value in the initializer expression. -和常量声明一样,如果变量名字是一个元组模式,元组中每一项的名字都会被绑定到初始化表达式的对应的值里 +和常量声明一样,如果变量名字是一个元组,元组中每一项的名字都会被绑定到初始化表达式的对应的值。 As their names suggest, the value of a stored variable or a stored variable property is stored in memory. -顾名思义,存储变量的或者存储属性的值是存储在内存中的。 +顾名思义,存储型变量或者存储型属性的值是存储在内存中的。 ##Computed Variables and Computed Properties @@ -203,7 +204,7 @@ As their names suggest, the value of a stored variable or a stored variable prop The following form declares a computed variable or computed property: -下面的形式声明了一个可计算的变量或者可计算的属性 +下面的形式声明了一个计算型变量或者计算型属性 var variable name: type { get { @@ -215,24 +216,24 @@ The following form declares a computed variable or computed property: } You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class, structure, enumeration, or extension declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, it is referred to as a computed variable. When it is declared in the context of a class, structure, or extension declaration, it is referred to as a computed property. -可以在全局范围,局部范围,或者类、结构、枚举或者定义可扩展的声明。如果这类型是的变量声明在全局或者函数的局部返回声明,指的是计算型变量。如果它在一个雷,结构或者扩展声明里,它就是指的是计算型属性。 +可以在全局范围,局部范围,或者类、结构、枚举或者扩展声明里定义这种形式的声明。如果这类型是的变量声明在全局范围或者函数的局部范围声明的,它指的是计算型变量。如果它在类,结构或者扩展声明里声明的,它指的就是计算型属性。 The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly, as described in Read-Only Computed Properties. But if you provide a setter clause, you must also provide a getter clause. -getter用于读取值,setter用于写入值。setter语句是可选的,仅仅getter方法是需要的,你可以把两者都忽略,只是简单的返回请求的值,正如在Read-Only Comuted Properties.但是如果你提供一个setter y语句,你不想页提供一个getter语句。 +getter用于读取值,setter用于写入值。setter子句是可选的,仅仅getter方法是必须的,你可以把两者都忽略,只是简单的直接返回请求值,如在Read-Only Comuted Properties描述的一样。但是如果你提供一个setter子句,你也必须要提供一个getter子句。 The setter name and enclosing parentheses is optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is newValue, as described in Shorthand Setter Declaration. -setter名字和封闭的大括号是可选的。如果你i供一个setter名字。如果你提供一个setter名字,它会被作为setter的参数的名称。如果你不提供setter名称,setter缺省的参数名是newvalue,正如在Shorthand Setter Declaration. +setter名字和封闭的括号是可选的。如果你提供了一个setter名字。如果你提供一个setter名字,它会被作为setter的参数的名称。如果你美欧提供setter名称,setter缺省的参数名是newvalue,如在Shorthand Setter Declaration描述的那样. Unlike stored named values and stored variable properties, the value of a computed named value or a computed property is not stored in memory. -不像存储的名字值和存储的变量属性,可计算名字的值或者计算属性的值不会存储到内存中。 +不像存储型命名值和存储型变量属性,计算型命名值或者计算型属性的值不会存储到内存中。 For more information and to see examples of computed properties, see Computed Properties. -获得更多信息,查看如何使用属性监视器的例子,请查看属性监视器(prpperty observers)一节。 +获得更多信息和如何使用属性监视器的例子,请查看属性监视器(prpperty observers)一节。 ##Stored Variable Observers and Property Observers @@ -240,36 +241,36 @@ For more information and to see examples of computed properties, see Computed Pr You can also declare a stored variable or property with willSet and didSet observers. A stored variable or property declared with observers has the following form: -你也可以声明一个存储变量或者属性使用willset和didset 观察者。一个存储变量或者声明的属性有以下的形式: +也可以使用willset和didset监视器声明一个存储型的变量或者属性。用监视器声明的存储型变量或者属性有以下的形式: -var variable name: type = expression { -willSet(setter name) { + var variable name: type = expression { + willSet(setter name) { statements -} -didSet(setter name { - statements -} -} + } + didSet(setter name) { + statements + } + } You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class or structure declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, the observers are referred to as stored variable observers. When it is declared in the context of a class or structure declaration, the observers are referred to as property observers. -你可以i在全局范围,函数的局部返回,或者类,结构环境里声明这种形式的变量。当这类型是的变量声明在全局范围或者函数的局部范围里声明的时候,观察者会被作为可存储的变量观察者。当在类或者结构声明中声明的时候,观察者会被作为属性的观察者。 +可以在全局范围,函数的局部返回,或类,结构的上下文环境里声明这种形式的变量。当这种类型是在在全局范围或者函数的局部范围里声明的时候,监视器会被作为存储型变量监视器。当在类或者结构声明中声明的时候,监视器会被作为属性监视器。 You can add property observers to any stored property. You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass, as described in Overriding Property Observers. -可以为任何存储属性增加观察器。你可以可以为继承的属性增加属性观察器(无论是存储的或是计算的)通过使用子类覆盖,就像Overriding PropertyOververs里描述的一样。 +可以为任何存储型属性增加监视器。也可以为继承的属性通过使用子类覆盖增加属性监视器(无论是存储型的或是计算型的),就像Overriding PropertyOververs里描述的一样。 The initializer expression is optional in the context of a class or structure declaration, but required elsewhere. The type annotation is required in all variable declarations that include observers, regardless of the context in which they are declared. -在类或者结构声明里,初始化表达式是可选的。但是在其他所有地方时必须的。类型保险在所有变量声明里是必须的,包括观测器,无论他们声明的环境。 +在类或者结构声明里,初始化表达式是可选的。但是在其它所有地方是必须的。类型标识在所有变量声明里是必须的,包括监视器,无论他们声明的环境。 The willSet and didSet observers provide a way to observe (and to respond appropriately) when the value of a variable or property is being set. The observers are not called when the variable or property is first initialized. Instead, they are called only when the value is set outside of an initialization context. -willset 和 didset 观察器提供了方式来观察好合适的响应在一个变量或者属性的值被设置的时候。观察器仅仅在初始化环境的外边可以被调用。 +willset 和 didset 监视器提供了一种方式来观察(适当的响应)什么时候变量或者属性的值被设置。监视器在变量或属性在第一次初始化的时候不会被调用,仅仅在初始化环境的外边设置的时候会被调用。 A willSet observer is called just before the value of the variable or property is set. The new value is passed to the willSet observer as a constant, and therefore it can’t be changed in the implementation of the willSet clause. The didSet observer is called immediately after the new value is set. In contrast to the willSet observer, the old value of the variable or property is passed to the didSet observer in case you still need access to it. That said, if you assign a value to a variable or property within its own didSet observer clause, that new value that you assign will replace the one that was just set and passed to the willSet observer. -willset观察器只是在变量或是属性被设置的时候被调用。新值会被作为常量传递给willset语句。didSet观察期在新值被设置的时候被调用。与willset相比,变量或属性的旧值。 +willset监视器只是在变量或是属性值被设置的时候调用。新值会被作为常量传递给willset语句,因此在willset子句实现的时候不能改变。didSet监视器在新值被设置的时候会立即被调用。与willset监视器相比,变量或属性的旧值会传给didSet监视器,以应对万一需要访问它 The setter name and enclosing parentheses in the willSet and didSet clauses are optional. If you provide setter names, they are used as the parameter names to the willSet and didSet observers. If you do not provide setter names, the default parameter name to the willSet observer is newValue and the default parameter name to the didSet observer is oldValue. @@ -288,6 +289,7 @@ For more information and to see an example of how to use property observers, see ##类和静态变量属性 To declare a class computed property, mark the declaration with the class keyword. To declare a static variable property, mark the declaration with the static keyword. Class and static properties are discussed in Type Properties. + 要声明一个类计算属性,要用class关键字标记声明。声明静态的变量属性,用关键字static标记声明。类和静态属性在Type属性里讨论。 >GRAMMAR OF A VARIABLE DECLARATION From 6c62a668115caac0f63855d9db6a2a88a47967b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Tue, 17 Jun 2014 12:39:49 +0800 Subject: [PATCH 089/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 53 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index 127060e..ba73e26 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -7,10 +7,11 @@ Type casting in Swift is implemented with the is and as operators. These two ope You can also use type casting to check whether a type conforms to a protocol, as described in Checking for Protocol Conformance. # 类型检查 -类型检查是一种方法来检查一个实例的类型,并且/或者处理该实例,就好像它是一个不同的超类或子类从别的在自己的类层次结构中的某个地方。 +类型检查是检查实例类型的方法,并且可以用来类型转换,就好像它是一个不同的超类或子类从别的在自己的类层次结构中的某个地方。 -类型转换使用`is`和`as`操作符来实现。这两个操作符提供了一种简单和富有表现力的方法来检查一个值的类型或者把某个值转换为不同的类型。 -你还可以使用类型转换来检查类型是否符合,如在检查协议一致性描述。 +类型检查使用`is`和`as`操作符来实现。这两个操作符提供了一种简单明了的方式来进行类型检查和类型转换。 + +你还可以使用类型检查来检查类型是否符合接口,以及是否和接口描述保持一致。 ##Defining a Class Hierarchy for Type Casting @@ -97,7 +98,7 @@ item is Movie returns true if the current MediaItem is a Movie instance and fals 这个例子遍历了数组中的所有元素,每一次循环,都会把数组中的一个实例赋值给`item`。 -如果`item`是`Movie`类型,则返回 `true`否则返回`false`,同样,也会检查`item`是否是`Song`类型。最后, `movieCount`和`songCount`就能统计出到底每个类型有多少个。 +如果`item`是`Movie`类型,则返回 `true`否则返回`false`,同样,也会检查`item`是否是`Song`类型。最后, `movieCount`和`songCount`就能统计出到底每个类型的数量。 ##Downcasting @@ -146,24 +147,21 @@ The example starts by trying to downcast the current item as a Movie. Because it Downcasting to Movie fails when applied to the two Song instances in the library array. To cope with this, the example above uses optional binding to check whether the optional Movie actually contains a value (that is, to find out whether the downcast succeeded.) This optional binding is written “if let movie = item as? Movie”, which can be read as: -当在库阵列施加到两个乐曲实例向下转换到电影失败。为了解决这个问题,上面的示例使用可选的绑定检查可选电影实际上是否包含一个值(也就是要找出垂头丧气是否成功。)这个可选的结合上记着说“如果让电影=项目作为?电影“,这可以被理解为: - “Try to access item as a Movie. If this is successful, set a new temporary constant called movie to the value stored in the returned optional Movie.” -“尝试访问项目作为一个电影。如果这是成功,树立了新的临时常数,称为电影存储在返回的可选电影的价值。“ +当把数组`library`中的两个`Song`对象进行向下转型为`Movie`时,会转型失败。为了解决这个问题,示例使用了一个临时的赋值来检查是否转型成功。临时赋值的写法是`if let movie = item as? Movie`,这句话的意思是“尝试把`item`转型为`Movie`,如果转型成功,则把转化后的对象存储在一个临时的变量`movie`中” If the downcasting succeeds, the properties of movie are then used to print a description for that Movie instance, including the name of its director. A similar principle is used to check for Song instances, and to print an appropriate description (including artist name) whenever a Song is found in the library. -如果向下转型成功,电影的属性,然后用于打印的Movie实例说明,包括其导演的名字。类似的原理是用来检查宋实例,并打印相应的描述(包括艺术家的名字),每当乐曲库中找到。 +如果向下转型成功,则会打印`Movie`对象相关的属性,包括导演的姓名,同样,如果`Song`转型成功,也会打印出`Song`相关的属性,例如歌手的姓名。 > NOTE > Casting does not actually modify the instance or change its values. The underlying instance remains the same; it is >simply treated and accessed as an instance of the type to which it has been cast. - - >注意 +>注意 ->铸造实际上并不修改实例或改变其值。相关实例保持不变;它是>简单的处理,并作为访问到它已被转换到的类型的一个实例。 +>实际上,类型转换并没有对对象进行修改,它底层仍然保持一致,只是使用时,被当作一种类型来处理和访问。 ##Type Casting for Any and AnyObject @@ -176,31 +174,30 @@ NOTE Use Any and AnyObject only when you explicitly need the behavior and capabilities they provide. It is always better to be specific about the types you expect to work with in your code. -## 类型转换为任何和AnyObject +## Any和AnyObject 的类型转换 -swift 提供了两种特殊类型的别名与非特定类型的工作: +`Swift` 提供了两种特殊类型,用来表示非特定类型。 -AnyObject可以代表任何类类型的实例。 -任何可以代表任何类型的实例可言,除了函数类型。 -注 - -使用任何与AnyObject只有当你明确需要他们提供的行为和能力。它始终是更好地具体说明你希望在你的代码工作的类型。 +`AnyObject`可以表示任何类类型的实例。 +`Any` 可以代表任何类型的实例,除了函数类型。 +注意: +只有当你确定需要使用`Any`和`AnyObject`的特性的时候,再使用它们。一般情况下,最好还是指定具体的类型。 ###AnyObject When working with Cocoa APIs, it is common to receive an array with a type of AnyObject[], or “an array of values of any object type”. This is because Objective-C does not have explicitly typed arrays. However, you can often be confident about the type of objects contained in such an array just from the information you know about the API that provided the array. ### AnyObject - -当Cocoa API的工作,是很常见的接收数组与一类AnyObject[],或者“任何对象类型的值的数组”。这是因为Objective-C中没有显式类型的数组。但是,你常常可以充满信心包含在刚刚从你了解所提供的数组的API的信息,例如一个数组对象的类型。 +当使用Cocoa APIs的时候,经常接收到一个AnyObject的数组,它里面可以放入任何类型。这是因为Object-C 没有确定类型的数组。尽管如此,通过对API的学习和了解,你仍然可以放心的使用这种API。 In these situations, you can use the forced version of the type cast operator (as) to downcast each item in the array to a more specific class type than AnyObject, without the need for optional unwrapping. The example below defines an array of type AnyObject[] and populates this array with three instances of the Movie class: -在这些情况下,您可以使用类型转换运算符的强迫版本(如)向下转换到每个项目在数组中以一个更具体的类类型比AnyObject,而不需要选配解缠。 -下面的例子定义类型AnyObject[]数组,并填充这个数组的Movie类的三个实例: +在这些情况下,您可以使用as 把AnyObject转化为一个具体的类型,而不需要进行拆包。 + +下面的例子定义了一个类型为AnyObject[]的数组,并填充了三个Movie类型的对象。 let someObjects: AnyObject[] = [ Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"), @@ -210,7 +207,7 @@ The example below defines an array of type AnyObject[] and populates this array Because this array is known to contain only Movie instances, you can downcast and unwrap directly to a non-optional Movie with the forced version of the type cast operator (as): -因为这个数组是已知含有唯一的电影实例,则可以向下转换,直接解开到一个非可选的电影与类型转换运算符(如)的强迫版本: +因为你已经知道这个数组中全都是Movie类型的对象,所以你可以直接使用as进行向下转型: for object in someObjects { let movie = object as Movie @@ -221,7 +218,7 @@ Because this array is known to contain only Movie instances, you can downcast an // Movie: 'Alien', dir. Ridley Scott For an even shorter form of this loop, downcast the someObjects array to a type of Movie[] instead of downcasting each item: -对于这个循环的一个更短的形式,向下转型的someObjects阵列的类型电影[]的,而不是向下转换每个项目: +上面的代码可以简写,你可以直接把数组进行转型而不用对数组中的每一个对象进行转型。 for movie in someObjects as Movie[] { println("Movie: '\(movie.name)', dir. \(movie.director)") @@ -236,7 +233,7 @@ Here’s an example of using Any to work with a mix of different types, includin ### Any -下面是使用Any与混合不同类型的,包括非类类型的工作的一个例子。该示例创建一个名为事情一个数组,它可以存储任何类型的值: +下面的例子中,使用了`Any`和其他多种混合类型,包括一些非类类型。在这个例子中,我们创建了一个`things`数组用来存储任何类型的元素。 var things = Any[]() @@ -253,9 +250,9 @@ The things array contains two Int values, two Double values, a String value, a t You can use the is and as operators in a switch statement’s cases to discover the specific type of a constant or variable that is known only to be of type Any or AnyObject. The example below iterates over the items in the things array and queries the type of each item with a switch statement. Several of the switch statement’s cases bind their matched value to a constant of the specified type to enable its value to be printed: -事情数组包含两个int值,两个Double值,一个字符串值,类型(Double,Double)的一个元组,和电影“捉鬼敢死队”,导演伊万·瑞特曼。 +`things`数组包含两个`int`值,两个`Double`值,一个字符串值,一个元组,和一个Movie对象。 -您可以使用is和as在switch语句的情况下,运营商发现,只知道是任何类型或AnyObject的常量或变量的具体类型。下面迭代的事情阵列项目的例子,查询每个项目的用switch语句的类型。几个switch语句的情况下,其匹配的值绑定到指定的类型,使其值要打印的常数: +你可以在`switch`语句中使用`is`和`as`操作符来确定数组中`Any`和`AnyObject`变量的的具体类型。下面的例子遍历了数组`things`中的每一个元素,并确定了他们的类型。为了打印元素的值,一些`switch` 语句把元素赋值给一个指定的类型。 for thing in things { switch thing { @@ -293,4 +290,4 @@ You can use the is and as operators in a switch statement’s cases to discover >注意 -> switch语句的情况下使用的类型转换运算符的强迫版本(作为,不作为?)检查并转换成一个>特定类型。这种检查始终是一个安全的switch case语句的上下文中。 +> 这个示例使用 `as` 而不是 `as?` 来进行类型转换,因为在`switch`1上下文中,类型检查时安全的。 From 17bd4d911ff2c5e5adc16ba77646696a367fc9ca Mon Sep 17 00:00:00 2001 From: mofengfly Date: Tue, 17 Jun 2014 13:22:05 +0800 Subject: [PATCH 090/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 2c3b71e..288fd42 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -124,7 +124,7 @@ If the constant name of a constant declaration is a tuple pattern, the name of e In this example, firstNumber is a named constant for the value 10, and secondNumber is a named constant for the value 42. Both constants can now be used independently: -在这个例子,firstNumer是一个命名常量,值是10。secondNumber是一个命命名常量,值是4。.这两个常量现在都可以独立的使用。 +在这个例子,firstNumer是一个命名常量,值是10。secondNumber是一个命名常量,值是4。这两个常量现在都可以独立的使用。 println("The first number is \(firstNumber).") // prints "The first number is 10." @@ -290,7 +290,7 @@ For more information and to see an example of how to use property observers, see To declare a class computed property, mark the declaration with the class keyword. To declare a static variable property, mark the declaration with the static keyword. Class and static properties are discussed in Type Properties. -要声明一个类计算属性,要用class关键字标记声明。声明静态的变量属性,用关键字static标记声明。类和静态属性在Type属性里讨论。 +要声明一个类的计算型属性,要用关键字class标记声明。声明静态的变量属性,用关键字static标记。类和静态属性在Type属性里有讨论。 >GRAMMAR OF A VARIABLE DECLARATION @@ -341,13 +341,13 @@ To declare a class computed property, mark the declaration with the class keywor A type alias declaration introduces a named alias of an existing type into your program. Type alias declarations begin with the keyword typealias and have the following form: -类型alias声明引入了一个存在类型的名字到你的程序当中。类型alias声明以关键字typelias开头,使用一下的形式: +类型别名声明引入了存在类型的名字到程序中,以关键字typelias开头,采用如下的形式: typealias name = existing type After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. The existing type can be a named type or a compound type. Type aliases do not create new types; they simply allow a name to refer to an existing type. -在一个类型alias声明后,声明的名字可以使用在你的程序的的任何地方使用了。存在的类型可能是一个命令类型或是计算类型。类型 alias不能创造新类型,他们只是简单的把名字指向一个存在的类型。 +在声明一个类型别名后,那个别名可以使用在你的程序的的任何有那个类型的地方使用了。存在的类型可能是命名类型或是复合类型。类型 别名不是创造新类型,它们只是简单的把名字指向一个存在的类型。 See also Protocol Associated Type Declaration. @@ -367,25 +367,27 @@ See also Protocol Associated Type Declaration. A :newTerm`function declaration` introduces a function or method into your program. A function declared in the context of class, structure, enumeration, or protocol is referred to as a method. Function declarations are declared using the keyword func and have the following form: -一个新术语”函数声明“引入了一个函数或者方法到程序中。在类,结构,枚举或者协议韩经理声明的函数会被挡住函数。番薯声明使用关键字func声明,采用以下的形式。 +新术语”函数声明“引入了一个函数或者方法到程序中。在类,结构,枚举或者协议里声明的函数会被当做方法。函数声明使用关键字func,采用以下的形式。 func function name(parameters) -> return type { statements } + If the function has a return type of Void, the return type can be omitted as follows: -如果函数有void的返回类型,返回类型可像下面这样忽略: +如果函数的返回类型是void,返回类型可像下面这样忽略: func function name(parameters) { statements } + The type of each parameter must be included—it can’t be inferred. By default, the parameters to a function are constants. Write var in front of a parameter’s name to make it a variable, scoping any changes made to the variable just to the function body, or write inout to make those changes also apply to the argument that was passed in the caller’s scope. For a discussion of in-out parameters, see In-Out Parameters. -每个参数的类型必须包含-不能通过推断。默认情况下,函数的参数是常量。在参数名的前面写一个var会让他成为一个变量,对变量的做的任何变化只会在函数体力有效,或者写入input使这些改变也会应用唉调用者范围的参数。 +必须包含每个参数的类型-参数类型不能通过推断。默认情况下,函数的参数是常量。在参数名的前面写一个var会让它成为一个变量,对变量的做的任何变化只会在函数内有效,或者用inout使的这些改变可以在调用域内生效。 Functions can return multiple values using a tuple type as the return type of the function. -函数可以使用元组类型作为函数的返回类型来返回多个值 +函数可以使用元组类型作为函数的返回类型来返回多个值。 A function definition can appear inside another function declaration. This kind of function is known as a nested function. For a discussion of nested functions, see Nested Functions. @@ -402,10 +404,10 @@ Function parameters are a comma separated list where each parameter has one of s For function parameters, the parameter name is used within the function body, but is not used when calling the function. For method parameters, the parameter name is used as within the function body, and is also used as a label for the argument when calling the method. The name of a method’s first parameter is used only within the function body, like the parameter of a function. For example: -对于函数参数,参数名字在函数体内部使用,但是在调用函数的时候不会使用。对于方法参数,参数名可以在函数体使用,也在调用方法时可以作为参数的标签使用。函数的一个参数名字仅仅在函数体力使用,就像函数的参数。例如 +对于函数参数,参数名字在函数体内部使用,但是在调用函数的时候不会使用。对于方法参数,参数名可以在函数体使用,在调用方法时也可以作为参数的标签使用。函数的一个参数名字仅仅在函数内使用,就像函数的参数。例如 -func f(x: Int, y: String) -> String { + func f(x: Int, y: String) -> String { return y + String(x) } f(7, "hello") // x and y have no name @@ -421,7 +423,7 @@ func f(x: Int, y: String) -> String { You can override the default behavior for how parameter names are used with one of the following forms: -你可以重写参数名字使用的默认行为,采用如下的形式: +可以重写参数名字使用的默认行为,采用如下的形式: external parameter name local parameter name: parameter type @@ -446,7 +448,8 @@ An underscore (_) before a local parameter name gives that parameter no name to ##特殊类型的参数 Parameters can be ignored, take a variable number of values, and provide default values using the following forms: -参数可以忽略,需要不同数量的值,会提供默认值。使用如下的形式: + +参数可以忽略,需要不同数量的值,会提供默认值,使用如下的形式: _ : <#parameter type#. @@ -456,11 +459,11 @@ Parameters can be ignored, take a variable number of values, and provide default A parameter named with an underscore (_) is explicitly ignored an can’t be accessed within the body of the function. -带有下划线的参数会显式的被忽略,在函数体内部不能被访问到。 +带有下划线的参数会显式的被忽略,在函数内部不能被访问到。 A parameter with a base type name followed immediately by three dots (...) is understood as a variadic parameter. A function can have at most one variadic parameter, which must be its last parameter. A variadic parameter is treated as an array that contains elements of the base type name. For instance, the variadic parameter Int... is treated as Int[]. For an example that uses a variadic parameter, see Variadic Parameters. -带有基本类型后面接着3个点的参数。 +基本类型名的参数,如果紧跟着三个点(...),被理解为是可变参数。一个函数最多可以有一个可变参数,且必须是最后一个参数。可变参数被作包含基本类型的元素数组。举例来讲,可变参数int...被看做是int[]。 查看可变参数的使用例子,详见可变参数(variadic parameters)一节。 A parameter with an equals sign (=) and an expression after its type is understood to have a default value of the given expression. If the parameter is omitted when calling the function, the default value is used instead. If the parameter is not omitted, it must have its name in the function call. For example, f() and f(x: 7) are both valid calls to a function with a single default parameter named x, but f(7) is invalid because it provides a value without a name. From 4edb503ec8e9b27918e4990460f4175c24d860de Mon Sep 17 00:00:00 2001 From: mofengfly Date: Tue, 17 Jun 2014 14:03:53 +0800 Subject: [PATCH 091/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 34 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 288fd42..3f9e2fb 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -557,7 +557,6 @@ Like structures but unlike classes, enumerations are value types; instances of a You can extend the behavior of an enumeration type with an extension declaration, as discussed in Extension Declaration. - 可以使用extension声明扩展枚举类型的行为,如果Extension Declaration Enumerations with Cases of Any Type描述的那样。 The following form declares an enumeration type that contains enumeration cases of any type: @@ -618,13 +617,13 @@ The raw value of an enumeration case can be accessed by calling its toRaw method ##访问枚举case -To reference the case of an enumeration type, use dot (.) syntax, as in EnumerationType.EnumerationCase. When the enumeration type can be inferred from context, you can omit it (the dot is still required), as described inEnumeration Syntax and Implicit Member Expression. +To reference the case of an enumeration type, use dot (.) syntax, as in EnumerationType.EnumerationCase. When the enumeration type can be inferred from context, you can omit it (the dot is still required), as described in Enumeration Syntax and Implicit Member Expression. -正如EnumerationType.EnumerationCase,可以使用语法.来引用一个enumeration类型的case,正如inEnumeration Syntax and Implicit Member Expression所描述的。 +和EnumerationType.EnumerationCase一样,可以使用语法.来引用一个enumeration类型的case,就像inEnumeration Syntax and Implicit Member Expression所描述的。 To check the values of enumeration cases, use a switch statement, as shown in Matching Enumeration Values with a Switch Statement. The enumeration type is pattern-matched against the enumeration case patterns in the case blocks of the switch statement, as described in Enumeration Case Pattern. -使用switch语句来检验枚举事件的值,正如使用switch语句匹配枚举值(Matching Enumeration Values with a Switch Statement)一节描述的那样。 +使用switch语句来检验枚举事件的值,如使用switch语句匹配枚举值(Matching Enumeration Values with a Switch Statement)一节描述的那样。 >GRAMMAR OF AN ENUMERATION DECLARATION @@ -646,10 +645,12 @@ To check the values of enumeration cases, use a switch statement, as shown in Ma raw-value-assignment → =­literal­ ##Structure Declaration + ##结构声明 + A structure declaration introduces a named structure type into your program. Structure declarations are declared using the keyword struct and have the following form: -结构声明引入了命名的类型到程序中。结构声明使用struct声明,采用如下的形式: +结构声明引入了命名的类型到程序中。结构声明使用关键字struct,采用如下的形式: struct structure name: adopted protocols { declarations @@ -658,11 +659,11 @@ A structure declaration introduces a named structure type into your program. Str The body of a structure contains zero or more declarations. These declarations can include both stored and computed properties, static properties, instance methods, static methods, initializers, type aliases, and even other structure, class, and enumeration declarations. Structure declarations can’t contain destructor or protocol declarations. For a discussion and several examples of structures that include various kinds of declarations, see Classes and Structures. -结构体包含0或者更多的声明。这个声明能包括可存储和计算的属性,静态属性,示例方法,静态方法,实例化,type aliases,甚至其他结构,类和枚举声明。结构声明不能包含析构或者协议声明。在Classes and Structures里,包括好几种了类型的声明的桃花好几个结构例子。 +结构体包含0或者更多的声明。这个声明能包括存储型和计算型的属性,静态属性,示例方法,静态方法,构造器,类型别名,甚至其它结构,类和枚举声明。结构声明不能包含析构或者协议声明。在Classes and Structures里,包括好几种了不同类型的声明的结构例子。 Structure types can adopt any number of protocols, but can’t inherit from classes, enumerations, or other structures. -结构类型可以采用任何数量的协议,但是从classes继承,枚举或者其他结构。 +结构类型可以采用任何数量的协议,但是不能从classes,枚举或者它结构继承。 There are three ways create an instance of a previously declared structure: @@ -682,18 +683,19 @@ There are three ways create an instance of a previously declared structure: The process of initializing a structure’s declared properties is described in Initialization. -初始化一个结构的声明的属性的过程在Initialization里描述的一样。 +初始化一个结构的声明的属性的过程在Initialization描述。 Properties of a structure instance can be accessed using dot (.) syntax, as described in Accessing Properties. -一个结构实例的属性使用通过.法来访问。 +一个结构实例的属性使用通过.语来访问。 Structures are value types; instances of a structure are copied when assigned to variables or constants, or when passed as arguments to a function call. For information about value types, see Structures and Enumerations Are Value Types. -结构是值类型;一个结构的实例复制在赋值给变量或者常量或者在传递参数给函数调用的时候。关于值类型的信息,请参看Structures and Enumerations Are Value Types. +结构是值类型;一个结构的实例在赋值给变量或者常量或者在传递参数给函数调用的时候采用复制的形式。关于值类型的信息,请参看Structures and Enumerations Are Value Types. You can extend the behavior of a structure type with an extension declaration, as discussed in Extension Declaration. -你可以用一个扩展声明来扩展一个结构类型的行为,正如Extension Declaration讨论的。 + +你可以用一个扩展声明来扩展结构类型的行为,正如Extension Declaration讨论的。 >GRAMMAR OF A STRUCTURE DECLARATION @@ -718,14 +720,14 @@ A class declaration introduces a named class type into your program. Class decla The body of a class contains zero or more declarations. These declarations can include both stored and computed properties, instance methods, class methods, initializers, a single destructor method, type aliases, and even other class, structure, and enumeration declarations. Class declarations can’t contain protocol declarations. For a discussion and several examples of classes that include various kinds of declarations, see Classes and Structures. -一个class的主题会包含0或多个声明。这些声明可以包括可存储的和可计算的属性,实例方法,类方法,初始化器,一个析构函数,类型 别名,和甚至其它的class,结构,枚举声明。类声明不能包括是协议声明。 +一个class的主题会包含0或多个声明。这些声明可以包括存储型和计算型的属性,实例方法,类方法,构造器,单个析构函数,类型 别名,和甚至其它的class,结构,枚举声明。类声明不能包括协议声明。详细讨论和例子请看 Classes and Structures A class type can inherit from only one parent class, its superclass, but can adopt any number of protocols. The superclass appears first in the type-inheritance-clause, followed by any adopted protocols. -一个class类只能从一个父类中继承,但是可以有多个洗衣。超类首先出现在类型继承语句中,后面跟着采用的协议。 +一个class类只能从一个父类中继承,但是可以有多个协议。超类首先出现在类型继承语句中,后面跟着采用的协议。 As discussed in Initializer Declaration, classes can have designated and convenience initializers. When you declare either kind of initializer, you can require any subclass to override it by marking the initializer with therequired attribute. The designated initializer of a class must initialize all of the class’s declared properties and it must do so before calling any of its superclass’s designated initializers. -正如在初始化声明讨论的一样,类的初始化很特别很便利。当你声明不同种类的初始化器时,你可以使用required属性要求任何子类重写他。这个特定的初始化器必须初始化类的所有声明的属性。在调用任何自雷的特定的初始化器时都必须这么做。 +正如在初始化声明讨论的一样,类可以有指定和便利的构造器。当你声明某种构造器时,可以使用required属性要求所有子类重写。这个特定的构造器必须初始化类的所有声明的属性。在调用任何超类的特定的构造器时都必须这么做。 A class can override properties, methods, and initializers of its superclass. Overridden methods and properties must be marked with the override keyword. @@ -733,7 +735,7 @@ A class can override properties, methods, and initializers of its superclass. Ov Although properties and methods declared in the superclass are inherited by the current class, designated initializers declared in the superclass are not. That said, if the current class overrides all of the superclass’s designated initializers, it inherits the superclass’s convenience initializers. Swift classes do not inherit from a universal base class. -尽管在子类中声明的属性和方法可以被当前的类继承,但是在超类中指定的构造器却不行。也就是说,如果当前类重写了超类的所有指定的构造器,它就会继续超类的便利构造器。Swift类不会从通用的基类中继承。 +尽管在子类中声明的属性和方法可以被当前的类继承,但是在超类中指定的构造器却不可以。也就是说,如果当前类重写了超类的所有指定的构造器,它就会继续超类的便利构造器。Swift类不会从通用的基类中继承。 There are two ways create an instance of a previously declared class: @@ -869,7 +871,7 @@ protocol-property-declaration → variable-declaration-head­variable-name­type Protocols declare that conforming types must implement a method by including a protocol method declaration in the body of the protocol declaration. Protocol method declarations have the same form as function declarations, with two exceptions: They don’t include a function body, and you can’t provide any default parameter values as part of the function declaration. For examples of conforming types that implement the method requirements of a protocol, see Method Requirements. -协议声明conforming类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 +协议声明一致性类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 To declare a class or static method requirement in a protocol declaration, mark the method declaration with the class keyword. Classes that implement this method also declare the method with the class keyword. Structures that implement it must declare the method with the static keyword instead. If you’re implementing the method in an extension, use the class keyword if you’re extending a class and the static keyword if you’re extending a structure. From 37fe74ab14a44cc83f1963428e2f99520f636440 Mon Sep 17 00:00:00 2001 From: Neekey Date: Tue, 17 Jun 2014 20:21:56 +0800 Subject: [PATCH 092/261] Update 07_Attributes.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 貌似`attribute`应该翻译为特性.... `property` 翻译为 属性 - -. --- src/chapter3/07_Attributes.md | 39 ++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/chapter3/07_Attributes.md b/src/chapter3/07_Attributes.md index 57ed087..55f1be4 100644 --- a/src/chapter3/07_Attributes.md +++ b/src/chapter3/07_Attributes.md @@ -81,9 +81,15 @@ You can apply a declaration attribute to declarations only. However, you can als > The `NSCopying` attribute behaves in a way similar to the Objective-C `copy` property attribute. +`NSCopying` +> 这个属性被应用在一个类的储存变量属性上。该属性将使得这个类的属性的setter // todo 翻译不能,hold住先 + `NSManaged` > Apply this attribute to a stored variable property of a class that inherits from `NSManagedObject` to indicate that the storage and implementation of the property are provided dynamically by Core Data at runtime based on the associated entity description. +`NSManaged` +> 这个属性被应用在继承了`NSManagedObject`的类的成员上,通过该属性来表明这个成员的存储和实现由Core Data根据相关实体描述来动态地提供。 + `objc` > Apply this attribute to any declaration that can be represented in Objective-C—for example, non-nested classes, protocols, properties and methods (including getters and setters) of classes and protocols, initializers, deinitializers, and subscripts. The `objc` attribute tells the compiler that a declaration is available to use in Objective-C code. @@ -101,21 +107,52 @@ You can apply a declaration attribute to declarations only. However, you can als } } ``` - + +`objc` +> 这个特性可以被应用在任何可以在Objective-C中使用的声明上,如非嵌套类、协议、类和协议的属性和方法(包括getter和setter)、构造函数、析构函数和子脚本。`objc`特性告诉编译器该声明可以在Objective-C的代码中被使用。 + +> `objc`特性可选地接收一个标识符作为参数。当你希望对Objective-C暴露一个不一样的名称时,你就可以使用这个属性参数。你可以使用这个参数来重新命名类、协议、方法、getter、setter和构造函数。下面的例子通过给定特性参数使得类`ExampleClass`的enabled这个属性以`isEnabled`这个属性暴露给Objective-C. + +``` + @objc + class ExampleClass { + var enabled: Bool { + @objc(isEnabled) get { + // 返回合适的值 + } + } + } +``` + `optional` > Apply this attribute to a protocol’s property, method, or subscript members to indicate that a conforming type isn’t required to implement those members. > You can apply the `optional` attribute only to protocols that are marked with the `objc` attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. For more information about how to use the `optional` attribute and for guidance about how to access optional protocol members—for example, when you’re not sure whether a conforming type implements them—see [Optional Protocol Requirements](#). +`optional` + +> 这个特性可以被应用在一个协议的属性,方法和子脚本成员上,以此来表明对遵循该协议的类型来说,这些成员的实现是可选的。 + +> 你只能将这个特性应用在被标记了`objc`特性的协议上。也就是说,只有类才能允许和实现一个包含了可选成员的协议。更多关于如何使用`optional`特性以及如何在不清楚一个类型是否遵守了被标记为`optional`协议的情况下读取可选属性的方法的信息,请参考[可选协议要求](#)。 + `required` > Apply this attribute to a designated or convenience initializer of a class to indicate that every subclass must implement that initializer. > Required designated initializers must be implemented explicitly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or when the subclass overrides the designated initializers with convenience initializers). +`required` +> 通过将该特性应用在预设构造函数或者便利构造函数上来说明每一个子类都必须实现这个构造函数。 + +> 必须的预设构造函数必须被显性地实现。必须的便利构造函数可以被显性地实现,或者当子类直接实现了所有父类的预设构造函数时(或者子类使用便利构造函数重写了预设构造函数),可以直接继承这个便利构造函数。 + ### Declaration Attributes Used by Interface Builder +## 在界面生成器中使用声明特性 + Interface Builder attributes are declaration attributes used by Interface Builder to synchronize with Xcode. Swift provides the following Interface Builder attributes: `IBAction`, `IBDesignable`, `IBInspectable`, and `IBOutlet`. These attributes are conceptually the same as their Objective-C counterparts. +界面生成器特性是被界面生成器用来和Xcode同步的声明特性。Swift提供了一下集中界面生成器特性: `IBAction`,`IBDesignable`,`IBInspectable`和`IBOutlet`。这些特性在概念上和他们的Objective-C同仁一样。 + You apply the `IBOutlet` and `IBInspectable` attributes to property declarations of a class. You apply the `IBAction` attribute to method declarations of a class and the `IBDesignable` attribute to class declarations. ## Type Attributes From 1d31b03705e5f116253ab462f9f1221262e900cb Mon Sep 17 00:00:00 2001 From: Neekey Date: Tue, 17 Jun 2014 21:33:30 +0800 Subject: [PATCH 093/261] Update 07_Attributes.md --- src/chapter3/07_Attributes.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/chapter3/07_Attributes.md b/src/chapter3/07_Attributes.md index 55f1be4..3187fab 100644 --- a/src/chapter3/07_Attributes.md +++ b/src/chapter3/07_Attributes.md @@ -155,17 +155,31 @@ Interface Builder attributes are declaration attributes used by Interface Builde You apply the `IBOutlet` and `IBInspectable` attributes to property declarations of a class. You apply the `IBAction` attribute to method declarations of a class and the `IBDesignable` attribute to class declarations. +`IBOutlet`和`IBInspectable`特性用于类的属性声明,`IBAction`特性用于类的方法声明而`IBDesignable`用于类的声明。 + ## Type Attributes +## 类型特性 + You can apply type attributes to types only. However, you can also apply the `noreturn` attribute to a function or method *declaration*. +类型特性只能应用在类型上。尽管如此,你还是可以将`noreturn`特性应用在函数和方法的声明上。 + `auto_closure` > This attribute is used to delay the evaluation of an expression by automatically wrapping that expression in a closure with no arguments. Apply this attribute to a function or method type that takes no arguments and that returns the type of the expression. For an example of how to use the `auto_closure` attribute, see [Function Type](#). +`auto_closure` +> 这个特性一般用于通过将表达式包裹在一个没有参数的闭包中来延迟表达式的计算。将该特性应用在不带任何参数的函数和方法中,而这些函数和方法的返回值就是需要延迟计算的表达式。关于如何使用`auto_closure`特性,参考[函数类型](#)中的例子。 + +`noreturn` +> Apply this attribute to the type of a function or method to indicate that the function or method doesn’t return to its caller. You can also mark a function or method declaration with this attribute to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. + `noreturn` -Apply this attribute to the type of a function or method to indicate that the function or method doesn’t return to its caller. You can also mark a function or method declaration with this attribute to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. +> 将这个特性应用在函数或者方法中来表明该函数或者方法不返回任何值给它的调用者。你也可以使用这个特性来标记函数或者方法声明以及来说明这个函数或者方法,`T`,是`@noreturn T`类型。 + +## GRAMMAR OF AN ATTRIBUTE -> GRAMMAR OF AN ATTRIBUTE +## 特性语法总结 > attribute → @attribute-nameattribute-argument-clauseopt From 6436c3763e9156cae436ce0ea28b3883cca2f14c Mon Sep 17 00:00:00 2001 From: Zeng Yun Date: Tue, 17 Jun 2014 21:45:41 +0800 Subject: [PATCH 094/261] update to 282 --- src/chapter2/09_Classes_and_Structures.md | 86 +++++++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index ef40eb7..79cbc1d 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -292,16 +292,92 @@ When `rememberedDirection` is assigned the value of `currentDirection`, it is ac 当`rememberedDirection`赋值为`currentDirection`时,实际上只是赋值了值拷贝而已。 Changing the value of `currentDirection` thereafter does not affect the copy of the original value that was stored in `rememberedDirection`. -改变`currentDirection` +改变`currentDirection`的值并不会影响存储了原始值副本的`rememberedDirection`。 ‌ -Classes Are Reference Types -Unlike value types, reference types are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used instead. +### Classes Are Reference Types +### 类是引用类型 -Here’s an example, using the VideoMode class defined above: +Unlike value types, *reference types* are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used instead. +与值类型不同,在赋值给变量、常量或者传参时,引用类型不会被复制,而是传递与当前值相同的引用。 + +Here’s an example, using the `VideoMode` class defined above: +请看这个例子,例子中使用了上文定义的`VideoMode`: + +``` let tenEighty = VideoMode() tenEighty.resolution = hd tenEighty.interlaced = true tenEighty.name = "1080i" tenEighty.frameRate = 25.0 -This example declares a new constant called tenEighty and sets it to refer to a new instance of the VideoMode class. The video mode is assigned a copy of the HD resolution of 1920 by 1080 from before. It is set to be interlaced, and is given a name of "1080i". Finally, it is set to a frame rate of 25.0 frames per second. \ No newline at end of file +``` + +This example declares a new constant called `tenEighty` and sets it to refer to a new instance of the `VideoMode` class. The video mode is assigned a copy of the HD resolution of `1920` by `1080` from before. It is set to be interlaced, and is given a name of `"1080i"`. Finally, it is set to a frame rate of `25.0` frames per second. + +例子中声明了一个名为`tenEighty`的新常量,并将它赋值为一个新的`VideoMode`实例。视频模式使用了上文的`hd`值的拷贝,其分辨率为`1920`x`1080`。`tenEighty`的`interlaced`为true,`name`为`1080i`,`frameRate`为`25.0`帧每秒。 + +Next, `tenEighty` is assigned to a new constant, called `alsoTenEighty`, and the frame rate of `alsoTenEighty` is modified: + +然后,一个新常量`alsoTenEighty`被赋值为`tenEighty`,`alsoTenEighty`的帧率做了如下修改: + +``` +let alsoTenEighty = tenEighty +alsoTenEighty.frameRate = 30.0 +``` + +Because classes are reference types, `tenEighty` and `alsoTenEighty` actually both refer to the same `VideoMode` instance. Effectively, they are just two different names for the same single instance. + +因为类是引用类型,`tenEighty`和`alsoTenEighty`都指向了同一个`VideoMode`实例。实际上它们是同一个实例的两个不同的名字而已。 + +Checking the `frameRate` property of `tenEighty` shows that it correctly reports the new frame rate of `30.0` from the underlying `VideoMode` instance: + +接下来我们检查一下`tenEighty`的属性`frameRate`,这能说明`VideoMode`实例的帧率真的变成了新值`30.0`。 + +``` +println("The frameRate property of tenEighty is now \(tenEighty.frameRate)") +// prints "The frameRate property of tenEighty is now 30.0" +``` + +Note that `tenEighty` and `alsoTenEighty` are declared as constants, rather than variables. However, you can still change `tenEighty.frameRate` and `alsoTenEighty.frameRate` because the values of the `tenEighty` and `alsoTenEighty` constants themselves do not actually change. `tenEighty` and `alsoTenEighty` themselves do not “store” the `VideoMode` instance—instead, they both refer to a `VideoMode` instance behind the scenes. It is the `frameRate` property of the underlying `VideoMode` that is changed, not the values of the constant references to that `VideoMode`. + +请注意`tenEighty`和`alsoTenEighty`都被声明成了常量而不是变量。但是因为修改其属性的值并不会改变`tenEighty`和`alsoTenEighty`的值,我们还是可以修改`tenEighty.frameRate`和`alsoTenEighty.frameRate`。`tenEighty`和`alsoTenEighty`并不存储`VideoMode`实例,而是引用一个`VideoMode`实例的地址。改变`frameRate`的值只是改变了引用的`VideoMode`实例的属性,并没有改变引用的`VideoMode`的地址。 +‌ +### Identity Operators +### 身份操作符 + +Because classes are reference types, it is possible for multiple constants and variables to refer to the same single instance of a class behind the scenes. (The same is not true for structures and enumerations, because they are value types and are always copied when they are assigned to a constant or variable, or passed to a function.) + +因为类是引用类型,因此允许多个常量和变量都引用同一个类实例。(结构体和枚举却不是,因为它们是值类型,并且在赋值给变量常量或者传值的时候传递的都是值的拷贝。) + +It can sometimes be useful to find out if two constants or variables refer to exactly the same instance of a class. To enable this, Swift provides two identity operators: + +* Identical to (===) +* Not identical to (!==) + +有时候需要判断两个常量或变量是否指向同一个类实例。Swift提供了两个身份操作符来实现这个功能: + + * 指向同一实例(===) + * 指向不同实例(!==) + +Use these operators to check whether two constants or variables refer to the same single instance: + +以下例子使用了这两个操作符来判断两个常量或变量是否是同一实例: + +``` +if tenEighty === alsoTenEighty { + println("tenEighty and alsoTenEighty refer to the same Resolution instance.") +} +// prints "tenEighty and alsoTenEighty refer to the same Resolution instance." +``` + +Note that “identical to” (represented by three equals signs, or ===) does not mean the same thing as “equal to” (represented by two equals signs, or ==): + +* “Identical to” means that two constants or variables of class type refer to exactly the same class instance. +* “Equal to” means that two instances are considered “equal” or “equivalent” in value, for some appropriate meaning of “equal”, as defined by the type’s designer. + + +When you define your own custom classes and structures, it is your responsibility to decide what qualifies as two instances being “equal”. The process of defining your own implementations of the “equal to” and “not equal to” operators is described in Equivalence Operators. + +‌ +Pointers +If you have experience with C, C++, or Objective-C, you may know that these languages use pointers to refer to addresses in memory. A Swift constant or variable that refers to an instance of some reference type is similar to a pointer in C, but is not a direct pointer to an address in memory, and does not require you to write an asterisk (*) to indicate that you are creating a reference. Instead, these references are defined like any other constant or variable in Swift. \ No newline at end of file From 28c48efed480d8f30e6ce1096ae06337964a5312 Mon Sep 17 00:00:00 2001 From: "moxin.xt" Date: Tue, 17 Jun 2014 21:55:55 +0800 Subject: [PATCH 095/261] add control_flow --- src/chapter2/05_Control_Flow.md | 209 ++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index e69de29..cce16a1 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -0,0 +1,209 @@ +# 控制流(Control Flow) + +## by moxin.xt + +Swift提供类似C语言的控制流语法,比如```for```和```while```循环;```if```和```switch```的条件判断表达式以及``` break```,```continue```这种跳出循环的语句。 + +Swift除了支持类似C语言这种```for-condition-increment```的表达式外,还支持```for-in```这种循环语句,可以轻松的遍历数组,字典,字符串等序列。 + +Swift的```switch```语句和C语言相比很强大,它不会像C语言那样,因为在case的分支中忘记写break而执行了下一条case的语句。同时case语句可以匹配任何类型 + + +#For循环 + +```for```循环可以将一段代码执行若干次。Swift提供两种```for```循环: + +* ```for-in```遍历并返回序列或集合中的每一个元素,执行一段代码 +* ```for-condition-increment```在符合某种条件下(通常是在每次循环结束时对计数器+1),返回序列或集合中的每一个元素,执行一段代码。 + +##For-In + +你可以使用```for-in```来遍历集合里的元素;一定范围内的数字;数组中的元素或者字符串中的字符。下面这个例子可以打印出一个5次循环的结果: + +``` +for index in 1...5{ + println("\(index) times 5 is \(index * 5)") +} +// 1 times 5 is 5 +// 2 times 5 is 10 +// 3 times 5 is 15 +// 4 times 5 is 20 +// 5 times 5 is 25 + +``` + +我们首先通过(```...```)表达式创建了一个数字集合,然后枚举集合中的每个元素,```index```值首先被赋值为range(```1```),然后执行循环体内的代码,上面这个例子中循环体内只有一行代码,作用是打印出```index```的值。当这行代码执行完后,```index```值会被更新,被赋值为range(```2```),```println```再次被调用,如此反复,直到循环结束。 + +上面例子中```index```是个常量,在每次循环开始的时候会被自动赋值,因此它不需要在使用前通过```let```声明,因为它会被```for-in```隐式声明。 + + 注意 + + 常量```index```的作用域只存在于循环体内。如果你想在循环体外查看```index```的值或者使用它 + 你需要在循环开始前声明它。 + +如果你在遍历某个集合时并不关心集合中的元素,你可以通过下划线来代替集合中的元素变量名: + +``` +let base = 3 +let power = 10 +var answer = 1 +for _ in 1...power { + answer *= base +} +println("\(base) to the power of \(power) is \(answer)") +// prints "3 to the power of 10 is 59049” +``` +这个例子用来计算某个数字的某次方(这里是计算3的10次方)。它用起始值1乘以3,循环10次。这种计算并不需要知道当前是第几次循环(循环的计数器),只需要保证它执行次数是正确的即可。 + +我们还可以使用```for-in```遍历数组中的元素: + +``` +“let names = ["Anna", "Alex", "Brian", "Jack"] +for name in names { + println("Hello, \(name)!") +} +// Hello, Anna! +// Hello, Alex! +// Hello, Brian! +// Hello, Jack!” + +``` +你也同样可以遍历字典中的key-value。遍历时,字典中的每个元素都以```(key,value)```元组结构返回,你也可以在```for-in```中将元组中的key,value当做常量显式的分解出来。这里,key被分解为为常量```animalName```,value被分解为```legCount```: + +``` +“let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] +for (animalName, legCount) in numberOfLegs { + println("\(animalName)s have \(legCount) legs") +} +// spiders have 8 legs +// ants have 6 legs +// cats have 4 legs” + +``` +```Dictionary```中的元素的顺序在被遍历时可能和我们插入它的顺序不同,这是由于```Dictionary```自身就是无序的,它在被遍历时无法保证元素的顺序。想了解更多关于数组和字典的内容,请查阅Collection Type一章。 + +除了数组和字典,你同样可以使用```for-in```来遍历字符串中的```Character```: + +``` +“for character in "Hello" { + println(character) +} +// H +// e +// l +// l +// o + +``` +## For-Condition-Increment + +除了使用```for-in```这种循环表达式,Swift还提供了传统的C风格的``for```循环表达式,通常它需要一个循环执行条件和一个累加器: + +``` +“for var index = 0; index < 3; ++index { + println("index is \(index)") +} +// index is 0 +// index is 1 +// index is 2 +``` +下面是这种语法通用的表达式: + +for ```initialization```;```condition```;```increment```{ +```statements``` +} + +和C语言一样,循环表达式被分号分割为3部分。但是和C语言不同的是,Swift不需要使用括号将"initialization;condition;increment"包围起来。 + +循环执行顺序如下: + +1,循环开始时执行一次initialization表达式,初始化循环使用的常量或变量。 + +2,condition表达式被执行,如果结果为```false```循环结束,执行循环体后面的代码。如果condition表达式结果为```true```,继续执行循环体内的代码 + +3,当循环体内的代码被执行完时,increment表达式被执行。通常情况是增加或减少计数器的值,然后执行第2步,condition表达式会被再次执行。 + +上面的for循环结构也可以如下表示: + +```initialization``` +while ```condition``` { +```statements``` +```increment``` +} + +在for循环初始化时创建的变量或者常量只在循环体内有效,如果想获取循环结束时的```index```值,你必须将```index```显式的声明到循环表达式前: + +``` +var index: Int +for index = 0; index < 3; ++index { + println("index is \(index)") +} +// index is 0 +// index is 1 +// index is 2 +println("The loop statements were executed \(index) times") +// prints "The loop statements were executed 3 times” + +``` +注意循环结束时,```index```值是```3```而不是```2```。当```++index```被最后一次执行时,```index```被赋值为```3```,这回导致```index<3```返回```false```,结束循环。 + +##While循环 + +一个```while```语句会循环执行一段代码直到条件变为```false```。这种循环语句在处理循环次数不确定的情况时非常有效。Swift提供两种```while```循环: + +* ```while```语句会在执行循环提前判断执行条件。 +* ```do-while```语句会在执行完循环体内代码后判断执行条件。 + +###while + +一个```while```循环从判断执行条件开始。如果条件为```true```,则循环执行循环体内的代码,知道条件变为```false```。下面是通用的```while```语法格式: + +``` +while condition { + statements +} +``` +下面是一个简单的Snakes and Ladders游戏(也叫Chutes and Ladders) + +【图】 + +游戏规则如下: + +* 板子上有25个方块,你的目标是到达或超过第25个方格。 +* 每次你需要通过掷骰子来决定前进几个放格,前进的方向由上图虚线的箭头所示。 +* 如果在你的回合结束时,你恰好到了梯子的尾部,你可以沿着梯子爬上去。 +* 如果在你的回合结束时,你恰好到了蛇的头部,则你会沿着蛇身滑下去。 + +游戏的板子可以看做是一个```Int```型的数组。大小由常量```finalSquare```决定,这个常量也会用来初始化数组和判断获胜条件。数组被初始化为26个0,注意不是25(数组范围从0到25): + +``` +let finalSquare = 25 +var board = Int[](count: finalSquare + 1, repeatedValue: 0)” +``` +板子上的许多方格用来被指定为梯子或者蛇。如果是梯子,那么这个方格的值为正数,如果是蛇,则方格的值为负数: + +``` +board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 +board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 + +``` +第三个方格被认定为是梯子的底部,它会让你走到第11个方格。为了表达这个意思,```board[03]```被复制为```+08```,它等价于整数8,考虑到所有的数字均为2位数,为了对齐和美观,(```+i```)用来和(```-i```)保持一致。 + +玩家从板子左下角的第0号方块开始,第一次掷骰子会将玩家移动到: + +``` +var square = 0 +var diceRoll = 0 +while square < finalSquare { + // roll the dice + if ++diceRoll == 7 { diceRoll = 1 } + // move by the rolled amount + square += diceRoll + if square < board.count { + // if we're still on the board, move up or down for a snake or a ladder + square += board[square] + } +} +println("Game over!") +``` +这个例子用了一个非常简单的方式来掷骰子。 From e9049bfcd2dedce3073447f455e561fdd34f1e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AD=B1=E8=B0=B7?= Date: Tue, 17 Jun 2014 23:46:25 +0800 Subject: [PATCH 096/261] =?UTF-8?q?2.3=20=E5=88=9D=E7=A8=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/03_Strings_and_Characters.md | 604 ++++++++++++++++++++++ 1 file changed, 604 insertions(+) diff --git a/src/chapter2/03_Strings_and_Characters.md b/src/chapter2/03_Strings_and_Characters.md index e69de29..5012592 100644 --- a/src/chapter2/03_Strings_and_Characters.md +++ b/src/chapter2/03_Strings_and_Characters.md @@ -0,0 +1,604 @@ +## 字符和字符串 + + +A string is an ordered collection of characters, such as "hello, world" or "albatross". Swift strings are represented by the String type, which in turn represents a collection of values of Character type. + +字符串指的是一组字符的有序集合,比如「hello, world」或者「albatoross」。在 Swift 里,字符串通过 `String` 类型表示,或者从另外一个角度来说,它是一组 `Character` 对象的值的集合。 + + + +Swift’s String and Character types provide a fast, Unicode-compliant way to work with text in your code. The syntax for string creation and manipulation is lightweight and readable, with a similar syntax to C strings. String concatenation is as simple as adding together two strings with the + operator, and string mutability is managed by choosing between a constant or a variable, just like any other value in Swift. + +Swift 的 `String` 和 `Character` 类型为代码里的字符操作提供了一种快速的、兼容 Unicode 的途径。跟 C 语言类似,在 Swift 里面新建和操作字符的语法十分简单易读。字符串的合并只需要在两个字符串中间见天一个 `+` 运算符,同时就像其它 Swift 值一样,可以通过定义字符串为常量或是变量来决定它是否可被修改。 + + +Despite this simplicity of syntax, Swift’s String type is a fast, modern string implementation. Every string is composed of encoding-independent Unicode characters, and provides support for accessing those characters in various Unicode representations. + +尽量语法十分简单,Swift 的 `String` 类型是一个快速且现代化的字符串实现。每个字符串都由一组独立编码的 Unicode 字符组成,并且对这些字符提供了多种可访问的 Unicode 编码形式。 + +Strings can also be used to insert constants, variables, literals, and expressions into longer strings, in a process known as string interpolation. This makes it easy to create custom string values for display, storage, and printing. + + +> #### NOTE +> +> Swift’s String type is bridged seamlessly to Foundation’s NSString class. If you are working with the Foundation framework in Cocoa or Cocoa Touch, the entire NSString API is available to call on any String value you create, in addition to the String features described in this chapter. You can also use a String value with any API that requires an NSString instance. +> +> For more information about using String with Foundation and Cocoa, see Using Swift with Cocoa and Objective-C. + +> #### 需要注意 + +> Swift 的 `String` 类型无缝接入了 Foundation 的 `NSString` 类。如果你之前在 Cocoa 或 Cocoa Touch 中使用了 Foundation 框架,所有 `NSString` 的 API 都可以用在新的 `String` 实例对象上,而且 `String` 对象还额外添加了下文中提到的特性。同时也可以把 `String` 对象用在任何需要传入 `NSString` 实例为参数的 API 中。 + +> 更多关于 `String` 和 Foundation 或 Coca 使用方法的信息,请查看 [Using Swift with Cocoa and Objective-C]()。 + +### String Literals + +### 字符串字面量 + +You can include predefined String values within your code as string literals. A string literal is a fixed sequence of textual characters surrounded by a pair of double quotes (""). + +我们可以在代码的前面先定义一些字符串字面量。字符串字面量是由一对引号("")包裹的含有相对顺序的字符集合。 + +A string literal can be used to provide an initial value for a constant or variable: + +字符串字面量可以给常量或者变量提供一个初始值: + + let someString = "Some string literal value" + +Note that Swift infers a type of String for the someString constant, because it is initialized with a string literal value. + +需要注意的是,Swift 会自动把 `someString` 定义为 `String` 类型,因为它的初始值是一个字符串字面量。 + + +String literals can include the following special characters: + +字符串字面量可以包含以下特殊字符: + +* The escaped special characters \0 (null character), \\ (backslash), \t (horizontal tab), \n (line feed), \r (carriage return), \" (double quote) and \' (single quote) +* Single-byte Unicode scalars, written as \xnn, where nn is two hexadecimal digits +* Two-byte Unicode scalars, written as \unnnn, where nnnn is four hexadecimal digits +* Four-byte Unicode scalars, written as \Unnnnnnnn, where nnnnnnnn is eight hexadecimal digits + +* 转义后的特殊字符 `\0`(空字符),`\\`(斜杠),`\t`(水平 Tab),`\n`(换行),`\r`(回车),`\"`(双引号),`\'`(单引号); +* 单字节 Unicode 字符,一般写为 `\xnn`,其中 `nn` 是两位十六进制数值; +* 双字节 Unicode 字符,一般写为 `\unnnn`,其中 `nnnn` 是四位十六进制数值; +* 四字节 Unicode 字符,一般写为 `\Unnnnnnnn`,其中 `nnnnnnnn` 是八个十六进制数值; + +The code below shows an example of each kind of special character. The wiseWords constant contains two escaped double quote characters. The dollarSign, blackHeart, and sparklingHeart constants demonstrate the three different Unicode scalar character formats: + +下面的代码中,对各种特殊字符举了一些例子。`wiseWords` 常量包含了两个被转义的引号字符。`dollarSign`、`blackHeart` 和 `sparklingHeart` 常量展示了三种不同类型的 Unicode 字符表示方式。 + + let wiseWords = "\"Imagination is more important than knowledge\" - Einstein" + // "Imagination is more important than knowledge" - Einstein + let dollarSign = "\x24" // $, Unicode 字符 U+0024 + let blackHeart = "\u2665" // ♥, Unicode 字符 U+2665 + let sparklingHeart = "\U0001F496" // 💖, Unicode 字符 U+1F496 + +### Initializing an Empty String + +### 初始化字符串 + +To create an empty String value as the starting point for building a longer string, either assign an empty string literal to a variable, or initialize a new String instance with initializer syntax: + + var emptyString = "" // empty string literal + var anotherEmptyString = String() // initializer syntax + // these two strings are both empty, and are equivalent to each other + +一般我们会初始化一个空白的字符串作为后面组装长字符串的基础,Swift 提供了两种初始化字符串的方式,第一种是给变量赋予一个空白的字符串字面量,第二种是通过新建实例的语法: + + + var emptyString = "" // 空白的字符串字面量 + var anotherEmptyString = String() // 新建 String 实例的语法 + // 这两个字符串都是空白的,而且相互等价。 + +You can find out whether a String value is empty by checking its Boolean isEmpty property: + +可以通过 `String` 对象的 `isEmpty` 属性获取一个字符串是否为空,该属性返回的是布尔值: + + if emptyString.isEmpty { + println("Nothing to see here") + } + // prints "Nothing to see here" + + + if emptyString.isEmpty { + println("你看不到我") + } + // 会输出 "你看不到我" + + +### String Mutability + +### 字符串操作 + +You indicate whether a particular String can be modified (or mutated) by assigning it to a variable (in which case it can be modified), or to a constant (in which case it cannot be modified): + + var variableString = "Horse" + variableString += " and carriage" + // variableString is now "Horse and carriage" + + let constantString = "Highlander" + constantString += " and another Highlander" + // this reports a compile-time error - a constant string cannot be modified + + +一个字符串是否能被操作取决于它被定义为常量(不能修改)还是变量(允许修改): + + var variableString = "Horse" + variableString += " and carriage" + // 运行后 variableString 将会是 "Horse and carriage" + + let constantString = "Highlander" + constantString += " and another Highlander" + // 这段代码会在编译时报错,因为常量不能被修改 + +> #### NOTE + +> This approach is different from string mutation in Objective-C and Cocoa, where you choose between two classes (NSString and NSMutableString) to indicate whether a string can be mutated. + +> #### 需要注意 + +> 这个地方跟 Objective-C 和 Cocoa 不一致,与前者不同,后者可以使用两种类型的字符串 `NSString` 和 `NSMutableString` 来区分该字符是否能被修改。 + + +### Strings Are Value Types + +### 字符串是值类型 + +Swift’s String type is a value type. If you create a new String value, that String value is copied when it is passed to a function or method, or when it is assigned to a constant or variable. In each case, a new copy of the existing String value is created, and the new copy is passed or assigned, not the original version. Value types are described in Structures and Enumerations Are Value Types. + + +Swift 中的 `String` 类型属于值类型,也就是说你一旦把一个字符串传进一个方法或者函数里面,或者重新赋值到一个新的常量或变量时,字符串的值都会被复制一遍。详细来说就是,String 类型会把原来的字符串复制为一个新的拷贝,再进行传递和分配,传递后的字符串已经不是原来的那个。关于值类型的详细介绍会在 [Structures and Enumerations Are Value Types]()。 + + +> #### NOTE + +> This behavior differs from that of NSString in Cocoa. When you create an NSString instance in Cocoa, and pass it to a function or method or assign it to a variable, you are always passing or assigning a reference to the same single NSString. No copying of the string takes place, unless you specifically request it. + +> ### 需要注意 + +> 这个行为和 Cocoa 里的 `NSString` 有所区别。每当实例化一个 `NSString` 对象之后,无论怎么在函数和方法之间传递,它都只是指向原来的值的引用,并不会每次复制这个字符串对象,除非你主动要求这么做。 + + +Swift’s copy-by-default String behavior ensures that when a function or method passes you a String value, it is clear that you own that exact String value, regardless of where it came from. You can be confident that the string you are passed will not be modified unless you modify it yourself. + +Swift 这种默认复制的行为确保了每个方法或者函数里面接收到的字符串都完全属于这个方法或函数的,并不需要考虑它从哪来,这样就保证了字符串不会变动,除非主动修改它。 + +Behind the scenes, Swift’s compiler optimizes string usage so that actual copying takes place only when absolutely necessary. This means you always get great performance when working with strings as value types. + +实际上,Swift 的编译器优化了字符串的使用过程,只有绝对需要时才会产生复制的实际操作。这样就意味着 Swift 可以在字符串操作上和值类型保持一样的高性能。 + + +### Working with Characters + +### 字符处理 + +Swift’s String type represents a collection of Character values in a specified order. Each Character value represents a single Unicode character. You can access the individual Character values in a string by iterating over that string with a for-in loop: + +Swift 的 `String` 类型是由一系列 `Character` 对象根据一定的顺序排列组成的。每个 `Character` 对象都对应着一个 Unicode 字符。我们可以用一个 `for-in` 循环逐个读取字符串中的 `Character` 对象: + + for character in "Dog!🐶" { + println(character) + } + // D + // o + // g + // ! + // 🐶 + + +The for-in loop is described in For Loops. + +`for-in` 循环的介绍在 [For Loops]()。 + +Alternatively, create a stand-alone Character constant or variable from a single-character string literal by providing a Character type annotation: + +此外,可以通过为一个单独的字符指定 `Character` 类型去定义一个独立的 `Character` 常量或者变量: + + let yenSign: Character = "¥" + + +### Counting Characters + +### 计算字符个数 + +To retrieve a count of the characters in a string, call the global countElements function and pass in a string as the function’s sole parameter: + + let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪" + println("unusualMenagerie has \(countElements(unusualMenagerie)) characters") + // prints "unusualMenagerie has 40 characters" + +如果需要计算一个字符串中字符的数量,可以通过调用全局方法 `countElements` 并把该字符串作为唯一的参数: + + let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪" + println("unusualMenagerie 拥有 \(countElements(unusualMenagerie)) 个字符") + // hui输出 "unusualMenagerie 拥有 40 个字符" + + +> #### NOTE + +> Different Unicode characters and different representations of the same Unicode character can require different amounts of memory to store. Because of this, characters in Swift do not each take up the same amount of memory within a string’s representation. As a result, the length of a string cannot be calculated without iterating through the string to consider each of its characters in turn. If you are working with particularly long string values, be aware that the countElements function must iterate over the characters within a string in order to calculate an accurate character count for that string. + +> Note also that the character count returned by countElements is not always the same as the length property of an NSString that contains the same characters. The length of an NSString is based on the number of 16-bit code units within the string’s UTF-16 representation and not the number of Unicode characters within the string. To reflect this fact, the length property from NSString is called utf16count when it is accessed on a Swift String value. + + +> #### 需要注意 + +> 不同的 Unicdoe 字符或者同一个 Unicode 字符的不同表示方式可能需要不同的内存大小进行存储。因此,在一个字符串中每个字符可能占用不同的内存大小。结果导致如果需要知道一个字符串的长度,必须通过迭代整个字符串中的字符才能计算出来。如果我们在处理一个超长字符串,必须要注意的是 `countElements` 方法会迭代整个字符串来精确计算该字符串的长度。 + +> 另外需要注意的是,对于同一个字符串,通过执行 `countElements` 方法返回的字符串数量不一定和 `NSString` 使用 `length` 属性得到的值一样。因为 `NSString` 的 `length` 值是基于 `UTF-16` 十六位编码方式统计的,并未直接统计字符串里 Unicode 字符的数量。为了反映这个事实,Swift 里 `String` 对象的 `utf16count` 属性对应 `NSString` 类的 `length` 值。 + + +### Concatenating Strings and Characters + +### 字符和字符串的拼接 + +String and Character values can be added together (or concatenated) with the addition operator (+) to create a new String value: + + let string1 = "hello" + let string2 = " there" + let character1: Character = "!" + let character2: Character = "?" + + let stringPlusCharacter = string1 + character1 // equals "hello!" + let stringPlusString = string1 + string2 // equals "hello there" + let characterPlusString = character1 + string1 // equals "!hello" let characterPlusCharacter = character1 + character2 // equals "!?" + +`String` 和 `Character` 对象可以通过 `+` 运算符进行组合(或者拼接),从而产生一个新的 `String` 对象: + + + let string1 = "hello" + let string2 = " there" + let character1: Character = "!" + let character2: Character = "?" + + let stringPlusCharacter = string1 + character1 // 等于 "hello!" + let stringPlusString = string1 + string2 // 等于 "hello there" + let characterPlusString = character1 + string1 // 等于 "!hello" let characterPlusCharacter = character1 + character2 // 等于 "!?" + + +You can also append a String or Character value to an existing String variable with the addition assignment operator (+=): + + var instruction = "look over" + instruction += string2 + // instruction now equals "look over there" + + var welcome = "good morning" + welcome += character1 + // welcome now equals "good morning!" + +也可以通过加法赋值运算符 `+=` 在一个已有的 `String` 变量后面追加 `String` 或 `Character` 对象: + + var instruction = "look over" + instruction += string2 + // instruction 现在是 "look over there" + + var welcome = "good morning" + welcome += character1 + // welcome now 现在是 "good morning!" + +> #### NOTE + +> You can’t append a String or Character to an existing Character variable, because a Character value must contain a single character only. + +> #### 需要注意 + +> 无法在 `Character` 对象后面追加任何 `String` 或 `Character` 字符,因为 `Character` 对象必须只有一个字符。 + + +### String Interpolation + +### 字符串插值 + +String interpolation is a way to construct a new String value from a mix of constants, variables, literals, and expressions by including their values inside a string literal. Each item that you insert into the string literal is wrapped in a pair of parentheses, prefixed by a backslash: + + let multiplier = 3 + let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)" + // message is "3 times 2.5 is 7.5" + + +字符串插值是一种新的创建 `String` 对象的方式,它可以在字符串中插入一系列的常量、变量、字面量和包含值运算的表达式。每种插值在字符串中必须用以斜线 `\` 打头并用圆括号 `()` 包裹起来: + + let multiplier = 3 + let message = "\(multiplier) 的 2.5 倍是 \(Double(multiplier) * 2.5)" + // 运行后输出 "3 的 2.5 倍是 7.5" + +In the example above, the value of multiplier is inserted into a string literal as \(multiplier). This placeholder is replaced with the actual value of multiplier when the string interpolation is evaluated to create an actual string. + +在上面的例子中,`multiplier` 的值以 `\(multiplier)` 的方式插入到字符串中,这个占位符会在字符串进行插值运算时自动替换成 `multiplier` 实际的值。 + +The value of multiplier is also part of a larger expression later in the string. This expression calculates the value of Double(multiplier) * 2.5 and inserts the result (7.5) into the string. In this case, the expression is written as \(Double(multiplier) * 2.5) when it is included inside the string literal. + +`multiplier` 同时也在字符串后面的表达式中出现,这个表达式会被执行并把计算结果(7.5)插入到字符串中。在这个案例里面,该表达式被写成了 `\(Double(multiplier) * 2.5)` 并插在了字符串里面。 + + +### Comparing Strings + +### 字符串比较 + +Swift provides three ways to compare String values: string equality, prefix equality, and suffix equality. + +Swift 提供了三种对比字符串的方式:全值比较、前缀比较和后缀比较。 + +#### String Equality + +#### 全值比较 + +Two String values are considered equal if they contain exactly the same characters in the same order: + + let quotation = "We're a lot alike, you and I." + let sameQuotation = "We're a lot alike, you and I." + if quotation == sameQuotation { + println("These two strings are considered equal") + } + // prints "These two strings are considered equal" + + + +如果两个字符串由相同的字符和一致的顺序组成,那就认为这两个字符串是完全相等的: + + let quotation = "We're a lot alike, you and I." + let sameQuotation = "We're a lot alike, you and I." + if quotation == sameQuotation { + println("这两个字符串是相等的") + } + // 运行后会输出 "这两个字符串是相等的" + +#### Prefix and Suffix Equality + +#### 前缀比较和后缀比较 + +To check whether a string has a particular string prefix or suffix, call the string’s hasPrefix and hasSuffix methods, both of which take a single argument of type String and return a Boolean value. Both methods perform a character-by-character comparison between the base string and the prefix or suffix string. + +通过调用字符串的 `hasPrefix` 或 `hasSuffix` 来判断该字符串是否含有特定的前缀或后缀,这两个方法分别都接收一个字符串参数,结果返回布尔值。这两个方法会在字符串和需要对比的前缀或后缀进行逐字对比。 + +The examples below consider an array of strings representing the scene locations from the first two acts of Shakespeare’s Romeo and Juliet: + + let romeoAndJuliet = [ + "Act 1 Scene 1: Verona, A public place", + "Act 1 Scene 2: Capulet's mansion", + "Act 1 Scene 3: A room in Capulet's mansion", + "Act 1 Scene 4: A street outside Capulet's mansion", + "Act 1 Scene 5: The Great Hall in Capulet's mansion", + "Act 2 Scene 1: Outside Capulet's mansion", + "Act 2 Scene 2: Capulet's orchard", + "Act 2 Scene 3: Outside Friar Lawrence's cell", + "Act 2 Scene 4: A street in Verona", + "Act 2 Scene 5: Capulet's mansion", + "Act 2 Scene 6: Friar Lawrence's cell" + ] + +下面的例子来自莎士比亚著作的《罗密欧与茱丽叶》,我们用前两场戏每一幕对应的地点组成一个数组: + + let romeoAndJuliet = [ + "Act 1 Scene 1: Verona, A public place", + "Act 1 Scene 2: Capulet's mansion", + "Act 1 Scene 3: A room in Capulet's mansion", + "Act 1 Scene 4: A street outside Capulet's mansion", + "Act 1 Scene 5: The Great Hall in Capulet's mansion", + "Act 2 Scene 1: Outside Capulet's mansion", + "Act 2 Scene 2: Capulet's orchard", + "Act 2 Scene 3: Outside Friar Lawrence's cell", + "Act 2 Scene 4: A street in Verona", + "Act 2 Scene 5: Capulet's mansion", + "Act 2 Scene 6: Friar Lawrence's cell" + ] + +You can use the hasPrefix method with the romeoAndJuliet array to count the number of scenes in Act 1 of the play: + + var act1SceneCount = 0 + for scene in romeoAndJuliet { + if scene.hasPrefix("Act 1 ") { + ++act1SceneCount + } + } + println("There are \(act1SceneCount) scenes in Act 1") + // prints "There are 5 scenes in Act 1" + +我们可以用 `hasPrefix` 方法统计在 `romeoAndJuliet` 数组中第一场戏一共有几幕: + + var act1SceneCount = 0 + for scene in romeoAndJuliet { + if scene.hasPrefix("Act 1 ") { + ++act1SceneCount + } + } + println("第一场戏一共有 \(act1SceneCount) 幕") + // 运行后输出: "第一场戏一共有 5 幕" + +Similarly, use the hasSuffix method to count the number of scenes that take place in or around Capulet’s mansion and Friar Lawrence’s cell: + + var mansionCount = 0 + var cellCount = 0 + for scene in romeoAndJuliet { + if scene.hasSuffix("Capulet's mansion") { + ++mansionCount + } else if scene.hasSuffix("Friar Lawrence's cell") { + ++cellCount + } + } + println("\(mansionCount) mansion scenes; \(cellCount) cell scenes") + // prints "6 mansion scenes; 2 cell scenes" + + +类似地,用 `hasSuffix` 方法来统计发生在 `Capulet's mansion` 和 `Friar Lawrence's cell` 场景的数量: + + var mansionCount = 0 + var cellCount = 0 + for scene in romeoAndJuliet { + if scene.hasSuffix("Capulet's mansion") { + ++mansionCount + } else if scene.hasSuffix("Friar Lawrence's cell") { + ++cellCount + } + } + println("\(mansionCount) mansion scenes; \(cellCount) cell scenes") + // 运行后输出: "6 mansion scenes; 2 cell scenes" + + +### Uppercase and Lowercase Strings + +### 字符串的大小写转换 + +You can access an uppercase or lowercase version of a string with its uppercaseString and lowercaseString properties: + +``` +let normal = "Could you help me, please?" +let shouty = normal.uppercaseString +// shouty is equal to "COULD YOU HELP ME, PLEASE?" +let whispered = normal.lowercaseString +// whispered is equal to "could you help me, please?" +``` + +可以通过字符串本身的 `uppercaseString` 或 `lowercaseString` 属性取得它的全大些或全小写版本: + + +``` +let normal = "Could you help me, please?" +let shouty = normal.uppercaseString +// shouty 等价于 "COULD YOU HELP ME, PLEASE?" +let whispered = normal.lowercaseString +// whispered 等价于 "could you help me, please?" +``` + + +### Unicode + +### Unicode 字符 + +Unicode is an international standard for encoding and representing text. It enables you to represent almost any character from any language in a standardized form, and to read and write those characters to and from an external source such as a text file or web page. + +Unicode 是一个用来编码和表示文本的国际标准。它允许我们用一个标准格式来表示世界上几乎所有的字符,并且提供了在类似文本文件或网页中读取和写入这些字符的能力。 + +Swift’s String and Character types are fully Unicode-compliant. They support a number of different Unicode encodings, as described below. + +Swift 的 `String` 和 `Character` 类型完全兼容 Unicode ,并且提供了大量 Unicode 编码的支持,下面我们会提到这点。 + +#### Unicode Terminology + +#### Unicode 的术语 + +Every character in Unicode can be represented by one or more unicode scalars. A unicode scalar is a unique 21-bit number (and name) for a character or modifier, such as U+0061 for LOWERCASE LATIN LETTER A ("a"), or U+1F425 for FRONT-FACING BABY CHICK ("🐥"). + +Unicode 里的每个字符都对应这一个或多个 uincode 标量。每个 unicode 标量是一个 21 位的数值(包括名称),代表着一个字符或者修饰符。比如 `U+0061` 是 `LOWERCASE LATIN LETTER A ("a")`, `U+1F425` 是 `FRONT-FACING BABY CHICK ("🐥")`。 + +When a Unicode string is written to a text file or some other storage, these unicode scalars are encoded in one of several Unicode-defined formats. Each format encodes the string in small chunks known as code units. These include the UTF-8 format (which encodes a string as 8-bit code units) and the UTF-16 format (which encodes a string as 16-bit code units). + +当一个 Unicode 的字符串被写进文本文件或者其它存储形式时,这些 unicode 标量就会从几种 Unicode 制定的编码方式中选取其中一种把该字符串编码成小块的编码单元。这些编码方式包括了 `UTF-8` 格式(会把字符串编码成 8 位编码单元),`UTF-16` 格式(把字符串编码成 16 位编码单元)。 + +#### Unicode Representations of Strings + +#### Unicode 字符串的表示方式 + +Swift provides several different ways to access Unicode representations of strings. + +Swift 对 Unicode 字符提供了几种不同的访问方式。 + +You can iterate over the string with a for-in statement, to access its individual Character values as Unicode characters. This process is described in Working with Characters. + +首先可以从字符串的逐字迭代中取得每个 `Character` 中的 Unicode 字符。这个过程在上面的 [字符处理]() 章节中有提到。 + +Alternatively, access a String value in one of three other Unicode-compliant representations: + +``` +A collection of UTF-8 code units (accessed with the string’s utf8 property) +A collection of UTF-16 code units (accessed with the string’s utf16 property) +A collection of 21-bit Unicode scalar values (accessed with the string’s unicodeScalars property) +``` + +另外,还可以通过以下三种方式中的一种访问字符串中兼容 Unicode 的字符数据: + +``` +一组以 UTF-8 编码的单元 (通过字符串的 utf8 属性访问) +一组以 UTF-16 编码的单元 (通过字符串的 utf16 属性访问) +一组以 21 位编码的单元 (通过字符串的 unicodeScalars 属性访问) +``` + +Each example below shows a different representation of the following string, which is made up of the characters D, o, g, !, and the 🐶 character (DOG FACE, or Unicode scalar U+1F436): + +下面的每个示例描述了以下字符串不同的几种表示方法,这个字符串由这几个字符组成:`D`、`o`、`g`、`!` 和 `🐶` 字符(`DOG FACE` 或者 Unicode 标量 `U+1F436`) + +``` +let dogString = "Dog!🐶" +``` + + +#### UTF-8 + +You can access a UTF-8 representation of a String by iterating over its utf8 property. This property is of type UTF8View, which is a collection of unsigned 8-bit (UInt8) values, one for each byte in the string’s UTF-8 representation: + +我们可以通过迭代访问字符串的 `utf8` 属性来获得该字符串的 `UTF-8` 编码形式。该属性的类型是 `UTF8View`,由一组无符号的 8 位数值(`UInt8`)组成,每个数值代表了字符串用 `UTF-8` 编码后的字节。 + +``` +for codeUnit in dogString.utf8 { + print("\(codeUnit) ") +} +print("\n") +// 68 111 103 33 240 159 144 182 +``` + +In the example above, the first four decimal codeUnit values (68, 111, 103, 33) represent the characters D, o, g, and !, whose UTF-8 representation is the same as their ASCII representation. The last four codeUnit values (240, 159, 144, 182) are a four-byte UTF-8 representation of the DOG FACE character. + +上面的例子中,前四位十进制的编码单元分别代表了 `D`、`o`、`g`、`!`,这几个字符的编码形式跟 ASCII 是一致的。最后四位编码单元(240,159,144,182)是一个 4 位的 UTF-8 编码表示形式,用来表示 `DOG FACE` 字符。 + +#### UTF-16 + +You can access a UTF-16 representation of a String by iterating over its utf16 property. This property is of type UTF16View, which is a collection of unsigned 16-bit (UInt16) values, one for each 16-bit code unit in the string’s UTF-16 representation: + +通过迭代访问字符串的 `utf16` 属性可以取得该字符串的 `UTF-16` 编码形式,该属性的类型是 `UTF16View`,即一组无符号 16 位数值(UInt16)的集合,每个数值代表了字符串用 `UTF-16` 编码后的字节。 + +``` +for codeUnit in dogString.utf16 { + print("\(codeUnit) ") +} +print("\n") +// 68 111 103 33 55357 56374 +``` + +Again, the first four codeUnit values (68, 111, 103, 33) represent the characters D, o, g, and !, whose UTF-16 code units have the same values as in the string’s UTF-8 representation. + +类似的,前四个编码单元(68,111,103,33)代表了前四个字符 `D`、`o`、`g` 和 `!`,这几个字符 `UTF-16` 和 `UTF-8` 拥有相同的表示方式。 + +The fifth and sixth codeUnit values (55357 and 56374) are a UTF-16 surrogate pair representation of the DOG FACE character. These values are a lead surrogate value of U+D83D (decimal value 55357) and a trail surrogate value of U+DC36 (decimal value 56374). + +第五个和第六个编码单元(55357 和 56374)则是 `DOG FACE` 字符的代理项。这两个数值由第一部分的 `U+D83D`(十进制 55357) 和 `U+DC36`(十进制 56374)组成。 + +#### Unicode Scalars + +#### Unicode 标量 + +You can access a Unicode scalar representation of a String value by iterating over its unicodeScalars property. This property is of type UnicodeScalarView, which is a collection of values of type UnicodeScalar. A Unicode scalar is any 21-bit Unicode code point that is not a lead surrogate or trail surrogate code point. + +通过迭代字符串的 `unicodeScalars` 属性可以获得该字符串的 Unicode 标量表示形式。该属性的类型是 `UnicodeScalarView`,由一组 `UnicodeScalar` 类型的值组成。一个 Unicode 标量是一个完整的 21 位编码,既没有首码位,也没有尾码位。 + +Each UnicodeScalar has a value property that returns the scalar’s 21-bit value, represented within a UInt32 value: + +每个 `UnicodeScalar` 都有一个 `value` 属性可以获得它的 21 位(UInt32)标量值: + +``` +for scalar in dogString.unicodeScalars { + print("\(scalar.value) ") +} +print("\n") +// 68 111 103 33 128054 +``` + +The value properties for the first four UnicodeScalar values (68, 111, 103, 33) once again represent the characters D, o, g, and !. The value property of the fifth and final UnicodeScalar, 128054, is a decimal equivalent of the hexadecimal value 1F436, which is equivalent to the Unicode scalar U+1F436 for the DOG FACE character. + +前四个 `UnicodeScalar` 对象的 `value` 属性值(68,111,103,33)按照惯例还是代表着 `D`、`o`、`g` 和 `!` 四个字符。而第五个也就是最后一个 `UnicodeScalar` 数值 128054 的十六进制是 1F436,刚好等价于 `DOG FACE` 字符的 Unicode 标量 `U+1F436` + +As an alternative to querying their value properties, each UnicodeScalar value can also be used to construct a new String value, such as with string interpolation: + +除了使用它们的 `value` 属性,每个 `UnicodeScalar` 对象也可以用来直接构造新的 `String` 对象,比如这里用的字符串插值方法: + +``` +for scalar in dogString.unicodeScalars { + println("\(scalar) ") +} +// D +// o +// g +// ! +// 🐶 +``` + From 10cb3ce66660f687f91b093f63806d052f2cbb95 Mon Sep 17 00:00:00 2001 From: jayson Date: Wed, 18 Jun 2014 10:57:22 +0800 Subject: [PATCH 097/261] add control_flow --- src/chapter2/05_Control_Flow.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index cce16a1..39ca975 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -206,4 +206,17 @@ while square < finalSquare { } println("Game over!") ``` -这个例子用了一个非常简单的方式来掷骰子。 +这个例子用了一个非常简单的方式来掷骰子。我们没有采用每次产生一个随机数的方法,取而代之的是我们先给```diceRoll```赋值为0,然后在每次while循环的过程中对```diceRoll```加1,然后检测它的值是否等于7,让它等于7的时候,再将它重置为1。这样,产生的一系列```diceRoll```的值为1,2,3,4,5,6,1,2...。 + +在掷完骰子后,玩家前进```diceRoll```个方格。玩家在前进的过程中很可能超过25,这种情况下游戏会结束。为了解决这种情况,当```square```在累加```board[quare]```的值前,会检查```square```的值是否小于```board.count```的值,同样它也会规避由数组越界带来的错误。 + +然后```while```循环体结束,这时会再次判断循环执行条件,如果玩家已经前进到了25或者越过了25,那么循环条件会返回```false```,游戏结束。 + +显然在上面这情况下,使用```while```循环是非常合适的,因为循环次数不确定,只能根据循环条件来判断是否要终止循环。 + +###Do-While +另一个```while```循环的变种是```do-while```表达式,它首先执行一次循环,然后在判断循环执行条件。如此反复,直到循环条件返回```false```。 + + + + From 59b06f95da48f1bddf8482eff21b68147f27f61e Mon Sep 17 00:00:00 2001 From: jayson Date: Wed, 18 Jun 2014 17:04:42 +0800 Subject: [PATCH 098/261] update flow control --- src/chapter2/05_Control_Flow.md | 376 +++++++++++++++++++++++++++++++- 1 file changed, 375 insertions(+), 1 deletion(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index 39ca975..bbe74a3 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -6,7 +6,7 @@ Swift提供类似C语言的控制流语法,比如```for```和```while```循环 Swift除了支持类似C语言这种```for-condition-increment```的表达式外,还支持```for-in```这种循环语句,可以轻松的遍历数组,字典,字符串等序列。 -Swift的```switch```语句和C语言相比很强大,它不会像C语言那样,因为在case的分支中忘记写break而执行了下一条case的语句。同时case语句可以匹配任何类型 +Swift的```switch```语句和C语言相比很强大,它不会像C语言那样,因为在case的分支中忘记写break而执行了下一条case的语句。同时case语句可以匹配任何类型模式,包括区间蒲培,元组和特定类型描述。 #For循环 @@ -217,6 +217,380 @@ println("Game over!") ###Do-While 另一个```while```循环的变种是```do-while```表达式,它首先执行一次循环,然后在判断循环执行条件。如此反复,直到循环条件返回```false```。 +下面是```do-while```表达式的格式: +``` +do { + statements +} while condition” + +``` + +还是上面的蛇和梯子的例子,我们来使用```do-while```实现,初始化变量的过程同```while```循环: + +``` +let finalSquare = 25 +var board = Int[](count: finalSquare + 1, repeatedValue: 0) +board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 +board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 +var square = 0 +var diceRoll = 0 + +``` +这次,我们首先来判断第一次遇到的是梯子还是蛇。因为没有梯子会把玩家直接送到25,所以这个判断是安全的。开始时,玩家的位置在"0",```board[0]```的值永远为0: + +``` +do { + // move up or down for a snake or ladder + square += board[square] + // roll the dice + if ++diceRoll == 7 { diceRoll = 1 } + // move by the rolled amount + square += diceRoll +} while square < finalSquare +println("Game over!") +``` + +在判断遇到的时梯子还是蛇之后,我们掷骰子,玩家前进```diceRoll```个格子。当前循环结束。 + +这里的循环条件(```while square < finalSquare```)和前面相同,但它会在循环结束后被执行。```do-while```循环结构比前面的```while```更适合这个游戏。使用```do-while```时,```square+=board[square]```会立刻被执行,它省去了上个例子中对数组越界的判断。 + +##条件表达式 +通常情况下我们需要在满足某种条件时执行一段代码或者在出错时执行另一段代码,也可能需要在某个值过大或过小时打印输出一些提示信息。这都需要你在代码中加入判断条件。 + +Swift提供了两种条件判断的表达式,它们是```if```和```switch```。 + +通常情况下,在条件分支比较少时,你使用```if```表达式,```switch```表达式用来处理复杂的判断条件和过多的条件分支,此外```switch```在模式匹配上非常有用。 + +###If + +```If```表达式很简单,当判断条件为```true```时,执行一段代码: + +``` +var temperatureInFahrenheit = 30 +if temperatureInFahrenheit <= 32 { + println("It's very cold. Consider wearing a scarf.") +} +// prints "It's very cold. Consider wearing a scarf. +``` +上面的例子会判断温度是否小于等于32华氏度。如果是,打印一条消息。 + +```if```表达式通常和```else```搭配使用,当```if```表达式返回```false```时,```else```分支的代码会被执行: + +``` +temperatureInFahrenheit = 40 +if temperatureInFahrenheit <= 32 { + println("It's very cold. Consider wearing a scarf.") +} else { + println("It's not that cold. Wear a t-shirt.") +} +// prints "It's not that cold. Wear a t-shirt. + +``` + +这种情况下```if```和```else```两个分支中的一个一定会被执行到,你也可以将多个```if```表达式连起来使用: + +``` +temperatureInFahrenheit = 90 +if temperatureInFahrenheit <= 32 { + println("It's very cold. Consider wearing a scarf.") +} else if temperatureInFahrenheit >= 86 { + println("It's really warm. Don't forget to wear sunscreen.") +} else { + println("It's not that cold. Wear a t-shirt.") +} +// prints "It's really warm. Don't forget to wear sunscreen. +``` +这里,多了一个```if```表达式用来判断特定的温度范围。最后的```else```语句是可选的: + +``` +temperatureInFahrenheit = 72 +if temperatureInFahrenheit <= 32 { + println("It's very cold. Consider wearing a scarf.") +} else if temperatureInFahrenheit >= 86 { + println("It's really warm. Don't forget to wear sunscreen.") +} +``` + +在这个例子中,温度不满足```if```和```else if ```的执行条件,因此没有信息会被打印出来。 + +###Switch + +```switch```表达式会将一个值和多种模式进行匹配。匹配成功则执行该条件所对应的代码。```switch```是一种可以替换```if```进行条件判断的表达式。```switch```的语法格式如下: + +``` +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```表达式。除了可以用```case```表达式来比较具体的值以外,Swift提供了许多复杂的模式匹配,下一小节会详细介绍。 + +```switch```语句内包含多个代码执行分支,这点和```if```表达式很像。```switch```表达式决定了那个分支会被执行,通常是根据变量值来决定的。 + +每个```switch```表达式必须是完整的,意思是它提供的分支条件必须能涵盖所有情况,你可以定义一个默认的分支条件用来处理一些意外的条件。这种分支通常用关键字```default```表示,并且它必须是最后一个分支条件。 + +这个例子使用```switch```表达式类匹配一个小写字母变量```someCharacter```: + +``` +let someCharacter: Character = "e" +switch someCharacter { +case "a", "e", "i", "o", "u": + println("\(someCharacter) is a vowel") +case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", +"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": + println("\(someCharacter) is a consonant") +default: + println("\(someCharacter) is not a vowel or a consonant") +} +// prints "e is a vowel” +``` +```switch```表达式的第一个```case```分支是匹配五个元音字母。同理,第二个```case```分支用来匹配所有的字符常量。 + +通常来说列举出所有的字符不太现实,因此```switch```表达式提供了```default```分支用来匹配所有其它的字符,这确保了```switch```表达式的完整性。 + + +###没有隐式贯穿 + + +和C语言或Objective-C相比,Swift中的```switch```表达式在执行完一条```case```分支的代码后,则认为```switch```语句执行完毕。在某个```case```分支没有```break```的情况下,不会继续执行下一条```case```分支的代码。这比C语言更简单和安全。 + + 注意: + 你也可以在```case```分支代码执行前使用```break```语句来跳出这个分支,详见后面的章节。 +每条```case```分支的函数体必须至少包含一行可执行代码。下面的代码是不合法的: + +``` +let anotherCharacter: Character = "a" +switch anotherCharacter { +case "a": +case "A": + println("The letter A") +default: + println("Not the letter A") +} +// this will report a compile-time error +``` + +和C语言不同,```switch```表达式不会既匹配`"a"`又匹配`"A"`。遇到这种情况,编译器会给出错误提示。这条规则会避免意外的执行了其它分支的代码。 + +一条```case```分支也可以匹配多个判断条件,用逗号隔开: + +``` +switch some value to consider { +case value 1, +value 2: + statements +} +``` + 注意 + 对于```switch```表达式的某个case分支,你可以通过使用```fallthrough```关键字来强制贯穿改```case```分支。 + 更对细节在Fallthrough一节有所介绍 + +###区间匹配 + +```switch```表达式的```case```分支可以是一个值区间同样支持范围匹配。下面这个例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式: + +``` +let count = 3_000_000_000_000 +let countedThings = "stars in the Milky Way" +var naturalCount: String +switch count { +case 0: + naturalCount = "no" +case 1...3: + naturalCount = "a few" +case 4...9: + naturalCount = "several" +case 10...99: + naturalCount = "tens of" +case 100...999: + naturalCount = "hundreds of" +case 1000...999_999: + naturalCount = "thousands of" +default: + naturalCount = "millions and millions of" +} +println("There are \(naturalCount) \(countedThings).") +// prints "There are millions and millions of stars in the Milky Way. +``` + +###元组 + +你可以使用元组在同一个```switch```表达式中测试多个值。元组中的每个元素可以是一个区间,也可以是不同的值。我们使用(_)来匹配任何可能的值。 + +下面的例子使用一个元组类型(```Int```,```Int```)的点(x,y)并用图标来描述它的分布: + +``` +let somePoint = (1, 1) +switch somePoint { +case (0, 0): + println("(0, 0) is at the origin") +case (_, 0): + println("(\(somePoint.0), 0) is on the x-axis") +case (0, _): + println("(0, \(somePoint.1)) is on the y-axis") +case (-2...2, -2...2): + println("(\(somePoint.0), \(somePoint.1)) is inside the box") +default: + println("(\(somePoint.0), \(somePoint.1)) is outside of the box") +} +// prints "(1, 1) is inside the box + +``` + +【图】 + +```switch```表达式用来判断这个点是否在原点;红色的X轴上;橘黄色的Y轴上;在蓝色的4x4的盒子内,还是在盒子外面。 + +不像C语言,Swift支持不同的```case```分支匹配同一个结果,在这个例子中,点(0,0)满足所有4个分之条件。这种情况下只有第一条```case```语句被执行。点(0,0)会首先匹配第一条```case(0,0)```,后面的```case```语句会被忽略掉。 + +###值绑定(Value Bindings) + +```switch```表达式允许在一个```case```分支中,将待匹配的值绑定到一些常量或临时变量上。这就是值绑定。 +下面的例子将使用值绑定的方法重写上面的代码: + +``` +let anotherPoint = (2, 0) +switch anotherPoint { +case (let x, 0): + println("on the x-axis with an x value of \(x)") +case (0, let y): + println("on the y-axis with a y value of \(y)") +case let (x, y): + println("somewhere else at (\(x), \(y))") +} +// prints "on the x-axis with an x value of 2 + +``` +【图】 + +上面我们通过```switch```表达式判断了```anotherPoint```这个点是否在红色的X,y轴上或者在非轴上的任意位置。 + +上面三条```case```语句使用临时变量```x```,```y```来匹配```anotherPoint```中的值。第一条```case(let x, 0)```语句用来匹配所有```y```值为0的点,并把该点的```x```值赋值给常量```x```。同理,```case(0,let y)```匹配所有```x```值为0的点,并把该点得```y```值赋给常量```y```。 + +临时变量被声明后,它就可以用在```case```分支的代码中。本例中```x```,```y```在```println```方法中被打印出来。 + +注意到上面的```switch```语句并没有```default```分支,原因是最后一条```case let(x,y)```涵盖了所有其他情况,因此我们不需要再写一个```default```分支了。 + +在上面的例子中,我们通过```let```关键字将```x```,```y```声明为常量,原因是我们不需要修改他们的值。同样我们也可以用```var```关键字声明他们为变量,如果把它们声明为变量则需要为他们指定合适的初始值。任何对于它们值的修改也仅仅局限在```case```分支的代码中有效。 + +###Where + +在```case```语句的条件分支中可以使用```where```关键字增加附加条件的判断。 + +还是上面的例子: + +``` +let yetAnotherPoint = (1, -1) +switch yetAnotherPoint { +case let (x, y) where x == y: + println("(\(x), \(y)) is on the line x == y") +case let (x, y) where x == -y: + println("(\(x), \(y)) is on the line x == -y") +case let (x, y): + println("(\(x), \(y)) is just some arbitrary point") +} +// prints "(1, -1) is on the line x == -y +``` +【图】 + +上面的```switch```表达式用来检测```yetAnotherPoint```这个点是否在绿色或紫色的对角线上。 + +上面的三条```switch```表达式声明了常量```x```和```y```用来临时保存```yetAnotherPoint```中的坐标值。这两个常量同时也被```where```用来创建一个过滤条件。只有当```where```的过滤条件返回```true```时,```case```分支的代码才会被执行。 + +和上面的例子一样```default```分支在这个例子中也可以被忽略。 + +###控转移表达式 + +控制转移表达式会改变代码执行的顺序。Swift提供了4个控制转移表达式: + +* continue +* break +* fallthrough +* return + +我们下面将会讨论```control```,```break````,```return```表达式,```return```将会在函数一章讨论。 + + + +###continue + +```continue```用来终止当前循环并开始执行下一次循环。它会说“本次循环结束了”,但并不会跳出循环。 + + 注意: + 在```for-condition-increment```一节,即使执行了```continue```,循环的累加器仍会自动加1。 + 循环会继续,仅仅是循环体内的代码不会被执行。 +下面的例子会移除一个小写字符串中所有的原因字母: + +``` +let puzzleInput = "great minds think alike" +var puzzleOutput = "" +for character in puzzleInput { + switch character { + case "a", "e", "i", "o", "u", " ": + continue + default: + puzzleOutput += character + } +} +println(puzzleOutput) +// prints "grtmndsthnklk +``` + +在上面的代码中,一旦出现元音字母,当前循环就会被终止,并重新开始下一次循环。这会让```switch```表达式去匹配元音字符或空字符时不做处理,而不是让每一个匹配到的字符都被打印出来。 + +###break + +```break```语句会立刻终止当前执行的整个控制流。```break```可被用在```switch```表达式里面或循环中用来提前结束控制流。 + +###循环体内的break + +当在循环体内执行```break```时,会退出整个循环,代码从循环体后面的第一行开始执行。 + +###Switch表达式中得break + +当在```switch```中使用```break```时,会立即终止改```switch``代码块的执行,并且跳转到```switch```代码块结束的大括号(```}```)后的第一行代码。 + +这种行为可被用来忽略或跳过```switch```中的某个```case```。由于Swift要求```switch```的分支条件必须完整并且不允许空的```case```分支,因此在有些情况下使用```break```特意跳出某个分支会很必要。你可以通过在```case```的代码快中加入```break````来达到这个效果。当```case```分支的代码块被执行时,```break```会终止```switch```语句的执行。 + + 注意: + 当```switch```的一个分支仅仅包含注释时,编译器会给出错误提示。 + 注释并不是真正的代码,他不能达到忽略这个```case```分支的作用。有哪次还是需要使用```break```。 + +下面这个例子用来判断一个字符的值是否是数字符号。为了简便,多个值被包含到一个分支中: + +``` +let numberSymbol: Character = "三" // Simplified Chinese for the number 3 +var possibleIntegerValue: Int? +switch numberSymbol { +case "1", "١", "一", "๑": + possibleIntegerValue = 1 +case "2", "٢", "二", "๒": + possibleIntegerValue = 2 +case "3", "٣", "三", "๓": + possibleIntegerValue = 3 +case "4", "٤", "四", "๔": + possibleIntegerValue = 4 +default: + break +} +if let integerValue = possibleIntegerValue { + println("The integer value of \(numberSymbol) is \(integerValue).") +} else { + println("An integer value could not be found for \(numberSymbol).") +} +// prints "The integer value of 三 is 3." + +``` +这个例子用来判断```numberSymbol```是否是拉丁文,阿拉伯文,中文或泰语中的1到4之一。如果被匹配到,该```switch```分支语句给```Int?```类型变量```possibleIntegerValue```设置一个整数值。 + +当switch代码块执行完后,接下来的代码先判断```possibleIntegerValue``是否被绑定成功。因为是可选类型的缘故,```possibleIntegerValue```有一个隐式的初始值nil,所以仅仅当```possibleIntegerValue```曾被switch代码块的前四个分支中的某个设置过一个值时,可选的绑定将会被判定为成功。 + +在上面的例子中,想要把```Character```所有的的可能性都枚举出来是不现实的,所以使用```default```分支来包含所有上面没有匹配到字符的情况。由于这个```default```分支不需要执行任何动作,所以它只写了一条```break```语句。一旦落入到```default```分支中后,```break```语句就完成了该分支的所有代码操作,代码继续向下,开始执行```if let```语句。 From fa7d0ed8c3b3f61a9b99e231f1d178d05c48b99b Mon Sep 17 00:00:00 2001 From: Neekey Date: Wed, 18 Jun 2014 23:58:09 +0800 Subject: [PATCH 099/261] Update 07_Attributes.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 完整了一遍,后续要继续查漏补缺 --- src/chapter3/07_Attributes.md | 64 +++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/chapter3/07_Attributes.md b/src/chapter3/07_Attributes.md index 3187fab..1a0e319 100644 --- a/src/chapter3/07_Attributes.md +++ b/src/chapter3/07_Attributes.md @@ -1,10 +1,10 @@ # Attributes -# 属性 +# 特性 *Attributes* provide more information about a declaration or type. There are two kinds of attributes in Swift, those that apply to declarations and those that apply to types. For instance, the `required` attribute—when applied to a designated or convenience initializer declaration of a class—indicates that every subclass must implement that initializer. And the `noreturn` attribute—when applied to a function or method type—indicates that the function or method doesn’t return to its caller. -*属性* 为声明和类型提供了更多的信息。在Swift中有两种类型的属性,一种应用在声明中,另一种应用于类型。比如,`required`属性——当被应用在一个类的预设初构造函数或者便利构造函数中时——表明了其所有的子类都必须实现这个构造函数。`noreturn`属性——当被应用在函数或者方法类型中时——表明这个函数或者方法不会返回任何值给调用者。 +*特性* 为声明和类型提供了更多的信息。在Swift中有两种类型的特性,一种用于修饰声明,另一种用于修饰类型。比如,`required`特性——当被用来修饰一个类的预设构造函数声明或者便利构造函数声明时——表明其所有的子类都必须实现这个构造函数。`noreturn`特性——当修饰函数或者方法类型时——表明这个函数或者方法不会返回任何值给其调用者。 You specify an attribute by writing the `@` symbol followed by the attribute’s name and any arguments that the attribute accepts: @@ -13,30 +13,30 @@ You specify an attribute by writing the `@` symbol followed by the attribute’s @attribute name(attribute arguments) ``` -你可以通过`@`符号以及紧随其后的属性名称和该属性接受的参数来指定属性。 +你可以通过`@`符号以及紧随其后的特性名称和该特性可以接受的参数来使用特性。 ``` - @属性名称 - @属性名称(属性参数) + @attribute name + @attribute name(attribute arguments) ``` Some declaration attributes accept arguments that specify more information about the attribute and how it applies to a particular declaration. These *attribute arguments* are enclosed in parentheses, and their format is defined by the attribute they belong to. -有些声明属性可以通过给定参数来指定该属性相关的更多信息,以及描述该属性如何应用于这个声明中。 +有些声明特性可以通过给定参数来补充该特性相关的更多信息,并说明该特性将如何应用于这个声明中。这些`特性参数`写在小括号里面,他们的具体格式需要根据他们所属的特性来确定。 ## Declaration Attributes -## 声明属性 +## 声明特性 You can apply a declaration attribute to declarations only. However, you can also apply the `noreturn` attribute to a function or method *type*. -你只能将声明属性应用在声明中。不过你还是可以将`noreturn`属性应用在函数或者方法*类型*中。 +声明特性只能描述声明。不过你还是可以使用`noreturn`特性来描述函数或者方法*类型*。 `assignment` > Apply this attribute to functions that overload a compound assignment operator. Functions that overload a compound assignment operator must mark their initial input parameter as `inout`. For an example of how to use the assignment attribute, see [Compound Assignment Operators](#). `assignment` -> 这个属性应用于那些重载了复合赋值运算符的函数上。 一个重载了复合赋值运算符必须将它的初始化输入参数标记为`inout`.查看[符合赋值运算符]中关于如何使用assigment属性的一个例子。 +> 这个特性用于描述重载了复合赋值运算符的函数。一个重载了复合赋值运算符的函数必须将它的初始化输入参数标记为`inout`.关于如何使用assigment特性请查看[符合赋值运算符](#)中的一个例子。 `class_protocol` > Apply this attribute to a protocol to indicate that the protocol can be adopted by class types only. @@ -44,27 +44,27 @@ You can apply a declaration attribute to declarations only. However, you can als > If you apply the `objc` attribute to a protocol, the `class_protocol` attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the `class_protocol` attribute explicitly. `class_protocol` -> 当这个属性被应用在协议上时,它表明这个协议只能被类使用。 +> 这个特性用于描述协议,它表明被修饰的协议只能被类使用[//todo adopted]。 -> 如果一个协议被应用了`objc`属性,那么`class_protocol`属性就被隐形地添加在这个协议上了,不需要再显性地添加一次。 +> 如果一个协议已经添加了`objc`特性,那么`class_protocol`特性就已经被隐形地添加在这个协议上了,不需要再显性地添加一次。 `exported` > Apply this attribute to an import declaration to export the imported module, submodule, or declaration from the current module. If another module imports the current module, that other module can access the items exported by the current module. `exported` -> 通过将这个属性应用给一个导入声明,使得当前模块中被导入进来的模块,子模块或者声明可以被导出。如果另一个模块导入了这个模块,那么这个模块可以访问所有被这个模块导出的项。 +> 这个特性被用于修饰导入声明。当一个导入声明具有该特性时,所有通过该声明导入的的模块,子模块或者声明都可以被导出。如果另一个模块导入了这个模块,那么那个模块可以访问所有被这个模块导出的项。 `final` > Apply this attribute to a class or to a property, method, or subscript member of a class. It’s applied to a class to indicate that the class can’t be subclassed. It’s applied to a property, method, or subscript of a class to indicate that that class member can’t be overridden in any subclass. `final` -> 这个属性被应用在一个类或者一个类的属性、方法、或者子脚本上。如果应用在类上,则表明这个类不能被继承。如果被应用在一个类的属性、方法或者子脚本上,则表明这个类的成员不能被任何子类覆盖。 +> 这个特性用于描述类或者类的属性、方法、或者下标脚本上。如若一个类具有该特性,则表明这个类不能被继承。如果一个类的属性、方法或者下标脚本具有该特性,则表明这个类的成员不能被任何子类覆盖。 `lazy` > Apply this attribute to a stored variable property of a class or structure to indicate that the property’s initial value is calculated and stored at most once, when the property is first accessed. For an example of how to use the `lazy` attribute, see [Lazy Stored Properties](#). `lazy` -> 通过将这个属性应用在一个类或者结构体的存储变量属性上,来指定这个属性的初始值只在第一次被读取时才进行一次计算。查看[懒惰存储属性](#)中给出的关于如何使用`lazy`的例子。 +> 如果一个类或者结构体的存储变量属性具有该特性,则这个属性的初始值最多只被计算和存储一次,且这一次的计算和存储发生在第一次被访问时。查看[懒惰存储属性](#)中给出的关于如何使用`lazy`的例子。 `noreturn` > Apply this attribute to a function or method declaration to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. You can mark a function or method type with this attribute to indicate that the function or method doesn’t return to its caller. @@ -72,9 +72,9 @@ You can apply a declaration attribute to declarations only. However, you can als > You can override a function or method that is not marked with the `noreturn` attribute with a function or method that is. That said, you can’t override a function or method that is marked with the `noreturn` attribute with a function or method that is not. Similar rules apply when you implement a protocol method in a conforming type. `noreturn` -> 将这个属性应用在函数或者方法声明中来指定这个函数或者方法,`T`,是`@noreturn T`类型。你可以通过使用这个关键词来标记函数或者方法来表明这个函数或者方法不返回任何值给它的调用者。 +> 可以通过将这个特性应用在函数或者方法声明中来指定这个函数或者方法,`T`,是`@noreturn T`类型。你可以通过使用这个特性来标记函数或者方法,借此来表明这个函数或者方法不返回任何值给它的调用者。 -> 你可以使用一个标记了这个属性的函数或者方法来覆盖一个没有标记过这个属性的函数或者方法,但是反过来不行。同样的,当你要实现一个协议方法时,也需要遵循这个规则。 +> 你可以使用一个标记了这个特性的函数或者方法来覆盖一个没有标记过这个特性的函数或者方法,但是反过来不行。同样的,当你要实现一个协议方法时,也需要遵循这个规则。 `NSCopying` > Apply this attribute to a stored variable property of a class. This attribute causes the property’s setter to be synthesized with a *copy* of the property’s value—returned by the `copyWithZone` method—instead of the value of the property itself. The type of the property must conform to the `NSCopying` protocol. @@ -82,13 +82,15 @@ You can apply a declaration attribute to declarations only. However, you can als > The `NSCopying` attribute behaves in a way similar to the Objective-C `copy` property attribute. `NSCopying` -> 这个属性被应用在一个类的储存变量属性上。该属性将使得这个类的属性的setter // todo 翻译不能,hold住先 +> 这个特性用于修饰一个类的储存变量属性。该特性将使得这个类的属性的setter方法与这个属性的返回值的*副本*合成——通过`copyWithZone`方法进行返回——而不是这个属性值本身。这个属性值的类型必须遵循`NSCopying`协议。 + +> `NSCopying`特性与Objective-C中的`copy`属性特性类似。 `NSManaged` > Apply this attribute to a stored variable property of a class that inherits from `NSManagedObject` to indicate that the storage and implementation of the property are provided dynamically by Core Data at runtime based on the associated entity description. `NSManaged` -> 这个属性被应用在继承了`NSManagedObject`的类的成员上,通过该属性来表明这个成员的存储和实现由Core Data根据相关实体描述来动态地提供。 +> 这个特性用于修饰继承了`NSManagedObject`的类的成员,通过该特性来表明这个成员的存储和实现由Core Data在运行时根据相关实体描述来动态地提供。 `objc` > Apply this attribute to any declaration that can be represented in Objective-C—for example, non-nested classes, protocols, properties and methods (including getters and setters) of classes and protocols, initializers, deinitializers, and subscripts. The `objc` attribute tells the compiler that a declaration is available to use in Objective-C code. @@ -109,9 +111,11 @@ You can apply a declaration attribute to declarations only. However, you can als ``` `objc` -> 这个特性可以被应用在任何可以在Objective-C中使用的声明上,如非嵌套类、协议、类和协议的属性和方法(包括getter和setter)、构造函数、析构函数和子脚本。`objc`特性告诉编译器该声明可以在Objective-C的代码中被使用。 +> 这个特性用于描述任何可以在Objective-C中表示的声明,如非嵌套类,协议,类和协议的属性和方法(包括getter和setter),构造函数,析构函数和下标脚本。`objc`特性告诉编译器该声明可以在Objective-C的代码中被使用。 + +> 如果一个类或者协议具有`objc`特性,那么这个类或者协议的所有成员都将隐形地具有`objc`特性。编译器甚至会隐形地添加`objc`特性给具有`objc`特性的类的子类。被标记`objc`特性的协议不能继承没有被标记`objc`特性的协议。 -> `objc`特性可选地接收一个标识符作为参数。当你希望对Objective-C暴露一个不一样的名称时,你就可以使用这个属性参数。你可以使用这个参数来重新命名类、协议、方法、getter、setter和构造函数。下面的例子通过给定特性参数使得类`ExampleClass`的enabled这个属性以`isEnabled`这个属性暴露给Objective-C. +> `objc`特性可选地接收一个标识符作为参数。你就可以使用这个特性参数让被标记的对象对Objective-C暴露一个不一样的名字。你可以使用这个参数来重新命名类,协议,方法,getter,setter和构造函数。下面的例子通过给定特性参数使得类`ExampleClass`的enabled这个属性以`isEnabled`这个名字暴露给Objective-C. ``` @objc @@ -131,9 +135,9 @@ You can apply a declaration attribute to declarations only. However, you can als `optional` -> 这个特性可以被应用在一个协议的属性,方法和子脚本成员上,以此来表明对遵循该协议的类型来说,这些成员的实现是可选的。 +> 这个特性用于描述协议的属性,方法和下标脚本,以此来表明遵循了该协议的类型,只需要可选地实现这些被标记的成员。 -> 你只能将这个特性应用在被标记了`objc`特性的协议上。也就是说,只有类才能允许和实现一个包含了可选成员的协议。更多关于如何使用`optional`特性以及如何在不清楚一个类型是否遵守了被标记为`optional`协议的情况下读取可选属性的方法的信息,请参考[可选协议要求](#)。 +> 这个特性只能被用于描述具有`objc`特性的协议。也就是说,只有类才能接受和遵循一个具有optional特性成员的协议。更多关于如何使用`optional`特性,以及对于一个遵循了具有`optional`特性的协议的类型,在无法明确它实现了哪些可选成员的情况下,如何正确地读取其可选成员的问题,请参考[可选协议要求](#)。 `required` > Apply this attribute to a designated or convenience initializer of a class to indicate that every subclass must implement that initializer. @@ -141,21 +145,21 @@ You can apply a declaration attribute to declarations only. However, you can als > Required designated initializers must be implemented explicitly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or when the subclass overrides the designated initializers with convenience initializers). `required` -> 通过将该特性应用在预设构造函数或者便利构造函数上来说明每一个子类都必须实现这个构造函数。 +> 通过为一个类的预设构造函数或者便利构造函数添加该特性来表明这个类的每一个子类都必须实现这个构造函数。 -> 必须的预设构造函数必须被显性地实现。必须的便利构造函数可以被显性地实现,或者当子类直接实现了所有父类的预设构造函数时(或者子类使用便利构造函数重写了预设构造函数),可以直接继承这个便利构造函数。 +> 具有该特性的预设构造函数必须被显性地实现。具有该特性的便利构造函数可以被显性地实现,或者当子类直接实现了所有父类的预设构造函数时(或者子类使用便利构造函数重写了预设构造函数),可以直接继承这个便利构造函数。 ### Declaration Attributes Used by Interface Builder -## 在界面生成器中使用声明特性 +## 在Interface Builder中使用声明特性 Interface Builder attributes are declaration attributes used by Interface Builder to synchronize with Xcode. Swift provides the following Interface Builder attributes: `IBAction`, `IBDesignable`, `IBInspectable`, and `IBOutlet`. These attributes are conceptually the same as their Objective-C counterparts. -界面生成器特性是被界面生成器用来和Xcode同步的声明特性。Swift提供了一下集中界面生成器特性: `IBAction`,`IBDesignable`,`IBInspectable`和`IBOutlet`。这些特性在概念上和他们的Objective-C同仁一样。 +Interface Builder特性是Interface Builder用来和Xcode同步的声明特性。Swift提供了以下几种Interface Builder特性: `IBAction`,`IBDesignable`,`IBInspectable`和`IBOutlet`。这些特性在概念上和Objective-C中对应的特性是一样的。 You apply the `IBOutlet` and `IBInspectable` attributes to property declarations of a class. You apply the `IBAction` attribute to method declarations of a class and the `IBDesignable` attribute to class declarations. -`IBOutlet`和`IBInspectable`特性用于类的属性声明,`IBAction`特性用于类的方法声明而`IBDesignable`用于类的声明。 +`IBOutlet`和`IBInspectable`特性用于描述类的属性声明,`IBAction`特性用于描述类的方法声明而`IBDesignable`用于描述类的声明。 ## Type Attributes @@ -163,19 +167,19 @@ You apply the `IBOutlet` and `IBInspectable` attributes to property declarations You can apply type attributes to types only. However, you can also apply the `noreturn` attribute to a function or method *declaration*. -类型特性只能应用在类型上。尽管如此,你还是可以将`noreturn`特性应用在函数和方法的声明上。 +类型特性只能描述类型。尽管如此,你还是可以使用`noreturn`特性去修饰函数和方法的声明。 `auto_closure` > This attribute is used to delay the evaluation of an expression by automatically wrapping that expression in a closure with no arguments. Apply this attribute to a function or method type that takes no arguments and that returns the type of the expression. For an example of how to use the `auto_closure` attribute, see [Function Type](#). `auto_closure` -> 这个特性一般用于通过将表达式包裹在一个没有参数的闭包中来延迟表达式的计算。将该特性应用在不带任何参数的函数和方法中,而这些函数和方法的返回值就是需要延迟计算的表达式。关于如何使用`auto_closure`特性,参考[函数类型](#)中的例子。 +> 这个特性通过自动地将表达式包裹在一个没有参数的闭包中来延迟表达式的求值。将该特性用于描述不带任何参数的函数和方法,而这些函数和方法返回表达式的类型。关于如何使用`auto_closure`特性,参考[函数类型](#)中的例子。 `noreturn` > Apply this attribute to the type of a function or method to indicate that the function or method doesn’t return to its caller. You can also mark a function or method declaration with this attribute to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. `noreturn` -> 将这个特性应用在函数或者方法中来表明该函数或者方法不返回任何值给它的调用者。你也可以使用这个特性来标记函数或者方法声明以及来说明这个函数或者方法,`T`,是`@noreturn T`类型。 +> 使用这个特性来描述函数或者方法,以此表明该函数或者方法不返回任何值给它的调用者。你也可以使用这个特性来标记函数或者方法声明,借此来表明这个函数或者方法,`T`,是`@noreturn T`类型。 ## GRAMMAR OF AN ATTRIBUTE From b2751cb46efbb40c0a2b492c51081b1707b3e92c Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Thu, 19 Jun 2014 01:11:19 +0800 Subject: [PATCH 100/261] update 01_the_basics - printIn and comment --- src/chapter2/01_The_Basics.md | 87 +++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 890722b..bafd030 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -113,6 +113,7 @@ The welcomeMessage variable can now be set to any string value without error: # 命名常量和变量 You can use almost any character you like for constant and variable names, including Unicode characters: + 你可以使用几乎所有你喜欢的符号来命名常量和变量,包括unicode字符: ``` @@ -153,3 +154,89 @@ Unlike a variable, the value of a constant cannot be changed once it is set. Att let languageName = "Swift" languageName = "Swift++" // this is a compile-time error - languageName cannot be changed + +# Printing Constants and Variables +# 输出常量和变量 + +You can print the current value of a constant or variable with the println function: + +你可以用`printIn`函数输出常量和变量的当前值: + +``` +println(friendlyWelcome) +// prints "Bonjour!" +// 输出 "Bonjour!" +``` + +println is a global function that prints a value, followed by a line break, to an appropriate output. If you are working in Xcode, for example, println prints its output in Xcode’s “console” pane. (A second function, print, performs the same task without appending a line break to the end of the value to be printed.) + +`printIn`是一个输出值的全局函数,为了得到良好的输出结果,输出后会加上一个空行。如果你使用的是Xcode,`printIn`会将结果输出到Xcode的调试信息栏。(另一个函数,`print`,会执行几乎相同的任务,除了不会在输出结果之后加空行以外。) + +The println function prints any String value you pass to it: + +`printIn`函数会输出任何你赋值的字符串: + +``` +println("This is a string") +// prints "This is a string" +``` + +The println function can print more complex logging messages, in a similar manner to Cocoa’s NSLog function. These messages can include the current values of constants and variables. + +`printIn`函数可以输出更复杂的记录信息,和Cocoa的NSlog函数类似。这些信息可以包含常量和变量的当前值。 + +Swift uses string interpolation to include the name of a constant or variable as a placeholder in a longer string, and to prompt Swift to replace it with the current value of that constant or variable. Wrap the name in parentheses and escape it with a backslash before the opening parenthesis: + +Swift使用字符串内插(string interpolation)的方式将常量或变量名以占位符的形式加入一个长的字符串中,并且提示Swift用常量或变量的当前值取代替它。将名字包裹在括号中并在前面加上反斜扛来转义。 + +``` +println("The current value of friendlyWelcome is \(friendlyWelcome)") +// prints "The current value of friendlyWelcome is Bonjour!" +// 输出 "The current value of friendlyWelcome is Bonjour!" +``` + +> NOTE + +> All options you can use with string interpolation are described in String Interpolation. + +> 注意 + +> 关于字符串插值的详细参数,参见[字符串插值](link)。 + +# Comments +# 注释 + +Use comments to include non-executable text in your code, as a note or reminder to yourself. Comments are ignored by the Swift compiler when your code is compiled. + +将代码中不会执行的文本,笔记或者备忘,用注释来表达。注释在编译时会被忽略。 + +Comments in Swift are very similar to comments in C. Single-line comments begin with two forward-slashes (//): + +Swift中的注释和C中的注释十分相似。单行的注释以两个正斜杠 (//)开头: + + // this is a comment + // 这是一个注释 + +You can also write multiline comments, which start with a forward-slash followed by an asterisk (/*) and end with an asterisk followed by a forward-slash (*/): + +你也可以写多行的注释,用一个正斜杠跟着一个星号开头 (/*) ,用一个星号跟着一个正斜杠结束(*/): + + /* this is also a comment, + but written over multiple lines */ + /* 这还是一个注释, + 但是是多行的 */ + +Unlike multiline comments in C, multiline comments in Swift can be nested inside other multiline comments. You write nested comments by starting a multiline comment block and then starting a second multiline comment within the first block. The second block is then closed, followed by the first block: + +和C中的多行注释不同,Swift的多行注释可以嵌套在另一个多行注释内部。你可以这样写嵌套的注释:开始一个多行注释块,在第一块多行注释内部跟着开始第二个多行注释。第二个多行注释块结束,然后第一个多行注释块结束。 + + /* this is the start of the first multiline comment + /* this is the second, nested multiline comment */ + this is the end of the first multiline comment */ + /* 这是第一个多行注释开始 + /* 这是第二个,嵌套的多行注释 */ + 这是第一个多行注释的结束 */ + +Nested multiline comments enable you to comment out large blocks of code quickly and easily, even if the code already contains multiline comments. + +嵌套的多行注释让你可以简单快捷的注释一大段代码,即使这块代码之前已经有多行注释块。 \ No newline at end of file From 5538d9ab4217d650996c6026334ff421d1b676a9 Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Thu, 19 Jun 2014 01:18:18 +0800 Subject: [PATCH 101/261] update 01_the_basics - all original content and update simicolons --- src/chapter2/01_The_Basics.md | 414 +++++++++++++++++++++++++++++++++- 1 file changed, 413 insertions(+), 1 deletion(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index bafd030..f4b14bb 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -239,4 +239,416 @@ Unlike multiline comments in C, multiline comments in Swift can be nested inside Nested multiline comments enable you to comment out large blocks of code quickly and easily, even if the code already contains multiline comments. -嵌套的多行注释让你可以简单快捷的注释一大段代码,即使这块代码之前已经有多行注释块。 \ No newline at end of file +嵌套的多行注释让你可以简单快捷的注释一大段代码,即使这块代码之前已经有多行注释块。 + +# Semicolons +# 分号 + +Unlike many other languages, Swift does not require you to write a semicolon (;) after each statement in your code, although you can do so if you wish. Semicolons are required, however, if you want to write multiple separate statements on a single line: + +和其他很多语言不同,Swift并不要求你在代码的每一个语句之后写一个分号(;),尽管如果你愿意你可以这么做。然而,如果你想在一行里写多个独立的语句,分号是必要的。 + + let cat = "🐱"; println(cat) + // prints "🐱" + +Integers + +Integers are whole numbers with no fractional component, such as 42 and -23. Integers are either signed (positive, zero, or negative) or unsigned (positive or zero). + +Swift provides signed and unsigned integers in 8, 16, 32, and 64 bit forms. These integers follow a naming convention similar to C, in that an 8-bit unsigned integer is of type UInt8, and a 32-bit signed integer is of type Int32. Like all types in Swift, these integer types have capitalized names. + +Integer Bounds + +You can access the minimum and maximum values of each integer type with its min and max properties: + +let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8 +let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8 +The values of these properties are of the appropriate-sized number type (such as UInt8 in the example above) and can therefore be used in expressions alongside other values of the same type. + +Int + +In most cases, you don’t need to pick a specific size of integer to use in your code. Swift provides an additional integer type, Int, which has the same size as the current platform’s native word size: + +On a 32-bit platform, Int is the same size as Int32. +On a 64-bit platform, Int is the same size as Int64. +Unless you need to work with a specific size of integer, always use Int for integer values in your code. This aids code consistency and interoperability. Even on 32-bit platforms, Int can store any value between -2,147,483,648 and 2,147,483,647, and is large enough for many integer ranges. + +UInt + +Swift also provides an unsigned integer type, UInt, which has the same size as the current platform’s native word size: + +On a 32-bit platform, UInt is the same size as UInt32. +On a 64-bit platform, UInt is the same size as UInt64. +NOTE + +Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference. + +Floating-Point Numbers + +Floating-point numbers are numbers with a fractional component, such as 3.14159, 0.1, and -273.15. + +Floating-point types can represent a much wider range of values than integer types, and can store numbers that are much larger or smaller than can be stored in an Int. Swift provides two signed floating-point number types: + +Double represents a 64-bit floating-point number. Use it when floating-point values must be very large or particularly precise. +Float represents a 32-bit floating-point number. Use it when floating-point values do not require 64-bit precision. +NOTE + +Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. + +Type Safety and Type Inference + +Swift is a type safe language. A type safe language encourages you to be clear about the types of values your code can work with. If part of your code expects a String, you can’t pass it an Int by mistake. + +Because Swift is type safe, it performs type checks when compiling your code and flags any mismatched types as errors. This enables you to catch and fix errors as early as possible in the development process. + +Type-checking helps you avoid errors when you’re working with different types of values. However, this doesn’t mean that you have to specify the type of every constant and variable that you declare. If you don’t specify the type of value you need, Swift uses type inference to work out the appropriate type. Type inference enables a compiler to deduce the type of a particular expression automatically when it compiles your code, simply by examining the values you provide. + +Because of type inference, Swift requires far fewer type declarations than languages such as C or Objective-C. Constants and variables are still explicitly typed, but much of the work of specifying their type is done for you. + +Type inference is particularly useful when you declare a constant or variable with an initial value. This is often done by assigning a literal value (or literal) to the constant or variable at the point that you declare it. (A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below.) + +For example, if you assign a literal value of 42 to a new constant without saying what type it is, Swift infers that you want the constant to be an Int, because you have initialized it with a number that looks like an integer: + +let meaningOfLife = 42 +// meaningOfLife is inferred to be of type Int +Likewise, if you don’t specify a type for a floating-point literal, Swift infers that you want to create a Double: + +let pi = 3.14159 +// pi is inferred to be of type Double +Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers. + +If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context: + +let anotherPi = 3 + 0.14159 +// anotherPi is also inferred to be of type Double +The literal value of 3 has no explicit type in and of itself, and so an appropriate output type of Double is inferred from the presence of a floating-point literal as part of the addition. + +Numeric Literals + +Integer literals can be written as: + +A decimal number, with no prefix +A binary number, with a 0b prefix +An octal number, with a 0o prefix +A hexadecimal number, with a 0x prefix +All of these integer literals have a decimal value of 17: + +let decimalInteger = 17 +let binaryInteger = 0b10001 // 17 in binary notation +let octalInteger = 0o21 // 17 in octal notation +let hexadecimalInteger = 0x11 // 17 in hexadecimal notation +Floating-point literals can be decimal (with no prefix), or hexadecimal (with a 0x prefix). They must always have a number (or hexadecimal number) on both sides of the decimal point. They can also have an optional exponent, indicated by an uppercase or lowercase e for decimal floats, or an uppercase or lowercase p for hexadecimal floats. + +For decimal numbers with an exponent of exp, the base number is multiplied by 10exp: + +1.25e2 means 1.25 × 102, or 125.0. +1.25e-2 means 1.25 × 10-2, or 0.0125. +For hexadecimal numbers with an exponent of exp, the base number is multiplied by 2exp: + +0xFp2 means 15 × 22, or 60.0. +0xFp-2 means 15 × 2-2, or 3.75. +All of these floating-point literals have a decimal value of 12.1875: + +let decimalDouble = 12.1875 +let exponentDouble = 1.21875e1 +let hexadecimalDouble = 0xC.3p0 +Numeric literals can contain extra formatting to make them easier to read. Both integers and floats can be padded with extra zeroes and can contain underscores to help with readability. Neither type of formatting affects the underlying value of the literal: + +let paddedDouble = 000123.456 +let oneMillion = 1_000_000 +let justOverOneMillion = 1_000_000.000_000_1 +Numeric Type Conversion + +Use the Int type for all general-purpose integer constants and variables in your code, even if they are known to be non-negative. Using the default integer type in everyday situations means that integer constants and variables are immediately interoperable in your code and will match the inferred type for integer literal values. + +Use other integer types only when they are are specifically needed for the task at hand, because of explicitly-sized data from an external source, or for performance, memory usage, or other necessary optimization. Using explicitly-sized types in these situations helps to catch any accidental value overflows and implicitly documents the nature of the data being used. + +Integer Conversion + +The range of numbers that can be stored in an integer constant or variable is different for each numeric type. An Int8 constant or variable can store numbers between -128 and 127, whereas a UInt8 constant or variable can store numbers between 0 and 255. A number that will not fit into a constant or variable of a sized integer type is reported as an error when your code is compiled: + +let cannotBeNegative: UInt8 = -1 +// UInt8 cannot store negative numbers, and so this will report an error +let tooBig: Int8 = Int8.max + 1 +// Int8 cannot store a number larger than its maximum value, +// and so this will also report an error +Because each numeric type can store a different range of values, you must opt in to numeric type conversion on a case-by-case basis. This opt-in approach prevents hidden conversion errors and helps make type conversion intentions explicit in your code. + +To convert one specific number type to another, you initialize a new number of the desired type with the existing value. In the example below, the constant twoThousand is of type UInt16, whereas the constant one is of type UInt8. They cannot be added together directly, because they are not of the same type. Instead, this example calls UInt16(one) to create a new UInt16 initialized with the value of one, and uses this value in place of the original: + +let twoThousand: UInt16 = 2_000 +let one: UInt8 = 1 +let twoThousandAndOne = twoThousand + UInt16(one) +Because both sides of the addition are now of type UInt16, the addition is allowed. The output constant (twoThousandAndOne) is inferred to be of type UInt16, because it is the sum of two UInt16 values. + +SomeType(ofInitialValue) is the default way to call the initializer of a Swift type and pass in an initial value. Behind the scenes, UInt16 has an initializer that accepts a UInt8 value, and so this initializer is used to make a new UInt16 from an existing UInt8. You can’t pass in any type here, however—it has to be a type for which UInt16 provides an initializer. Extending existing types to provide initializers that accept new types (including your own type definitions) is covered in Extensions. + +Integer and Floating-Point Conversion + +Conversions between integer and floating-point numeric types must be made explicit: + +let three = 3 +let pointOneFourOneFiveNine = 0.14159 +let pi = Double(three) + pointOneFourOneFiveNine +// pi equals 3.14159, and is inferred to be of type Double +Here, the value of the constant three is used to create a new value of type Double, so that both sides of the addition are of the same type. Without this conversion in place, the addition would not be allowed. + +The reverse is also true for floating-point to integer conversion, in that an integer type can be initialized with a Double or Float value: + +let integerPi = Int(pi) +// integerPi equals 3, and is inferred to be of type Int +Floating-point values are always truncated when used to initialize a new integer value in this way. This means that 4.75 becomes 4, and -3.9 becomes -3. + +NOTE + +The rules for combining numeric constants and variables are different from the rules for numeric literals. The literal value 3 can be added directly to the literal value 0.14159, because number literals do not have an explicit type in and of themselves. Their type is inferred only at the point that they are evaluated by the compiler. + +Type Aliases + +Type aliases define an alternative name for an existing type. You define type aliases with the typealias keyword. + +Type aliases are useful when you want to refer to an existing type by a name that is contextually more appropriate, such as when working with data of a specific size from an external source: + +typealias AudioSample = UInt16 +Once you define a type alias, you can use the alias anywhere you might use the original name: + +var maxAmplitudeFound = AudioSample.min +// maxAmplitudeFound is now 0 +Here, AudioSample is defined as an alias for UInt16. Because it is an alias, the call to AudioSample.min actually calls UInt16.min, which provides an initial value of 0 for the maxAmplitudeFound variable. + +Booleans + +Swift has a basic Boolean type, called Bool. Boolean values are referred to as logical, because they can only ever be true or false. Swift provides two Boolean constant values, true and false: + +let orangesAreOrange = true +let turnipsAreDelicious = false +The types of orangesAreOrange and turnipsAreDelicious have been inferred as Bool from the fact that they were initialized with Boolean literal values. As with Int and Double above, you don’t need to declare constants or variables as Bool if you set them to true or false as soon as you create them. Type inference helps make Swift code more concise and readable when it initializes constants or variables with other values whose type is already known. + +Boolean values are particularly useful when you work with conditional statements such as the if statement: + +if turnipsAreDelicious { + println("Mmm, tasty turnips!") +} else { + println("Eww, turnips are horrible.") +} +// prints "Eww, turnips are horrible." +Conditional statements such as the if statement are covered in more detail in Control Flow. + +Swift’s type safety prevents non-Boolean values from being be substituted for Bool. The following example reports a compile-time error: + +let i = 1 +if i { + // this example will not compile, and will report an error +} +However, the alternative example below is valid: + +let i = 1 +if i == 1 { + // this example will compile successfully +} +The result of the i == 1 comparison is of type Bool, and so this second example passes the type-check. Comparisons like i == 1 are discussed in Basic Operators. + +As with other examples of type safety in Swift, this approach avoids accidental errors and ensures that the intention of a particular section of code is always clear. + +Tuples + +Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other. + +In this example, (404, "Not Found") is a tuple that describes an HTTP status code. An HTTP status code is a special value returned by a web server whenever you request a web page. A status code of 404 Not Found is returned if you request a webpage that doesn’t exist. + +let http404Error = (404, "Not Found") +// http404Error is of type (Int, String), and equals (404, "Not Found") +The (404, "Not Found") tuple groups together an Int and a String to give the HTTP status code two separate values: a number and a human-readable description. It can be described as “a tuple of type (Int, String)”. + +You can create tuples from any permutation of types, and they can contain as many different types as you like. There’s nothing stopping you from having a tuple of type (Int, Int, Int), or (String, Bool), or indeed any other permutation you require. + +You can decompose a tuple’s contents into separate constants or variables, which you then access as usual: + +let (statusCode, statusMessage) = http404Error +println("The status code is \(statusCode)") +// prints "The status code is 404" +println("The status message is \(statusMessage)") +// prints "The status message is Not Found" +If you only need some of the tuple’s values, ignore parts of the tuple with an underscore (_) when you decompose the tuple: + +let (justTheStatusCode, _) = http404Error +println("The status code is \(justTheStatusCode)") +// prints "The status code is 404" +Alternatively, access the individual element values in a tuple using index numbers starting at zero: + +println("The status code is \(http404Error.0)") +// prints "The status code is 404" +println("The status message is \(http404Error.1)") +// prints "The status message is Not Found" +You can name the individual elements in a tuple when the tuple is defined: + +let http200Status = (statusCode: 200, description: "OK") +If you name the elements in a tuple, you can use the element names to access the values of those elements: + +println("The status code is \(http200Status.statusCode)") +// prints "The status code is 200" +println("The status message is \(http200Status.description)") +// prints "The status message is OK" +Tuples are particularly useful as the return values of functions. A function that tries to retrieve a web page might return the (Int, String) tuple type to describe the success or failure of the page retrieval. By returning a tuple with two distinct values, each of a different type, the function provides more useful information about its outcome than if it could only return a single value of a single type. For more information, see Functions with Multiple Return Values. + +NOTE + +Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple. For more information, see Classes and Structures. + +Optionals + +You use optionals in situations where a value may be absent. An optional says: + +There is a value, and it equals x +or + +There isn’t a value at all +NOTE + +The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structs, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there is a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants. + +Here’s an example. Swift’s String type has a method called toInt, which tries to convert a String value into an Int value. However, not every string can be converted into an integer. The string "123" can be converted into the numeric value 123, but the string "hello, world" does not have an obvious numeric value to convert to. + +The example below uses the toInt method to try to convert a String into an Int: + +let possibleNumber = "123" +let convertedNumber = possibleNumber.toInt() +// convertedNumber is inferred to be of type "Int?", or "optional Int" +Because the toInt method might fail, it returns an optional Int, rather than an Int. An optional Int is written as Int?, not Int. The question mark indicates that the value it contains is optional, meaning that it might contain some Int value, or it might contain no value at all. (It can’t contain anything else, such as a Bool value or a String value. It’s either an Int, or it’s nothing at all.) + +If Statements and Forced Unwrapping + +You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to true; if it has no value at all, it evaluates to false. + +Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value: + +if convertedNumber { + println("\(possibleNumber) has an integer value of \(convertedNumber!)") +} else { + println("\(possibleNumber) could not be converted to an integer") +} +// prints "123 has an integer value of 123" +For more on the if statement, see Control Flow. + +NOTE + +Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value. + +Optional Binding + +You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used with if and while statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action. if and while statements are described in more detail in Control Flow. + +Write optional bindings for the if statement as follows: + +if let constantName = someOptional { + statements +} +You can rewrite the possibleNumber example from above to use optional binding rather than forced unwrapping: + +if let actualNumber = possibleNumber.toInt() { + println("\(possibleNumber) has an integer value of \(actualNumber)") +} else { + println("\(possibleNumber) could not be converted to an integer") +} +// prints "123 has an integer value of 123" +This can be read as: + +“If the optional Int returned by possibleNumber.toInt contains a value, set a new constant called actualNumber to the value contained in the optional.” + +If the conversion is successful, the actualNumber constant becomes available for use within the first branch of the if statement. It has already been initialized with the value contained within the optional, and so there is no need to use the ! suffix to access its value. In this example, actualNumber is simply used to print the result of the conversion. + +You can use both constants and variables with optional binding. If you wanted to manipulate the value of actualNumber within the first branch of the if statement, you could write if var actualNumber instead, and the value contained within the optional would be made available as a variable rather than a constant. + +nil + +You set an optional variable to a valueless state by assigning it the special value nil: + +var serverResponseCode: Int? = 404 +// serverResponseCode contains an actual Int value of 404 +serverResponseCode = nil +// serverResponseCode now contains no value +NOTE + +nil cannot be used with non-optional constants and variables. If a constant or variable in your code needs to be able to cope with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type. + +If you define an optional constant or variable without providing a default value, the constant or variable is automatically set to nil for you: + +var surveyAnswer: String? +// surveyAnswer is automatically set to nil +NOTE + +Swift’s nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a non-existent object. In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types. + +Implicitly Unwrapped Optionals + +As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist. + +Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time. + +These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional. + +Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties. + +An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it is accessed. The following example shows the difference in behavior between an optional String and an implicitly unwrapped optional String: + +let possibleString: String? = "An optional string." +println(possibleString!) // requires an exclamation mark to access its value +// prints "An optional string." + +let assumedString: String! = "An implicitly unwrapped optional string." +println(assumedString) // no exclamation mark is needed to access its value +// prints "An implicitly unwrapped optional string." +You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used. Rather than placing an exclamation mark after the optional’s name each time you use it, you place an exclamation mark after the optional’s type when you declare it. + +NOTE + +If you try to access an implicitly unwrapped optional when it does not contain a value, you will trigger a runtime error. The result is exactly the same as if you place an exclamation mark after a normal optional that does not contain a value. + +You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value: + +if assumedString { + println(assumedString) +} +// prints "An implicitly unwrapped optional string." +You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement: + +if let definiteString = assumedString { + println(definiteString) +} +// prints "An implicitly unwrapped optional string." +NOTE + +Implicitly unwrapped optionals should not be used when there is a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable. + +Assertions + +Optionals enable you to check for values that may or may not exist, and to write code that copes gracefully with the absence of a value. In some cases, however, it is simply not possible for your code to continue execution if a value does not exist, or if a provided value does not satisfy certain conditions. In these situations, you can trigger an assertion in your code to end code execution and to provide an opportunity to debug the cause of the absent or invalid value. + +Debugging with Assertions + +An assertion is a runtime check that a logical condition definitely evaluates to true. Literally put, an assertion “asserts” that a condition is true. You use an assertion to make sure that an essential condition is satisfied before executing any further code. If the condition evaluates to true, code execution continues as usual; if the condition evaluates to false, code execution ends, and your app is terminated. + +If your code triggers an assertion while running in a debug environment, such as when you build and run an app in Xcode, you can see exactly where the invalid state occurred and query the state of your app at the time that the assertion was triggered. An assertion also lets you provide a suitable debug message as to the nature of the assert. + +You write an assertion by calling the global assert function. You pass the assert function an expression that evaluates to true or false and a message that should be displayed if the result of the condition is false: + +let age = -3 +assert(age >= 0, "A person's age cannot be less than zero") +// this causes the assertion to trigger, because age is not >= 0 +In this example, code execution will continue only if age >= 0 evaluates to true, that is, if the value of age is non-negative. If the value of age is negative, as in the code above, then age >= 0 evaluates to false, and the assertion is triggered, terminating the application. + +Assertion messages cannot use string interpolation. The assertion message can be omitted if desired, as in the following example: + +assert(age >= 0) +When to Use Assertions + +Use an assertion whenever a condition has the potential to be false, but must definitely be true in order for your code to continue execution. Suitable scenarios for an assertion check include: + +An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high. +A value is passed to a function, but an invalid value means that the function cannot fulfill its task. +An optional value is currently nil, but a non-nil value is essential for subsequent code to execute successfully. +See also Subscripts and Functions. + +NOTE + +Assertions cause your app to terminate and are not a substitute for designing your code in such a way that invalid conditions are unlikely to arise. Nonetheless, in situations where invalid conditions are possible, an assertion is an effective way to ensure that such conditions are highlighted and noticed during development, before your app is published. \ No newline at end of file From cec837d38a36a9d474c49c3988d0e9b149cb798d Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Thu, 19 Jun 2014 02:33:43 +0800 Subject: [PATCH 102/261] update 01_the_basics - till UInt --- src/chapter2/01_The_Basics.md | 53 +++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index f4b14bb..cc08cb4 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -251,37 +251,74 @@ Unlike many other languages, Swift does not require you to write a semicolon (;) let cat = "🐱"; println(cat) // prints "🐱" -Integers +# Integers +# 整数 Integers are whole numbers with no fractional component, such as 42 and -23. Integers are either signed (positive, zero, or negative) or unsigned (positive or zero). +整数就是没有小数部分的完整的数字,如42和-23.整数可以有符号(正数,0,或负数),也可以没有符号(正数或0)。 + Swift provides signed and unsigned integers in 8, 16, 32, and 64 bit forms. These integers follow a naming convention similar to C, in that an 8-bit unsigned integer is of type UInt8, and a 32-bit signed integer is of type Int32. Like all types in Swift, these integer types have capitalized names. -Integer Bounds +Swift提供8,16,32和64进制的带符号和不带符号的整数类型。这些整数遵从和C类似的命名约定,在这个约定中,8进制的无符号整数的类型为`UInt8`,而一个32进制的有符号整数的类型是`Int32`。和Swift的所有类型一样,这些整数的类型是首字母大写的。 + +# Integer Bounds +# 整数边界 You can access the minimum and maximum values of each integer type with its min and max properties: -let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8 -let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8 +你可以通过整数类型的`max`和`min`属性来访问它的最大值和最小值: + + let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8 + let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8 + let minValue = UInt8.min // 最小值是 0, 类型是 UInt8 + let maxValue = UInt8.max // 最大值是 255, 类型是 UInt8 + The values of these properties are of the appropriate-sized number type (such as UInt8 in the example above) and can therefore be used in expressions alongside other values of the same type. -Int +这些属性值是相应数字类型的合适范围(比如上面例子里的`UInt8`),因此它们可以在其他拥有相同类型值的表达式中沿用。 + +# Int +# 整数 In most cases, you don’t need to pick a specific size of integer to use in your code. Swift provides an additional integer type, Int, which has the same size as the current platform’s native word size: +在大多数情况下,你不需要在代码中指定整数的范围。Swift提供了一个专门的整数类型,`Int`,它和当前平台的原生长度范围相同。 + On a 32-bit platform, Int is the same size as Int32. + +在32位的平台上,`Int`和`Int32`范围相同。 + On a 64-bit platform, Int is the same size as Int64. + +在64位的平台上,`Int`和`Int64`范围相同。 + Unless you need to work with a specific size of integer, always use Int for integer values in your code. This aids code consistency and interoperability. Even on 32-bit platforms, Int can store any value between -2,147,483,648 and 2,147,483,647, and is large enough for many integer ranges. -UInt +如果你不需要处理特定的整数范围,请在代码中的整数值使用`Int`类型。这有助于代码的一致性和可复用性。即使在32位的平台上,`Int`类型可以储存从-2,147,483,648到2,147,483,647的整数,大多数情况下这足够用了。 + +# UInt +# 无符号整数 Swift also provides an unsigned integer type, UInt, which has the same size as the current platform’s native word size: +Swift也提供了无符号整数类型,`UInt`,它和当前平台的原生长度范围相同。 + On a 32-bit platform, UInt is the same size as UInt32. + +在32位的平台上,`UInt`和`UInt32`范围相同。 + On a 64-bit platform, UInt is the same size as UInt64. -NOTE -Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference. +在64位的平台上,`UInt`和`UInt64`范围相同。 + +> NOTE + +> Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference. + +> 注意 + +> 只在你需要特别指定无符号整数与当前平台原生长度范围相同时才使用`UInt`,否则,推荐使用`Int`,即使是你知道不会存储负值的时候。使用一致的`Int`整数类型有助于代码的服用,避免了不同数字类型之间的转换,并且匹配整数的类型推断,详见[类型安全和类型推断](link)。 Floating-Point Numbers From 54a865c03466aabe552b9dd419b77d429b603754 Mon Sep 17 00:00:00 2001 From: yozomk Date: Thu, 19 Jun 2014 13:57:46 +0800 Subject: [PATCH 103/261] 20% translated --- .../16_Automatic_Reference_Counting.md | 135 +++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index cb7f3d7..011e616 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -21,7 +21,7 @@ Every time you create a new instance of a class, ARC allocates a chunk of memory Additionally, when an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purposes instead. This ensures that class instances do not take up space in memory when they are no longer needed. -当你创建一个类实例的时候,ARC会为之分配一块内存来存储该实例的相关信息。这些信息包括:该实例的类型及其相关的属性和值。当该实例不再需要的时候,ARC会释放其占用的内存留作他用。这种机制保证了不需要的类实例占用内存会及时得到释放。 +当你创建一个类实例的时候,ARC会为之分配一块内存来存储该实例的相关信息。这些信息包括:该实例的类型及其相关的属性和值。当该实例不再需要的时候,ARC会释放其占用的内存留作他用。这种机制保证了不需要的类实例占用的内存会及时得到释放。 However, if ARC were to deallocate an instance that was still in use, it would no longer be possible to access that instance’s properties, or call that instance’s methods. Indeed, if you tried to access the instance, your app would most likely crash. @@ -34,3 +34,136 @@ To make sure that instances don’t disappear while they are still needed, ARC t To make this possible, whenever you assign a class instance to a property, constant, or variable, that property, constant, or variable makes a strong reference to the instance. The reference is called a “strong“ reference because it keeps a firm hold on that instance, and does not allow it to be deallocated for as long as that strong reference remains. 为了保证ARC机制的有效运行,无论何时你将一个类实例分配给一个属性、常量或一个变量,那么这个属性、常量或变量与类实例之间将建立起一种强引用关系。之所以称为“强引用”,是它会牢牢保持与类实例的引用关系,只要指向类实例的强引用存在,该实例就是不允许被销毁的。 + +## ARC 实践 +Here’s an example of how Automatic Reference Counting works. This example starts with a simple class called Person, which defines a stored constant property called name: + +下面的例子展示了自动引用计数是如何工作的。这是一个名为Person的类,其内部定义了一个名为name的属性: + +``` +class Person { + let name: String + init(name: String) { + self.name = name + println("\(name) is being initialized") + } + deinit { + println("\(name) is being deinitialized") + } +} +``` +The Person class has an initializer that sets the instance’s name property and prints a message to indicate that initialization is underway. The Person class also has a deinitializer that prints a message when an instance of the class is deallocated. + + +Person类有一个构造函数init,负责为其实例属性name赋值并打印出一条信息表明初始化过程正在进行。 +Person类也有一个析构函数deinit,会在Person的实例被销毁时打印出一条信息。 + +The next code snippet defines three variables of type Person?, which are used to set up multiple references to a new Person instance in subsequent code snippets. Because these variables are of an optional type (Person?, not Person), they are automatically initialized with a value of nil, and do not currently reference a Person instance. + +下面的代码片段定义了三个类型为Person?的变量,在随后的代码中,它们将用于设置指向一个Person类实例的多个引用。 +由于这些变量是可选类型(类型为Person?,不是Person),他们将自动初始化为nil(即初始值为nil),而不是引用到Person的实例。 + +``` +var reference1: Person? +var reference2: Person? +var reference3: Person? +``` + +You can now create a new Person instance and assign it to one of these three variables: +现在你可以创建Person类的新实例,并且将它赋值给三个变量其中的一个: +``` +reference1 = Person(name: "John Appleseed") +// prints "John Appleseed is being initialized” +``` + +Note that the message "John Appleseed is being initialized" is printed at the point that you call the Person class’s initializer. This confirms that initialization has taken place. + +注意,当你调用Person类的构造函数的时候,此消息:"John Appleseed is being initialized"将会被打印出来。这表明初始化已经完成。 + +Because the new Person instance has been assigned to the reference1 variable, there is now a strong reference from reference1 to the new Person instance. Because there is at least one strong reference, ARC makes sure that this Person is kept in memory and is not deallocated. + +由于该Person实例被赋值给了变量reference1,因此建立了一个由reference1指向该Person实例的强引用。 +ARC会保证该Person实例保持在内存中不被销毁,因为它这满足了至少有一个强引用的条件。 + +If you assign the same Person instance to two more variables, two more strong references to that instance are established: +如果你将该实例赋值给多个变量,那么就会建立指向该实例的多个强引用: +``` +reference2 = reference1 +reference3 = reference1 +``` +There are now three strong references to this single Person instance. +现在这个Person实例已经有三个强引用了。 + +If you break two of these strong references (including the original reference) by assigning nil to two of the variables, a single strong reference remains, and the Person instance is not deallocated: +如果你通过给任意两个变量赋值nil的方式断开两个强引用(包括原始引用),只留下一个强引用,该Person实例不会被销毁: +``` +reference2 = nil +reference3 = nil +``` +ARC does not deallocate the Person instance until the third and final strong reference is broken, at which point it is clear that you are no longer using the Person instance: +ARC不会销毁该Person实例,直到第三个也是最后一个强引用断开,即能够清楚的表明你不再需要该实例的时候。 +``` +reference3 = nil +// prints "John Appleseed is being deinitialized" +``` + +## 类实例间的强引用循环 + +In the examples above, ARC is able to track the number of references to the new Person instance you create and to deallocate that Person instance when it is no longer needed. + +在上面的例子中,ARC能够跟踪指向Person实例的引用个数,并且在该Person实例不在需要的时候销毁它。 + +However, it is possible to write code in which an instance of a class never gets to a point where it has zero strong references. This can happen if two class instances hold a strong reference to each other, such that each instance keeps the other alive. This is known as a strong reference cycle. + +然而,我们可能会写出这样的代码,导致一个类实例永远不会有0个强引用。这种情况发生在两个类实例互相保持对方的强引用,以致于彼此都无法被销毁。这就是所谓的强引用循环。 + +You resolve strong reference cycles by defining some of the relationships between classes as weak or unowned references instead of as strong references. This process is described in Resolving Strong Reference Cycles Between Class Instances. However, before you learn how to resolve a strong reference cycle, it is useful to understand how such a cycle is caused. +你可以通过定义类之间的关系为弱引用或者无主引用来替代强引用,从而解决循环强引用的问题。具体的过程在解决类实例之间的循环强引用中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是如何产生的。 + +Here’s an example of how a strong reference cycle can be created by accident. +This example defines two classes called Person and Apartment, which model a block of apartments and its residents: +这是一个意外导致强引用循环的例子。例子定义了两个名为Person和Apartment的类,用来模拟公寓和公寓里的居民: +``` +class Person { + let name: String + init(name: String) { self.name = name } + var apartment: Apartment? + deinit { println("\(name) is being deinitialized") } +} + +class Apartment { + let number: Int + init(number: Int) { self.number = number } + var tenant: Person? + deinit { println("Apartment #\(number) is being deinitialized") } +} +``` +Every Person instance has a name property of type String and an optional apartment property that is initially nil. The apartment property is optional, because a person may not always have an apartment. +每一个Person实例都有一个String类型的属性name和一个初始化为nil的可选类型属性apartment。之所以将apartment定义为可选类型,是因为某人可能不总是租公寓。 + +Similarly, every Apartment instance has a number property of type Int and has an optional tenant property that is initially nil. The tenant property is optional because an apartment may not always have a tenant. + +类似的,每一个Apartment实例都有一个Int类型的属性number,和一个初始化为nil的可选类型属性tenant。之所以将tenant定义为可选类型,是因为某公寓也不总是有租客住。 + +Both of these classes also define a deinitializer, which prints the fact that an instance of that class is being deinitialized. This enables you to see whether instances of Person and Apartment are being deallocated as expected. + +两个类都定义了析构函数,它们将在类实例被析构时输出一段信息。这能够让你清楚的知道Person和Apartment的实例是否如预期那样被销毁了。 + +This next code snippet defines two variables of optional type called john and number73, which will be set to a specific Apartment and Person instance below. Both of these variables have an initial value of nil, by virtue of being optional: + +下面的代码片段定义了两个可选类型变量john和number73,接下来,他们将被设置为具体的Apartment实例和Person实例。两个变量的初始值都是nil,因为它们都是可选类型的: +``` +var john: Person? +var number73: Apartment? +``` +You can now create a specific Person instance and Apartment instance and assign these new instances to the john and number73 variables: +现在创建具体的Person实例和Apartment实例,并把这两个新实例分别赋值给john和number73: +``` +john = Person(name: "John Appleseed") +number73 = Apartment(number: 73) +``` +Here’s how the strong references look after creating and assigning these two instances. The john variable now has a strong reference to the new Person instance, and the number73 variable has a strong reference to the new Apartment instance: +下图展示了创建和分配两个实例之后的强引用关系。john变量和新Person实例之间有一条强引用关系,number73变量和新Apartment实例之间也有一条强引用关系。 + +![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/referenceCycle01_2x.png) + From 8f0ae382a1161bef4b5e49bdb1818ddb9c6833f5 Mon Sep 17 00:00:00 2001 From: Joven Pan Date: Thu, 19 Jun 2014 14:01:40 +0800 Subject: [PATCH 104/261] Update 23_Advanced_Operators.md --- src/chapter2/23_Advanced_Operators.md | 169 ++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index f3a997c..f7670e3 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -272,10 +272,179 @@ Swift操作符的优先级和结合性的完整规则,请看表达式。 类和结构体重新自定义已有操作符的功能,这称为操作符重载。 +下面的例子展示了一个自定义结构体的加法运算。加操作符是一个二元操作符,因为它有两个操作数,而且是中置操作符,必须出现在两个操作数之间。 +例子中定义了一个名为Vector2D 的结构体,表示二维坐标向量(x, y)。随后定义了Vector2D 实例对象相加的操作符函数。 +``` +struct Vector2D { + var x = 0.0, y = 0.0 +} +@infix func + (left: Vector2D, right: Vector2D) -> Vector2D { + return Vector2D(x: left.x + right.x, y: left.y + right.y) +} +``` + +该操作符函数定义了一个全局的+函数,参数是两个Vector2D 类型的实例,返回值也是一个Vector2D 类型。函数声明中,在关键字fun之前用@infix 属性定义一个中置操作符。 + +在这个代码实现中,参数被命名为left和right,代表+左边和右边的两个Vector2D对象。函数返回了一个新的Vector2D对象,这个对象的x和y分别等于两个参数对象的x和y的和。 + +这个函数是全局的,而不是Vector2D结构的成员方法,所以任意两个Vector2D对象都可以使用这个中置运算符: + +``` +let vector = Vector2D(x: 3.0, y: 1.0) +let anotherVector = Vector2D(x: 2.0, y: 4.0) +let combinedVector = vector + anotherVector +// combinedVector 是一个Vector2D 实例 ,值为(5.0, 5.0) +``` + +这个例子将向量 (3.0,1.0) 和 (2.0,4.0) 相加,得到向量 (5.0,5.0),如下图所示: + +## 前置和后置操作符 +上个例子演示了一个二元中置操作符的自定义实现,同样类和结构体也可以重载标准的一元操作符。一元操作符只有一个操作数,在操作数之前为前置操作符(比如-a),在操作数之后为后置操作符(比如i++)。 + +函数声明中,在关键字fun之前用@ prefix 属性定义前置操作符,@postfix 定义后置操作符。 + +``` +@prefix func - (vector: Vector2D) -> Vector2D { + return Vector2D(x: -vector.x, y: -vector.y) +} +``` + +这段代码实现了Vector2D对象的一元减操作符(-a),@prefix表明它是前置的。 + +对于数值,一元减操作符可以把正数变负数,把负数变正数。对于Vector2D对象,一元减操作符将其x和y都进行一元减运算。 + +``` +let positive = Vector2D(x: 3.0, y: 4.0) +let negative = -positive +// negative 是 Vector2D实例,值为(-3.0, -4.0) +let alsoPositive = -negative +// alsoPositive 也是 Vector2D实例,值为(3.0, 4.0) +``` + +## 复合赋值操作符 + +复合赋值是其他操作符和赋值操作符一起执行的运算。如+=把加运算和赋值运算组合成一个操作。实现一个复合赋值操作符需要使用@assignment属性,操作符左边的参数作为函数输入,函数内再修改它的值。 + +下面的例子实现了Vector2D 对象的+=操作符: + +``` +@assignment func += (inout left: Vector2D, right: Vector2D) { + left = left + right +} +``` + +加法运算之前定义过了,这里无需重新定义。加赋操作符函数使用已有的加法运算将左值加上右值: + +``` +var original = Vector2D(x: 1.0, y: 2.0) +let vectorToAdd = Vector2D(x: 3.0, y: 4.0) +original += vectorToAdd +// 运算后original 等于 (4.0, 6.0) +``` + +可以将 @assignment 属性和 @prefix 或 @postfix 属性组合起来,比如像下面Vector2D对象的前置运算符(++a): + +``` +@prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D { + vector += Vector2D(x: 1.0, y: 1.0) + return vector +} +``` + +这个自加操作符函数使用了前面定义过的加赋运算,将自己加上一个值为 (1.0,1.0) 的对象然后将返回值赋给自己。 + +``` +var toIncrement = Vector2D(x: 3.0, y: 4.0) +let afterIncrement = ++toIncrement +// toIncrement 等于(4.0, 5.0) +// afterIncrement 也等于 (4.0, 5.0) +``` + +> 注意: +> +> 默认的赋值符(=)是不可重载的。只有复合赋值符可以重载。条件操作符 a?b:c 也是不可重载的。 + +## 比较操作符 + +自定义的类和结构体默认没有相等(==)和不等(!=)操作符,因为Swift无法知道自定义类型怎样算相等,怎样算不等。 + +定义相等操作符跟定义其他中置操作符类似: + +``` +@infix func == (left: Vector2D, right: Vector2D) -> Bool { + return (left.x == right.x) && (left.y == right.y) +} +@infix func != (left: Vector2D, right: Vector2D) -> Bool { + return !(left == right) +} +``` + +上述代码实现了相等操作符==来判断两个Vector2D对象是否相等,相等的概念就是它们有相同的x值和y值。将相等操作符==的结果取反就实现了不等运算符!=。 + +现在我们可以使用这两个操作符来判断两个Vector2D对象是否相等。 + +``` +let twoThree = Vector2D(x: 2.0, y: 3.0) +let anotherTwoThree = Vector2D(x: 2.0, y: 3.0) +if twoThree == anotherTwoThree { +println("这两个向量相等") +} +// 输出结果 "这两个向量相等" +``` + +## 自定义操作符 + +除了标准的操作符,你还可以声明一些个性的操作符,但自定义操作符只能使用这些字符/ = - + * % < >!& | ^。~。 + +新的操作符需要在全局域使用operator关键字声明,可以声明为前置,中置或后置的。 + +``` +operator prefix +++ {} +``` + +这段代码定义了一个新的前置操作符+++,此前Swift并不存在这个操作符,此处针对Vector2D 对象的这个操作符具有个性化的含义。+++被定义为 双自增 操作符,它使用之前定义的加赋运算将自已加上自己然后返回。 + +``` +@prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D { +vector += vector +return vector +} +``` + +Vector2D 的 +++ 和 ++ 很类似, 唯一不同的是前者加自己, 后者是加值为 (1.0, 1.0) 的向量。 + +``` +var toBeDoubled = Vector2D(x: 1.0, y: 4.0) +let afterDoubling = +++toBeDoubled +// toBeDoubled 等于 (2.0, 8.0) +// afterDoubling 也等于 (2.0, 8.0) +``` + +## 自定义中置操作符的优先级和结合性 + +可以为自定义的中置操作符指定优先级和结合性。可以回头看看优先级和结合性中解释的,这两个因素是如何影响复合表达式的求值顺序的。 + +结合性有left,right和none三种情况。左结合操作符跟其他优先级相同的左结合操作符写在一起时,会跟左边的操作数结合。同理,右结合操作符会跟右边的操作数结合。而非结合操作符不能跟其他优先级相同的操作符写在一起。 + +结合性默认为none,优先级默认为100。 + +下面的例子定义了一个左结合且优先级为140的中置操作符+-。 + +``` +operator infix +- { associativity left precedence 140 } +func +- (left: Vector2D, right: Vector2D) -> Vector2D { + return Vector2D(x: left.x + right.x, y: left.y - right.y) +} +let firstVector = Vector2D(x: 1.0, y: 2.0) +let secondVector = Vector2D(x: 3.0, y: 4.0) +let plusMinusVector = firstVector +- secondVector +// plusMinusVector 是 Vector2D实例,等于 (4.0, -2.0) +``` +这个操作符把两个向量的x相加, y相减。因为它实际上属于加减运算,所以让它保持了和加减法一样的结合性和优先级(左结合,优先级为140)。查阅完整的Swift默认优先级和结合性的设置,请移步表达式; From 3447a6e3a87ce9e9fc062de98a5b4c76cd6cb4da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=98=E5=A2=83?= Date: Thu, 19 Jun 2014 14:04:19 +0800 Subject: [PATCH 105/261] =?UTF-8?q?+=E9=9B=86=E5=90=88=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit complete 100%。 --- src/chapter2/04_Collection_Types.md | 567 ++++++++++++++++++++++++++++ 1 file changed, 567 insertions(+) diff --git a/src/chapter2/04_Collection_Types.md b/src/chapter2/04_Collection_Types.md index e69de29..f3cb809 100644 --- a/src/chapter2/04_Collection_Types.md +++ b/src/chapter2/04_Collection_Types.md @@ -0,0 +1,567 @@ +##Collection Types +##集合类型 + +Swift provides two *collection types*, known as arrays and dictionaries, for storing collections of values. Arrays store ordered lists of values of the same type. Dictionaries store unordered collections of values of the same type, which can be referenced and looked up through a unique identifier (also known as a *key*). + +Swift提供了两种*集合类型* 来存储数据集合,分别是数组(arrays)和词典(dictionaries)。数组用来存储有序的相同类型数据的列表。字典用来存储无序的相同类型的数据的集合,这些数据可以通过一个唯一的标识符(称为*键*)来引用和查找。 + +Arrays and dictionaries in Swift are always clear about the types of values and keys that they can store. This means that you cannot insert a value of the wrong type into an array or dictionary by mistake. It also means you can be confident about the types of values you will retrieve from an array or dictionary. Swift’s use of explicitly typed collections ensures that your code is always clear about the types of values it can work with and enables you to catch any type mismatches early in your code’s development. + +在Swift中,数组和词典能够存储的键值类型一直是很明确的。这意味着我们不能错误地把类型不正确的数据插入到一个数组或词典中。这也意味着我们能够清楚的知道从一个数组或词典中获取到的数据的类型。Swift的显式类型的集合使得我们清楚代码中能够处理哪种类型的数据,并使得我们可以更早的在代码开发过程中发现任何类型错误。 + +>NOTE + +>Swift’s `Array` type exhibits different behavior to other types when assigned to a constant or variable, or when passed to a function or method. For more information, see Mutability of Collections and Assignment and Copy Behavior for Collection Types. + +>注意 + +>Swift的`Array`类型在赋值给常量和变量,还有传入函数和方法时与其他类型有所不同。获取更多信息请参见[Mutability of Collections and Assignment](id1) 和 [Copy Behavior for Collection Types](id2)这两个章节。 + + +###Arrays +###数组 +An *array* stores multiple values of the same type in an ordered list. The same value can appear in an array multiple times at different positions. + +*数组*在一个有序列表中存储了多个相同类型的数据。相同的数据可以多次出现在数组的不同位置。 + +Swift arrays are specific about the kinds of values they can store. They differ from Objective-C’s `NSArray` and `NSMutableArray` classes, which can store any kind of object and do not provide any information about the nature of the objects they return. In Swift, the type of values that a particular array can store is always made clear, either through an explicit type annotation, or through type inference, and does not have to be a class type. If you create an array of `Int` values, for example, you can’t insert any value other than `Int` values into that array. Swift arrays are type safe, and are always clear about what they may contain. + +Swift数组能够存储的数据类型是确定的。这与Objective-C的类`NSArray`和`NSMutableArray`是不同的,这两个类能够存储任何一种类型的对象,并且不会提供它们返回的对象的任何信息。在Swift中,某个数组能够存储的数据类型是确定的,不是通过显式的类型声明,就是通过类型推断,不需要为class类型。假我们你创建了一个`Int`型的数组,那么就不能插入其他任何非`Int`型的值到这个数组中。Swift数组是类型安全的,并且它们能够包含的值也是明确的。 +‌ +####Array Type Shorthand Syntax +####数组类型缩写语法 +The type of a Swift array is written in full as `Array`, where `SomeType` is the type that the array is allowed to store. You can also write the type of an array in shorthand form as `SomeType[]`. Although the two forms are functionally identical, the shorthand form is preferred, and is used throughout this guide when referring to the type of an array. + +Swift数组的类型的完整写法是`Array`, 这里的`SomeType`指的是数组能够存储的类型。我们也可以把它缩写为`SomeType[]`。这两种形式的数组在功能上完全相同,不过建议使用缩写的形式,本书中提到数组类型时都会以这种形式表示。 +‌ +####Array Literals +####数组字面量 + +You can initialize an array with an *array literal*, which is a shorthand way to write one or more values as an array collection. An array literal is written as a list of values, separated by commas, surrounded by a pair of square brackets: + +你可以用*数组字面量*来初始化数组,这是把一个或多个值作为数组集合的缩写方式。数组字面量被写作一个数值列表,由逗号分隔开来,被一对方括号括起来: + +``` + [value 1, value 2, value 3] +``` + +The example below creates an array called `shoppingList` to store `String` values: + +下面这个例子创建了一个命名为`shoppingList`的数组来存储`String`类型的数据。 + +``` +var shoppingList: String[] = ["Eggs", "Milk"] +// shoppingList has been initialized with two initial items +``` + +The `shoppingList` variable is declared as “an array of `String` values”, written as `String[]`. Because this particular array has specified a value type of `String`, it is *only* allowed to store `String` values. Here, the `shoppingList` array is initialized with two `String` values (`"Eggs" `and `"Milk"`), written within an array literal. + +变量shoppingList被声明为“一个`String`类型的数组”,写为`String[]`。这个特定数组的类型确定为`String`,因此它*只能*存储`String`类型的数据。这里的`shoppingList`数组被写在一个数组字面量中的两个`String`值(`“Egg”`和`"Milk"`)初始化。 + +>NOTE + +>The `shoppingList` array is declared as a variable (with the `var` introducer) and not a constant (with the `let` introducer) because more items are added to the shopping list in the examples below. + +>注意 + +>数组`shoppingList`被声明为变量(通过关键字`var`)而不是常量(通过关键字`let`),因为在下面的例子中,更多的数组项被添加到这个购物列表中。 + +In this case, the array literal contains two `String `values and nothing else. This matches the type of the `shoppingList` variable’s declaration (an array that can only contain `String` values), and so the assignment of the array literal is permitted as a way to initialize `shoppingList` with two initial items. + +在这个例子中,该数组字面量只包含了两个`String`值。这和shoppingList变量的声明(只能包含`String`值的数组)是一致的,因此数组字面量的赋值被用来作为一种用两个初始项来初始化shopplingList的方式。 + +Thanks to Swift’s type inference, you don’t have to write the type of the array if you’re initializing it with an array literal containing values of the same type. The initialization of `shoppingList` could have been written in a shorter form instead: + +感谢Swift的类型推断,通过包含相同类型数据的数组字面量,我们不需要去写正在初始化的数组的类型。`shopplingList`的初始化可以缩写为: + +``` +var shoppingList = ["Eggs", "Milk"] +``` + +Because all values in the array literal are of the same type, Swift can infer that `String[]` is the correct type to use for the `shoppingList` variable. + +因为数组字面量中所有的值的类型是相同的,Swift能够推断出`String[]`是`shoppingList`变量使用的正确类型。 +‌ +####Accessing and Modifying an Array +####获取和修改数组 +You access and modify an array through its methods and properties, or by using subscript syntax. + +我们可以通过数组的方法、属性或下标语法来访问和修改数组。 + +To find out the number of items in an array, check its read-only `count` property: + +可以通过数组的只读属性`count`来获得数组包含的数组项个数,。 + +``` +println("The shopping list contains \(shoppingList.count) items.") +// prints "The shopping list contains 2 items." +``` + +Use the Boolean `isEmpty` property as a shortcut for checking whether the `count` property is equal to `0`: + +用布尔值`isEmpty`属性来作为查看`count`属性是否等于`0`的快捷方式。 + +``` +if shoppingList.isEmpty { + println("The shopping list is empty.") +} else { + println("The shopping list is not empty.") +} +// prints "The shopping list is not empty.” +``` + +You can add a new item to the end of an array by calling the array’s `append` method: + +我们可以通过调用数组的`append`方法来插入一个新的数组项到数组的末尾。 + +``` +shoppingList.append("Flour") +// shoppingList now contains 3 items, and someone is making pancakes +``` + +Alternatively, add a new item to the end of an array with the addition assignment operator (`+=`): + +或者,可以通过加法赋值运算符(`+=`)来添加新的数组项到数组的末尾。 + +``` +shoppingList += "Baking Powder" +// shoppingList now contains 4 items +``` + +You can also append an array of compatible items with the addition assignment operator (`+=`): + +你还可以通过加法赋值运算符(`+=`)来插入一个同类型的数组。 + +``` +shoppingList += ["Chocolate Spread", "Cheese", "Butter"] +// shoppingList now contains 7 items +``` + +Retrieve a value from the array by using *subscript syntax*, passing the index of the value you want to retrieve within square brackets immediately after the name of the array: + +通过*下标语法*从数组中获取某个值,即在数组名之后紧跟由方括号括起来的想要获取的值的索引: + +``` +var firstItem = shoppingList[0] +// firstItem is equal to "Eggs" +``` + +Note that the first item in the array has an index of `0`, not `1`. Arrays in Swift are always zero-indexed. + +注意,数组中第一个数组项的索引为`0`,而不是`1`。Swift数组的索引是从零开始的。 + +You can use subscript syntax to change an existing value at a given index: + +通过指定的索引,我们可以使用下标语法来修改一个已经存在的值: + +``` +shoppingList[0] = "Six eggs" +// the first item in the list is now equal to "Six eggs" rather than "Eggs" +``` + +You can also use subscript syntax to change a range of values at once, even if the replacement set of values has a different length than the range you are replacing. The following example replaces `"Chocolate Spread"`, `"Cheese"`, and `"Butter"` with `"Bananas"` and `"Apples"`: + +我们还可以通过下标语法一次改变一个范围内的值,即使要替换的值的长度和被替换的值的长度不一致。下面的例子用`"Bananas"` and `"Apples"`替换了`"Chocolate Spread"`, `"Cheese"`, and `"Butter"`: + +``` +shoppingList[4...6] = ["Bananas", "Apples"] +// shoppingList now contains 6 items +``` + +>NOTE + +>You can’t use subscript syntax to append a new item to the end of an array. If you try to use subscript syntax to retrieve or set a value for an index that is outside of an array’s existing bounds, you will trigger a runtime error. However, you can check that an index is valid before using it, by comparing it to the array’s `count` property. Except when `count` is `0` (meaning the array is empty), the largest valid index in an array will always be `count - 1`, because arrays are indexed from zero.” + +>注意 + +>我们不能使用下标语法插入一个新的数组项到数组的末尾。如果我们试图用一个超过数组边界的下标访问或设置某个数值时,会导致运行时错误。不过,我们可以通过比较索引和数组的`count`属性来判断该索引是否有效。数组中最大的有效索引为`count-1`,除了count为`0`时(意味着这个数组是空的),因为数组的索引是从0开始的。 + + +To insert an item into the array at a specified index, call the array’s `insert(atIndex:)` method: + +要给数组的指定索引处插入一个数组项,可以调用数组的`insert(atIndex:)`方法: + +``` +shoppingList.insert("Maple Syrup", atIndex: 0) +// shoppingList now contains 7 items +// "Maple Syrup" is now the first item in the list +``` + +This call to the `insert` method inserts a new item with a value of `"Maple Syrup"` at the very beginning of the shopping list, indicated by an index of `0`. + +上面的例子中,调用了`insert`方法插入了一个值为`“Maple Syrup”`的新数组项到数组的开头,用索引`0`来表示。 + +Similarly, you remove an item from the array with the `removeAtIndex` method. This method removes the item at the specified index and returns the removed item (although you can ignore the returned value if you do not need it): + +相同地,`removeAtIndex`方法可以从数组中移除一个数组项。该方法移除指定索引的数组项,并返回被移除的数组项(如果不需要,我们可以忽略返回的值): + +```let mapleSyrup = shoppingList.removeAtIndex(0) +// the item that was at index 0 has just been removed +// shoppingList now contains 6 items, and no Maple Syrup +// the mapleSyrup constant is now equal to the removed" Maple Syrup" string +``` + +Any gaps in an array are closed when an item is removed, and so the value at index `0` is once again equal to `"Six eggs"`: + +当一个数组项被移除后数组中的空出项会被自动填补,因此索引`0`对应的值再次等于`“Six eggs”`: + +``` +firstItem = shoppingList[0] +// firstItem is now equal to "Six eggs" +``` +If you want to remove the final item from an array, use the `removeLast` method rather than the `removeAtIndex `method to avoid the need to query the array’s `count` property. Like the `removeAtIndex` method, `removeLast` returns the removed item: + +如果我们想要从数组中移除最后一个数组项,最好使用`removeLast`方法,而不是`removeAtIndex`方法,这样能够避免去查询数组的`count`属性。像`removeAtIndex`方法那样,`removeLast`方法也会返回被移除的数组项: + +``` +let apples = shoppingList.removeLast() +// the last item in the array has just been removed +// shoppingList now contains 5 items, and no cheese +// the apples constant is now equal to the removed "Apples" string +``` + +####Iterating Over an Array +####遍历数组 +You can iterate over the entire set of values in an array with the `for-in` loop: + +我们可以使用`for-in`循环来遍历数组中的所有数组项: + +``` +for item in shoppingList { + println(item) +} +// Six eggs +// Milk +// Flour +// Baking Powder +// Bananas +``` +If you need the integer index of each item as well as its value, use the global `enumerate` function to iterate over the array instead. The `enumerate` function returns a tuple for each item in the array composed of the index and the value for that item. You can decompose the tuple into temporary constants or variables as part of the iteration: + +如果我们除了需要每个数组项的值之外,还需要每个数组项的索引,那么可以使用全局函数`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 +``` +For more about the `for-in` loop, see [For Loops](). + +获取更多关于`for-in`循环的介绍,请参见[For循环](id3)。 + +####Creating and Initializing an Array +####创建和初始化数组 +You can create an empty array of a certain type (without setting any initial values) using initializer syntax: + +我们可以使用初始化语法来创建某一特定类型的空数组(没有设置任何初始值): + +``` +var someInts = Int[]() +println("someInts is of type Int[] with \(someInts.count) items.") +// prints "someInts is of type Int[] with 0 items." +``` +Note that the type of the `someInts` variable is inferred to be `Int[]`, because it is set to the output of an `Int[]` initializer. + +注意,变量`someInts`的类型被认为是`Int[]`,因为它的设置自于`Int[]`初始化的输出。 + +Alternatively, if the context already provides type information, such as a function argument or an already-typed variable or constant, you can create an empty array with an empty array literal, which is written as `[]` (an empty pair of square brackets): + +或者,如果上下文已经提供了类型信息,例如一个函数参数,或一个已经指定类型的变量或常量,我们可以用空数组字面量来创建空数组,写为`[]`(一对空的方括号): + +``` +someInts.append(3) +// someInts now contains 1 value of type Int +someInts = [] +// someInts is now an empty array, but is still of type Int[] +``` +Swift’s `Array` type also provides an initializer for creating an array of a certain size with all of its values set to a provided default value. You pass this initializer the number of items to be added to the new array (called `count`) and a default value of the appropriate type (called `repeatedValue`): + +Swift`数组`类型还提供了一个构造器来创建指定大小的数组,该数组的数组项的值是默认的。我们传递给构造器新加的数组项的大小(称为`count`),以及适合类型的默认值(称为`repeatedValue`)。 + +``` +var threeDoubles = Double[](count: 3, repeatedValue: 0.0) +// threeDoubles is of type Double[], and equals [0.0, 0.0, 0.0] +``` +Thanks to type inference, you don’t need to specify the type to be stored in the array when using this initializer, because it can be inferred from the default value: + +感谢类型推导,我们在使用构造器时不需要指定数组中数值的具体类型,因为类型可以从默认值中推导出来: + +``` +var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5) +// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5] +``` +Finally, you can create a new array by adding together two existing arrays of compatible type with the addition operator (`+`). The new array’s type is inferred from the type of the two arrays you add together: + +最后,我们可以使用加法操作符(`+`)把两个已经存在的相同类型的数组相加来创建一个新的数组。这个新数组的类型是从两个相加的数组的类型推导出来的: + +``` +var sixDoubles = threeDoubles + anotherThreeDoubles +// sixDoubles is inferred as Double[], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] +``` + +###Dictionaries +###字典 +A *dictionary* is a container that stores multiple values of the same type. Each value is associated with a unique *key*, which acts as an identifier for that value within the dictionary. Unlike items in an array, items in a dictionary do not have a specified order. You use a dictionary when you need to look up values based on their identifier, in much the same way that a real-world dictionary is used to look up the definition for a particular word. + +*字典*是存储多重相同类型数值的容器。每个值和字典中作为值的唯一标识符的*键*(key)相关联。和数组中的数据项不同,字典中的数据项没有顺序。我们可以使用字典查找基于标识符的数据,就像在现实世界中可以用字典来查找某个特定字词的定义。 + +Swift dictionaries are specific about the types of keys and values they can store. They differ from Objective-C’s `NSDictionary` and `NSMutableDictionary` classes, which can use any kind of object as their keys and values and do not provide any information about the nature of these objects. In Swift, the type of keys and values that a particular dictionary can store is always made clear, either through an explicit type annotation or through type inference. + +Swift字典能够存储的键和值的类型是确定的。他们和Objective-C的类`NSDictionary`和`NSMutableDictionary`有所不同,这些类能够用任意一种对象作为他们的键和值,且不提供这些对象本质相关的任何信息。在Swift中,确定的字典能够存储的键和值的类型是确定的,要么通过显示的类型声明而来,要么通过类型推断而来。 + +Swift’s dictionary type is written as `Dictionary`, where `KeyType` is the type of value that can be used as a dictionary key, and `ValueType` is the type of value that the dictionary stores for those keys. + +Swift字典类型被写为`Dictionary`,这里的`KeyType`是能够被作为字典键的数据的类型,`ValueType`是字典中存储的与键相关联的数据的类型。 + +The only restriction is that `KeyType` must be *hashable*—that is, it must provide a way to make itself uniquely representable. All of Swift’s basic types (such as `String`, `Int`, `Double`, and `Bool`) are hashable by default, and all of these types can be used as the keys of a dictionary. Enumeration member values without associated values (as described in Enumerations) are also hashable by default. + +`KeyType`的唯一限制是它必须是*可哈希的*——也就是说,它必须提供一个方法来使得自己能够被唯一表示。所有的Swift基础类型(如`String`, `Int`, `Double`, 和`Bool`)默认都是可哈希的,所有的这些类型都能够被用来作为字典的键。没有关联数值的枚举类型(参见[Enumerations](#Enumerations))也是默认可枚举的。 + +‌ +####Dictionary Literals +####字典字面量 +You can initialize a dictionary with a *dictionary literal*, which has a similar syntax to the array literal seen earlier. A dictionary literal is a shorthand way to write one or more key-value pairs as a `Dictionary` collection. + +你可以用*字典字面量*来初始化一个字典,这个和之前的数组字面量有着相似的语法。一个字典字面量是一个缩写的方式来表示作为`字典`集合的一个或多个键值对。 + +A *key-value pair* is a combination of a key and a value. In a dictionary literal, the key and value in each key-value pair are separated by a colon. The key-value pairs are written as a list, separated by commas, surrounded by a pair of square brackets: + +一个*键-值对*是键和值的组合。在字典字面量中,每个键-值对中的键和值由冒号分隔开来。键值对被写作一个列表,用逗号隔开,由方括号括起来: + +``` + [key 1: value 1, key 2: value 2, key 3: value 3] + ``` +The example below creates a dictionary to store the names of international airports. In this dictionary, the keys are three-letter International Air Transport Association codes, and the values are airport names: + +下面的例子创建了一个字典来储存国际机场的名字。在这个字典中,键是由三个字母组成的国际航空运输协会代码,值是机场的名称: + +``` +var airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin"] +``` +The `airports` dictionary is declared as having a type of `Dictionary`, which means “a `Dictionary` whose keys are of type `String`, and whose values are also of type `String`”. + +`airports`字典被声明为`Dictionary`类型,即“一个键和值的类型都是`String`类型的字典”。 + +>NOTE + +>The `airports` dictionary is declared as a variable (with the `var` introducer), and not a constant (with the `let` introducer), because more airports will be added to the dictionary in the examples below. + +>注意 + +>`airports`字典被声明为变量(用关键字`var`),而不是常量(用关键字`let`),因为在下面的例子中,会有更多的机场被添加到这个字典里。 + +The `airports` dictionary is initialized with a dictionary literal containing two key-value pairs. The first pair has a key of `"TYO"` and a value of `"Tokyo"`. The second pair has a key of `"DUB"` and a value of `"Dublin"`. + +`airports`字典由包含两对键值对的字典字面量初始化。第一对有一个键`“TYO”`和一个值`“Tokyo”`。第二对有一个键`“DUB”`和一个值`“Dublin”`。 + +This dictionary literal contains two `String`: `String` pairs. This matches the type of the `airports` variable declaration (a dictionary with only `String` keys, and only `String` values) and so the assignment of the dictionary literal is permitted as a way to initialize the `airports` dictionary with two initial items. + +这个字典字面量包含两个`String`:`String`类型的键值对。这和变量`airports`声明(只有`String`键和`String`值的字典)的类型一致,因此字典字面量的赋值被用来作为一种初始化方法来用两个初始项构建这个`airports`字典。 + +As with arrays, you don’t have to write the type of the dictionary if you’re initializing it with a dictionary literal whose keys and values have consistent types. The initialization of `airports` could have been be written in a shorter form instead: + +像数组那样,如用我们用键值类型相同的字典字面量来初始化字典,那么我们不需要写出它的类型。`airports`的初始化可以被简写为以下形式: + +``` +var airports = ["TYO": "Tokyo", "DUB": "Dublin"] +``` +Because all keys in the literal are of the same type as each other, and likewise all values are of the same type as each other, Swift can infer that `Dictionary` is the correct type to use for the `airports` dictionary. +由于字面量中的键和值都是相同类型的,因而Swift能够推断出`Dictionary` 是使用字典`airports`的正确类型。 +‌ +####Accessing and Modifying a Dictionary +You access and modify a dictionary through its methods and properties, or by using subscript syntax. As with an array, you can find out the number of items in a `Dictionary` by checking its read-only `count` property: + +我们能够通过字典的方法和属性,以及下标语法来访问和修改字典。像数组那样,我们可以通过查询只读属性`count`来得到一个`字典`中数据项的数量。 + +``` +println("The dictionary of airports contains \(airports.count) items.") +// prints "The dictionary of airports contains 2 items." +``` +You can add a new item to a dictionary with subscript syntax. Use a new key of the appropriate type as the subscript index, and assign a new value of the appropriate type: + +我们可以通过下标语法给字典添加新的数据项。使用合适类型的键作为下标索引,赋予合适类型的值: + +``` +airports["LHR"] = "London" +// the airports dictionary now contains 3 items +``` + +You can also use subscript syntax to change the value associated with a particular key: + +我们还可以使用下标语法来改变和某个特定键相关联的值: + +``` +airports["LHR"] = "London Heathrow" +// the value for "LHR" has been changed to "London Heathrow" +``` +As an alternative to subscripting, use a dictionary’s `updateValue(forKey:)` method to set or update the value for a particular key. Like the subscript examples above, the `updateValue(forKey:)` method sets a value for a key if none exists, or updates the value if that key already exists. Unlike a subscript, however, the `updateValue(forKey:)` method returns the old value after performing an update. This enables you to check whether or not an update took place. + +字典的`updateValue(forKey:)`方法可作为下标的替代来设置或更新某个特定键相关联的值。像上面下标的那个例子,`updateValue(forKey:)`方法可以设置某个不存在的键的值或者更新某个已有的键的值。和下标不同的是,`updateValue(forKey:)`方法在更新数据后会返回更新之前的数值。这使得我们可以检查更新是否成功。 + +The `updateValue(forKey:)` method returns an optional value of the dictionary’s value type. For a dictionary that stores `String` values, for example, the method returns a value of type `String?`, or “optional `String`”. This optional value contains the old value for that key if one existed before the update, or `nil` if no value existed: + +`updateValue(forKey:)`方法返回字典值类型的可选值。举个例子,对于一个储存了`String`数据的字典,这个方法返回了一个`String?类型`或“可选的`String`”类型的数据。如果在更新之前这个键是存在的,则这个可选数据返回更新之前的值,否则返回`nil`。 + +``` +if let oldValue = airports.updateValue("Dublin International", forKey: "DUB") { + println("The old value for DUB was \(oldValue).") +} +// prints "The old value for DUB was Dublin." +``` +You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type. If the dictionary contains a value for the requested key, the subscript returns an optional value containing the existing value for that key. Otherwise, the subscript returns `nil`: + +我们也可以使用下标语法来访问一个字典中某个特定键对应的值。因为查询某个不存在对应值的键也是有可能的,字典的下标会返回字典数据类型的可选值。如果字典包含了与要查找的键相对应的值,下标返回的可选值包含那个键对应的值,否则下标返回`nil`。 + +``` +if let airportName = airports["DUB"] { + println("The name of the airport is \(airportName).") +} else { + println("That airport is not in the airports dictionary.") +} +// prints "The name of the airport is Dublin International." +``` +You can use subscript syntax to remove a key-value pair from a dictionary by assigning a value of `nil` for that key: + +我们可以使用下标语法设置某个指定键的值为`nil`来从字典中移除该键值对。 + +``` +airports["APL"] = "Apple International" +// "Apple International" is not the real airport for APL, so delete it +airports["APL"] = nil +// APL has now been removed from the dictionary +``` + +Alternatively, remove a key-value pair from a dictionary with the `removeValueForKey` method. This method removes the key-value pair if it exists and returns the removed value, or returns `nil` if no value existed: + +我们还可以使用`removeValueForKey`方法从字典中移除一个键值对。如果要移除的键对应的值对存在,该方法会移除它们并返回被移除的值,如果对应的值不存在,则返回`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. +``` + +####Iterating Over a Dictionary +####字典遍历 +You can iterate over the key-value pairs in a dictionary with a `for-in` loop. Each item in the dictionary is returned as a (`key, value`) tuple, and you can decompose the tuple’s members into temporary constants or variables as part of the iteration: + +我们可以用`for-in`循环遍历一个字典中的键值对。字典中的每个数据项返回相应的(`键, 值`)原则,我们可以把元组分解为临时常量或变量用于遍历: + +``` +for (airportCode, airportName) in airports { + println("\(airportCode): \(airportName)") +} +// TYO: Tokyo +// LHR: London Heathrow +``` +For more about the `for-in` loop, see For Loops. + +更多关于`for-in`循环的介绍,请参见[For循环](id3)。 + +You can also retrieve an iteratable collection of a dictionary’s keys or values by accessing its `keys` and `values` properties: + +我们还能够通过字典的`keys`或`values`属性来遍历字典的键或值。 + +``` +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 +``` + +If you need to use a dictionary’s keys or values with an API that takes an `Array` instance, initialize a new array with the `keys` or `values` property: + +如果我们需要使用一个使用字典的键和值,并用`Array`实例作为参数的接口,可以用`keys`或`values`属性来初始化一个新的数组。 + +``` +let airportCodes = Array(airports.keys) +// airportCodes is ["TYO", "LHR"] + +let airportNames = Array(airports.values) +// airportNames is ["Tokyo", "London Heathrow"] +``` +>NOTE + +>Swift’s Dictionary type is an unordered collection. The order in which keys, values, and key-value pairs are retrieved when iterating over a dictionary is not specified. + +>注意 + +>Swift字典类型是无序的集合。遍历字典时键、值以及键值对的访问顺序是不确定的。 +‌ + +####Creating an Empty Dictionary +####创建空字典 +As with arrays, you can create an empty `Dictionary` of a certain type by using initializer syntax: + +如同字典,我们可以使用初始化语法创建一个特定类型的空`字典`。 + +``` +var namesOfIntegers = Dictionary() +// namesOfIntegers is an empty Dictionary +``` +This example creates an empty dictionary of type `Int`, `String` to store human-readable names of integer values. Its keys are of type `Int`, and its values are of type `String`. + +这个例子创建了`Int`,`String`类型的空字典来存储整型数据的可读性名称。它的键的类型是`Int`,值的类型是`String`。 + +If the context already provides type information, create an empty dictionary with an empty dictionary literal, which is written as [`:`] (a colon inside a pair of square brackets): + +如果上下文已经提供了类型信息,可以用空字典字面量来创建空字典,写为[`:`] (中括号中放一个冒号): + +``` +namesOfIntegers[16] = "sixteen" +// namesOfIntegers now contains 1 key-value pair +namesOfIntegers = [:] +// namesOfIntegers is once again an empty dictionary of type Int, String +``` + +>NOTE + +>Behind the scenes, Swift’s array and dictionary types are implemented as *generic collections*. For more on generic types and collections, see [Generics](). + +>注意 + +>在后台,Swift数组和字典类型都是由*泛型集合*实现的。更多关于泛型类型和集合的介绍,请参见[Generics](id3)。 + +‌ +###Mutability of Collections +###集合的易变性 + +Arrays and dictionaries store multiple values together in a single collection. If you create an array or a dictionary and assign it to a variable, the collection that is created will be *mutable*. This means that you can change (or *mutate*) the size of the collection after it is created by adding more items to the collection, or by removing existing items from the ones it already contains. Conversely, if you assign an array or a dictionary to a constant, that array or dictionary is *immutable*, and its size cannot be changed. + +数组和字典在单个集合中存储了多个数据。如果我们创建一个数组或字典并把它声明为变量,这个被创建出来的集合是*易变的*。这表示我们能够在创建集合之后通过添加更多的数据项到集合中或从中移除现有的数据项来*改变*它的大小。相反的,如果把一个数组或字典声明为常量,则这个数组或字典是*不可变*的,它的大小是不会变化的。 + +For dictionaries, immutability also means that you cannot replace the value for an existing key in the dictionary. An immutable dictionary’s contents cannot be changed once they are set. + +对字典来说,不可变还意味着我们不能替换字典中某个现有的键对应的值。一个不可变字典的内容一旦被设置就不能再被改变。 + +Immutability has a slightly different meaning for arrays, however. You are still not allowed to perform any action that has the potential to change the size of an immutable array, but you *are* allowed to set a new value for an existing index in the array. This enables Swift’s `Array` type to provide optimal performance for array operations when the size of an array is fixed. + +对数组来说,不可变的意义稍有不同。我们仍不允许有改变不可变数组的大小的行为,但是,我们*被*允许改变数组中某个现有索引对应的值。这使得Swift的`Array`类型能够在操作固定大小的数组时提供最佳性能。 + +The mutability behavior of Swift’s `Array` type also affects how array instances are assigned and modified. For more information, see [Assignment and Copy Behavior for Collection Types](). + +Swift的`Array`类型的可变性还影响了数组实例是怎么被声明和修改的。更多介绍请参见[集合类型的声明和复制]()。 + +>NOTE + +>It is good practice to create immutable collections in all cases where the collection’s size does not need to change. Doing so enables the Swift compiler to optimize the performance of the collections you create. + +>注意 +>当集合的大小不需要改变时,创建一个不可变的集合是比较好的做法。这样做使得Swift编译器优化我们创建的集合的性能。 + + From 49a74e596325727f449f90b98a00eb7e9a48fb96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=98=E5=A2=83?= Date: Thu, 19 Jun 2014 14:09:30 +0800 Subject: [PATCH 106/261] update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改 --- src/chapter2/04_Collection_Types.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/chapter2/04_Collection_Types.md b/src/chapter2/04_Collection_Types.md index f3cb809..bef9e30 100644 --- a/src/chapter2/04_Collection_Types.md +++ b/src/chapter2/04_Collection_Types.md @@ -195,7 +195,8 @@ Similarly, you remove an item from the array with the `removeAtIndex` method. Th 相同地,`removeAtIndex`方法可以从数组中移除一个数组项。该方法移除指定索引的数组项,并返回被移除的数组项(如果不需要,我们可以忽略返回的值): -```let mapleSyrup = shoppingList.removeAtIndex(0) +``` +let mapleSyrup = shoppingList.removeAtIndex(0) // the item that was at index 0 has just been removed // shoppingList now contains 6 items, and no Maple Syrup // the mapleSyrup constant is now equal to the removed" Maple Syrup" string @@ -254,6 +255,7 @@ For more about the `for-in` loop, see [For Loops](). 获取更多关于`for-in`循环的介绍,请参见[For循环](id3)。 + ####Creating and Initializing an Array ####创建和初始化数组 You can create an empty array of a certain type (without setting any initial values) using initializer syntax: @@ -304,6 +306,7 @@ var sixDoubles = threeDoubles + anotherThreeDoubles // sixDoubles is inferred as Double[], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] ``` + ###Dictionaries ###字典 A *dictionary* is a container that stores multiple values of the same type. Each value is associated with a unique *key*, which acts as an identifier for that value within the dictionary. Unlike items in an array, items in a dictionary do not have a specified order. You use a dictionary when you need to look up values based on their identifier, in much the same way that a real-world dictionary is used to look up the definition for a particular word. From 3c4e55e4bbcff66c92c784a1f8f2991d742a2db9 Mon Sep 17 00:00:00 2001 From: yozomk Date: Thu, 19 Jun 2014 14:11:18 +0800 Subject: [PATCH 107/261] 20% translated fix mistakes --- .../16_Automatic_Reference_Counting.md | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index 011e616..ed2b0e2 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -70,7 +70,9 @@ var reference3: Person? ``` You can now create a new Person instance and assign it to one of these three variables: -现在你可以创建Person类的新实例,并且将它赋值给三个变量其中的一个: + +现在创建Person类的新实例,并且将它赋值给三个变量中的一个: + ``` reference1 = Person(name: "John Appleseed") // prints "John Appleseed is being initialized” @@ -86,22 +88,30 @@ Because the new Person instance has been assigned to the reference1 variable, th ARC会保证该Person实例保持在内存中不被销毁,因为它这满足了至少有一个强引用的条件。 If you assign the same Person instance to two more variables, two more strong references to that instance are established: + 如果你将该实例赋值给多个变量,那么就会建立指向该实例的多个强引用: + ``` reference2 = reference1 reference3 = reference1 ``` + There are now three strong references to this single Person instance. + 现在这个Person实例已经有三个强引用了。 If you break two of these strong references (including the original reference) by assigning nil to two of the variables, a single strong reference remains, and the Person instance is not deallocated: -如果你通过给任意两个变量赋值nil的方式断开两个强引用(包括原始引用),只留下一个强引用,该Person实例不会被销毁: + +如果你通过给任意两个变量赋值nil的方式断开两个强引用(包括原始引用),留下一个强引用,该Person实例不会被销毁: + ``` reference2 = nil reference3 = nil ``` ARC does not deallocate the Person instance until the third and final strong reference is broken, at which point it is clear that you are no longer using the Person instance: -ARC不会销毁该Person实例,直到第三个也是最后一个强引用断开,即能够清楚的表明你不再需要该实例的时候。 + +直到第三个也是最后一个强引用断开,即能够清楚的断定你不再需要该实例的时候,ARC才会销毁该Person实例。 + ``` reference3 = nil // prints "John Appleseed is being deinitialized" @@ -111,18 +121,21 @@ reference3 = nil In the examples above, ARC is able to track the number of references to the new Person instance you create and to deallocate that Person instance when it is no longer needed. -在上面的例子中,ARC能够跟踪指向Person实例的引用个数,并且在该Person实例不在需要的时候销毁它。 +在上面的例子中,ARC能够跟踪指向Person实例的引用个数,并且在该Person实例不再需要的时候销毁它。 However, it is possible to write code in which an instance of a class never gets to a point where it has zero strong references. This can happen if two class instances hold a strong reference to each other, such that each instance keeps the other alive. This is known as a strong reference cycle. -然而,我们可能会写出这样的代码,导致一个类实例永远不会有0个强引用。这种情况发生在两个类实例互相保持对方的强引用,以致于彼此都无法被销毁。这就是所谓的强引用循环。 +然而,我们可能会写出这样的代码,导致类实例永远不会有0个强引用。这种情况发生在两个类实例互相保持对方的强引用,以致于彼此都无法被销毁的时候。这就是所谓的强引用循环。 You resolve strong reference cycles by defining some of the relationships between classes as weak or unowned references instead of as strong references. This process is described in Resolving Strong Reference Cycles Between Class Instances. However, before you learn how to resolve a strong reference cycle, it is useful to understand how such a cycle is caused. -你可以通过定义类之间的关系为弱引用或者无主引用来替代强引用,从而解决循环强引用的问题。具体的过程在解决类实例之间的循环强引用中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是如何产生的。 + +你可以通过定义类之间的关系为弱引用或者无主引用的方式来解决循环强引用的问题。具体的过程在解决类实例之间的循环强引用中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是如何产生的。 Here’s an example of how a strong reference cycle can be created by accident. This example defines two classes called Person and Apartment, which model a block of apartments and its residents: + 这是一个意外导致强引用循环的例子。例子定义了两个名为Person和Apartment的类,用来模拟公寓和公寓里的居民: + ``` class Person { let name: String @@ -138,7 +151,9 @@ class Apartment { deinit { println("Apartment #\(number) is being deinitialized") } } ``` + Every Person instance has a name property of type String and an optional apartment property that is initially nil. The apartment property is optional, because a person may not always have an apartment. + 每一个Person实例都有一个String类型的属性name和一个初始化为nil的可选类型属性apartment。之所以将apartment定义为可选类型,是因为某人可能不总是租公寓。 Similarly, every Apartment instance has a number property of type Int and has an optional tenant property that is initially nil. The tenant property is optional because an apartment may not always have a tenant. @@ -152,17 +167,21 @@ Both of these classes also define a deinitializer, which prints the fact that an This next code snippet defines two variables of optional type called john and number73, which will be set to a specific Apartment and Person instance below. Both of these variables have an initial value of nil, by virtue of being optional: 下面的代码片段定义了两个可选类型变量john和number73,接下来,他们将被设置为具体的Apartment实例和Person实例。两个变量的初始值都是nil,因为它们都是可选类型的: + ``` var john: Person? var number73: Apartment? ``` You can now create a specific Person instance and Apartment instance and assign these new instances to the john and number73 variables: + 现在创建具体的Person实例和Apartment实例,并把这两个新实例分别赋值给john和number73: + ``` john = Person(name: "John Appleseed") number73 = Apartment(number: 73) ``` Here’s how the strong references look after creating and assigning these two instances. The john variable now has a strong reference to the new Person instance, and the number73 variable has a strong reference to the new Apartment instance: + 下图展示了创建和分配两个实例之后的强引用关系。john变量和新Person实例之间有一条强引用关系,number73变量和新Apartment实例之间也有一条强引用关系。 ![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/referenceCycle01_2x.png) From eae480e8dd792e79ce74c077e699c1889b057ff9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=98=E5=A2=83?= Date: Thu, 19 Jun 2014 14:25:03 +0800 Subject: [PATCH 108/261] add links add links for reference --- src/chapter2/04_Collection_Types.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/chapter2/04_Collection_Types.md b/src/chapter2/04_Collection_Types.md index bef9e30..66fc205 100644 --- a/src/chapter2/04_Collection_Types.md +++ b/src/chapter2/04_Collection_Types.md @@ -11,11 +11,11 @@ Arrays and dictionaries in Swift are always clear about the types of values and >NOTE ->Swift’s `Array` type exhibits different behavior to other types when assigned to a constant or variable, or when passed to a function or method. For more information, see Mutability of Collections and Assignment and Copy Behavior for Collection Types. +>Swift’s `Array` type exhibits different behavior to other types when assigned to a constant or variable, or when passed to a function or method. For more information, see [Mutability of Collections](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/04_Collection_Types.md#mutability-of-collections) and [Assignment and Copy Behavior for Collection Types](). >注意 ->Swift的`Array`类型在赋值给常量和变量,还有传入函数和方法时与其他类型有所不同。获取更多信息请参见[Mutability of Collections and Assignment](id1) 和 [Copy Behavior for Collection Types](id2)这两个章节。 +>Swift的`Array`类型在赋值给常量和变量,还有传入函数和方法时与其他类型有所不同。获取更多信息请参见[Mutability of Collections](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/04_Collection_Types.md#mutability-of-collections)and[AssignmentCopy Behavior for Collection Types]()这两个章节。 ###Arrays @@ -251,9 +251,9 @@ for (index, value) in enumerate(shoppingList) { // Item 4: Baking Powder // Item 5: Bananas ``` -For more about the `for-in` loop, see [For Loops](). +For more about the `for-in` loop, see [For Loops](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF). -获取更多关于`for-in`循环的介绍,请参见[For循环](id3)。 +获取更多关于`for-in`循环的介绍,请参见[For循环](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF)。 ####Creating and Initializing an Array @@ -321,9 +321,9 @@ Swift’s dictionary type is written as `Dictionary`, where Swift字典类型被写为`Dictionary`,这里的`KeyType`是能够被作为字典键的数据的类型,`ValueType`是字典中存储的与键相关联的数据的类型。 -The only restriction is that `KeyType` must be *hashable*—that is, it must provide a way to make itself uniquely representable. All of Swift’s basic types (such as `String`, `Int`, `Double`, and `Bool`) are hashable by default, and all of these types can be used as the keys of a dictionary. Enumeration member values without associated values (as described in Enumerations) are also hashable by default. +The only restriction is that `KeyType` must be *hashable*—that is, it must provide a way to make itself uniquely representable. All of Swift’s basic types (such as `String`, `Int`, `Double`, and `Bool`) are hashable by default, and all of these types can be used as the keys of a dictionary. Enumeration member values without associated values (as described in [Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md)) are also hashable by default. -`KeyType`的唯一限制是它必须是*可哈希的*——也就是说,它必须提供一个方法来使得自己能够被唯一表示。所有的Swift基础类型(如`String`, `Int`, `Double`, 和`Bool`)默认都是可哈希的,所有的这些类型都能够被用来作为字典的键。没有关联数值的枚举类型(参见[Enumerations](#Enumerations))也是默认可枚举的。 +`KeyType`的唯一限制是它必须是*可哈希的*——也就是说,它必须提供一个方法来使得自己能够被唯一表示。所有的Swift基础类型(如`String`, `Int`, `Double`, 和`Bool`)默认都是可哈希的,所有的这些类型都能够被用来作为字典的键。没有关联数值的枚举类型(参见[Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md))也是默认可枚举的。 ‌ ####Dictionary Literals @@ -465,9 +465,9 @@ for (airportCode, airportName) in airports { // TYO: Tokyo // LHR: London Heathrow ``` -For more about the `for-in` loop, see For Loops. +For more about the `for-in` loop, see [For Loops](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF). -更多关于`for-in`循环的介绍,请参见[For循环](id3)。 +更多关于`for-in`循环的介绍,请参见[For循环](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF)。 You can also retrieve an iteratable collection of a dictionary’s keys or values by accessing its `keys` and `values` properties: @@ -534,11 +534,11 @@ namesOfIntegers = [:] >NOTE ->Behind the scenes, Swift’s array and dictionary types are implemented as *generic collections*. For more on generic types and collections, see [Generics](). +>Behind the scenes, Swift’s array and dictionary types are implemented as *generic collections*. For more on generic types and collections, see [Generics](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/22_Generics.md). >注意 ->在后台,Swift数组和字典类型都是由*泛型集合*实现的。更多关于泛型类型和集合的介绍,请参见[Generics](id3)。 +>在后台,Swift数组和字典类型都是由*泛型集合*实现的。更多关于泛型类型和集合的介绍,请参见[Generics](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/22_Generics.md)。 ‌ ###Mutability of Collections From c542e69b0f30345905012c19211fbed3a48398c1 Mon Sep 17 00:00:00 2001 From: yozomk Date: Thu, 19 Jun 2014 16:29:20 +0800 Subject: [PATCH 109/261] 25% translated! by mk --- .../16_Automatic_Reference_Counting.md | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index ed2b0e2..8283957 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -182,7 +182,43 @@ number73 = Apartment(number: 73) ``` Here’s how the strong references look after creating and assigning these two instances. The john variable now has a strong reference to the new Person instance, and the number73 variable has a strong reference to the new Apartment instance: -下图展示了创建和分配两个实例之后的强引用关系。john变量和新Person实例之间有一条强引用关系,number73变量和新Apartment实例之间也有一条强引用关系。 +这里展示了创建和分配两个实例之后的强引用关系。john变量和新Person实例之间有一条强引用关系,number73变量和新Apartment实例之间也有一条强引用关系。 ![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/referenceCycle01_2x.png) +You can now link the two instances together so that the person has an apartment, and the apartment has a tenant. Note that an exclamation mark (!) is used to unwrap and access the instances stored inside the john and number73 optional variables, so that the properties of those instances can be set: + +现在将两个实例连接在一起,让人住进一间公寓,公寓也有了一个租客。注意那个感叹号(!),它用于打开和访问存储于john和number73实例中的可选变量,这样实例的属性才能够被设置: + +``` +john!.apartment = number73 +number73!.tenant = john +``` + +Here’s how the strong references look after you link the two instances together: +这里展示了两个实例连接在一直之后的强引用关系: + +![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/referenceCycle02_2x.png) + +Unfortunately, linking these two instances creates a strong reference cycle between them. The Person instance now has a strong reference to the Apartment instance, and the Apartment instance has a strong reference to the Person instance. Therefore, when you break the strong references held by the john and number73 variables, the reference counts do not drop to zero, and the instances are not deallocated by ARC: + +不幸的是,连接两个实例后导致它们之间形成了强引用循环。现在Person实例有一个指向Apartment的强引用,同时Apartment实例也有一个指向Person的强引用。因此,当你断开由变量john和number73保持的强引用时,引用计数不会减为0,因此实例也不会被ARC销毁。 + +``` +john = nil +number73 = nil +``` + +Note that neither deinitializer was called when you set these two variables to nil. The strong reference cycle prevents the Person and Apartment instances from ever being deallocated, causing a memory leak in your app. + +需要注意的是,尽管在你将john和number73设为nil时析构函数也会被调用,但是强引用循环阻止了Person 和 Apartment类实例的销毁,在你的App中导致了内存泄漏。 + +Here’s how the strong references look after you set the john and number73 variables to nil: + +下图展示了将john和number73设为nil后的强引用关系: + +![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/referenceCycle03_2x.png) + +The strong references between the Person instance and the Apartment instance remain and cannot be broken. + +Person类实例与Apartment类实例之间的强引用关系将保持且无法被断开。 \ No newline at end of file From 35dab5ca6adbb6a79656c0c32e776496d876285c Mon Sep 17 00:00:00 2001 From: mofengfly Date: Thu, 19 Jun 2014 16:29:33 +0800 Subject: [PATCH 110/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 3f9e2fb..19ed69e 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -670,13 +670,13 @@ There are three ways create an instance of a previously declared structure: 有3种方式创建过去声明过的示例结构的示例。 - * Call one of the initializers declared within the structure, as described in Initializers. + -Call one of the initializers declared within the structure, as described in Initializers. 就像Initializers描述的,调用结构里的一个初始器之一。 - * If no initializers are declared, call the structure’s memberwise initializer, as described in Memberwise Initializers for Structure Types. + -If no initializers are declared, call the structure’s memberwise initializer, as described in Memberwise Initializers for Structure Types. 如果没有初始器被声明,就可以调用结构区的成员 - * If no initializers are declared, and all properties of the structure declaration were given initial values, call the structure’s default initializer, as described in Default Initializers. + -If no initializers are declared, and all properties of the structure declaration were given initial values, call the structure’s default initializer, as described in Default Initializers. 如果没有初始化器被声明,结构所有其他声明的属性就会被给予初始化的值,调用结构的某人初始化器,正如Default Initializers .描述的那样。 @@ -1188,11 +1188,12 @@ A postfix operator is a unary operator that is written immediately after its ope 后缀运算符一元运算符,紧跟在操作数之前,比如表达式 i++ 中的前后缀递增运算符(++)。 As with prefix operators, postfix operator declarations don’t specify a precedence level. Postfix operators are nonassociative. + 与前缀运算符一样,后缀运算符声明不会指定优先级。后缀运算符也是非结合性的。 After declaring a new operator, you implement it by declaring a function that has the same name as the operator. To see an example of how to create and implement a new operator, see Custom Operators. -在声明了一个新的运算符止呕,要声明一个和运算符同名的函数来实现它。如何创建和实现新的操作符,请看Custom Operators。 +在声明了一个新的运算符之后,要声明一个和运算符同名的函数来实现它。如何创建和实现新的操作符,请看Custom Operators。 From 190ef7f5d0252354b747914c48825c4642e6702e Mon Sep 17 00:00:00 2001 From: mofengfly Date: Thu, 19 Jun 2014 16:32:20 +0800 Subject: [PATCH 111/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 19ed69e..4148d8e 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -670,14 +670,14 @@ There are three ways create an instance of a previously declared structure: 有3种方式创建过去声明过的示例结构的示例。 - -Call one of the initializers declared within the structure, as described in Initializers. - 就像Initializers描述的,调用结构里的一个初始器之一。 +- Call one of the initializers declared within the structure, as described in Initializers. + 就像Initializers描述的,调用结构里的一个初始器之一。 - -If no initializers are declared, call the structure’s memberwise initializer, as described in Memberwise Initializers for Structure Types. - 如果没有初始器被声明,就可以调用结构区的成员 +- If no initializers are declared, call the structure’s memberwise initializer, as described in Memberwise Initializers for Structure Types. + 如果没有初始器被声明,就可以调用结构区的成员 - -If no initializers are declared, and all properties of the structure declaration were given initial values, call the structure’s default initializer, as described in Default Initializers. - 如果没有初始化器被声明,结构所有其他声明的属性就会被给予初始化的值,调用结构的某人初始化器,正如Default Initializers .描述的那样。 +- If no initializers are declared, and all properties of the structure declaration were given initial values, call the structure’s default initializer, as described in Default Initializers. + 如果没有初始化器被声明,结构所有其他声明的属性就会被给予初始化的值,调用结构的某人初始化器,正如Default Initializers .描述的那样。 From 15a770395c1d971e10b5f1e36c231f0e70b69f74 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Thu, 19 Jun 2014 16:33:27 +0800 Subject: [PATCH 112/261] Update 06_Declarations.md --- src/chapter3/06_Declarations.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md index 4148d8e..85e263f 100644 --- a/src/chapter3/06_Declarations.md +++ b/src/chapter3/06_Declarations.md @@ -741,13 +741,10 @@ There are two ways create an instance of a previously declared class: 有两种方式创建过去声明的类的实例: - - * Call one of the initializers declared within the class, as described in Initializers. - 在类的内部调用声明的初始化器。 - - * If no initializers are declared, and all properties of the class declaration were given initial values, call the class’s default initializer, as described in Default Initializers. - - 如果没有声明的初始化器,类声明的素有属性会有一个初始化值,是通过调用类的默认的初始化器来完成的。正如Default Initializers描述的。 +- Call one of the initializers declared within the class, as described in Initializers. + 在类的内部调用声明的初始化器。 +- If no initializers are declared, and all properties of the class declaration were given initial values, call the class’s default initializer, as described in Default Initializers. + 如果没有声明的初始化器,类声明的素有属性会有一个初始化值,是通过调用类的默认的初始化器来完成的。正如Default Initializers描述的。 From 5dc00e5fde9eac8f56b9ae916f7b1b366eb6323d Mon Sep 17 00:00:00 2001 From: Joven Pan Date: Thu, 19 Jun 2014 17:50:09 +0800 Subject: [PATCH 113/261] Update 23_Advanced_Operators.md --- src/chapter2/23_Advanced_Operators.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index f7670e3..51234fe 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -19,6 +19,8 @@ Swift支持C语言里所有的位操作符,如下所述: 按位非操作符(~)对操作数每一位取反: +![按位非操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseNOT_2x.png) + 按位非是前置操作符,紧置于操作数之前,不带空格: ``` From f626eb6046816db9f4372cf2d8fa661cb7caa479 Mon Sep 17 00:00:00 2001 From: Joven Pan Date: Thu, 19 Jun 2014 18:11:55 +0800 Subject: [PATCH 114/261] Update 23_Advanced_Operators.md --- src/chapter2/23_Advanced_Operators.md | 53 +++++++++++++++++++-------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index 51234fe..7be7b5d 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -19,7 +19,7 @@ Swift支持C语言里所有的位操作符,如下所述: 按位非操作符(~)对操作数每一位取反: -![按位非操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseNOT_2x.png) +![按位非](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseNOT_2x.png) 按位非是前置操作符,紧置于操作数之前,不带空格: @@ -28,16 +28,19 @@ let initialBits: UInt8 = 0b00001111 let invertedBits = ~initialBits // 等于 11110000 ``` -UInt8 是8位无符号整型,可以存储0-255之间的任意数。这个例子先初始化了一个UInt8 整型变量initialBits,二进制值为00001111,前四位为0,后四位为1,换算成十进制等于15。 +`UInt8` 是8位无符号整型,可以存储0-255之间的任意数。这个例子先初始化了一个`UInt8` 整型变量`initialBits`,二进制值为`00001111`,前四位为0,后四位为1,换算成十进制等于15。 -接着将这个变量initialBits进行按位非操作得到常量invertedBits,0变成1,1变成0,得到的二进制值为11110000,换算成十进制等于240。 +接着将这个变量`initialBits`进行按位非操作得到常量`invertedBits`,0变成1,1变成0,得到的二进制值为`11110000`,换算成十进制等于240。 ### 按位与 按位与操作符(&)有两个操作数。按位与操作就是将两个操作数的每一位对齐,当对应位都是1时返回1,其他情况都返回0。 -以下代码,firstSixBits 和lastSixBits 中间4个位都等于1,将它们按位与操作后得到二进制数00111100,换算成十进制为60: +![按位与](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseAND_2x.png) + + +以下代码,`firstSixBits` 和`lastSixBits` 中间4个位都等于1,将它们按位与操作后得到二进制数`00111100`,换算成十进制为60: ``` let firstSixBits: UInt8 = 0b11111100 @@ -49,7 +52,10 @@ let middleFourBits = firstSixBits & lastSixBits // 等于 00111100 按位或操作符(|)也有两个操作数。按位或操作就是将两个操作数的每一位对齐,当对应位有一个是1时就返回1,而只有两个位都是0的情况才返回0。 -以下代码,someBits 和moreBits 在不同位上有1,将它们按位或操作后得到二进制数11111110,换算成十进制为254: +![按位或](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseOR_2x.png) + + +以下代码,`someBits` 和`moreBits` 在不同位上有1,将它们按位或操作后得到二进制数`11111110`,换算成十进制为254: ``` let someBits: UInt8 = 0b10110010 @@ -61,7 +67,10 @@ let combinedbits = someBits | moreBits // 等于 11111110 按位异或操作符(^)比较两个操作数的对应位,当两个位不同时返回1,相同时返回0。 -以下代码,firstBits 和otherBits 对应位相同的情况返回0,不同的情况返回1: +![按位异或](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitwiseXOR_2x.png) + + +以下代码,`firstBits` 和`otherBits` 对应位相同的情况返回0,不同的情况返回1: ``` let firstBits: UInt8 = 0b00010100 @@ -69,14 +78,14 @@ let otherBits: UInt8 = 0b00000101 let outputBits = firstBits ^ otherBits // 等于 00010001 ``` -## 按位左移、右移操作符 +### 按位左移、右移操作符 -左移操作符(<<)和右移操作符()将操作数的所有位向左或向右移动指定的位数。 +左移操作符(<<)和右移操作符(>>)将操作数的所有位向左或向右移动指定的位数。 按位左移和右移的效果等同于将操作数乘以或除以2的倍数。向左移动一位相当于将操作数乘以2,向右移动一位相当于将操作数除以2。 -### 无符号移位操作 +#### 无符号移位操作 无符号移位的规则如下: @@ -86,7 +95,9 @@ let outputBits = firstBits ^ otherBits // 等于 00010001 这种方法称为逻辑移位。 -下图展示了11111111 << 1(11111111 左移一位)和11111111 >> 1(11111111 右移一位)的结果。蓝色数字表示被移动位,灰色表示被丢弃位,空位用橙色的0填充。 +下图展示了`11111111 << 1`(11111111 左移一位)和`11111111 >> 1`(11111111 右移一位)的结果。蓝色数字表示被移动位,灰色表示被丢弃位,空位用橙色的0填充。 + +![无符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftUnsigned_2x.png) Swift移位操作代码: @@ -108,36 +119,46 @@ let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent是0x66, 即102 let blueComponent = pink & 0x0000FF // blueComponent是0x99, 即153 ``` -这个例子中用一个UInt32 常量pink 来存储css中粉色的颜色值。CSS中颜色#CC6699在Swift用十六进制0xCC6699来表示。这个颜色值经过按位与(&)和按位右移操作后可分解出它的红色成分(CC)、绿色成分(66)和蓝色成分(99)。 +这个例子中用一个`UInt32` 常量`pink` 来存储css中粉色的颜色值。CSS中颜色`#CC6699`在Swift用十六进制`0xCC6699`来表示。这个颜色值经过按位与(&)和按位右移操作后可分解出它的红色成分(CC)、绿色成分(66)和蓝色成分(99)。 -对0xCC6699 和0xFF0000进行按位与操作就可以得到红色成分。0xFF0000 里的0类似于遮罩,将0xCC6699的第二和第三字节过滤掉后返回0xCC0000 。 +对`0xCC6699` 和`0xFF0000`进行按位与操作就可以得到红色成分。`0xFF0000` 里的0类似于遮罩,将`0xCC6699`的第二和第三字节过滤掉后返回`0xCC0000` 。 -然后,将0xCC0000 向右移动16位。因为十六进制中每两个字符占8个比特位,所以移动16位的结果是把0xCC0000 变成0x0000CC,等同于0xCC,换算成十进制是204。 +然后,将`0xCC0000` 向右移动16位。因为十六进制中每两个字符占8个比特位,所以移动16位的结果是把`0xCC0000` 变成`0x0000CC`,等同于0xCC,换算成十进制是204。 -同理,对0xCC6699 和0x00FF00进行按位与操作可以得到绿色成分。将结果值0x006600再向右移动8位得到0x66,换算成十进制是102。 +同理,对`0xCC6699` 和`0x00FF00`进行按位与操作可以得到绿色成分。将结果值`0x006600`再向右移动8位得到0x66,换算成十进制是102。 -最后,对0xCC6699 和0x0000FF进行按位与操作可以得到蓝色成分。结果值0x000099不需要再做移位操作,因为0x000099 等价于0x99,换算成十进制是153。 +最后,对`0xCC6699` 和`0x0000FF`进行按位与操作可以得到蓝色成分。结果值`0x000099`不需要再做移位操作,因为`0x000099` 等价于0x99,换算成十进制是153。 -### 有符号移位操作 +#### 有符号移位操作 有符号的移位操作相对复杂得多,因为正负号也是用二进制位表示的。(下面举的例子虽然都是8位的,但原理是通用的。) 有符号整型的第一位为符号位,0代表正数,1代表负数,其余的为数值位。有符号和无符号正整数的存储结构是相同的,比如数值4的二进制结构图: +![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSignedFour_2x.png) + 符号位为0,代表正数,其余7个数值位用二进制表示十进制的4。 负数的存储不太一样,它存储的是2的n次方减去它的绝对值,n为数值位的位数。比如一个8位的数有7个数值位,所以是2的7次方,即128。我们来看下数值-4的二进制结构图: +![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSignedMinusFour_2x.png) + 这里符号位为1,代表负数,其余7个数值位的值是124(即128-4): +![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSignedMinusFourValue_2x.png) + 负数的编码方式称为二进制补码表示。这种表示方式看起来很奇怪,但它有几个优点。 首先,对全部8个比特位(包括符号位)做标准的二进制加法就可以完成-1 加 -4 的操作,加法过程中丢弃超出的比特位。 +![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSignedAddition_2x.png) + 第二,使用二进制补码表示方式,我们可以和正数一样对负数进行按位左移或右移,同样也是左移1位时乘于2,右移1位时除于2。但是,对有符号整型的右移有一个特别的要求: + 有符号和无符号整型按位右移时规则相同,但有符号整型移位后出现的空位使用符号位来填充,而不是0。 +![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSigned_2x.png) + 这就确保了按位右移后,有符号整型的符号不会发生变化。这称为算术移位。 因为正数和负数特殊的存储方式,向右移位都会使它们更接近于0。移位过程中保持符号位不变,所以负数向右移位时值虽然接近于0但始终是负数。 From 7d30f90906f3deadd7e9b88be9b4e06ee45bc71e Mon Sep 17 00:00:00 2001 From: Joven Pan Date: Thu, 19 Jun 2014 18:41:16 +0800 Subject: [PATCH 115/261] Update 23_Advanced_Operators.md --- src/chapter2/23_Advanced_Operators.md | 61 +++++++++++++++------------ 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index 7be7b5d..a5cf5f9 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -167,7 +167,7 @@ let blueComponent = pink & 0x0000FF // blueComponent是0x99, 即153 当给整型常量或变量赋值溢出时,Swift默认会报错,这就保证了操作过大或过小数据时的安全性。 -举个例子,Int16整型能表示-32768 到 32767之间任意的有符号整数,但如果给它 赋值超出该范围则会导致错误: +举个例子,`Int16`整型能表示-32768 到 32767之间任意的有符号整数,但如果给它 赋值超出该范围则会导致错误: ``` var potentialOverflow = Int16.max @@ -197,13 +197,18 @@ willOverflow = willOverflow &+ 1 // 现在willOverflow 等于 0 ``` -willOverflow 等于UInt8 所能表示的最大值255(二进制11111111),使用溢出加法&+加1,如下图所示因为上溢出UInt8 无法表示出这个新值了。溢出后,有效位为00000000,也就是0。 +`willOverflow` 等于`UInt8` 所能表示的最大值255(二进制`11111111`),使用溢出加法&+加1,如下图所示因为上溢出`UInt8` 无法表示出这个新值了。溢出后,有效位为`00000000`,也就是0。 + +![上溢出](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/overflowAddition_2x.png) + ### 下溢出 数值也有可能因为太小而越界。举个例子: -UInt8能表示的最小值是0(二进制为00000000)。对00000000使用溢出减法&-减1,就会得到二进制数11111111,即十进制的255。 +`UInt8`能表示的最小值是0(二进制为`00000000`)。对`00000000`使用溢出减法&-减1,就会得到二进制数`11111111`,即十进制的255。 + +![下溢出](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/overflowUnsignedSubtraction_2x.png) 代码如下: @@ -214,7 +219,9 @@ willUnderflow = willUnderflow &- 1 // 现在willUnderflow 等于255 ``` -有符号整型也有类似的下溢出,它所有的减法都是对包括符号位在内的二进制数进行二进制减法,这在 "按位左移、右移操作符" 一节提到过。Int8 能表示的最小整数是-128,即二进制的10000000。用溢出减法减去1后,变成了01111111,即Int8 能表示的最大整数127。 +有符号整型也有类似的下溢出,它所有的减法都是对包括符号位在内的二进制数进行二进制减法,这在 "按位左移、右移操作符" 一节提到过。`Int8` 能表示的最小整数是-128,即二进制的`10000000`。用溢出减法减去1后,变成了`01111111`,即`Int8` 能表示的最大整数127。 + +![下溢出](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/overflowSignedSubtraction_2x.png) 代码如下: @@ -297,7 +304,7 @@ Swift操作符的优先级和结合性的完整规则,请看表达式。 下面的例子展示了一个自定义结构体的加法运算。加操作符是一个二元操作符,因为它有两个操作数,而且是中置操作符,必须出现在两个操作数之间。 -例子中定义了一个名为Vector2D 的结构体,表示二维坐标向量(x, y)。随后定义了Vector2D 实例对象相加的操作符函数。 +例子中定义了一个名为`Vector2D` 的结构体,表示二维坐标向量`(x, y)`。随后定义了`Vector2D` 实例对象相加的操作符函数。 ``` struct Vector2D { @@ -308,11 +315,11 @@ struct Vector2D { } ``` -该操作符函数定义了一个全局的+函数,参数是两个Vector2D 类型的实例,返回值也是一个Vector2D 类型。函数声明中,在关键字fun之前用@infix 属性定义一个中置操作符。 +该操作符函数定义了一个全局的+函数,参数是两个`Vector2D` 类型的实例,返回值也是一个`Vector2D` 类型。函数声明中,在关键字fun之前用@infix 属性定义一个中置操作符。 -在这个代码实现中,参数被命名为left和right,代表+左边和右边的两个Vector2D对象。函数返回了一个新的Vector2D对象,这个对象的x和y分别等于两个参数对象的x和y的和。 +在这个代码实现中,参数被命名为left和right,代表+左边和右边的两个`Vector2D`对象。函数返回了一个新的`Vector2D`对象,这个对象的x和y分别等于两个参数对象的x和y的和。 -这个函数是全局的,而不是Vector2D结构的成员方法,所以任意两个Vector2D对象都可以使用这个中置运算符: +这个函数是全局的,而不是`Vector2D`结构的成员方法,所以任意两个`Vector2D`对象都可以使用这个中置运算符: ``` let vector = Vector2D(x: 3.0, y: 1.0) @@ -321,13 +328,15 @@ let combinedVector = vector + anotherVector // combinedVector 是一个Vector2D 实例 ,值为(5.0, 5.0) ``` -这个例子将向量 (3.0,1.0) 和 (2.0,4.0) 相加,得到向量 (5.0,5.0),如下图所示: +这个例子将向量 `(3.0,1.0)` 和 `(2.0,4.0)` 相加,得到向量 `(5.0,5.0)`,如下图所示: + +![操作符函数](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/vectorAddition_2x.png) -## 前置和后置操作符 +### 前置和后置操作符 上个例子演示了一个二元中置操作符的自定义实现,同样类和结构体也可以重载标准的一元操作符。一元操作符只有一个操作数,在操作数之前为前置操作符(比如-a),在操作数之后为后置操作符(比如i++)。 -函数声明中,在关键字fun之前用@ prefix 属性定义前置操作符,@postfix 定义后置操作符。 +函数声明中,在关键字fun之前用`@ prefix` 属性定义前置操作符,`@postfix` 定义后置操作符。 ``` @prefix func - (vector: Vector2D) -> Vector2D { @@ -335,9 +344,9 @@ let combinedVector = vector + anotherVector } ``` -这段代码实现了Vector2D对象的一元减操作符(-a),@prefix表明它是前置的。 +这段代码实现了`Vector2D`对象的一元减操作符(-a),`@prefix`表明它是前置的。 -对于数值,一元减操作符可以把正数变负数,把负数变正数。对于Vector2D对象,一元减操作符将其x和y都进行一元减运算。 +对于数值,一元减操作符可以把正数变负数,把负数变正数。对于`Vector2D`对象,一元减操作符将其x和y都进行一元减运算。 ``` let positive = Vector2D(x: 3.0, y: 4.0) @@ -347,11 +356,11 @@ let alsoPositive = -negative // alsoPositive 也是 Vector2D实例,值为(3.0, 4.0) ``` -## 复合赋值操作符 +### 复合赋值操作符 -复合赋值是其他操作符和赋值操作符一起执行的运算。如+=把加运算和赋值运算组合成一个操作。实现一个复合赋值操作符需要使用@assignment属性,操作符左边的参数作为函数输入,函数内再修改它的值。 +复合赋值是其他操作符和赋值操作符一起执行的运算。如+=把加运算和赋值运算组合成一个操作。实现一个复合赋值操作符需要使用`@assignment`属性,操作符左边的参数作为函数输入,函数内再修改它的值。 -下面的例子实现了Vector2D 对象的+=操作符: +下面的例子实现了`Vector2D` 对象的+=操作符: ``` @assignment func += (inout left: Vector2D, right: Vector2D) { @@ -368,7 +377,7 @@ original += vectorToAdd // 运算后original 等于 (4.0, 6.0) ``` -可以将 @assignment 属性和 @prefix 或 @postfix 属性组合起来,比如像下面Vector2D对象的前置运算符(++a): +可以将 `@assignment` 属性和 `@prefix` 或 `@postfix` 属性组合起来,比如像下面`Vector2D`对象的前置运算符(++a): ``` @prefix @assignment func ++ (inout vector: Vector2D) -> Vector2D { @@ -390,7 +399,7 @@ let afterIncrement = ++toIncrement > > 默认的赋值符(=)是不可重载的。只有复合赋值符可以重载。条件操作符 a?b:c 也是不可重载的。 -## 比较操作符 +### 比较操作符 自定义的类和结构体默认没有相等(==)和不等(!=)操作符,因为Swift无法知道自定义类型怎样算相等,怎样算不等。 @@ -405,9 +414,9 @@ let afterIncrement = ++toIncrement } ``` -上述代码实现了相等操作符==来判断两个Vector2D对象是否相等,相等的概念就是它们有相同的x值和y值。将相等操作符==的结果取反就实现了不等运算符!=。 +上述代码实现了相等操作符==来判断两个`Vector2D`对象是否相等,相等的概念就是它们有相同的x值和y值。将相等操作符==的结果取反就实现了不等运算符!=。 -现在我们可以使用这两个操作符来判断两个Vector2D对象是否相等。 +现在我们可以使用这两个操作符来判断两个`Vector2D`对象是否相等。 ``` let twoThree = Vector2D(x: 2.0, y: 3.0) @@ -420,15 +429,15 @@ println("这两个向量相等") ## 自定义操作符 -除了标准的操作符,你还可以声明一些个性的操作符,但自定义操作符只能使用这些字符/ = - + * % < >!& | ^。~。 +除了标准的操作符,你还可以声明一些个性的操作符,但自定义操作符只能使用这些字符`/ = - + * % < >!& | ^ . ~` -新的操作符需要在全局域使用operator关键字声明,可以声明为前置,中置或后置的。 +新的操作符需要在全局域使用`operator`关键字声明,可以声明为前置,中置或后置的。 ``` operator prefix +++ {} ``` -这段代码定义了一个新的前置操作符+++,此前Swift并不存在这个操作符,此处针对Vector2D 对象的这个操作符具有个性化的含义。+++被定义为 双自增 操作符,它使用之前定义的加赋运算将自已加上自己然后返回。 +这段代码定义了一个新的前置操作符+++,此前Swift并不存在这个操作符,此处针对`Vector2D` 对象的这个操作符具有个性化的含义。+++被定义为双自增操作符,它使用之前定义的加赋运算将自已加上自己然后返回。 ``` @prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D { @@ -437,7 +446,7 @@ return vector } ``` -Vector2D 的 +++ 和 ++ 很类似, 唯一不同的是前者加自己, 后者是加值为 (1.0, 1.0) 的向量。 +`Vector2D` 的 +++ 和 ++ 很类似, 唯一不同的是前者加自己, 后者是加值为 `(1.0, 1.0)` 的向量。 ``` var toBeDoubled = Vector2D(x: 1.0, y: 4.0) @@ -446,7 +455,7 @@ let afterDoubling = +++toBeDoubled // afterDoubling 也等于 (2.0, 8.0) ``` -## 自定义中置操作符的优先级和结合性 +### 自定义中置操作符的优先级和结合性 可以为自定义的中置操作符指定优先级和结合性。可以回头看看优先级和结合性中解释的,这两个因素是如何影响复合表达式的求值顺序的。 @@ -467,7 +476,7 @@ let plusMinusVector = firstVector +- secondVector // plusMinusVector 是 Vector2D实例,等于 (4.0, -2.0) ``` -这个操作符把两个向量的x相加, y相减。因为它实际上属于加减运算,所以让它保持了和加减法一样的结合性和优先级(左结合,优先级为140)。查阅完整的Swift默认优先级和结合性的设置,请移步表达式; +这个操作符把两个向量的x相加, y相减。因为它实际上属于加减运算,所以让它保持了和加减法一样的结合性和优先级(左结合,优先级为140)。查阅完整的Swift默认优先级和结合性的设置,请移步[表达式](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-XID_655). From 31c3ae5b21ead1a53cec3144008b618003cd5e58 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Thu, 19 Jun 2014 18:56:03 +0800 Subject: [PATCH 116/261] =?UTF-8?q?=E4=B8=AD=E8=8B=B1=E5=8F=8C=E8=AF=AD?= =?UTF-8?q?=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/12_Subscripts.md | 121 +++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/src/chapter2/12_Subscripts.md b/src/chapter2/12_Subscripts.md index 078d7e0..719a184 100644 --- a/src/chapter2/12_Subscripts.md +++ b/src/chapter2/12_Subscripts.md @@ -1,16 +1,34 @@ +# Subscripts # 下标 (Subscripts) +Classes, structures, and enumerations can define subscripts, which are shortcuts for accessing the member elements of a collection, list, or sequence. You use subscripts to set and retrieve values by index without needing separate methods for setting and retrieval. For example, you access elements in an Array instance as someArray[index] and elements in a Dictionary instance as someDictionary[key]. + 下标可以定义在类(Class)、结构体(structures)和枚举(enumerations)这些目标中,可以认为是访问对象、集合或序列的快捷方式。举例来说,用下标访问一个数组(Array)实例中的元素可以这样写 `someArray[index]` ,访问字典(Dictionary)实例中的元素可以这样写 `someDictionary[key]`,而不需要再调用实例的某个方法来获得元素的值。 +You can define multiple subscripts for a single type, and the appropriate subscript overload to use is selected based on the type of index value you pass to the subscript. Subscripts are not limited to a single dimension, and you can define subscripts with multiple input parameters to suit your custom type’s needs. + 对于同一个目标可以定义多个下标,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。 > 译者:这里下标重载在本小节中原文并没有任何演示 - +## Subscript Syntax ## 下标语法 +Subscripts enable you to query instances of a type by writing one or more values in square brackets after the instance name. Their syntax is similar to both instance method syntax and computed property syntax. You write subscript definitions with the subscript keyword, and specify one or more input parameters and a return type, in the same way as instance methods. Unlike instance methods, subscripts can be read-write or read-only. This behavior is communicated by a getter and setter in the same way as for computed properties: + 下标允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例进行访问和赋值。语法类似于实例方法和实例属性的混合。与定义实例方法类似,定义下标使用`subscript`关键字,显式声明入参(一个或多个)和返回类型。与实例方法不同的是下标可以设定为读写或只读。这种方式又有点像实例属性的getter和setter: +``` +subscript(index: Int) -> Int { + get { + // return an appropriate subscript value here + } + set(newValue) { + // perform a suitable setting action here + } +} +``` + ``` subscript(index: Int) -> Int { get { @@ -23,18 +41,42 @@ subscript(index: Int) -> Int { } ``` +The type of newValue is the same as the return value of the subscript. As with computed properties, you can choose not to specify the setter’s (newValue) parameter. A default parameter called newValue is provided to your setter if you do not provide one yourself. + `newValue`的类型必须和下标定义的返回类型相同。与实例属性相同的是set的入参声明`newValue`就算不写,在set代码块中依然可以使用`newValue`这个变量来访问新赋的值。 +As with read-only computed properties, you can drop the get keyword for read-only subscripts: + 与只读实例属性一样,可以直接将原本应该写在get代码块中的代码写在subscript中即可: +``` +subscript(index: Int) -> Int { + // return an appropriate subscript value here +} +``` + ``` subscript(index: Int) -> Int { // 返回与入参匹配的Int类型的值 } ``` +Here’s an example of a read-only subscript implementation, which defines a TimesTable structure to represent an n-times-table of integers: + 下面代码演示了一个在TimesTable结构体中使用只读下标的用法,该结构体用来展示传入整数的N倍。 +``` +struct TimesTable { + let multiplier: Int + subscript(index: Int) -> Int { + return multiplier * index + } +} +let threeTimesTable = TimesTable(multiplier: 3) +println("six times three is \(threeTimesTable[6])") +// prints "six times three is 18" +``` + ``` struct TimesTable { let multiplier: Int @@ -47,19 +89,31 @@ println("3的6倍是\(threeTimesTable[6])") // 输出 "3的6倍是18" ``` +In this example, a new instance of TimesTable is created to represent the three-times-table. This is indicated by passing a value of 3 to the structure’s initializer as the value to use for the instance’s multiplier parameter. + 在上例中,通过TimesTable结构体创建了一个用来表示索引值三倍的实例。数值3作为结构体构造函数入参表示这个值将成为实例成员multiplier的值。 +You can query the threeTimesTable instance by calling its subscript, as shown in the call to threeTimesTable[6]. This requests the sixth entry in the three-times-table, which returns a value of 18, or 3 times 6. + 你可以通过下标来来得到结果,比如`threeTimesTable[6]`。这句话访问了threeTimesTable的第六个元素,返回18或者6的3倍。 +> NOTE +> +> An n-times-table is based on a fixed mathematical rule. It is not appropriate to set threeTimesTable[someIndex] to a new value, and so the subscript for TimesTable is defined as a read-only subscript. + > 提示 > > TimesTable例子是基于一个固定的数学公式。它并不适合开放写权限来对threeTimesTable[someIndex]进行赋值操作,这也是为什么下标只定义为只读的原因。 - +## Subscript Usage ## 下标用法 +The exact meaning of “subscript” depends on the context in which it is used. Subscripts are typically used as a shortcut for accessing the member elements in a collection, list, or sequence. You are free to implement subscripts in the most appropriate way for your particular class or structure’s functionality. + 下标根据使用场景不同也具有不同的含义。通常下标是用来访问集合(collection),列表(list)或序列(sequence)中元素的快捷方式。你可以为特定的类或结构体中自由的实现下标来提供合适的功能。 +For example, Swift’s Dictionary type implements a subscript to set and retrieve the values stored in a Dictionary instance. You can set a value in a dictionary by providing a key of the dictionary’s key type within subscript braces, and assigning a value of the dictionary’s value type to the subscript: + 例如,Swift的字典(Dictionary)实现了通过下标来对其实例中存放的值进行存取操作。在字典中设值可以通过给字典提供一个符合字典索引类型的索引值的表达式赋一个与字典存放值类型匹配的值来做到: ``` @@ -67,23 +121,68 @@ var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] numberOfLegs["bird"] = 2 ``` +``` +var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] +numberOfLegs["bird"] = 2 +``` + +The example above defines a variable called numberOfLegs and initializes it with a dictionary literal containing three key-value pairs. The type of the numberOfLegs dictionary is inferred to be Dictionary. After creating the dictionary, this example uses subscript assignment to add a String key of "bird" and an Int value of 2 to the dictionary. + 上例定义一个名为numberOfLegs的变量并用一个字典表达式初始化出了包含三对键值的字典实例。numberOfLegs的字典存放值类型推断为`Dictionary`。字典实例创建完成之后通过下标的方式将整型值`2`赋值到字典实例的索引为`bird`的位置中。 +For more information about Dictionary subscripting, see [Accessing and Modifying a Dictionary](#). + 更多关于字典(Dictionary)下标的信息请参考[字典的访问与修改](#) +> NOTE + +> Swift’s Dictionary type implements its key-value subscripting as a subscript that takes and receives an optional type. For the numberOfLegs dictionary above, the key-value subscript takes and returns a value of type Int?, or “optional int”. The Dictionary type uses an optional subscript type to model the fact that not every key will have a value, and to give a way to delete a value for a key by assigning a nil value for that key. + > 提示 > > Swift中Dictionary的下标实现中,在get部分返回值是`Int?`,也就是说不是每个字典的索引都能得到一个整型值,对于没有设过值的索引的访问返回的结果就是`nil`;同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为`nil`即可。 +## Subscript Options ## 下标选项 +Subscripts can take any number of input parameters, and these input parameters can be of any type. Subscripts can also return any type. Subscripts can use variable parameters and variadic parameters, but cannot use in-out parameters or provide default parameter values. + 下标允许任意数量的入参索引,并且每个入参类型也没有限制。下标的返回值也可以是任何类型。下标可以使用变量参数和可变参数,但使用in-out参数或给参数设置默认值都是不允许的。 +A class or structure can provide as many subscript implementations as it needs, and the appropriate subscript to be used will be inferred based on the types of the value or values that are contained within the subscript braces at the point that the subscript is used. This definition of multiple subscripts is known as subscript overloading. + 一个类或结构体可以根据自身需要提供多个下标实现,在定义下标时通过入参个类型进行区分,使用下标时会自动匹配合适的下标实现运行,这就是下标的重载。 +While it is most common for a subscript to take a single parameter, you can also define a subscript with multiple parameters if it is appropriate for your type. The following example defines a Matrix structure, which represents a two-dimensional matrix of Double values. The Matrix structure’s subscript takes two integer parameters: + 一个下标入参是最常见的情况,但只要有合适的场景也可以定义多个下标入参。如下例定义了一个Matrix结构体,将呈现一个Double类型的二维数组。Matrix结构体的下标需要两个整型参数: +``` +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 { + return row >= 0 && row < rows && column >= 0 && column < columns + } + subscript(row: Int, column: Int) -> Double { + get { + assert(indexIsValidForRow(row, column: column), "Index out of range") + return grid[(row * columns) + column] + } + set { + assert(indexIsValidForRow(row, column: column), "Index out of range") + grid[(row * columns) + column] = newValue + } + } +} +``` + ``` struct Matrix { let rows: Int, columns: Int @@ -109,14 +208,24 @@ struct Matrix { } ``` +Matrix provides an initializer that takes two parameters called rows and columns, and creates an array that is large enough to store rows * columns values of type Double. Each position in the matrix is given an initial value of 0.0. To achieve this, the array’s size, and an initial cell value of 0.0, are passed to an array initializer that creates and initializes a new array of the correct size. This initializer is described in more detail in [Creating and Initializing an Array](#). + Matrix提供了一个两个入参的构造方法,入参分别是`rows`和`columns`,创建了一个足够容纳rows * columns个数的Double类型数组。为了存储,将数组的大小和数组每个元素初始值0.0,都传入数组的构造方法中来创建一个正确大小的新数组。关于数组的构造方法和析构方法请参考[Creating and Initializing an Array](#)。 +You can construct a new Matrix instance by passing an appropriate row and column count to its initializer: + 你可以通过传入合适的row和column的数量来构造一个新的Matrix实例: ``` var matrix = Matrix(rows: 2, columns: 2) ``` +``` +var matrix = Matrix(rows: 2, columns: 2) +``` + +The preceding example creates a new Matrix instance with two rows and two columns. The grid array for this Matrix instance is effectively a flattened version of the matrix, as read from top left to bottom right: + 上例中创建了一个新的两行两列的Matrix实例。在阅读顺序从左上到右下的Matrix实例中的数组实例grid是矩阵二维数组的扁平化存储: ``` @@ -128,6 +237,8 @@ row0 [0.0, 0.0, row1 0.0, 0.0] ``` +Values in the matrix can be set by passing row and column values into the subscript, separated by a comma: + 将值赋给带有row和column下标的matrix实例表达式可以完成赋值操作,下标入参使用逗号分割 ``` @@ -135,6 +246,8 @@ matrix[0, 1] = 1.5 matrix[1, 0] = 3.2 ``` +These two statements call the subscript’s setter to set a value of 1.5 in the top right position of the matrix (where row is 0 and column is 1), and 3.2 in the bottom left position (where row is 1 and column is 0): + 上面两句话分别让matrix的右上值为1.5,坐下值为3.2: ``` @@ -142,6 +255,8 @@ matrix[1, 0] = 3.2 3.2, 0.0] ``` +The Matrix subscript’s getter and setter both contain an assertion to check that the subscript’s row and column values are valid. To assist with these assertions, Matrix includes a convenience method called indexIsValid, which checks whether the requested row or column is outside the bounds of the matrix: + Matrix下标的getter和setter中同时调用了下标入参的row和column是否有效的判断。为了方便进行断言,Matrix包含了一个名为indexIsValid的成员方法,用来确认入参的row或column值是否会造成数组越界: ``` @@ -150,6 +265,8 @@ func indexIsValidForRow(row: Int, column: Int) -> Bool { } ``` +An assertion is triggered if you try to access a subscript that is outside of the matrix bounds: + 断言在下标越界时触发: ``` From 5228f095b5bc43ef55c4ff8fa993426554b840ca Mon Sep 17 00:00:00 2001 From: rainoxu Date: Thu, 19 Jun 2014 20:04:04 +0800 Subject: [PATCH 117/261] =?UTF-8?q?=E9=98=B6=E6=AE=B5=E6=80=A7=E9=83=A8?= =?UTF-8?q?=E5=88=86=E5=B7=A5=E4=BD=9C=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../09_Generic_Parameters_and_Arguments.md | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/chapter3/09_Generic_Parameters_and_Arguments.md b/src/chapter3/09_Generic_Parameters_and_Arguments.md index e69de29..f8ce1c8 100644 --- a/src/chapter3/09_Generic_Parameters_and_Arguments.md +++ b/src/chapter3/09_Generic_Parameters_and_Arguments.md @@ -0,0 +1,87 @@ +# Generic Parameters and Arguments +# 泛型参数 + + +This chapter describes parameters and arguments for generic types, functions, and initializers. When you declare a generic type, function, or initializer, you specify the type parameters that the generic type, function, or initializer can work with. These type parameters act as placeholders that are replaced by actual concrete type arguments when an instance of a generic type is created or a generic function or initializer is called. + +本章节介绍泛型类型、函数、初始构造器的参数。当你在声明泛型类型、函数或者初始化构造器时,你指定了它们能够使用的类型参数。这些类型参数起到了占位符的作用,在泛型类型的实例创建或者泛型方法、初始化构造器调用时,它们会被替换为实际的参数。 + +For an overview of generics in Swift, see [Generics](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-XID_234). + +关于Swift泛型的概述,可以详见[泛型](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-XID_234)。 + +## Generic Parameter Clause +## 泛型参数句式 + +A generic parameter clause specifies the type parameters of a generic type or function, along with any associated constraints and requirements on those parameters. A generic parameter clause is enclosed in angle brackets (<>) and has one of the following forms: + +泛型参数句式指定了泛型类型或函数的参数类型,以及与这些参数相关的约束、依赖条件。泛型参数句式的内容用一对尖括号包围,并且是以下形式中的一种: + +``` + + +``` +The generic parameter list is a comma-separated list of generic parameters, each of which has the following form: +泛型参数列表是用逗号分隔的一组参数,其中的每一个都类似以下的形式: + +``` +type parameter: constraint +``` + +A generic parameter consists of a type parameter followed by an optional constraint. A type parameter is simply the name of a placeholder type (for instance, T, U, V, KeyType, ValueType, and so on). You have access to the type parameters (and any of their associated types) in the rest of the type, function, or initializer declaration, including in the signature of the function or initializer. + +泛型参数由类型形参组成,紧跟其后的是是一个可选的约束条件。类型形参只是一个占位符类型的名称(比如:T、U、V、KeyType、ValueType等)。You have access to the type parameters (and any of their associated types) in the rest of the type, function, or initializer declaration, including in the signature of the function or initializer. + +The constraint specifies that a type parameter inherits from a specific class or conforms to a protocol or protocol composition. For instance, in the generic function below, the generic parameter T: Comparable indicates that any type argument substituted for the type parameter T must conform to the Comparable protocol. + +约束条件指定了类型形参是继承自特定的类或者符合某个协议、或协议的组件部分。比如,在下面的泛型函数中,泛型形参T: Comparable表明替换泛型类型形参的任何类型实参都必须符合Comparable协议。 + +``` +func simpleMin(x: T, y: T) -> T { + if x < y { + return y + } + return x +} +``` + +Because Int and Double, for example, both conform to the Comparable protocol, this function accepts arguments of either type. In contrast with generic types, you don’t specify a generic argument clause when you use a generic function or initializer. The type arguments are instead inferred from the type of the arguments passed to the function or initializer. + +比如,Int与Double都符合Comparable协议,所以这个函数接受任意一种实参类型。与泛型类型形参相反的是,当使用泛型方式或者初始构造器时,无需指定泛型实参的句式,实参由传入函数或初始化构造器的实际类型推断得出。 + + +``` +simpleMin(17, 42) // T被推断是Int +simpleMin(3.14159, 2.71828) // T被推断是Double +``` + +## Where Clauses +## Where 句式 + +You can specify additional requirements on type parameters and their associated types by including a where clause after the generic parameter list. A where clause consists of the keyword where, followed by a comma-separated list of one or more requirements. + +通过在泛型形参列表之后引入where句式,在类型形参及相关的类型上定义额外的依赖条件。where句式由where关键字和紧随其后的由逗号分隔的一个或多个依赖条件组成。 + +The requirements in a where clause specify that a type parameter inherits from a class or conforms to a protocol or protocol composition. Although the where clause provides syntactic sugar for expressing simple constraints on type parameters (for instance, T: Comparable is equivalent to T where T: Comparable and so on), you can use it to provide more complex constraints on type parameters and their associated types. For instance, you can express the constraints that a generic type T inherits from a class C and conforms to a protocol P as . + +As mentioned above, you can constrain the associated types of type parameters to conform to protocols. For example, the generic parameter clause specifies that T conforms to the Generator protocol and the associated type of T, T.Element, conforms to the Equatable protocol (T has the associated type Element because Generator declares Element and T conforms to Generator). + +You can also specify the requirement that two types be identical, using the == operator. For example, the generic parameter clause expresses the constraints that T and U conform to the Generator protocol and that their associated types must be identical. + +Any type argument substituted for a type parameter must meet all the constraints and requirements placed on the type parameter. + +You can overload a generic function or initializer by providing different constraints, requirements, or both on the type parameters in the generic parameter clause. When you call an overloaded generic function or initializer, the compiler uses these constraints to resolve which overloaded function or initializer to invoke. + +You can subclass a generic class, but the subclass must also be a generic class. + + + + + + + + + + + + From aa495cf3c6e2e6321981f8c293692ecc59de0f7f Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Thu, 19 Jun 2014 20:05:53 +0800 Subject: [PATCH 118/261] =?UTF-8?q?=E5=85=88=E6=9D=A5=E4=B8=80=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/09_Classes_and_Structures.md | 61 ++++++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index 79cbc1d..467b6fa 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -372,12 +372,69 @@ if tenEighty === alsoTenEighty { Note that “identical to” (represented by three equals signs, or ===) does not mean the same thing as “equal to” (represented by two equals signs, or ==): +提示:三个等号(===)的身份相等与两个等号(==)的值相等操作符是不一样的。 + * “Identical to” means that two constants or variables of class type refer to exactly the same class instance. * “Equal to” means that two instances are considered “equal” or “equivalent” in value, for some appropriate meaning of “equal”, as defined by the type’s designer. + * 身份相等操作符两端的变量或常量比较的是是否从同一个类实例化而来。 + * 值相等操作符比较的则是两端的值或者对象的内存地址是否相等,这更接近我们平常理解的相等比较。 When you define your own custom classes and structures, it is your responsibility to decide what qualifies as two instances being “equal”. The process of defining your own implementations of the “equal to” and “not equal to” operators is described in Equivalence Operators. +每当你定义一个类或者结构体时,你就有义务对两个实例的“相等”标准作出决断。在[比较运算符](#)中会描述如何去对对相等和不等的比较进行实现。 ‌ -Pointers -If you have experience with C, C++, or Objective-C, you may know that these languages use pointers to refer to addresses in memory. A Swift constant or variable that refers to an instance of some reference type is similar to a pointer in C, but is not a direct pointer to an address in memory, and does not require you to write an asterisk (*) to indicate that you are creating a reference. Instead, these references are defined like any other constant or variable in Swift. \ No newline at end of file +### Pointers +### 指针 + +If you have experience with C, C++, or Objective-C, you may know that these languages use pointers to refer to addresses in memory. A Swift constant or variable that refers to an instance of some reference type is similar to a pointer in C, but is not a direct pointer to an address in memory, and does not require you to write an asterisk (*) to indicate that you are creating a reference. Instead, these references are defined like any other constant or variable in Swift. + +如果你之前有过编写C、C++或者Objective-C的经验,你应该会知道这些语言的指针都是对一个内存中的地址做引用的。一个变量或常量在Swift中与C的指针类似引用一个可以被引用的实例,但它不直接指向内存的某一个地址,也不需要在申明引用的变量名前加上星号(*)。在Swift中除此之外,引用的定义与其他语言相同。 + +## Choosing Between Classes and Structures + +You can use both classes and structures to define custom data types to use as the building blocks of your program’s code. + +在定义时你可以在你的代码中同时使用类和结构体来表示合适的数据类型。 + +However, structure instances are always passed by value, and class instances are always passed by reference. This means that they are suited to different kinds of tasks. As you consider the data constructs and functionality that you need for a project, decide whether each data construct should be defined as a class or as a structure. + +他们拥有不同的特性,结构体实例被赋值时始终传递的是值的拷贝,而类实例则始终传递的是引用。将他们根据项目的实际情况去选择定义出合适的数据是代码构建者应该去仔细斟酌的。 + +As a general guideline, consider creating a structure when one or more of these conditions apply: + +通常来说,符合以下一个或多个条件时应该使用结构体去定义数据: + +* The structure’s primary purpose is to encapsulate a few relatively simple data values. +* It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure. +* Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced. +* The structure does not need to inherit properties or behavior from another existing type. + +* 结构体主要目的时用来将少量相关数据进行封装。 +* 当期望实例在赋值时传递的是封装的值的被拷贝而不是仅仅是引用。 +* 当期望数据结构中的只类型也一同拷贝传值而不是传递引用。 +* 这个数据结构不需要去继承别的类。 + +Examples of good candidates for structures include: + + + +The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double. +A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int. +A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double. +In all other cases, define a class, and create instances of that class to be managed and passed by reference. In practice, this means that most custom data constructs should be classes, not structures. + +## Assignment and Copy Behavior for Collection Types + +Swift’s Array and Dictionary types are implemented as structures. However, arrays have slightly different copying behavior from dictionaries and other structures when they are assigned to a constant or variable, and when they are passed to a function or method. + +The behavior described for Array and Dictionary below is different again from the behavior of NSArray and NSDictionary in Foundation, which are implemented as classes, not structures. NSArray and NSDictionary instances are always assigned and passed around as a reference to an existing instance, rather than as a copy. + +> NOTE +> +> The descriptions below refer to the “copying” of arrays, dictionaries, strings, and other values. Where copying is mentioned, the behavior you see in your code will always be as if a copy took place. However, Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so. Swift manages all value copying to ensure optimal performance, and you should not avoid assignment to try to preempt this optimization. + +### Assignment and Copy Behavior for Dictionaries + +### Assignment and Copy Behavior for Arrays + From 0092813e29dfecb78d69da9a4f50b71c8d72c77b Mon Sep 17 00:00:00 2001 From: yozomk Date: Thu, 19 Jun 2014 20:24:10 +0800 Subject: [PATCH 119/261] 43% translated! by mk --- .../16_Automatic_Reference_Counting.md | 124 +++++++++++++++++- 1 file changed, 117 insertions(+), 7 deletions(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index 8283957..3de9ea4 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -117,7 +117,7 @@ reference3 = nil // prints "John Appleseed is being deinitialized" ``` -## 类实例间的强引用循环 +## 类实例间的循环强引用 In the examples above, ARC is able to track the number of references to the new Person instance you create and to deallocate that Person instance when it is no longer needed. @@ -125,7 +125,7 @@ In the examples above, ARC is able to track the number of references to the new However, it is possible to write code in which an instance of a class never gets to a point where it has zero strong references. This can happen if two class instances hold a strong reference to each other, such that each instance keeps the other alive. This is known as a strong reference cycle. -然而,我们可能会写出这样的代码,导致类实例永远不会有0个强引用。这种情况发生在两个类实例互相保持对方的强引用,以致于彼此都无法被销毁的时候。这就是所谓的强引用循环。 +然而,我们可能会写出这样的代码,导致类实例永远不会有0个强引用。这种情况发生在两个类实例互相保持对方的强引用,以致于彼此都无法被销毁的时候。这就是所谓的循环强引用。 You resolve strong reference cycles by defining some of the relationships between classes as weak or unowned references instead of as strong references. This process is described in Resolving Strong Reference Cycles Between Class Instances. However, before you learn how to resolve a strong reference cycle, it is useful to understand how such a cycle is caused. @@ -134,7 +134,7 @@ You resolve strong reference cycles by defining some of the relationships betwee Here’s an example of how a strong reference cycle can be created by accident. This example defines two classes called Person and Apartment, which model a block of apartments and its residents: -这是一个意外导致强引用循环的例子。例子定义了两个名为Person和Apartment的类,用来模拟公寓和公寓里的居民: +这是一个意外导致循环强引用的例子。例子定义了两个名为Person和Apartment的类,用来模拟公寓和公寓里的居民: ``` class Person { @@ -196,13 +196,13 @@ number73!.tenant = john ``` Here’s how the strong references look after you link the two instances together: -这里展示了两个实例连接在一直之后的强引用关系: +这里展示了两个实例连接在一起之后的强引用关系: ![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/referenceCycle02_2x.png) Unfortunately, linking these two instances creates a strong reference cycle between them. The Person instance now has a strong reference to the Apartment instance, and the Apartment instance has a strong reference to the Person instance. Therefore, when you break the strong references held by the john and number73 variables, the reference counts do not drop to zero, and the instances are not deallocated by ARC: -不幸的是,连接两个实例后导致它们之间形成了强引用循环。现在Person实例有一个指向Apartment的强引用,同时Apartment实例也有一个指向Person的强引用。因此,当你断开由变量john和number73保持的强引用时,引用计数不会减为0,因此实例也不会被ARC销毁。 +不幸的是,连接两个实例后导致它们之间形成了循环强引用。现在Person实例有一个指向Apartment的强引用,同时Apartment实例也有一个指向Person的强引用。因此,当你断开由变量john和number73保持的强引用时,引用计数不会减为0,因此实例也不会被ARC销毁。 ``` john = nil @@ -211,7 +211,7 @@ number73 = nil Note that neither deinitializer was called when you set these two variables to nil. The strong reference cycle prevents the Person and Apartment instances from ever being deallocated, causing a memory leak in your app. -需要注意的是,尽管在你将john和number73设为nil时析构函数也会被调用,但是强引用循环阻止了Person 和 Apartment类实例的销毁,在你的App中导致了内存泄漏。 +需要注意的是,你将john和number73设为nil时两个析构函数都没有被调用。循环强引用阻止了Person 和 Apartment类实例的销毁,在你的App中导致了内存泄漏。 Here’s how the strong references look after you set the john and number73 variables to nil: @@ -221,4 +221,114 @@ Here’s how the strong references look after you set the john and number73 vari The strong references between the Person instance and the Apartment instance remain and cannot be broken. -Person类实例与Apartment类实例之间的强引用关系将保持且无法被断开。 \ No newline at end of file +Person类实例与Apartment类实例之间的强引用关系将保持且无法被断开。 + +## 解决类实例间的循环强引用 + +Swift provides two ways to resolve strong reference cycles when you work with properties of class type: weak references and unowned references. + +Swift提供了两种方式来解决你在处理类属性时遇到的循环强引用问题:弱引用和无主引用。 + +Weak and unowned references enable one instance in a reference cycle to refer to the other instance without keeping a strong hold on it. The instances can then refer to each other without creating a strong reference cycle. + +弱引用和无主引用允许循环引用中的一个实例引用另外一个实例而不保持强引用。这样实例能够互相引用而不产生循环强引用。 + +Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialization. + +对于生命周期中会变为nil的实例使用弱引用。相反的,对于初始化赋值后再也不会被赋值为nil的实例,使用无主引用。 + +### 弱引用 + +A weak reference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance. This behavior prevents the reference from becoming part of a strong reference cycle. You indicate a weak reference by placing the weak keyword before a property or variable declaration. + +弱引用不会强制保持引用的实例,并且不会阻止 ARC 销毁被引用的实例。这阻止了引用成为循环强引用的组成部分。声明属性或者变量时,在前面加上weak关键字表明这是一个弱引用。 + +Use a weak reference to avoid reference cycles whenever it is possible for that reference to have “no value” at some point in its life. If the reference will always have a value, use an unowned reference instead, as described in Unowned References. In the Apartment example above, it is appropriate for an apartment to be able to have “no tenant” at some point in its lifetime, and so a weak reference is an appropriate way to break the reference cycle in this case. + +在引用对象的生命周期中,如果某些时候引用对象可能无值,就使用弱引用阻止产生循环强引用。如果引用对象总是有值,则应使用无主引用,这将在无主引用部分详述。在上面Apartment的例子中,一个公寓的生命周期中,有时是没有“租客”的,这种情况下适合使用弱引用来打破引用循环。 + +> NOTE +> +> Weak references must be declared as variables, to indicate that their value can change at runtime. A weak reference cannot be declared as a constant. +> 注意 +> 弱引用必须声明为变量,以表明它们的值在运行时是可以改变的。弱引用不能声明为常量。 + +Because weak references are allowed to have “no value”, you must declare every weak reference as having an optional type. Optional types are the preferred way to represent the possibility for “no value” in Swift. + +由于弱引用类型允许没有值,因此你必须声明所有弱引用变量为可选类型。在Swift里,可选类型是表示可能没有值的变量的首选方式。 + +Because a weak reference does not keep a strong hold on the instance it refers to, it is possible for that instance to be deallocated while the weak reference is still referring to it. Therefore, ARC automatically sets a weak reference to nil when the instance that it refers to is deallocated. You can check for the existence of a value in the weak reference, just like any other optional value, and you will never end up with a reference to an invalid instance that no longer exists. + +由于弱引用与其指向的实例之间不会保持强引用关系,因此即使有弱引用指向实例,实例也有可能被销毁。弱引用指向的实例被销毁后,ARC会将该弱引用指向nil。像其他可选类型变量一样,你可以检查弱引用类型的变量是否存在值来避免引用一个不存在的实例。 + +The example below is identical to the Person and Apartment example from above, with one important difference. This time around, the Apartment type’s tenant property is declared as a weak reference: + +下面的例子与上文提到的Person 和 Apartment 的例子类似,但有一处重要的不同。这次,Apartment的属性tenant被声明为弱引用类型: + +``` +class Person { + let name: String + init(name: String) { self.name = name } + var apartment: Apartment? + deinit { println("\(name) is being deinitialized") } +} + +class Apartment { + let number: Int + init(number: Int) { self.number = number } + weak var tenant: Person? + deinit { println("Apartment #\(number) is being deinitialized") } +} +``` +The strong references from the two variables (john and number73) and the links between the two instances are created as before: + +两个变量(john和number73)的强引用以及两个实例之间的连接都与之前一样被创建: + +``` +var john: Person? +var number73: Apartment? + +john = Person(name: "John Appleseed") +number73 = Apartment(number: 73) + +john!.apartment = number73 +number73!.tenant = john +``` + +Here’s how the references look now that you’ve linked the two instances together: +下图展示了现在的引用关系: + +![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/weakReference01_2x.png) + +The Person instance still has a strong reference to the Apartment instance, but the Apartment instance now has a weak reference to the Person instance. This means that when you break the strong reference held by the john variables, there are no more strong references to the Person instance: + +Person实例依然保持对Apartment实例的强引用,但是Apartment实例只有对Person实例的弱引用。这意味着当你断开john变量所保持的强引用时,就没有指向Person实例的强引用了: + +![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/weakReference02_2x.png) + +Because there are no more strong references to the Person instance, it is deallocated: +由于没有指向Person实例的强引用了,所以它被销毁了: + +``` +john = nil +// prints "John Appleseed is being deinitialized" +``` +The only remaining strong reference to the Apartment instance is from the number73 variable. If you break that strong reference, there are no more strong references to the Apartment instance: + +仅存的指向Apartment实例的强引用来自变量number73。如果你断开这个强引用,也就没有强引用指向Apartment的实例了: + +![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/weakReference03_2x.png) + +Because there are no more strong references to the Apartment instance, it too is deallocated: +由于也没有指向Apartment类实例的强引用了,它也被销毁了: + +``` +number73 = nil +// prints "Apartment #73 is being deinitialized" +``` + +The final two code snippets above show that the deinitializers for the Person instance and Apartment instance print their “deinitialized” messages after the john and number73 variables are set to nil. This proves that the reference cycle has been broken. + +上面的两段代码展示了变量john和number73在被赋值为nil后,Person实例和Apartment实例的析构函数都打印出“销毁”的信息。这证明了引用循环被打破了。 + +## \ No newline at end of file From 085c0b6c092cbbcffdeb1da407fa172219d7f289 Mon Sep 17 00:00:00 2001 From: rainoxu Date: Thu, 19 Jun 2014 20:59:10 +0800 Subject: [PATCH 120/261] =?UTF-8?q?=E9=98=B6=E6=AE=B5=E6=80=A7=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../09_Generic_Parameters_and_Arguments.md | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/chapter3/09_Generic_Parameters_and_Arguments.md b/src/chapter3/09_Generic_Parameters_and_Arguments.md index f8ce1c8..ce52195 100644 --- a/src/chapter3/09_Generic_Parameters_and_Arguments.md +++ b/src/chapter3/09_Generic_Parameters_and_Arguments.md @@ -11,7 +11,7 @@ For an overview of generics in Swift, see [Generics](https://developer.apple.com 关于Swift泛型的概述,可以详见[泛型](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-XID_234)。 ## Generic Parameter Clause -## 泛型参数句式 +## 泛型形参句式 A generic parameter clause specifies the type parameters of a generic type or function, along with any associated constraints and requirements on those parameters. A generic parameter clause is enclosed in angle brackets (<>) and has one of the following forms: @@ -34,7 +34,7 @@ A generic parameter consists of a type parameter followed by an optional constra The constraint specifies that a type parameter inherits from a specific class or conforms to a protocol or protocol composition. For instance, in the generic function below, the generic parameter T: Comparable indicates that any type argument substituted for the type parameter T must conform to the Comparable protocol. -约束条件指定了类型形参是继承自特定的类或者符合某个协议、或协议的组件部分。比如,在下面的泛型函数中,泛型形参T: Comparable表明替换泛型类型形参的任何类型实参都必须符合Comparable协议。 +约束条件指定了类型形参是继承自特定的类、符合某个协议或者协议的组件部分。比如,在下面的泛型函数中,泛型形参T: Comparable表明替换泛型类型形参的任何类型实参都必须符合Comparable协议。 ``` func simpleMin(x: T, y: T) -> T { @@ -64,19 +64,59 @@ You can specify additional requirements on type parameters and their associated The requirements in a where clause specify that a type parameter inherits from a class or conforms to a protocol or protocol composition. Although the where clause provides syntactic sugar for expressing simple constraints on type parameters (for instance, T: Comparable is equivalent to T where T: Comparable and so on), you can use it to provide more complex constraints on type parameters and their associated types. For instance, you can express the constraints that a generic type T inherits from a class C and conforms to a protocol P as . +where句式的依赖条件指定了类型形参是继承自特定的类、符合某个协议或者协议的组成部分。尽管where句式提供了语法糖来简化表达类型形参的约束条件(比如,T: Comparable等同于T where T: Comparable等),但仍可以在类型形参和相关类型上提供复杂的约束条件。比如:泛型类型T继承自类C且符合协议P可以表达为``````。 + As mentioned above, you can constrain the associated types of type parameters to conform to protocols. For example, the generic parameter clause specifies that T conforms to the Generator protocol and the associated type of T, T.Element, conforms to the Equatable protocol (T has the associated type Element because Generator declares Element and T conforms to Generator). +如上所述,可以约束类型形参的相关类形符合特定的协议。比如:泛型参数句式``````指定了T符合Generator协议,且T的Element类型符合Equatable协议(T有关联系的Element类型是因为Generator协议声明了Element,而T符合Generator协议)。 + You can also specify the requirement that two types be identical, using the == operator. For example, the generic parameter clause expresses the constraints that T and U conform to the Generator protocol and that their associated types must be identical. +你也可以用```==```运符符指定两种类型完全相等的依赖条件。比如,泛型形参句式``````表明T和U符合Generator协议,并且他们关联的类型必须完全相等的约束条件。 Any type argument substituted for a type parameter must meet all the constraints and requirements placed on the type parameter. +所有实参在替换类型形参时必须实现所有的约束和依赖条件。 You can overload a generic function or initializer by providing different constraints, requirements, or both on the type parameters in the generic parameter clause. When you call an overloaded generic function or initializer, the compiler uses these constraints to resolve which overloaded function or initializer to invoke. +通过在泛型参数句式中为类型形参定义不同的约束条件、依赖条件来实现泛型函数、初始化构造器的重载。当调用重载的泛型函数或初始化构造器时,编译器会使用这些约束条件来实现它们的调用。 You can subclass a generic class, but the subclass must also be a generic class. +泛型类可以子类化,但子类也必须是一个泛型类。 + +> **GRAMMAR OF A GENERIC PARAMETER CLAUSE** + +> generic-parameter-clause → <­generic-parameter-list­requirement-clause­opt­>­ +> generic-parameter-list → generic-parameter­ generic-parameter­,­generic-parameter-list­ +> generic-parameter → type-name­ +> generic-parameter → type-name­:­type-identifier­ +> generic-parameter → type-name­:­protocol-composition-type­ +> requirement-clause → where­requirement-list­ +> requirement-list → requirement­ requirement­,­requirement-list­ +> requirement → conformance-requirement­ same-type-requirement­ +> conformance-requirement → type-identifier­:­type-identifier­ +> conformance-requirement → type-identifier­:­protocol-composition-type­ +> same-type-requirement → type-identifier­==­type-identifier­ +## Generic Argument Clause +## 泛型实参句式 +A generic argument clause specifies the type arguments of a generic type. A generic argument clause is enclosed in angle brackets (<>) and has the following form: +泛型实参句式指定了泛型类型的类型实参。它由一对尖括号包围,形式如下: + +``` + +``` + +The generic argument list is a comma-separated list of type arguments. A type argument is the name of an actual concrete type that replaces a corresponding type parameter in the generic parameter clause of a generic type. The result is a specialized version of that generic type. As an example, the Swift standard library defines a generic dictionary type as: + +泛型实参列表是由一组逗号分隔组成的类型实参 + +``` +struct Dictionary: Collection, DictionaryLiteralConvertible { + /* ... */ +} +``` From 7e1c86406da4047161bbc15d8a7874ace45d51ec Mon Sep 17 00:00:00 2001 From: yozomk Date: Thu, 19 Jun 2014 21:27:29 +0800 Subject: [PATCH 121/261] 45% 12 pages were translated! by mk --- .../16_Automatic_Reference_Counting.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index 3de9ea4..b905540 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -331,4 +331,21 @@ The final two code snippets above show that the deinitializers for the Person in 上面的两段代码展示了变量john和number73在被赋值为nil后,Person实例和Apartment实例的析构函数都打印出“销毁”的信息。这证明了引用循环被打破了。 -## \ No newline at end of file +### 无主引用 + +Like weak references, an unowned reference does not keep a strong hold on the instance it refers to. Unlike a weak reference, however, an unowned reference is assumed to always have a value. Because of this, an unowned reference is always defined as a non-optional type. You indicate an unowned reference by placing the unowned keyword before a property or variable declaration. + +与弱引用类似,无主引用也不会与其指向的类实例间保持强引用关系。不同的是,无主引用假定一直都是有值的。因此,无主引用总是被定义为非可选类型。你可以在属性和变量之前加上unowned关键词来声明这是无主引用。 + +Because an unowned reference is non-optional, you don’t need to unwrap the unowned reference each time it is used. An unowned reference can always be accessed directly. However, ARC cannot set the reference to nil when the instance it refers to is deallocated, because variables of a non-optional type cannot be set to nil. + +由于无主引用是非可选类型的,你不必在使用的时候展开它,它可以被直接访问。与弱引用不同,当无主引用指向的实例被销毁后,ARC不会将其指向nil。 + +> NOTE +> +> If you try to access an unowned reference after the instance that it references is deallocated, you will trigger a runtime error. Use unowned references only when you are sure that the reference will always refer to an instance. +> +> Note also that Swift guarantees your app will crash if you try to access an unowned reference after the instance it references is deallocated. You will never encounter unexpected behavior in this situation. Your app will always crash reliably, although you should, of course, prevent it from doing so. +> 注意 +> 在无主引用指向的实例被销毁后,如果依然试图访问该无主引用,你会触发运行时错误。使用无主引用,需要你你能够确保引用指向的实例未被销毁。 +> 需要格外注意的是,在无主引用指向的实例被销毁后,你依然试图访问该无主引用,Swift保证,你的app会毫无意外地直接崩溃,这确实会发生。不是应该而是你必须阻止这样的情况发生。 \ No newline at end of file From f0f20e00a713905ec3451f23b202b12d885566d0 Mon Sep 17 00:00:00 2001 From: yozomk Date: Thu, 19 Jun 2014 21:55:44 +0800 Subject: [PATCH 122/261] 45% 12 pages were translated! fix mistakes --- .../16_Automatic_Reference_Counting.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index b905540..f1b1e76 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -27,7 +27,7 @@ However, if ARC were to deallocate an instance that was still in use, it would n To make sure that instances don’t disappear while they are still needed, ARC tracks how many properties, constants, and variables are currently referring to each class instance. ARC will not deallocate an instance as long as at least one active reference to that instance still exists. -然而,如果ARC释放了一个正在使用的类实例的内存,那会导致该实例的方法和属性都不能访问。而且,如果你试图访问已被ARC释放的实例,你的APP很可能会崩溃。 +然而,如果ARC释放了一个正在使用的类实例的内存,那会导致该实例的方法和属性都不能访问。而且,如果你试图访问已被ARC释放的实例,你的APP多半会崩溃。 为了确保使用中的类实例不会无端消失(被ARC回收),ARC会跟踪和统计每个类实例被多少属性,常量,变量所引用。即使只有一个活动引用存在,该类实例也不会被ARC回收。 @@ -129,12 +129,12 @@ However, it is possible to write code in which an instance of a class never gets You resolve strong reference cycles by defining some of the relationships between classes as weak or unowned references instead of as strong references. This process is described in Resolving Strong Reference Cycles Between Class Instances. However, before you learn how to resolve a strong reference cycle, it is useful to understand how such a cycle is caused. -你可以通过定义类之间的关系为弱引用或者无主引用的方式来解决循环强引用的问题。具体的过程在解决类实例之间的循环强引用中有描述。不管怎样,在你学习怎样解决循环强引用之前,很有必要了解一下它是如何产生的。 +你可以通过定义类之间的关系为弱引用或者无主引用的方式来解决循环强引用的问题。具体过程将在“解决类实例之间的循环强引用”中详述。不管怎样,在学习怎样解决循环强引用之前,很有必要了解一下它是如何产生的。 Here’s an example of how a strong reference cycle can be created by accident. This example defines two classes called Person and Apartment, which model a block of apartments and its residents: -这是一个意外导致循环强引用的例子。例子定义了两个名为Person和Apartment的类,用来模拟公寓和公寓里的居民: +这是一个意外导致循环强引用的例子。例子定义了名为Person和Apartment的两个类,用来模拟公寓和公寓里的居民: ``` class Person { @@ -188,7 +188,7 @@ Here’s how the strong references look after creating and assigning these two i You can now link the two instances together so that the person has an apartment, and the apartment has a tenant. Note that an exclamation mark (!) is used to unwrap and access the instances stored inside the john and number73 optional variables, so that the properties of those instances can be set: -现在将两个实例连接在一起,让人住进一间公寓,公寓也有了一个租客。注意那个感叹号(!),它用于打开和访问存储于john和number73实例中的可选变量,这样实例的属性才能够被设置: +现在将两个实例连接在一起,让john住进number73公寓,number73公寓也有了一个租客john。注意那个感叹号(!),它用于打开和访问存储于john和number73实例中的可选变量,这样实例的属性才能够被设置: ``` john!.apartment = number73 @@ -196,6 +196,7 @@ number73!.tenant = john ``` Here’s how the strong references look after you link the two instances together: + 这里展示了两个实例连接在一起之后的强引用关系: ![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/referenceCycle02_2x.png) @@ -211,7 +212,7 @@ number73 = nil Note that neither deinitializer was called when you set these two variables to nil. The strong reference cycle prevents the Person and Apartment instances from ever being deallocated, causing a memory leak in your app. -需要注意的是,你将john和number73设为nil时两个析构函数都没有被调用。循环强引用阻止了Person 和 Apartment类实例的销毁,在你的App中导致了内存泄漏。 +需要注意的是,你将john和number73设为nil时两个析构函数都没有被调用。循环强引用阻止了Person 和 Apartment类实例的销毁,这在你的App中导致了内存泄漏。 Here’s how the strong references look after you set the john and number73 variables to nil: @@ -241,17 +242,17 @@ Use a weak reference whenever it is valid for that reference to become nil at so A weak reference is a reference that does not keep a strong hold on the instance it refers to, and so does not stop ARC from disposing of the referenced instance. This behavior prevents the reference from becoming part of a strong reference cycle. You indicate a weak reference by placing the weak keyword before a property or variable declaration. -弱引用不会强制保持引用的实例,并且不会阻止 ARC 销毁被引用的实例。这阻止了引用成为循环强引用的组成部分。声明属性或者变量时,在前面加上weak关键字表明这是一个弱引用。 +弱引用不会强制保持引用的实例,并且不会阻止 ARC 销毁被引用的实例。这避免了引用成为循环强引用的组成部分。声明属性或者变量时,在前面加上weak关键字表明这是一个弱引用。 Use a weak reference to avoid reference cycles whenever it is possible for that reference to have “no value” at some point in its life. If the reference will always have a value, use an unowned reference instead, as described in Unowned References. In the Apartment example above, it is appropriate for an apartment to be able to have “no tenant” at some point in its lifetime, and so a weak reference is an appropriate way to break the reference cycle in this case. -在引用对象的生命周期中,如果某些时候引用对象可能无值,就使用弱引用阻止产生循环强引用。如果引用对象总是有值,则应使用无主引用,这将在无主引用部分详述。在上面Apartment的例子中,一个公寓的生命周期中,有时是没有“租客”的,这种情况下适合使用弱引用来打破引用循环。 +在引用的生命周期中,如果某些时候引用可能无值,就使用弱引用避免产生循环强引用。如果引用总是有值,则应使用无主引用,这将在无主引用部分详述。在上面Apartment的例子中,一个公寓的生命周期中,有时是没有“租客”的,这种情况下适合使用弱引用来打破引用循环。 > NOTE > > Weak references must be declared as variables, to indicate that their value can change at runtime. A weak reference cannot be declared as a constant. > 注意 -> 弱引用必须声明为变量,以表明它们的值在运行时是可以改变的。弱引用不能声明为常量。 +> 弱引用必须声明为变量而不能声明为常量,以表明它们的值在运行时是可以改变的。 Because weak references are allowed to have “no value”, you must declare every weak reference as having an optional type. Optional types are the preferred way to represent the possibility for “no value” in Swift. @@ -348,4 +349,4 @@ Because an unowned reference is non-optional, you don’t need to unwrap the uno > Note also that Swift guarantees your app will crash if you try to access an unowned reference after the instance it references is deallocated. You will never encounter unexpected behavior in this situation. Your app will always crash reliably, although you should, of course, prevent it from doing so. > 注意 > 在无主引用指向的实例被销毁后,如果依然试图访问该无主引用,你会触发运行时错误。使用无主引用,需要你你能够确保引用指向的实例未被销毁。 -> 需要格外注意的是,在无主引用指向的实例被销毁后,你依然试图访问该无主引用,Swift保证,你的app会毫无意外地直接崩溃,这确实会发生。不是应该而是你必须阻止这样的情况发生。 \ No newline at end of file +> 需要格外注意的是,在无主引用指向的实例被销毁后,若你依然试图访问该无主引用,Swift保证,你的app会毫无意外地直接崩溃。不是应该而是你必须避免这样的情况发生。 \ No newline at end of file From 6410e6949605addef24f9588261ad587b9574ad6 Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Thu, 19 Jun 2014 22:18:48 +0800 Subject: [PATCH 123/261] update 01_the_basics - Floating-Point Numbers --- src/chapter2/01_The_Basics.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index cc08cb4..91c742c 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -320,19 +320,35 @@ On a 64-bit platform, UInt is the same size as UInt64. > 只在你需要特别指定无符号整数与当前平台原生长度范围相同时才使用`UInt`,否则,推荐使用`Int`,即使是你知道不会存储负值的时候。使用一致的`Int`整数类型有助于代码的服用,避免了不同数字类型之间的转换,并且匹配整数的类型推断,详见[类型安全和类型推断](link)。 -Floating-Point Numbers +# Floating-Point Numbers +# 浮点型数字 Floating-point numbers are numbers with a fractional component, such as 3.14159, 0.1, and -273.15. +浮点型数字是指有小数部分的数字,比如3.14159, 0.1 和 -273.15。 + Floating-point types can represent a much wider range of values than integer types, and can store numbers that are much larger or smaller than can be stored in an Int. Swift provides two signed floating-point number types: +浮点类型比整数类型范围大很多,它可以储存比整数更大或者更小的数。Swift提供了两种有符号的浮点数类型: + Double represents a 64-bit floating-point number. Use it when floating-point values must be very large or particularly precise. + +`Double`代表64位浮点数。当你需要特别大和特别精确的值的时候使用`Double`类型。 + Float represents a 32-bit floating-point number. Use it when floating-point values do not require 64-bit precision. -NOTE -Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. +`Float`代表32位浮点数。当不需要像64位那么精确的时候使用`Float`就够了。 + +> NOTE + +> Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. + +> 注意 + +> `Double`有至少15位数字的精确度,而`Float`的精确度最少只有6位数字。根据业务需要的值的范围去选择合适的浮点类型。 -Type Safety and Type Inference +# Type Safety and Type Inference +# 类型安全和类型推断 Swift is a type safe language. A type safe language encourages you to be clear about the types of values your code can work with. If part of your code expects a String, you can’t pass it an Int by mistake. From bf29b9849714f444af424a2fdb432d770b83fd82 Mon Sep 17 00:00:00 2001 From: Lucars Date: Thu, 19 Jun 2014 22:56:23 +0800 Subject: [PATCH 124/261] Translation Completed --- src/chapter2/14_Initialization.md | 895 ++++++++++++++++++++++++++++++ 1 file changed, 895 insertions(+) diff --git a/src/chapter2/14_Initialization.md b/src/chapter2/14_Initialization.md index e69de29..d278db2 100644 --- a/src/chapter2/14_Initialization.md +++ b/src/chapter2/14_Initialization.md @@ -0,0 +1,895 @@ +## 问题 + +* `initializer` 的定义?『构造方法』 +* `deinitializer` 的定义?『析构方法』 +* `Stored Properties` 的定义?『属性值』 +* `observers` 的定义?『观察者方法』 +* `external name` 的定义?『外部名称』 +* `local name` 的定义?『内部名称』 +* `constant properties` 的定义?『恒定属性』 +* `Optional Property Types` 的定义?『可选属性类型』 +* `Memberwise` 的定义?『成员式』 +* `Initializer Delegation` 的定义?『构造代理』 +* `designated initializers` 的定义?『指定构造方法』 +* `convenience initializers` 的定义?『便利构造方法』 +* `delegates up` 的定义?『向上委托』 +* `nonetheless` 的定义?『仍然』 + +## 构造过程 (Initialization) + +_构造过程_是准备实例化类、结构或枚举的过程。该过程需要为当前实例化对象的每个属性值设置初始值,并且在其准备好之前执行所需的设置或初始化。 + +> “Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that is required before the new instance is ready to for use.” + +你通过定义_构造方法_来实现构造过程,就好比能够创建特定类型的新实例化对象的特殊方法。与 Objective-C 不同的是,Swift 的构造方法没有返回值。其主要作用是保证一个类的新实例在其首次使用之前能够被正确地初始化。 + +> “You implement this initialization process by defining initializers, which are like special methods that can be called to create a new instance of a particular type. Unlike Objective-C initializers, Swift initializers do not return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they are used for the first time.” + +你也可以为类的实例实现一个_析构方法_,这可以让该实例在被释放前执行任意自定义的清理工作。需要了解更多关于析构方法的信息,请见『析构过程』章节。 + +> “Instances of class types can also implement a deinitializer, which performs any custom cleanup just before an instance of that class is deallocated. For more information about deinitializers, see Deinitialization.” + +### 初始化属性值 (Setting Initial Values for Stored Properties) + +类和结构都_必须_在该类(或结构)的实例被创建时为其属性值设定合适的初始值。属性值不能是一个不确定的状态。 + +> “Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties cannot be left in an indeterminate state.” + +你可以在构造方法中为属性值设定初始值,或者在属性值的定义中指定一个默认值。我们会在接下来的章节中描述这些操作。 + +> “You can set an initial value for a stored property within an initializer, or by assigning a default property value as part of the property’s definition. These actions are described in the following sections.” + +提示: + +> 无论是你为属性值指定默认值,还是通过构造方法设定初始值,该属性值的真实值被直接设定,而不会调用属性值观察者方法。 +> > “When you assign a default value to a stored property, or set its initial value within an initializer, the value of that property is set directly, without calling any property observers.” + +### 构造方法 (Initializers) + +_构造方法_用来创建类的新实例对象。其最简单的形式就是使用 `init` 关键字,类似一个没有参数的实例方法。 + +> “Initializers are called to create a new instance of a particular type. In its simplest form, an initializer is like an instance method with no parameters, written using the init keyword.” + +在接下来的例子中定义了一个叫 `Fahrenheit` 的结构来存储用华氏表示的温度。`Fahrenheit` 结构拥有一个类型为 `Double` 的属性值 `temperature`: + +> “The example below defines a new structure called Fahrenheit to store temperatures expressed in the Fahrenheit scale. The Fahrenheit structure has one stored property, temperature, which is of type Double:” + +``` +struct Fahrenheit { + var temperature: Double + init() { + temperature = 32.0 + } +} +var f = Fahrenheit() +println("The default temperature is \(f.temperature)° Fahrenheit") +// prints "The default temperature is 32.0° Fahrenheit +``` + +该结构只定义了一个不带任何参数的构造方法 `init`,该构造方法为属性值 `temperature` 设定了初始值 `32.0`(在华氏温度中表示水的冰点温度)。 + +> “The structure defines a single initializer, init, with no parameters, which initializes the stored temperature with a value of 32.0 (the freezing point of water when expressed in the Fahrenheit scale).” + +### 默认属性值 (Default Property Values) + +如上所示,你可以在一个构造方法中设定属性值的初始值。另外,你也可以在属性值声明时为其指定_默认值_。 + +> “You can set the initial value of a stored property from within an initializer, as shown above. Alternatively, specify a default property value as part of the property’s declaration. You specify a default property value by assigning an initial value to the property when it is defined.” + +提示: + +> 如果一个属性值总是拥有相同的初始值,请为其提供默认值,而不是在构造方法中设定初始值。虽然结果是一样的,*但默认值将属性值声明和初始化更紧密地绑在一起。这样不仅更简短,也更清晰,能够让你通过默认值来判断该属性值的数据类型。默认值也能让你更容易理解默认构造方法与构造方法继承,我们会在接下来的章节中描述它们。 +> > “If a property always takes the same initial value, provide a default value rather than setting a value within an initializer. The end result is the same, but the default value ties the property’s initialization more closely to its declaration. It makes for shorter, clearer initializers and enables you to infer the type of the property from its default value. The default value also makes it easier for you to take advantage of default initializers and initializer inheritance, as described later in this chapter.” + +你可以将上面的 `Fahrenheit` 结构简单写成在属性 `temperature` 被申明时提供一个默认值: + +>“You can write the Fahrenheit structure from above in a simpler form by providing a default value for its temperature property at the point that the property is declared:” + +``` +struct Fahrenheit { + var temperature = 32.0 +} +``` + +### 自定义构造过程 (Customizing Initialization) + +你可以自定义构造过程中的输入参数和可选属性类型,也可以在构造过程中修改常量,我们会在接下来的章节中描述它们。 + +> “You can customize the initialization process with input parameters and optional property types, or by modifying constant properties during initialization, as described in the following sections.” + +#### 初始化参数 (Initialization Parameters) + +要自定义构造过程,你可以在构造方法的定义中提供_初始化参数_,并定义其类型和名字。初始化参数的作用和语法与函数和方法的参数相同。 + +> “You can provide initialization parameters as part of an initializer’s definition, to define the types and names of values that customize the initialization process. Initialization parameters have the same capabilities and syntax as function and method parameters.” + +在接下来的例子中定义了一个 `Celsius` 的结构来存储用摄氏表示的温度。`Celsius` 结构实现了两个自定义的构造方法,分别是 `init(fromFahrenheit:)` 和 `init(fromKelvin:)`,能够通过不同的温标值分别初始化该结构的实例。 + +> “The following example defines a structure called Celsius, which stores temperatures expressed in the Celsius scale. The Celsius structure implements two custom initializers called init(fromFahrenheit:) and init(fromKelvin:), which initialize a new instance of the structure with a value from a different temperature scale:” + +``` +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 is 100.0 +let freezingPointOfWater = Celsius(fromKelvin: 273.15) +// freezingPointOfWater.temperatureInCelsius is 0.0 +``` + +第一个构造方法拥有一个外部名称为 `fromFahrenheit` 内部名称为 `fahrenheit` 的初始化参数。第二个构造方法拥有一个外部名称为 `fromKelvin` 内部名称为 `kelvin` 的初始化参数。这两个构造方法都将各自的参数转换为摄氏温标值,并保存在属性值 `temperatureInCelsius` 中。 + +> “The first initializer has a single initialization parameter with an external name of fromFahrenheit and a local name of fahrenheit. The second initializer has a single initialization parameter with an external name of fromKelvin and a local name of kelvin. Both initializers convert their single argument into a value in the Celsius scale and store this value in a property called temperatureInCelsius.” + +##### 参数的外部名称和内部名称 (Local and External Parameter Names) + +如同函数和方法的参数一样,初始化参数能同时拥有在构造方法体内使用的内部名称,和构造方法被调用时的外部名称。 + +> “As with function and method parameters, initialization parameters can have both a local name for use within the initializer’s body and an external name for use when calling the initializer.” + +可是,构造方法不像函数和方法那样在其括号前有确定的方法名。因此,初始化参数的类型和名字在明确哪个构造方法被调用时起到了特别重要的作用。正因如此,如果你没有提供外部名称,Swift 会自动为构造方法中的_每个_参数提供外部名称。自动生成的外部名称与内部名称相同,就如你在每个初始化参数前写了 # 符号。 + +> “However, initializers do not have an identifying function name before their parentheses in the way that functions and methods do. Therefore, the names and types of an initializer’s parameters play a particularly important role in identifying which initializer should be called. Because of this, Swift provides an automatic external name for every parameter in an initializer if you don’t provide an external name yourself. This automatic external name is the same as the local name, as if you had written a hash symbol before every initialization parameter.” + +提示: + +> 如果你不想在构造方法的参数中提供外部名称,请将下划线(_)作为申明为该参数的外部名称以复写上面描述中的默认行为。 +> > “If you do not want to provide an external name for a parameter in an initializer, provide an underscore (_) as an explicit external name for that parameter to override the default behavior described above.” + +在接下来的例子中定义了一个 `Color` 的结构,其拥有三个恒定属性 `red`,`green` 和 `blue`。这些属性值在 `0.0` 到 `1.0` 之间,分别用来表示颜色值中的红、绿、蓝数值。 + +> “The following example defines a structure called Color, with three constant properties called red, green, and blue. These properties store a value between 0.0 and 1.0 to indicate the amount of red, green, and blue in the color.” + +`Color` 定义了一个拥有三个 `Double` 类型且参数名合适的构造方法: + +> “Color provides an initializer with three appropriately named parameters of type 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 + } +} +``` + +当你创建 `Color` 实例时,你通过这三种颜色名作为外部名称调用该构造方法: + +> “Whenever you create a new Color instance, you call its initializer using external names for each of the three color components:” + +``` +let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) +``` + +请注意,想不使用外部名称直接调用该构造方法是不可能的。外部名称一旦被定义,在调用时必须使用它,否则会产生编译错误: + +> “Note that it is not possible to call this initializer without using the external names. External names must always be used in an intializer if they are defined, and omitting them is a compile-time error:” + +``` +let veryGreen = Color(0.0, 1.0, 0.0) +// this reports a compile-time error - external names are required +``` + +#### 可选属性类型 (Optional Property Types) + +如果你有一个自定义类型的属性值允许设置为『空值』——可能因为该属性值不能在构造过程中赋值,也可能因为在某些时候允许为『空值』——定义该属性值为_可选_类型。可选类型的属性值会被自动初始化为 `nil`,申明该属性值在构造过程有意设定为『空值』。 + +> “If your custom type has a stored property that is logically allowed to have “no value”—perhaps because its value cannot be set during initialization, or because it is allowed to have “no value” at some later point—declare the property with an optional type. Properties of optional type are automatically initialized with a value of nil, indicating that the property is deliberately intended to have “no value yet” during initialization.” + +在接下来的例子中定义了一个 `SurveyQuestion` 的结构,其拥有一个可选的 `String` 类型属性值 `response`: + +> “The following example defines a class called SurveyQuestion, with an optional String property called 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() +// prints "Do you like cheese?" +cheeseQuestion.response = "Yes, I do like cheese. +``` + +你无法知道一个调查问题的回应直到它被回答了,因此属性值 `response` 被声明为 `String?` 类型,或称 『可选 `String`』。当一个新的 `SurveyQuestion` 实例被初始化时,它会被自动分配默认值 `nil`,表示『空字符串』。 + +> “The response to a survey question cannot be known until it is asked, and so the response property is declared with a type of String?, or “optional String”. It is automatically assigned a default value of nil, meaning “no string yet”, when a new instance of SurveyQuestion is initialized.” + +### 在构造过程中修改恒定属性 (Modifying Constant Properties During Initialization) + +你可以在构造过程中的任意时候修改恒定属性的值,只要在构造过程结束前设定为一个明确的值。 + +> “You can modify the value of a constant property at any point during initialization, as long as it is set to a definite value by the time initialization finishes.” + +提示: + +> 对于类的实例,一个恒定属性值只能在申明它的类初始化期间进行修改。它不能由子类修改。 + +> > “For class instances, a constant property can only be modified during initialization by the class that introduces it. It cannot be modified by a subclass.” + +你可以修改上面的 `SurveyQuestion` 例子,使问题的 `text` 属性使用一个恒定属性而不是一个可变属性,以表明一旦 `SurveyQuestion` 的实例被创建,问题属性便不能改变。即使 `text` 属性现在是一个恒定属性,它仍然可以在类的构造方法中设定: + +> “You can revise the SurveyQuestion example from above to use a constant property rather than a variable property for the text property of the question, to indicate that the question does not change once an instance of SurveyQuestion is created. Even though the text property is now a constant, it can still be set within the class’s initializer:” + +``` +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() +// prints "How about beets?" +beetsQuestion.response = "I also like beets. (But not with cheese.) +``` + +### 默认构造方法 (Default Initializers) + +Swift 为每个结构或基类提供了_默认构造方法_来为它们的所有属性值提供默认值,**?并不提供一个构造方法。默认构造方法简单的创建一个设定了所有属性值为默认值的新实例。 + +> “Swift provides a default initializer for any structure or base class that provides default values for all of its properties and does not provide at least one initializer itself. The default initializer simply creates a new instance with all of its properties set to their default values.” + +在接下来的例子中定义了一个叫 `ShoppingListItem` 的类,其封装了购物清单中一件商品的名字、数量和支付状态: + +> “This example defines a class called ShoppingListItem, which encapsulates the name, quantity, and purchase state of an item in a shopping list:” + +``` +class ShoppingListItem { + var name: String? + var quantity = 1 + var purchased = false +} +var item = ShoppingListItem() +``` + +因为 `ShoppingListItem` 类中所有的属性值都拥有默认值,且这是一个没有父类的基类,`ShoppingListItem` 自动获得了一个默认构造方法,该方法创建一个设定了所有属性值为默认值的新实例。(`name` 属性是一个可选的 `String` 类型属性,因此它自动获得默认值为 `nil`,尽管这个值并没有写在代码中。)上面的例子使用默认构造方法为 `ShoppingListItem` 类创建实例化对象,构造方法语法写作 `ShoppingListItem()` 并将此实例赋值给 `item` 变量。 + +> “Because all properties of the ShoppingListItem class have default values, and because it is a base class with no superclass, ShoppingListItem automatically gains a default initializer implementation that creates a new instance with all of its properties set to their default values. (The name property is an optional String property, and so it automatically receives a default value of nil, even though this value is not written in the code.) The example above uses the default initializer for the ShoppingListItem class to create a new instance of the class with initializer syntax, written as ShoppingListItem(), and assigns this new instance to a variable called item.” + +#### 结构类型的成员式构造方法 (Memberwise Initializers for Structure Types) + +除了上面提到的默认构造方法,如果结构类型为其所有属性值提供了默认值且没有自定义构造方法,那么该结构类型自动接收一个_成员式构造方法_。 + +> “In addition to the default initializers mentioned above, structure types automatically receive a memberwise initializer if they provide default values for all of their stored properties and do not define any of their own custom initializers.” + +成员式构造方法是初始化新结构实例的成员属性的一种简写方式。新实例的属性的初始值可以通过名称传递给成员式构造方法。 + +> “The memberwise initializer is a shorthand way to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name.” + +在接下来的例子中定义了一个叫 `Size` 的结构,其拥有两个属性值分别是 `width` 和 `height`。通过分配了 `0.0` 作为它们的默认值,两个属性均被推断为 `Double` 类型。 + +> “The example below defines a structure called Size with two properties called width and height. Both properties are inferred to be of type Double by assigning a default value of 0.0.” + +由于所有属性值均拥有默认值,`Size` 这个结构自动接受一个成员式构造方法 `init(width:height:)`,你可以通过这个成员式构造方法创建新的 `Size` 实例: + +> “Because both stored properties have a default value, the Size structure automatically receives an init(width:height:) memberwise initializer, which you can use to initialize a new Size instance:” + +``` +struct Size { + var width = 0.0, height = 0.0 +} +let twoByTwo = Size(width: 2.0, height: 2.0) +``` + +### 值类型的构造代理 (Initializer Delegation for Value Types) + +构造方法可以调用其他的构造方法作为实例构造过程的一部分。这个过程称为_构造代理_,其避免了在多个构造方法中的重复代码。“ + +> “Initializers can call other initializers to perform part of an instance’s initialization. This process, known as initializer delegation, avoids duplicating code across multiple initializers.” + +构造代理的工作原理,以及哪些形式的代理是被允许的,针对值类型和类类型是不同的。值类型(结构和枚举)不支持继承,因此他们的构造代理过程比较简单,因为它们只能委托给由它们自己提供的其他构造方法。但是,类类型可以从其他类继承,如『继承』这一章节所描述。这意味着类有更多的责任去确保它们继承了的所有属性值在构造过程中被分配一个合适的值。这些责任将在接下来的『类的继承和初始化』中说明。 + +> “The rules for how initializer delegation works, and for what forms of delegation are allowed, are different for value types and class types. Value types (structures and enumerations) do not support inheritance, and so their initializer delegation process is relatively simple, because they can only delegate to another initializer that they provide themselves. Classes, however, can inherit from other classes, as described in Inheritance. This means that classes have additional responsibilities for ensuring that all stored properties they inherit are assigned a suitable value during initialization. These responsibilities are described in Class Inheritance and Initialization below.” + +对于值类型,当你自定义构造方法时,你使用 `self.init` 来关联同一值类型的其他构造方法。你只能在构造方法中调用 `self.init`。 + +> “For value types, you use self.init to refer to other initializers from the same value type when writing your own custom initializers. You can only call self.init from within an initializer.” + +请注意,如果你为值类型定义一个自定义构造方法,你将不再能够访问该类型的默认构造方法(或成员式构造方法,如果它是一个结构)。这个约束防止一种情况的出现,即你提供了一个更为复杂的构造方法来执行必要的设置,但有人却不小心绕过它使用了自动生成构造方法。 + +> “Note that if you define a custom initializer for a value type, you will no longer have access to the default initializer (or the memberwise structure initializer, if it is a structure) for that type. This constraint prevents a situation in which you provide a more complex initializer that performs additional essential setup is circumvented by someone accidentally using one of the automatic initializers instead.” + +提示: + +> 如果你期望你自定义的值类型能够被默认构造方法和成员式构造方法初始化,并且同时也能够被自定义构造方法初始化,把你的自定义构造方法写在扩展中,而不是该值类型源生实现中的一部分。请参见『扩展』章节了解更多信息。 + +> > “If you want your custom value type to be initializable with the default initializer and memberwise initializer, and also with your own custom initializers, write your custom initializers in an extension rather than as part of the value type’s original implementation. For more information, see Extensions.” + +在接下来的例子中定义了一个叫 `Rect` 的结构来表示一个几何矩形。该例子需要 `Size` 和 `Point` 这两个结构的支持,两个结构均使用 `0.0` 作为它们属性值的默认值: + +> “The following example defines a custom Rect structure to represent a geometric rectangle. The example requires two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties:” + +``` +struct Size { + var width = 0.0, height = 0.0 +} +struct Point { + var x = 0.0, y = 0.0 +} +``` +你可以通过下面三种方式中的一种来初始化 `Rect` 结构: + +* 使用 `origin` 和 `size` 的默认属性值 +* 提供一个特定的原始点和大小 +* 提供一个中心点和大小 + +这些构造过程选项由三个自定义构造方法提供,它们均定义在 `Rect` 结构中: + +> “You can initialize the Rect structure below in one of three ways—by using its default zero-initialized origin and size property values, by providing a specific origin point and size, or by providing a specific center point and size. These initialization options are represented by three custom initializers that are part of the Rect structure’s definition:” + +``` +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)`: + +> “The first Rect initializer, init(), is functionally the same as the default initializer that the structure would have received if it did not have its own custom initializers. This initializer has an empty body, represented by an empty pair of curly braces {}, and does not perfom any initialization. Calling this initializer returns a Rect instance whose origin and size properties are both initialized with the default values of Point(x: 0.0, y: 0.0) and Size(width: 0.0, height: 0.0) from their property definitions:” + +``` +let basicRect = Rect() +// basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0) +``` + +第二个 `Rect` 构造方法 `init(origin:size:)` 在功能上和没有提供自定义构造方法的成员式构造方法相同。该构造方法简单地将 `origin` 和 `size` 参数分配给恰当的属性值: + +> “The second Rect initializer, init(origin:size:), is functionally the same as the memberwise initializer that the structure would have received if it did not have its own custom initializers. This initializer simply assigns the origin and size argument values to the appropriate stored properties:” + +``` +let originRect = Rect(origin: Point(x: 2.0, y: 2.0), + size: Size(width: 5.0, height: 5.0)) +// originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0) +``` + +第三个 `Rect` 构造方法 `init(center:size:)` 稍微复杂一些。它从基于中心点和大小值计算相应的原点开始。然后,它调用(或委托)到 `init(origin:size:)` 构造方法,将新的原点和大小保存到合适的属性中: + +> “The third Rect initializer, init(center:size:), is slightly more complex. It starts by calculating an appropriate origin point based on a center point and a size value. It then calls (or delegates) to the init(origin:size:) initializer, which stores the new origin and size values in the appropriate properties:” + +``` +let centerRect = Rect(center: Point(x: 4.0, y: 4.0), + size: Size(width: 3.0, height: 3.0)) +// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0) +``` + +尽管构造方法 `init(center:size:)` 也能够自己将新的 `origin` 和 `size` 分配给合适的属性。可是,构造方法 `init(center:size:)` 使用已经具有相同功能的构造函数来实现更简单(逻辑清楚)。 + +> “The init(center:size:) initializer could have assigned the new values of origin and size to the appropriate properties itself. However, it is more convenient (and clearer in intent) for the init(center:size:) initializer to take advantage of an existing initializer that already provides exactly that functionality.” + +提示: + +> 如果你想通过不定义 `init()` 和 `init(origin:size:)` 构造方法来替代例子中的方法,请见『扩展』章节。 + +> > “For an alternative way to write this example without defining the init() and init(origin:size:) initializers yourself, see Extensions.” + +### 类的继承与构造过程 + +一个类的所有属性值——包括所有它从父类继承的属性——_必须_在构造过程中分配初始值。 + +> “All of a class’s stored properties—including any properties the class inherits from its superclass—must be assigned an initial value during initialization.” + +Swift 定义了两种类类型的构造方法来保证所有的属性值接收到初始值。它们被称为指定构造方法和便利构造方法。 + +> “Swift defines two kinds of initializers for class types to help ensure all stored properties receive an initial value. These are known as designated initializers and convenience initializers.” + +#### 指定构造方法和便利构造方法 (Designated Initializers and Convenience Initializers) + +_指定构造方法_是类的主要构造方法。一个指定构造方法完全初始化所有该类申明的属性并调用合适的父类构造方法来继续向上追溯构造过程的父类链。 + +> “Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.” + +类往往只有少数指定构造方法,而且只有一个指定构造方法也是很常见的。**?指定构造方法是通过构造过程发生的『漏斗』点,并通过其继续向上追溯构造过程的父类链。 + +> “Classes tend to have very few designated initializers, and it is quite common for a class to have only one. Designated initializers are “funnel” points through which initialization takes place, and through which the initialization process continues up the superclass chain.” + +每个类必须至少拥有一个指定构造方法。在某些情况下,这一要求由从父类继承一个或多个指定构造方法满足,这将在接下来的『自动构造方法继承』中说明。 + +> “Every class must have at least one designated initializer. In some cases, this requirement is satisfied by inheriting one or more designated initializers from a superclass, as described in Automatic Initializer Inheritance below.” + +_便利构造方法_是次要的,是类的辅助构造方法。你可以在同一个类下定义一个便利构造方法来调用指定构造方法,该便利构造方法定义了指定构造方法参数的默认值。你也可以定义一个便利构造方法用于创建特定用例或**?输入值类型的实例。 + +> “Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.” + +如果你的类不需要便利构造方法,你可以不提供它。每当一个通用构造过程模型的快捷方式能够节省事件或让该类的构造过程的意图更清晰,请使用创建便利构造方法。 + +> “You do not have to provide convenience initializers if your class does not require them. Create convenience initializers whenever a shortcut to a common initialization pattern will save time or make initialization of the class clearer in intent.” + +#### 构造方法链 (Initializer Chaining) + +为了简化指定构造方法和便利构造方法的关系,在构造方法委托调用中 Swift 应用了以下三条规则: + +> “To simplify the relationships between designated and convenience initializers, Swift applies the following three rules for delegation calls between initializers:” + +* __规则一:__指定构造方法只能从其直接父类中调用指定构造方法。 +* __规则二:__便利构造方法只能调用_该类自身_定义的其他构造方法。 +* __规则三:__便利构造方法必须在最终调用一个指定构造方法。 + +> * __Rule 1__ “Designated initializers must call a designated initializer from their immediate superclass.” +> * __Rule 2__ “Convenience initializers must call another initializer available in the same class.” +> * __Rule 3__ “Convenience initializers must ultimately end up calling a designated initializer.” + +一个简单的方法来记住这些: + +* **?指定构造方法必须总是_向上_委托 +* **?便利构造方法必须总是_穿过_委托 + +> “A simple way to remember this is:” +> +> * “Designated initializers must always delegate up.” +> * “Convenience initializers must always delegate across.” + +这些规则如下图所示: + +> “These rules are illustrated in the figure below:” + +**?插图[1] Page 408 + +在这里,父类只有一个指定构造方法和两个便利构造方法。一个便利构造方法调用了其中另一个便利构造方法,而该构造方法调用了唯一那个便利构造方法。这符合上面的规则 2 和 3。该父类自身没有父类,因此不适用规则 1。 + +> “Here, the superclass has a single designated initializer and two convenience initializers. One convenience initializer calls another convenience initializer, which in turn calls the single designated initializer. This satisfies rules 2 and 3 from above. The superclass does not itself have a further superclass, and so rule 1 does not apply.” + +上图中的子类拥有两个指定构造方法和一个便利构造方法。这个便利构造方法必须调用那两个指定构造方法中的一个,因为便利构造方法必须调用其类自身的其他构造方法。这符合上面的规则 2 和 3。该子类中两个指定构造方法都必须调用父类中唯一那个指定构造方法,来符合上面的规则 1。 + +> “The subclass in this figure has two designated initializers and one convenience initializer. The convenience initializer must call one of the two designated initializers, because it can only call another initializer from the same class. This satisfies rules 2 and 3 from above. Both designated initializers must call the single designated initializer from the superclass, to satisfy rule 1 from above.” + +提示: + +> 这些规则并不会影响你的类用户如何_创建_各类的实例。上图中的任何构造方法都能用于创建其所在类的完整实例。这些规则只会影响你如何写这些类的实现。 + +> > “These rules don’t affect how users of your classes create instances of each class. Any initializer in the diagram above can be used to create a fully-initialized instance of the class they belong to. The rules only affect how you write the class’s implementation.” + +下面的图显示了一个更为复杂的 4 个类的层次结构。它表现了指定构造方法如何在类构造过程中用作『漏斗』点,简化了这些类层级间的相互关联。 + +> “The figure below shows a more complex class hierarchy for four classes. It illustrates how the designated initializers in this hierarchy act as “funnel” points for class initialization, simplifying the interrelationships among classes in the chain:” + +**?插图[2] Page 410 + +#### 构造过程的两个阶段 (Two-Phase Initialization) + +在 Swift 中类的构造过程有两个阶段。在第一个阶段,每个属性值被申明它的类分配一个初始值。一旦每个属性值的初始状态被确认,第二阶段便开始,每个类能够在新实例被认为是可以使用之前进一步制定其属性值。 + +> “Class initialization in Swift is a two-phase process. In the first phase, each stored property is assigned an initial value by the class that introduced it. Once the initial state for every stored property has been determined, the second phase begins, and each class is given the opportunity to customize its stored properties further before the new instance is considered ready for use.” + +构造过程的两个阶段使构造过程更安全,同时仍然给予一个类层级中每个类以完全的灵活性。构造过程的两个阶段防止属性值在它们被初始化之前被访问,并防止属性值被另一个构造方法意外地设置为其他值。 + +> “The use of a two-phase initialization process makes initialization safe, while still giving complete flexibility to each class in a class hierarchy. Two-phase initialization prevents property values from being accessed before they are initialized, and prevents property values from being set to a different value by another initializer unexpectedly.” + +提示: + +> Swift 的构造过程的两个阶段和 Objective-C 的构造过程类似。主要的不同之处在第一阶段 Objective-C 分配 0 或 null (如 `0` 或 `nil`) 值给每个属性。Swift 的构造过程更加灵活,因此它可以让你设置自定义初始值,并可以应付 `0` 或 `nil` 不是一个有效默认值的类型。 + +> > “Swift’s two-phase initialization process is similar to initialization in Objective-C. The main difference is that during phase 1, Objective-C assigns zero or null values (such as 0 or nil) to every property. Swift’s initialization flow is more flexible in that it lets you set custom initial values, and can cope with types for which 0 or nil is not a valid default value.” + +Swift 的编译器执行了四个安全检查,来保证构造过程的两个阶段过程中没有错误: + +> “Swift’s compiler performs four helpful safety-checks to make sure that two-phase initialization is completed without error:” + +* __安全检查一:__指定构造方法必须保证其所在类申明的属性在向上委托到父类构造方法前被初始化。 + +> * __Safety Check 1__ “A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.” + +正如上面所提到的,一个对象的内存只会被初始化一次,该对象的所有属性值的初始化状态都是已知的。为了符合这条规范,一个指定构造方法必须保证其所有属性在它脱手给继承链前是已经被初始化了的。 + +> “As mentioned above, the memory for an object is only considered fully initialized once the initial state of all of its stored properties is known. In order for this rule to be satisfied, a designated initializer must make sure that all its own properties are initialized before it hands off up the chain.” + +* __安全检查二:__一个指定构造方法在给继承的属性赋值之前必须向上委托至一个父类的构造方法。如果不是这样,该指定构造方法分配的新值会被父类的构造过程覆盖。 +* __安全检查三:__一个便利构造方法必须在给_任何_属性(包裹其所在类定义的属性)赋值前委托给另一个构造方法。如果不是这样,该便利构造方法分配的新值会被其自身类委托的构造方法覆盖。 +* __安全检查四:__直到构造过程的第一阶段完成前,任何构造方法都不能调用实例方法,不能读取任何实例属性,或引用自身为一个值。 + +> * __Safety Check 2__ “A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property. If it doesn’t, the new value the designated initializer assigns will be overwritten by the superclass as part of its own initialization.” +> * __Safety Check 3__ “A convenience initializer must delegate to another initializer before assigning a value to any property (including properties defined by the same class). If it doesn’t, the new value the convenience initializer assigns will be overwritten by its own class’s designated initializer.” +> * __Safety Check 4__ “An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.” + +在第一阶段完成前,类的实例并不是完全有效的。当在第一阶段结束时,类实例被认为是有效的,属性只能被访问,方法只能被调用,“ + +> “The class instance is not fully valid until the first phase ends. Properties can only be accessed, and methods can only be called, once the class instance is known to be valid at the end of the first phase.” + +下面是构造过程的两个阶段如何基于上面的 4 个安全检查实现的: + +> “Here’s how two-phase initialization plays out, based on the four safety checks above:” + +##### 第一阶段 + +* 一个指定或便利构造方法在一个类中被调用。 +* 该类的一个新实例内存被分配。但内存还未被初始化。 +* 该类的一个指定构造方法确保该类中申明的所有属性值拥有一个值。这些属性值的内存现在被初始化了。 +* 该指定构造方法脱手给父类的构造方法来为它拥有的属性值执行相同的任务。 +* 该过程持续向上追溯继承链,直到到达链条顶端。 +* 一旦达到继承链的顶端,最终的类必须保证其所有的属性值都拥有一个值,然后该实例的内存被认为是完全初始化的,第一阶段结束。 + +> * “A designated or convenience initializer is called on a class.” +> * “Memory for a new instance of that class is allocated. The memory is not yet initialized.” +> * “A designated initializer for that class confirms that all stored properties introduced by that class have a value. The memory for these stored properties is now initialized.” +> * “The designated initializer hands off to a superclass initializer to perform the same task for its own stored properties.” +> * “This continues up the class inheritance chain until the top of the chain is reached.” +> * “Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance’s memory is considered to be fully initialized, and phase 1 is complete.” + +##### 第二阶段 + +* 从继承链的顶端向下工作,继承链中每个指定构造方法都能够进一步自定义该实例。现在构造方法可以访问 `self` 并且能够修改其属性,调用实例方法,等等。 +* 最后,继承链中每个便利构造方法能够自定义该实例,并且使用 `self` 操作。 + +> * “Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access self and can modify its properties, call its instance methods, and so on.” +> * “Finally, any convenience initializers in the chain have the option to customize the instance and to work with self.” + +下图显示了第一阶段在假想的子类和父类中如何寻找构造过程的调用: + +> “Here’s how phase 1 looks for an initialization call for a hypothetical subclass and superclass:” + +**?插图[3] Page 415 + +在这个例子中,构造过程开始于对子类中便利构造方法的调用。该便利构造方法当前还不能修改任何属性。它委托给同一类下的一个指定构造方法。 + +> “In this example, initialization begins with a call to a convenience initializer on the subclass. This convenience initializer cannot yet modify any properties. It delegates across to a designated initializer from the same class.” + +该指定构造方法确保所有子类中的属性都拥有一个值,如安全检查 1。然后它调用了父类的一个指定构造方法来继续向上追溯构造过程。 + +> “The designated initializer makes sure that all of the subclass’s properties have a value, as per safety check 1. It then calls a designated initializer on its superclass to continue the initialization up the chain.” + +父类的指定构造方法确保了父类的所有属性都拥有一个值。在没有往上的父类可以追溯,也不需要进一步的委托。 + +> “The superclass’s designated initializer makes sure that all of the superclass properties have a value. There are no further superclasses to initialize, and so no further delegation is needed.” + +在所有的父类属性都拥有值的时候,内存被认为完全初始化,第一阶段结束。 + +> “As soon as all properties of the superclass have an initial value, its memory is considered fully initialized, and Phase 1 is complete.” + +下图显示了第二阶段如何寻找构造过程的调用: + +> “Here’s how phase 2 looks for the same initialization call:” + +**?插图[4] Page 416 + +父类的指定构造方法已经可以进一步自定义实例(这不是必须的)。 + +> “The superclass’s designated initializer now has an opportunity to customize the instance further (although it does not have to).” + +一旦父类的指定构造方法结束,子类的指定构造方法便可执行额外的自定义操作(同样的,这不是必须的)。 + +> “Once the superclass’s designated initializer is finished, the subclass’s designated initializer can perform additional customization (although again, it does not have to).” + +最后,一旦子类的指定构造方法结束,最早被调用的便利构造方法可以执行额外的自定义操作了。 + +> “Finally, once the subclass’s designated initializer is finished, the convenience initializer that was originally called can perform additional customization.” + +#### 构造方法的继承与重写 (Initializer Inheritance and Overriding) + +与 Objective-C 的子类不同,Swift 的子类会默认继承它们父类的构造方法。Swift 可以防止一种情况:一个简单的父类构造方法被一个更专业的子类自动继承,并用于创建不完整或不正确的子类实例。 + +> “Unlike subclasses in Objective-C, Swift subclasses do not not inherit their superclass initializers by default. Swift’s approach prevents a situation in which a simple initializer from a superclass is automatically inherited by a more specialized subclass and is used to create a new instance of the subclass that is not fully or correctly initialized.” + +如果你希望你的自定义子类能够提供一个多个与父类相同的构造方法——可能在构造过程中需要一些自定义——你可以在你自定义的子类中提供一个相同构造方法的重写来实现。 + +> “If you want your custom subclass to present one or more of the same initializers as its superclass—perhaps to perform some customization during initialization—you can provide an overriding implementation of the same initializer within your custom subclass.” + +如果你重写的构造方法是一个指定构造方法,你可以在你的子类中重写它的实现,并且能够在子类的重写版方法中调用父类父类版方法。 + +> “If the initializer you are overriding is a designated initializer, you can override its implementation in your subclass and call the superclass version of the initializer from within your overriding version.” + +如果你重写的构造方法是一个便利构造方法,你重写的方法必须调用子类自身申明的另一个指定构造方法,正如前面『构造方法链』说明的规则那样。 + +> “If the initializer you are overriding is a convenience initializer, your override must call another designated initializer from its own subclass, as per the rules described above in Initializer Chaining.” + +提示: + +> 与方法、属性和下标不同,当你重写一个构造方法时不需要写 `override` 关键字。 + +> > “Unlike methods, properties, and subscripts, you do not need to write the override keyword when overriding an initializer.” + +#### 自动继承构造方法 (Automatic Initializer Inheritance) + +正如上面所描述的,子类会默认继承它们父类的构造方法。可是,在某些情况下,父类的构造方法会被自动继承。在实践中,**?这意味着​​在许多常见情况下你不需要重写构造方法,并且可以最小影响地继承父类的构造方法,这样做是安全。 + +> “As mentioned above, subclasses do not not inherit their superclass initializers by default. However, superclass initializers are automatically inherited if certain conditions are met. In practice, this means that you do not need to write initializer overrides in many common scenarios, and can inherit your superclass initializers with minimal effort whenever it is safe to do so.” + +假设你为你的子类中申明的任何新属性提供默认值,有下面两个规则要遵守: + +> “Assuming that you provide default values for any new properties you introduce in a subclass, the following two rules apply:” + +* __规则一:__如果你的子类没有定义任何指定构造方法,它会自动继承父类所有的指定构造方法。 +* __规则二:__如果你的子类提供了其父类所有的指定构造方法的实现——或者仅仅如『规则一』所说的继承它们,或者在其自身定义中提供自定义的实现——那么该子类会自动继承父类所有的便利构造方法。 + +> * __Rule 1__ “If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.” +> * __Rule 2__ “If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers.” + +即使你在子类中添加了更多的便利构造方法,这两个规则依然适用。 + +> “These rules apply even if your subclass adds further convenience initializers.” + +提示: + +> 一个子类可以实现一个父类的指定构造方法为子类的一个便利构造方法,这是符合『规则二』的。 + +> > “A subclass can implement a superclass designated initializer as a subclass convenience initializer as part of satisfying rule 2.” + +#### 指定与便利构造方法的语法 (Syntax for Designated and Convenience Initializers) + +类的指定构造方法的编写方法如值类型的构造方法一样简单: + +> “Designated initializers for classes are written in the same way as simple initializers for value types:” + +``` +init(parameters) { + statements +} +``` + +便利构造方法的编写方法也是如此,但必须在 `init` 关键字前面加上 `convenience` 关键字,并以空格分隔: + +> “Convenience initializers are written in the same style, but with the convenience keyword placed before the init keyword, separated by a space:” + +``` +convenience init(parameters) { + statements +} +``` + +#### 指定与便利构造方法的行为 (Designated and Convenience Initializers in Action) + +在接下来的例子显示了指定构造方法,便利构造方法和自动继承的构造方法的行为。这个例子定义了叫 `Food`,`RecipeIngredient` 和 `ShoppingListItem` 三个类的层级关系,并示范了它们之间是如何相互作用的。 + +> “The following example shows designated initializers, convenience initializers, and automatic initializer inheritance in action. This example defines a hierarchy of three classes called Food, RecipeIngredient, and ShoppingListItem, and demonstrates how their initializers interact.” + +该层级中的基类是 `Food`,它是一个仅仅描述了食物名字的简单类。`Food` 类仅有一个 `String` 类型的属性 `name`,并有两个构造方法来创造 `Food` 的实例: + +> “The base class in the hierarchy is called Food, which is a simple class to encapsulate the name of a foodstuff. The Food class introduces a single String property called name and provides two initializers for creating Food instances:” + +``` +class Food { + var name: String + init(name: String) { + self.name = name + } + convenience init() { + self.init(name: "[Unnamed]") + } +} +``` + +下图显示了 `Food` 类的构造方法链: + +> “The figure below shows the initializer chain for the Food class:” + +**?插图[5] Page 421 + +类并没有默认的成员式构造方法,因此 `Food` 类提供了一个仅拥有一个 `name` 参数的指定构造方法。该构造方法可以用来创建指定了名字的 `Food` 实例: + +``` +let namedMeat = Food(name: "Bacon") +// namedMeat's name is "Bacon" +``` + +在 `Food` 类中的 `init(name: String)` 构造方法是一个_指定构造方法_,因为它保证了 `Food` 实例中的所有属性值是完全初始化的。`Food` 并没有父类,因此构造方法 `init(name: String)` 并不需要在其构造过程中调用 `super.init()`。 + +> “The init(name: String) initializer from the Food class is provided as a designated initializer, because it ensures that all stored properties of a new Food instance are fully initialized. The Food class does not have a superclass, and so the init(name: String) initializer does not need to call super.init() to complete its initialization.” + +该 `Food` 类也提供了一个没有参数的_便利构造方法_ `init()`。构造方法 `init()` 通过将赋值为 `[Unnamed]` 的 `name` 参数委托给 `Food` 类的 `init(name: String)`,提供了食物的默认名字: + +> “The Food class also provides a convenience initializer, init(), with no arguments. The init() initializer provides a default placeholder name for a new food by delegating across to the Food class’s init(name: String) with a name value of [Unnamed]:” + +``` +let mysteryMeat = Food() +// mysteryMeat's name is "[Unnamed]" +``` + +该层级中的第二个类是 `Food` 的一个子类,叫做 `RecipeIngredient`。该 `RecipeIngredient` 类创建了一个烹饪食谱的原料模型。它申明了一个 `Int` 类型的属性 `quantity`(从 `Food` 中继承了 `name` 属性)并定义了两个构造方法来创建 `RecipeIngredient` 实例: + +> “The second class in the hierarchy is a subclass of Food called RecipeIngredient. The RecipeIngredient class models an ingredient in a cooking recipe. It introduces an Int property called quantity (in addition to the name property it inherits from Food) and defines two initializers for creating RecipeIngredient instances:” + +``` +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` 类的构造方法链: + +> “The figure below shows the initializer chain for the RecipeIngredient class:” + +**?插图[6] Page 423 + +类 `RecipeIngredient` 拥有唯一一个指定构造方法 `init(name: String, quantity: Int)`,它可以完成新 `RecipeIngredient` 实例的所有属性的填充。该构造方法开始于将传入的 `quantity` 参数赋值给在 `RecipeIngredient` 中申明的新属性 `quantity`。而后,该构造方法向上委托给 `Food` 的构造方法 `init(name: String)`。该过程符合之前『构造过程的两个阶段』章节中的安全检查 1。 + +> “The RecipeIngredient class has a single designated initializer, init(name: String, quantity: Int), which can be used to populate all of the properties of a new RecipeIngredient instance. This initializer starts by assigning the passed quantity argument to the quantity property, which is the only new property introduced by RecipeIngredient. After doing so, the initializer delegates up to the init(name: String) initializer of the Food class. This process satisfies safety check 1 from Two-Phase Initialization above.” + +同时 `RecipeIngredient` 定义了一个便利构造方法 `init(name: String)`,它用于只使用名字来创建 `RecipeIngredient` 实例。该便利构造方法假定了所有没有明确数量的 `RecipeIngredient` 实例的数量为 `1`。该构造方法的定义使创建 `RecipeIngredient` 更加便捷快速,并能够避免创造多个单数量 `RecipeIngredient` 实例时产生的代码冗余。该便利构造方法简单得委托给了其所在类的指定构造方法。 + +> “RecipeIngredient also defines a convenience initializer, init(name: String), which is used to create a RecipeIngredient instance by name alone. This convenience initializer assumes a quantity of 1 for any RecipeIngredient instance that is created without an explicit quantity. The definition of this convenience initializer makes RecipeIngredient instances quicker and more convenient to create, and avoids code duplication when creating several single-quantity RecipeIngredient instances. This convenience initializer simply delegates across to the class’s designated initializer.” + +请注意,`RecipeIngredient` 类提供的便利构造方法 `init(name: String)` 使用了与 `Food` 类中制_指定构造方法_ `init(name: String)` 一样的参数。尽管 `RecipeIngredient` 将其作为便利构造方法,`RecipeIngredient` 仍然提供了其父类所有指定构造方法的实现。因此,`RecipeIngredient` 自动继承了其父类所有的便利构造方法。 + +> “Note that the init(name: String) convenience initializer provided by RecipeIngredient takes the same parameters as the init(name: String) designated initializer from Food. Even though RecipeIngredient provides this initializer as a convenience initializer, RecipeIngredient has nonetheless provided an implementation of all of its superclass’s designated initializers. Therefore, RecipeIngredient automatically inherits all of its superclass’s convenience initializers too.” + +在这个例子中,`RecipeIngredient` 的父类是 `Food`,`Food` 只有一个叫 `init()` 的便利构造方法。因此该构造方法被 `RecipeIngredient` 所继承。继承了的 `init()` 方法和 `Food` 中的一样,只是它委托的是 `RecipeIngredient` 中的 `init(name: String)` 而不是 `Food` 中的。 + +> “In this example, the superclass for RecipeIngredient is Food, which has a single convenience initializer called init(). This initializer is therefore inherited by RecipeIngredient. The inherited version of init() functions in exactly the same way as the Food version, except that it delegates to the RecipeIngredient version of init(name: String) rather than the Food version.” + +这三种构造方法均可以用于创建 `RecipeIngredient` 对象: + +> “All three of these initializers can be used to create new RecipeIngredient instances:” + +``` +let oneMysteryItem = RecipeIngredient() +let oneBacon = RecipeIngredient(name: "Bacon") +let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6) +``` + +第三个并且是最后一个类是 `RecipeIngredient` 的子类,叫做 `ShoppingListItem`。该 `ShoppingListItem` 类创建了一个食谱购物清单的模型。 + +> “The third and final class in the hierarchy is a subclass of RecipeIngredient called ShoppingListItem. The ShoppingListItem class models a recipe ingredient as it appears in a shopping list.” + +购物清单中的所有商品的初始状态都是『未支付』。为了实现它,`ShoppingListItem` 申明了一个默认值为 `false` 的 `Boolean` 的属性 `purchased`。同时,`ShoppingListItem` 也申明了一个计算过的 `description` 属性,它提供了对 `ShoppingListItem` 实例的文本描述: + +> “Every item in the shopping list starts out as “unpurchased”. To represent this fact, ShoppingListItem introduces a Boolean property called purchased, with a default value of false. ShoppingListItem also adds a computed description property, which provides a textual description of a ShoppingListItem instance:” + +``` +class ShoppingListItem: RecipeIngredient { + var purchased = false + var description: String { + var output = "\(quantity) x \(name.lowercaseString)" + output += purchased ? " ✔" : " ✘" + return output + } +} +``` + +提示: + +> `ShoppingListItem` 并没有定义为 `purchased` 提供初始值的构造方法,因为在购物清单中的商品(按这里的模型)的初始状态总是未支付。 + +> > “ShoppingListItem does not define an initializer to provide an initial value for purchased, because items in a shopping list (as modeled here) always start out unpurchased.” + +因为 `ShoppingListItem` 为所有其申明的属性均提供了默认值,并且其自身没有定义任何构造方法。`ShoppingListItem` 自动继承了其父类的所有指定和便利构造方法。 + +> “Because it provides a default value for all of the properties it introduces and does not define any initializers itself, ShoppingListItem automatically inherits all of the designated and convenience initializers from its superclass.” + +下图显示了这三个类的构造方法链的概览: + +> “The figure below shows the overall initializer chain for all three classes:” + +**?插图[7] Page 427 + +这三个继承的构造方法均可以用于创建 `ShoppingListItem` 对象: + +> “You can use all three of the inherited initializers to create a new ShoppingListItem instance:” + +``` +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 ✘ +``` + +至此,一个包含了三个新 `ShoppingListItem` 实例的数组 `breakfastList` 被创建出来。这个数组的类型被推断为 `ShoppingListItem[]`。在该数组被创建后,该数组的第一个 `ShoppingListItem` 实例的名字从 `[Unnamed]` 改变为 `Orange`,并且其被标记为已支付状态。输出数组中每个实例的详细描述,显示出它们的默认状态均被按预期地设置了。 + +> “Here, a new array called breakfastList is created from an array literal containing three new ShoppingListItem instances. The type of the array is inferred to be ShoppingListItem[]. After the array is created, the name of the ShoppingListItem at the start of the array is changed from "[Unnamed]" to "Orange juice" and it is marked as having been purchased. Printing the description of each item in the array shows that their default states have been set as expected.” + +### 通过闭包或方法设置默认属性 (Setting a Default Property Value with a Closure or Function) + +如果一个属性值的默认值需要一些自定义或者设置,你可以使用闭包或者全局方法来为该属性提供自定义默认值。无论该属性所在类的实例何时被初始化,闭包或方法会被调用,并且其返回值会被分配给该属性作为默认值。 + +> “If a stored property’s default value requires some customization or setup, you can use a closure or global function to provide a customized default value for that property. Whenever a new instance of the type that the property belongs to is initialized, the closure or function is called, and its return value is assigned as the property’s default value.” + +这种类型的闭包和方法为该属性创建了一个相同类型的临时值,**?定制的该值是初始状态所期望的,然后返回这个临时值作为该属性的默认值。 + +> “These kinds of closures or functions typically create a temporary value of the same type as the property, tailor that value to represent the desired initial state, and then return that temporary value to be used as the property’s default value.” + +下面是一个如何使用闭包给属性提供默认值的概览: + +> “Here’s a skeleton outline of how a closure can be used to provide a default property value:” + +``` +class SomeClass { + let someProperty: SomeType = { + // create a default value for someProperty inside this closure + // someValue must be of the same type as SomeType + return someValue + }() +} +``` + +请注意,闭包结束的花括号后面紧跟着一堆空的圆括号。这会告诉 Swift 立即执行该闭包。如果你漏掉了圆括号,你会把闭包本身赋值给该属性,而不是这个闭包的返回值。 + +> “Note that the closure’s end curly brace is followed by an empty pair of parentheses. This tells Swift to execute the closure immediately. If you omit these parentheses, you are trying to assign the closure itself to the property, and not the return value of the closure.” + +提示: + +> 如果你使用一个闭包来初始化一个属性,请记住,在该闭包被执行的时候该实例的其他部分还没有被初始化。这意味着你无法在闭包中访问任何其他属性,即使这些属性有默认值也不行。你也不能使用 `self` 属性,或调用任何实例方法。 + +> > “If you use a closure to initialize a property, remember that the rest of the instance has not yet been initialized at the point that the closure is executed. This means that you cannot access any other property values from within your closure, even if those properties have default values. You also cannot use the implicit self property, or call any of the instance’s methods.” + +在接下来的例子中定义了一个叫 `Checkerboard` 的结构,它创建了一个_跳棋_游戏桌面的模型: + +> “The example below defines a structure called Checkerboard, which models a board for the game of Checkers (also known as Draughts):” + +**?插图[8] Page 431 + +_跳棋_游戏在一个黑白相间的 10x10 方格的桌面上进行。为了表示这个游戏桌面,`Checkerboard` 结构有唯一一个属性 `boardColors`,该属性是一个拥有 100 个 `Bool` 值的数组。数组中的 `true` 值表示一个黑色方块,`false` 表示一个白色方块。数组中的第一个对象表示桌面左上角的方块,最后一个对象表示桌面右下角的方块。 + +> “The game of Checkers is played on a ten-by-ten board, with alternating black and white squares. To represent this game board, the Checkerboard structure has a single property called boardColors, which is an array of 100 Bool values. A value of true in the array represents a black square and a value of false represents a white square. The first item in the array represents the top left square on the board and the last item in the array represents the bottom right square on the board.” + +`boardColors` 数组由一个闭包来初始化其颜色值: + +> “The boardColors array is initialized with a closure to set up its color values:” + +``` +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` 中使用。 + +> “Whenever a new Checkerboard instance is created, the closure is executed, and the default value of boardColors is calculated and returned. The closure in the example above calculates and sets the appropriate color for each square on the board in a temporary array called temporaryBoard, and returns this temporary array as the closure’s return value once its setup is complete. The returned array value is stored in boardColors and can be queried with the squareIsBlackAtRow utility function:” + +``` +let board = Checkerboard() +println(board.squareIsBlackAtRow(0, column: 1)) +// prints "true" +println(board.squareIsBlackAtRow(9, column: 9)) +// prints "false" +``` + + + + + From 997fe147e2a8f45a381021a85bb1d3ac4bb1335e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qi=20Tao=20=28=E7=A5=81=E6=B6=9B=29?= Date: Fri, 20 Jun 2014 09:30:55 +0800 Subject: [PATCH 125/261] Update 19_Nested_Types.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 翻译初成 --- src/chapter2/19_Nested_Types.md | 180 ++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/src/chapter2/19_Nested_Types.md b/src/chapter2/19_Nested_Types.md index e69de29..6b0805a 100644 --- a/src/chapter2/19_Nested_Types.md +++ b/src/chapter2/19_Nested_Types.md @@ -0,0 +1,180 @@ +* ` Memberwise Initializers for Structure Types` 引自 `Initialization`,中文翻译参考了刘康的`《结构类型的成员式构造方法》` +* `Initializers`: 构造方法 +* `raw Character`: 字符? 原生字符? +* `raw Int`: 整型?原生整型? +* `computed property`: 计算属性? + +> 备注: +> 以下翻译并未遵循英文的第二人称叙事方式,整体使用第一人称讲述嵌套类型。 +> 由于中英文表达的差异,为兼顾译文的流畅性,本人擅自改动了一些原文的语言结构。更正时还请麻烦告知我,鄙人渴望多听取专家意见、希望在翻译的道路上越走越深~ 谢谢~ + + +#Nested Types +#嵌套类型 + +Enumerations are often created to support a specific class or structure’s functionality. Similarly, it can be convenient to define utility classes and structures purely for use within the context of a more complex type. To accomplish this, Swift enables you to define nested types, whereby you nest supporting enumerations, classes, and structures within the definition of the type they support. + +我们常常创建枚举类型来支持特定类或结构体的功能。同样的,枚举类型可以被方便的用于定义工具类(utility classes)和结构体,而这些工具类和结构体仅仅用在更复杂类型的上下文中。为实现这些功能,Swift可以定义嵌套类型,因此我们可以把枚举类型、类、结构体嵌套到支持他们的类型的定义中。 + +To nest a type within another type, write its definition within the outer braces of the type it supports. Types can be nested to as many levels as are required. + +要嵌套一个类型到另一个类型,只需把它的定义写在外层类型的大括号{}内,这个操作有个前提:外层类型支持嵌套内层类型。嵌套类型没有层数限制,想嵌多少层都可以。 + +##Nested Types in Action +##嵌套类型实例 + +The example below defines a structure called `BlackjackCard`, which models a playing card as used in the game of Blackjack. The `BlackJack` structure contains two nested enumeration types called `Suit` and `Rank`. + +下面的例子定义了一个`BlackjackCard`(21点牌)的结构体,来模仿21点出牌。`BlackJack`结构体包含了两个嵌套类型`Suit`和`Rank`。 + +In Blackjack, the Ace cards have a value of either one or eleven. This feature is represented by a structure called Values, which is nested within the Rank enumeration: + +在21点规则中,A牌(Ace)即可算作1点也可算作11点。这一特征用一个嵌套在枚举类型Rank中的结构体Values来代表。 + +``` +struct BlackjackCard { + + // nested Suit enumeration + enum Suit: Character { + case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣" + } + + // nested Rank enumeration + 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.toRaw(), second: nil) + } + } + } + + // BlackjackCard properties and methods + let rank: Rank, suit: Suit + var description: String { + var output = "suit is \(suit.toRaw())," + output += " value is \(rank.values.first)" + if let second = rank.values.second { + output += " or \(second)" + } + return output + } +} + +``` + +``` +struct BlackjackCard { + + // nested Suit enumeration + enum Suit: Character { + case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣" + } + + // nested Rank enumeration + 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.toRaw(), second: nil) + } + } + } + + // BlackjackCard的属性和方法 + let rank: Rank, suit: Suit + var description: String { + var output = "suit is \(suit.toRaw())," + output += " value is \(rank.values.first)" + if let second = rank.values.second { + output += " or \(second)" + } + return output + } +} + +``` + +The `Suit` enumeration describes the four common playing card suits, together with a raw `Character` value to represent their symbol. + +枚举类型`Suit`描述了扑克牌中的4种花色,每一种花色用一个`字符`(Character)代表。 + +The `Rank` enumeration describes the thirteen possible playing card ranks, together with a raw `Int` value to represent their face value. (This raw `Int` value is not used for the Jack, Queen, King, and Ace cards.) + +枚举类型`Rank`描述了相同花色的13张牌,每张牌的面值用一个`整型值`(Int)代表。(这个整型值不用再J、Q、K、A这四张牌上。) + +As mentioned above, the `Rank` enumeration defines a further nested structure of its own, called `Values`. This structure encapsulates the fact that most cards have one value, but the Ace card has two values. The `Values` structure defines two properties to represent this: + +* `first`, of type `Int` +* `second`, of type `Int?`, or “optional `Int`” + +如上所述,枚举类型`Rank`定义了一个内嵌的结构体`Values`。结构体`Values`通过定义两个属性描述了一个实事:大部分牌只有一个面值,而A牌有两个面值。属性如下: + +* `first`, `Int`型 +* `second`, `Int?`型,或者 “optional `Int`” + + +`Rank` also defines a computed property, `values`, which returns an instance of the `Values` structure. This computed property considers the rank of the card and initializes a new `Values` instance with appropriate values based on its rank. It uses special values for `Jack`, `Queen`, `King`, and `Ace`. For the numeric cards, it uses the rank’s raw `Int` value. + +`Rank`还定义了一个返回结构体`Values`实例的计算属性`values`。这个计算属性依据扑克牌的点数,初始化一个基于扑克牌点数推算出正确值的`Values`实例。计算属性`values`赋予J、Q、K和A这四张牌特定的值,赋予其他数字牌rank中定义的原始整型值(raw `Int`)。 + +The `BlackjackCard` structure itself has two properties—`rank` and `suit`. It also defines a computed property called `description`, which uses the values stored in `rank` and `suit` to build a description of the name and value of the card. The `description` property uses optional binding to check whether there is a second value to display, and if so, inserts additional description detail for that second value. + +结构体`BlackjackCard`定义了两个属性`rank`和`suit`,同时还定义了一个计算属性`description`,这个计算属性使用了`rank`和`suit`中存储的值来描述扑克牌的花色和点数。`description`使用可选绑定(optional binding)来判断是否存在第二个值,如果存在,则为第二个值插入额外的描述。 + +Because `BlackjackCard` is a structure with no custom initializers, it has an implicit memberwise initializer, as described in [Memberwise Initializers for Structure Types](). You can use this initializer to initialize a new constant called `theAceOfSpades`: + +因为结构体`BlackjackCard`没有自定义构造方法,所以它有一个默认的成员式构造方法(memberwise initializer),正如[《结构类型的成员式构造方法》]()所描述的。我们可以使用这个构造方法创建一个新的常量(constant)`theAceOfSpades`: + +``` +let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades) +println("theAceOfSpades: \(theAceOfSpades.description)") +// prints "theAceOfSpades: suit is ♠, value is 1 or 11 + +``` + +``` +let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades) +println("theAceOfSpades: \(theAceOfSpades.description)") +// 输出 "theAceOfSpades: suit is ♠, value is 1 or 11 + +``` + +Even though `Rank` and `Suit` are nested within `BlackjackCard`, their type can be inferred from context, and so the initialization of this instance is able to refer to the enumeration members by their member names (`.Ace` and `.Spades`) alone. In the example above, the `description` property correctly reports that the Ace of Spades has a value of `1` or `11`. + +即使`Rank`和`Suit`被嵌套在`BlackjackCard`里,他们依然可以被~~更外层的~~上下文引用。所以构造`BlackjackCard`实例时,可以仅通过成员名称(`.Ace` 和 `.Spades`)来引用枚举类型的成员。上面的例子中,属性`description`如我们所愿,输出了黑桃A的值`1`或`11`。 + +##Referring to Nested Types +##引用嵌套类型 + +To use a nested type outside of its definition context, prefix its name with the name of the type it is nested within: + +外部引用嵌套类型时,仅需在其名称前加上外层类型的名称即可: + +``` +let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw() +// heartsSymbol is "♡" +``` + +For the example above, this enables the names of `Suit`, `Rank`, and `Values` to be kept deliberately short, because their names are naturally qualified by the context in which they are defined. + +正如上例所示,嵌套类型的引用方式可以使`Suit`、`Rank`和`Values`的名字尽可能的简短,因为他们的名字会自然地被所定义的上下文限制。 + From 01919ac913860f3c4add146780ce5d12c6c78cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Qi=20Tao=20=28=E7=A5=81=E6=B6=9B=29?= Date: Fri, 20 Jun 2014 09:32:09 +0800 Subject: [PATCH 126/261] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改进度 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b5fd9a..4f79d21 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ The Swift Programming Language 中文化项目 * 自动引用计数 * 可选链 * 类型检查 - * 嵌套类型 + * 嵌套类型 [已完成 by 导演] * 扩展 * 接口 * 泛型 From feaa14af2c28e08df9d6124afb84a2d87fad25d8 Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Fri, 20 Jun 2014 09:56:44 +0800 Subject: [PATCH 127/261] Update 06_Functions.md commit --- src/chapter2/06_Functions.md | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/chapter2/06_Functions.md b/src/chapter2/06_Functions.md index e69de29..f3b459c 100644 --- a/src/chapter2/06_Functions.md +++ b/src/chapter2/06_Functions.md @@ -0,0 +1,80 @@ +# Functions +# 函数 + +Functions are self-contained chunks of code that perform a specific task. You give a function a name that identifies what it does, and this name is used to “call” the function to perform its task when needed. + +函数是执行特定任务的独立代码块。你可以给函数起一个名字来标识它的功能,并在需要时使用这个名字来“调用”该函数执行任务。 + +Swift’s unified function syntax is flexible enough to express anything from a simple C-style function with no parameter names to a complex Objective-C-style method with local and external parameter names for each parameter. Parameters can provide default values to simplify function calls and can be passed as in-out parameters, which modify a passed variable once the function has completed its execution. + +Swift的统一标准函数语法足够灵活来表达一切,从简单的无参数名的C风格函数到复杂的每个参数都有本地和外部参数名的Objective-C风格方法。可以为参数提供默认值来简化函数调用,也可以为参数传入in-out参数,一旦函数完成执行,传入的变量会被修改。 + +Every function in Swift has a type, consisting of the function’s parameter types and return type. You can use this type like any other type in Swift, which makes it easy to pass functions as parameters to other functions, and to return functions from functions. Functions can also be written within other functions to encapsulate useful functionality within a nested function scope. + +Swift的每个函数都有类型,包含函数参数类型和返回类型。你可以像swift中任何其他类型那样使用,这让函数作为参数传递给其他函数,和从函数返回函数变得十分容易。函数也可以定义在另一个函数中, 在嵌套函数范围内,封装特定功能。 + +Defining and Calling Functions + +定义和调用函数 + +When you define a function, you can optionally define one or more named, typed values that the function takes as input (known as parameters), and/or a type of value that the function will pass back as output when it is done (known as its return type). + +定义函数时,你可以为其定义一个或多个具有名称、类型的值作为输入(称为参数),和/或该函数执行完毕后传回的一个有类型的值作为输出(称为返回值)。 + +Every function has a function name, which describes the task that the function performs. To use a function, you “call” that function with its name and pass it input values (known as arguments) that match the types of the function’s parameters. A function’s arguments must always be provided in the same order as the function’s parameter list. + +每个函数都有一个函数名用来描述此函数运行的任务。使用函数时,通过函数名并传入符合函数参数类型的输入值(称为参数)来“调用”函数。必须按照函数参数列表相同的顺序提供函数参数。 + +The function in the example below is called greetingForPerson, because that’s what it does—it takes a person’s name as input and returns a greeting for that person. To accomplish this, you define one input parameter—a String value called personName—and a return type of String, which will contain a greeting for that person: + +下面例子中的函数叫做sayHello,因为这就是它的功能——它以人名作为输入,并返回对这个人的问候(greeting)。为了实现这一点,需要定义一个输入参数——一个名为personName的字符串值,和一个字符串类型的返回值带有对此人的问候。 + +```js +func sayHello(personName: String) -> String { + let greeting = "Hello, " + personName + "!" + return greeting +} +``` + +All of this information is rolled up into the function’s definition, which is prefixed with the func keyword. You indicate the function’s return type with the return arrow -> (a hyphen followed by a right angle bracket), which is followed by the name of the type to return. + +所有这些信息构成了一个函数的定义,并以 func 关键字作为前缀。使用返回箭头->(连字符后跟一个右尖括号)和紧接着的返回类型名来声明函数的返回类型。 + +The definition describes what the function does, what it expects to receive, and what it returns when it is done. The definition makes it easy for the function to be called elsewhere in your code in a clear and unambiguous way: + +函数定义描述这个函数是做什么的,期望接收什么和运行结束后返回什么。这个定义使得在代码中任何地方用清晰明白的方式调用函数变得容易。 + +```js + +println(sayHello("Anna")) +// prints "Hello, Anna!" +println(sayHello("Brian")) +// prints "Hello, Brian!” +``` + +You call the sayHello function by passing it a String argument value in parentheses, such as sayHello("Anna"). Because the function returns a String value, sayHello can be wrapped in a call to the println function to print that string and see its return value, as shown above. + +通过在括号中传入一个字符串参数值来调用sayHello函数,如sayHello(“Anna”)。由于函数返回了一个字符串类型的值,sayHello可以包装在 println 函数中,用来打印这个字符串并查看它的返回值,如上所示。 + +The body of the sayHello function starts by defining a new String constant called greeting and setting it to a simple greeting message for personName. This greeting is then passed back out of the function using the return keyword. As soon as return greeting is called, the function finishes its execution and returns the current value of greeting. + +sayHello 函数的主体始于定义一个名为 greeting 的字符串常量,并为它设置对personName的简单问候信息。然后通过 return 关键字把 greeting 传出函数。一旦执行了 return greeting,函数结束执行并返回当前的greeting值。 + +You can call the sayHello function multiple times with different input values. The example above shows what happens if it is called with an input value of "Anna", and an input value of "Brian". The function returns a tailored greeting in each case. + +你可以传入不同的输入值多次调用 sayHello 函数。上述例子展示了输入值为“Anna”和“Brian”时发生了什么。每个例子中函数返回了定制的greeting。 + +To simplify the body of this function, combine the message creation and the return statement into one line: + +为了简化函数体,可以把消息创建和返回语句合并为一行: + +```js +func sayHelloAgain(personName: String) -> String { + return "Hello again, " + personName + "!" +} +println(sayHelloAgain("Anna")) +// prints "Hello again, Anna!” +``` + +Function Parameters and Return Values +函数参数和返回值 From 41583639a70178c9603b31a9969e5aacf5e90252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82?= Date: Fri, 20 Jun 2014 10:27:22 +0800 Subject: [PATCH 128/261] Update 18_Type_Casting.md --- src/chapter2/18_Type_Casting.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index ba73e26..384d367 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -7,11 +7,11 @@ Type casting in Swift is implemented with the is and as operators. These two ope You can also use type casting to check whether a type conforms to a protocol, as described in Checking for Protocol Conformance. # 类型检查 -类型检查是检查实例类型的方法,并且可以用来类型转换,就好像它是一个不同的超类或子类从别的在自己的类层次结构中的某个地方。 +类型检查是检查实例类型的方法,并且可以用来类型转换,可以让实例找到自己所在的继承树,以及在继承树中上下转换类型。 类型检查使用`is`和`as`操作符来实现。这两个操作符提供了一种简单明了的方式来进行类型检查和类型转换。 -你还可以使用类型检查来检查类型是否符合接口,以及是否和接口描述保持一致。 +你还可以使用类型检查来检查类型是否符合接口,以及是否和接口描述保持一致 ,就像[Checking for Protocol Conformance](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_363)描述的那样。 ##Defining a Class Hierarchy for Type Casting @@ -19,11 +19,11 @@ You can use type casting with a hierarchy of classes and subclasses to check the The first snippet defines a new base class called MediaItem. This class provides basic functionality for any kind of item that appears in a digital media library. Specifically, it declares a name property of type String, and an init name initializer. (It is assumed that all media items, including all movies and songs, will have a name.) -## 定义一个类继承为类型转换 +## 为类型检查定义一个继承树 -您可以使用类型转换与类和子类的层次结构来检查一个特定的类实例的类型和投该实例到另一个类中的同一层级内。下面的三个代码片段定义的类层次结构和包含这些类的实例数组,用于类型转换的一个例子使用。 +你可以使用类型检查来检查一个实例的具体类型,也可以把实例转化为继承树中的另一种类型。下面的三个代码片段定义的类层次结构和包含这些类的实例数组,作为类型转换的一个例子使用。 -第一个片段定义了一个名为`MediaItem`新的基类。这个类提供基本功能,任何类型的项目出现在一个数字媒体库。具体来说,它声明一个`String`类型的`name`属性,以及一个`init`名称初始值设定项。 (假设所有的媒体项目,包括所有的电影和歌曲,将有一个名称。) +第一个片段定义了一个名为`MediaItem`新的基类。这个类提供基本功能。具体来说,它声明一个`String`类型的`name`属性,以及一个`init`名称初始值设定项。 (假设所有的媒体项目,包括所有的电影和歌曲,将有一个名称。) class MediaItem { var name: String From 05b17193f5f97b6f80f447490f575e0f19ab3a06 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Fri, 20 Jun 2014 10:28:08 +0800 Subject: [PATCH 129/261] =?UTF-8?q?=E5=8F=88=E7=BF=BB=E8=AF=91=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=BA=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/09_Classes_and_Structures.md | 28 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index 467b6fa..b98214e 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -417,24 +417,44 @@ As a general guideline, consider creating a structure when one or more of these Examples of good candidates for structures include: +适合使用结构体的场景: +* The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double. +* A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int. +* A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double. -The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double. -A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int. -A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double. In all other cases, define a class, and create instances of that class to be managed and passed by reference. In practice, this means that most custom data constructs should be classes, not structures. +* 用来描述几何图形的尺寸,包含了浮点类型的宽和高两个属性。 +* 用来描述一个范围,包含一个整型开始值和一个整型长度。 +* 用来描述一个三维坐标系统,包含双精度的x,y和z三个属性。 + +所有其他情况请定义类并使用类的实例以引用方式传递。实际上大多数情况还是应该用类来作为主要的数据结构承载,结构体仅在必要时。 + ## Assignment and Copy Behavior for Collection Types +## 集合的赋值与拷贝 + Swift’s Array and Dictionary types are implemented as structures. However, arrays have slightly different copying behavior from dictionaries and other structures when they are assigned to a constant or variable, and when they are passed to a function or method. +在Swift中Array和Dictionary类型都是使用结构体实现的。然而当Array被赋值给常量、变量或者当作参数传入一个方法或者函数中时拷贝操作与Dictionary和其他结构体略有不同。 + The behavior described for Array and Dictionary below is different again from the behavior of NSArray and NSDictionary in Foundation, which are implemented as classes, not structures. NSArray and NSDictionary instances are always assigned and passed around as a reference to an existing instance, rather than as a copy. +以下Array和Dictionary与Foundation框架中的NSArray和NSDictionary的实现方式是有去别的,后者使用类实现,其实例在传递过程中均以引用形式进行传递而不是拷贝。 + > NOTE > > The descriptions below refer to the “copying” of arrays, dictionaries, strings, and other values. Where copying is mentioned, the behavior you see in your code will always be as if a copy took place. However, Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so. Swift manages all value copying to ensure optimal performance, and you should not avoid assignment to try to preempt this optimization. +> 提示 +> +> 以下是对于数组,字典,字符串和其它值的拷贝的描述。 在你的代码中出现拷贝引用的地方便会一直时拷贝引用。然而,Swift只在确实有必要发生拷贝行为的场景下才回执行拷贝操作。为了性能的最优,Swift将会在最合适的实际进行拷贝操作,以达到性能最优的目的,而开发者不关心这方面的性能问题也没关系。 + ### Assignment and Copy Behavior for Dictionaries -### Assignment and Copy Behavior for Arrays +### Dictionary的赋值与拷贝 + +Whenever you assign a Dictionary instance to a constant or variable, or pass a Dictionary instance as an argument to a function or method call, the dictionary is copied at the point that the assignment or call takes place. This process is described in Structures and Enumerations Are Value Types. +只要将一个Dictionary实例进行赋值或者传参操作,就会产生拷贝行为,在[结构体和枚举都是值类型](#)小节中有详细描述过。 From aad7f2974f55a48dd7f108aa6b3734142a5193fb Mon Sep 17 00:00:00 2001 From: rainoxu Date: Fri, 20 Jun 2014 10:59:24 +0800 Subject: [PATCH 130/261] =?UTF-8?q?=E9=98=B6=E6=AE=B5=E6=80=A7=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../09_Generic_Parameters_and_Arguments.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/chapter3/09_Generic_Parameters_and_Arguments.md b/src/chapter3/09_Generic_Parameters_and_Arguments.md index ce52195..35d65f8 100644 --- a/src/chapter3/09_Generic_Parameters_and_Arguments.md +++ b/src/chapter3/09_Generic_Parameters_and_Arguments.md @@ -110,7 +110,7 @@ A generic argument clause specifies the type arguments of a generic type. A gene The generic argument list is a comma-separated list of type arguments. A type argument is the name of an actual concrete type that replaces a corresponding type parameter in the generic parameter clause of a generic type. The result is a specialized version of that generic type. As an example, the Swift standard library defines a generic dictionary type as: -泛型实参列表是由一组逗号分隔组成的类型实参 +泛型实参列表是由一组逗号分隔组成的类型实参组成。类型实参是泛型参数句式中替换对应类型形参的具体实参的名称。由此得到此泛型类形的一个特定配置。比如,Swift标准库定义泛型字典类型是这样实现的: ``` struct Dictionary: Collection, DictionaryLiteralConvertible { @@ -118,9 +118,22 @@ struct Dictionary: Collection, DictionaryLiteralCo } ``` +The specialized version of the generic Dictionary type, Dictionary is formed by replacing the generic parameters KeyType: Hashable and ValueType with the concrete type arguments String and Int. Each type argument must satisfy all the constraints of the generic parameter it replaces, including any additional requirements specified in a where clause. In the example above, the KeyType type parameter is constrained to conform to the Hashable protocol and therefore String must also conform to the Hashable protocol. +You can also replace a type parameter with a type argument that is itself a specialized version of a generic type (provided it satisfies the appropriate constraints and requirements). For example, you can replace the type parameter T in Array with a specialized version of an array, Array, to form an array whose elements are themselves arrays of integers. +``` +let arrayOfArrays: Array> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +``` + +As mentioned in Generic Parameter Clause, you don’t use a generic argument clause to specify the type arguments of a generic function or initializer. + +> **GRAMMAR OF A GENERIC ARGUMENT CLAUSE** + +> generic-argument-clause → <­generic-argument-list­>­ +> generic-argument-list → generic-argument­ generic-argument­,­generic-argument-list­ +> generic-argument → type­ From 7b8c3a3c743ea5bb5ee44c86a97291e714127914 Mon Sep 17 00:00:00 2001 From: Neekey Date: Fri, 20 Jun 2014 11:13:18 +0800 Subject: [PATCH 131/261] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E5=90=8D=E8=AF=8D=E5=88=97=E8=A1=A8=EF=BC=8C=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E6=9C=89=E7=96=91=E9=97=AE=E7=9A=84=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/words.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/words.md b/src/words.md index cb4ca6e..0eea62e 100644 --- a/src/words.md +++ b/src/words.md @@ -1 +1,12 @@ -Class - 类 - Classes, structures, and enumerations can define subscripts \ No newline at end of file +- Class - 类 - Classes, structures, and enumerations can define subscripts +- attribute - 特性 +- property - 属性 +- initializer - 构造函数?(和Constructor怎么区分?) +- designated initializer - 预设构造函数 +- convenience initializer - 便利构造函数 +- argument - 参数(实际参数) +- parameter - 参数(形式参数) --> argument 和 parameter 的区别参考[这篇文章](http://www.blogjava.net/flysky19/articles/89963.html) +- overload 重载 +- override 覆盖 +- adopt - ?一般说 a class adopted a protocol +- conform - adopt 和 conform 都和protocal有关,看句子`only class types can adopt and conform to a protocol`,这里两个词的区别比较难翻译 From 068a11fe8861ee1df88a2c75930083cff2b92664 Mon Sep 17 00:00:00 2001 From: Neekey Date: Fri, 20 Jun 2014 11:14:41 +0800 Subject: [PATCH 132/261] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=8B=E6=A0=87?= =?UTF-8?q?=E8=84=9A=E6=9C=AC=E4=B8=BA=E4=B8=8B=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter3/07_Attributes.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chapter3/07_Attributes.md b/src/chapter3/07_Attributes.md index 1a0e319..b285b60 100644 --- a/src/chapter3/07_Attributes.md +++ b/src/chapter3/07_Attributes.md @@ -58,7 +58,7 @@ You can apply a declaration attribute to declarations only. However, you can als > Apply this attribute to a class or to a property, method, or subscript member of a class. It’s applied to a class to indicate that the class can’t be subclassed. It’s applied to a property, method, or subscript of a class to indicate that that class member can’t be overridden in any subclass. `final` -> 这个特性用于描述类或者类的属性、方法、或者下标脚本上。如若一个类具有该特性,则表明这个类不能被继承。如果一个类的属性、方法或者下标脚本具有该特性,则表明这个类的成员不能被任何子类覆盖。 +> 这个特性用于描述类或者类的属性、方法、或者下标上。如若一个类具有该特性,则表明这个类不能被继承。如果一个类的属性、方法或者下标具有该特性,则表明这个类的成员不能被任何子类覆盖。 `lazy` > Apply this attribute to a stored variable property of a class or structure to indicate that the property’s initial value is calculated and stored at most once, when the property is first accessed. For an example of how to use the `lazy` attribute, see [Lazy Stored Properties](#). @@ -111,7 +111,7 @@ You can apply a declaration attribute to declarations only. However, you can als ``` `objc` -> 这个特性用于描述任何可以在Objective-C中表示的声明,如非嵌套类,协议,类和协议的属性和方法(包括getter和setter),构造函数,析构函数和下标脚本。`objc`特性告诉编译器该声明可以在Objective-C的代码中被使用。 +> 这个特性用于描述任何可以在Objective-C中表示的声明,如非嵌套类,协议,类和协议的属性和方法(包括getter和setter),构造函数,析构函数和下标。`objc`特性告诉编译器该声明可以在Objective-C的代码中被使用。 > 如果一个类或者协议具有`objc`特性,那么这个类或者协议的所有成员都将隐形地具有`objc`特性。编译器甚至会隐形地添加`objc`特性给具有`objc`特性的类的子类。被标记`objc`特性的协议不能继承没有被标记`objc`特性的协议。 @@ -135,7 +135,7 @@ You can apply a declaration attribute to declarations only. However, you can als `optional` -> 这个特性用于描述协议的属性,方法和下标脚本,以此来表明遵循了该协议的类型,只需要可选地实现这些被标记的成员。 +> 这个特性用于描述协议的属性,方法和下标,以此来表明遵循了该协议的类型,只需要可选地实现这些被标记的成员。 > 这个特性只能被用于描述具有`objc`特性的协议。也就是说,只有类才能接受和遵循一个具有optional特性成员的协议。更多关于如何使用`optional`特性,以及对于一个遵循了具有`optional`特性的协议的类型,在无法明确它实现了哪些可选成员的情况下,如何正确地读取其可选成员的问题,请参考[可选协议要求](#)。 From 6725649b6e63580bff38c67f1d1a34f4611b043a Mon Sep 17 00:00:00 2001 From: Neekey Date: Fri, 20 Jun 2014 11:29:53 +0800 Subject: [PATCH 133/261] =?UTF-8?q?=E4=BF=AE=E6=AD=A3adopt=E5=92=8Cconform?= =?UTF-8?q?=E7=9A=84=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/words.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/words.md b/src/words.md index 0eea62e..1c945e5 100644 --- a/src/words.md +++ b/src/words.md @@ -8,5 +8,5 @@ - parameter - 参数(形式参数) --> argument 和 parameter 的区别参考[这篇文章](http://www.blogjava.net/flysky19/articles/89963.html) - overload 重载 - override 覆盖 -- adopt - ?一般说 a class adopted a protocol -- conform - adopt 和 conform 都和protocal有关,看句子`only class types can adopt and conform to a protocol`,这里两个词的区别比较难翻译 +- adopt - 适配。但是一般用于被动。如 `a protocol can be adopted by a class`: 协议可以被类适配。 +- conform - 遵循。如果一个类适配了一个协议,我们就说这个类遵循这个协议。`this class conforms to that protocol`。 From 380715d076d224e61edb22c9035dcd06cadf8ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=8E=89=E6=9E=97=28=E9=A3=9E=E9=95=BF=29?= Date: Fri, 20 Jun 2014 11:30:13 +0800 Subject: [PATCH 134/261] Update 10_Summary_of_the_Grammar.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 代替无独提交 --- src/chapter3/10_Summary_of_the_Grammar.md | 844 ++++++++++++++++++++++ 1 file changed, 844 insertions(+) diff --git a/src/chapter3/10_Summary_of_the_Grammar.md b/src/chapter3/10_Summary_of_the_Grammar.md index e69de29..7736c87 100644 --- a/src/chapter3/10_Summary_of_the_Grammar.md +++ b/src/chapter3/10_Summary_of_the_Grammar.md @@ -0,0 +1,844 @@ +#语法总结 + +##语句 + +###语句语法 +语句→表达式;可选 + +语句→声明;可选 + +语句→循环语句;可选 + +语句→分支语句;可选 + +语句→标记语句;可选 + +语句→控制转移语句;可选 + +多条语句→语句 多条语句;可选 + +###循环语句语法 +循环语句 → for语句 +循环语句 → for in 语句 +循环语句 → while 语句 +循环语句 → do-while 语句 + +###for 语句语法 +for语句 → for 初始条件 可选; 表达式 可选 ;表达式 可选 代码块 + +for语句 → for ( 初始条件 可选; 表达式 可选 ;表达式 可选 ) 代码块 + +for 初始条件 → 变量声明 | 表达式列表 + +###for-in 语句语法 +for-in 语句 → for 模式 in 表达式代码块 + +###while 语句语法 +while语句 → while while条件代码块 + +while条件 →表达式 | 声明 + +###do-while 语句语法 +do-while语句 → do 代码块 while while条件 + +###分支语句语法 + +分支语句 → if语句 + +分支语句 → switch语句 + +###if 语句语法 +if语句 → if if条件 代码块 else 子句 可选 + +if条件 → 表达式 | 什么 + +else子句 → else 代码块 | else if语句 + +###switch语句语法 +switch语句 → switch 表达式 { switch-case列表 可选 } + +switch-case列表 → switch-case 列表 可选 + +switch-case → case标签 多条语句 | default标签 多条语句 + +switch-case → case标签 ; | default标签 ; + +case标签 → case case项列表 : + +case项列表 → 模式 guard-clause 可选 | 模式 guard-clause 可选 , case项列表 + +default标签 → default : + +guard-clause → where guard-expression + +guard-expression → 表达式 + +###标记语句语法 +标记语句 → 语句标签 循环语句 | 语句标签 switch语句 + +语句标签 → 标签名称 : + +标签名称 → 标识符 + +###控制传递语句语法 +控制传递语句 → break语句 + +控制传递语句 → continue语句 + +控制传递语句 → fallthrough语句 + +控制传递语句 → return语句 + +####break 语句语法 +break语句 → break 标签名称 可选 + +####continue 语句语法 +continue语句 → continue 标签名称 可选 + +####fallthrough 语句语法 +fallthrough语句 → fallthrough + +####return 语句语法 +return语句 → return 表达式 可选 + +###泛型参数 +泛型形参子句语法 泛型参数子句 → < 泛型参数列表 约束子句 可选 > + +泛型参数列表 → 泛形参数 | 泛形参数 , 泛型参数列表 + +泛形参数 → 类型名称 + +泛形参数 → 类型名称 : 类型标识 + +泛形参数 → 类型名称 : 协议合成类型 + +约束子句 → where 约束列表 + +约束列表 → 约束 | 约束 , 约束列表 + +约束 → 一致性约束 | 同类型约束 + +一致性约束 → 类型标识 : 类型标识 + +一致性约束 → 类型标识 : 协议合成类型 + +同类型约束 → 类型标识 == 类型标识 + +###泛型参数子句语法 +泛型参数子句 → < 泛型参数列表 > + +泛型参数列表 → 泛型参数 | 泛型参数 , 泛型参数列表 + +泛型参数 → 类型 + +###声明 +声明语法 + +声明 → 导入声明 + +声明 → 常量声明 + +声明 → 变量声明 + +声明 → 类型别名声明 + +声明 → 函数声明 + +声明 → 枚举声明 + +声明 → 结构体声明 + +声明 → 类声明 + +声明 → 协议声明 + +声明 → 构造器声明 + +声明 → 析构器声明 + +声明 → 扩展声明 + +声明 → 下标脚本声明 + +声明 → 运算符声明 + +声明列表 → 声明 声明列表 可选 + +声明描述符列表 → 声明描述符 声明描述符列表 可选 + +声明描述符 → class | mutating | nonmutating | override | static | unowned | unowned(safe) | unowned(unsafe) | weak + +####顶级声明语法 +顶级声明 → 多条语句 可选 + +###代码块语法 +代码块 → { 多条语句 可选 } + +###导入声明语法 +导入声明 → 属性列表 可选 import 导入类型 可选 导入路径 + +导入类型 → typealias | struct | class | enum | protocol | var | func + +导入路径 → 导入路径标识符 | 导入路径标识符 . 导入路径 + +导入路径标识符 → 标识符 | 运算符 + +###常数声明语法 +常量声明 → 属性列表 可选 声明描述符(Specifiers)列表 可选 let 模式构造器列表 + +模式构造器列表 → 模式构造器 | 模式构造器 , 模式构造器列表 + +模式构造器 → 模式 构造器 可选 + +构造器 → = 表达式 + +###变量声明语法 +变量声明 → 变量声明头 模式构造器列表 + +变量声明 → 变量声明头 变量名 类型注解 代码块 + +变量声明 → 变量声明头 变量名 类型注解 getter-setter块 + +变量声明 → 变量声明头 变量名 类型注解 getter-setter关键字(Keyword)块 + +变量声明 → 变量声明头 变量名 类型注解 构造器 可选 willSet-didSet代码块 + +变量声明头 → 属性列表 可选 声明描述符列表 可选 var + +变量名称 → 标识符 + +getter-setter块 → { getter子句 setter子句 可选 } + +getter-setter块 → { setter子句 getter子句 } + +getter子句 → 属性列表 可选 get 代码块 + +setter子句 → 属性列表 可选 set setter名称 可选 代码块 + +setter名称 → ( 标识符 ) + +getter-setter关键字块 → { getter关键字子句 setter关键字子句 可选 } + +getter-setter关键字块 → { setter关键字子句 getter关键字子句 } + +getter关键字子句 → 属性列表 可选 get + +setter关键字子句 → 属性列表 可选 set + +willSet-didSet代码块 → { willSet子句 didSet子句 可选 } + +willSet-didSet代码块 → { didSet子句 willSet子句 } + +willSet子句 → 属性列表 可选 willSet setter名称 可选 代码块 + +didSet子句 → 属性列表 可选 didSet setter名称 可选 代码块 + +####类型别名声明语法 + +类型别名声明 → 类型别名头 类型别名赋值 + +类型别名头 → typealias 类型别名名称 + +类型别名名称 → 标识符 + +类型别名赋值 → = 类型 + +####函数声明语法 +函数声明 → 函数头 函数名 泛型参数子句 可选 函数签名 函数体 + +函数头 → 属性列表 可选 声明描述符列表 可选 func + +函数名 → 标识符 | 运算符 + +函数签名 → parameter-clauses 函数结果 可选 + +函数结果 → → 属性列表 可选 类型 + +函数体 → 代码块 + +parameter-clauses → 参数子句 parameter-clauses 可选 + +参数子句 → ( ) | ( 参数列表 ... 可选 ) + +参数列表 → 参数 | 参数 , 参数列表 + +参数 → inout 可选 let 可选 # 可选 参数名 局部参数名 可选 类型注解 默认参数子句 可选 + +参数 → inout 可选 var # 可选 参数名 局部参数名 可选 类型注解 默认参数子句 可选 + +参数 → 属性列表 可选 类型 + +参数名 → 标识符 | _ + +局部参数名 → 标识符 | _ + +默认参数子句 → = 表达式 + +###枚举声明语法 +枚举声明 → 属性列表 可选 联合式枚举 | 属性列表 可选 原始值式枚举 + +联合式枚举 → 枚举名 泛型参数子句 可选 { union-style-enum-members 可选 } + +union-style-enum-members → union-style-enum-member union-style-enum-members 可选 + +union-style-enum-member → 声明 | 联合式(Union Style)的枚举case子句 + +联合式(Union Style)的枚举case子句 → 属性列表 可选 case 联合式(Union Style)的枚举case列表 + +联合式(Union Style)的枚举case列表 → 联合式(Union Style)的case | 联合式(Union Style)的case , 联合式(Union Style)的枚举case列表 + +联合式(Union Style)的case → 枚举的case名 元组类型 可选 + +枚举名 → 标识符 + +枚举的case名 → 标识符 + +原始值式枚举 → 枚举名 泛型参数子句 可选 : 类型标识 { 原始值式枚举成员列表 可选 } + +原始值式枚举成员列表 → 原始值式枚举成员 原始值式枚举成员列表 可选 + +原始值式枚举成员 → 声明 | 原始值式枚举case子句 + +原始值式枚举case子句 → 属性列表 可选 case 原始值式枚举case列表 + +原始值式枚举case列表 → 原始值式枚举case | 原始值式枚举case , 原始值式枚举case列表 + +原始值式枚举case → 枚举的case名 原始值赋值 可选 + +原始值赋值 → = 字面量 + +####结构体声明语法 +结构体声明 → 属性列表 可选 struct 结构体名称 泛型参数子句 可选 类型继承子句 可选 结构体主体 + +结构体名称 → 标识符 + +结构体主体 → { 声明列表 可选 } + +####类声明语法 +类声明 → 属性列表 可选 class 类名 泛型参数子句 可选 类型继承子句 可选 类主体 + +类名 → 标识符 + +类主体 → { 声明列表 可选 } + +####协议声明语法 +协议声明 → 属性列表 可选 protocol 协议名 类型继承子句 可选 协议主体 + +协议名 → 标识符 + +协议主体 → { 协议成员声明列表 可选 } + +协议成员声明 → 协议属性声明 + +协议成员声明 → 协议方法声明 + +协议成员声明 → 协议构造器声明 + +协议成员声明 → 协议下标脚本声明 + +协议成员声明 → 协议关联类型声明 + +协议成员声明列表 → 协议成员声明 协议成员声明(Declarations)列表 可选 + +####协议属性声明语法 +协议属性声明 → 变量声明头 变量名 类型注解 getter-setter关键字(Keyword)块 + +####协议方法声明语法 +协议方法声明 → 函数头 函数名 泛型参数子句 可选 函数签名(Signature) + +####协议构造器声明语法 +协议构造器声明 → 构造器头 泛型参数子句 可选 参数子句 + +####协议下标脚本声明语法 +协议下标脚本声明 → 下标脚本头 下标脚本结果(Result) getter-setter关键字(Keyword)块 + +####协议关联类型声明语法 +协议关联类型声明 → 类型别名头 类型继承子句 可选 类型别名赋值 可选 + +####构造器声明语法 + +构造器声明 → 构造器头 泛型参数子句 可选 参数子句 构造器主体 + +构造器头 → 属性列表 可选 convenience 可选 init + +构造器主体 → 代码块 + +####析构器声明语法 + +析构器声明 → 属性列表 可选 deinit 代码块 + +####扩展声明语法 +扩展声明 → extension 类型标识 类型继承子句 可选 extension-主体 + +extension-主体 → { 声明列表 可选 } + +####下标脚本声明语法 +下标脚本声明 → 下标脚本头 下标脚本结果 代码块 + +下标脚本声明 → 下标脚本头 下标脚本结果 getter-setter块 + +下标脚本声明 → 下标脚本头 下标脚本结果 getter-setter关键字块 + +下标脚本头 → 属性列表 可选 subscript 参数子句 + +下标脚本结果 → → 属性列表 可选 类型 + +####运算符声明语法 +运算符声明 → 前置运算符声明 | 后置运算符声明 | 中置运算符声明 + +前置运算符声明 → 运算符 prefix 运算符 { } + +后置运算符声明 → 运算符 postfix 运算符 { } + +中置运算符声明 → 运算符 infix 运算符 { 中置运算符属性 可选 } + +中置运算符属性 → 优先级子句 可选 结和性子句 可选 + +优先级子句 → precedence 优先级水平 + +优先级水平 → 数值 0 到 255 + +结和性子句 → associativity 结和性 + +结和性 → left | right | none + +###模式 +模式语法 + +模式 → 通配符模式 类型注解 可选 + +模式 → 标识符模式 类型注解 可选 + +模式 → 值绑定模式 + +模式 → 元组模式 类型注解 可选 + +模式 → 枚举用例模式 + +模式 → 类型转换模式 + +模式 → 表达式模式 + +####通配符模式语法 + +通配符模式 → _ + +###标识符模式语法 +标识符模式 → 标识符 + +####值绑定模式语法 + +值绑定模式 → var 模式 | let 模式 + +####元组模式语法 +元组模式 → ( 元组模式元素列表 可选 ) + +元组模式元素列表 → 元组模式元素 | 元组模式元素 , 元组模式元素列表 + +元组模式元素 → 模式 + +####枚举用例模式语法 + +枚举用例模式 → 类型标识 可选 . 枚举的case名 元组模式 可选 + +####类型转换模式语法 +类型转换模式 → is模式 | as模式 + +is模式 → is 类型 + +as模式 → 模式 as 类型 + +####表达式模式语法 +表达式模式 → 表达式 + +###属性 +####特性语法 +属性 → @ 属性名 属性参数子句 可选 + +属性名 → 标识符 + +属性参数子句 → ( 平衡令牌列表 可选 ) + +属性列表 → 属性 属性列表 可选 + +平衡令牌列表 → 平衡令牌 平衡令牌列表 可选 + +平衡令牌 → ( 平衡令牌列表 可选 ) + +平衡令牌 → [ 平衡令牌列表 可选 ] + +平衡令牌 → { 平衡令牌列表 可选 } + +平衡令牌 → 任意标识符, 关键字, 字面量或运算符 + +平衡令牌 → 任意标点除了(, ), [, ], {, 或 } + +###表达式 +####表达式语法 +表达式 → 前置表达式 二元表达式列表 可选 + +表达式列表 → 表达式 | 表达式 , 表达式列表 + +####前置表达式语法 +前置表达式 → 前置运算符 可选 后置表达式 + +前置表达式 → 写入写出表达式 + +写入写出表达式 → & 标识符 + +####二元表达式语法 +二元表达式 → 二元运算符 前置表达式 + +二元表达式 → 赋值运算符 前置表达式 + +二元表达式 → 条件运算符 前置表达式 + +二元表达式 → 类型转换运算符 + +二元表达式列表 → 二元表达式 二元表达式列表 可选 + +####赋值运算符语法 +赋值运算符 → = + +####三元条件运算符语法 +三元条件运算符 → ? 表达式 : + +####类型转换运算符语法 +类型转换运算符 → is 类型 | as ? 可选 类型 + +####主表达式语法 +主表达式 → 标识符 泛型参数子句 可选 + +主表达式 → 字面量表达式 + +主表达式 → self表达式 + +主表达式 → 超类表达式 + +主表达式 → 闭包表达式 + +主表达式 → 圆括号表达式 + +主表达式 → 隐式成员表达式 + +主表达式 → 通配符表达式 + +####字面量表达式语法 +字面量表达式 → 字面量 + +字面量表达式 → 数组字面量 | 字典字面量 + +字面量表达式 → __FILE__ | __LINE__ | __COLUMN__ | __FUNCTION__ + +数组字面量 → [ 数组字面量项列表 可选 ] + +数组字面量项列表 → 数组字面量项 , 可选 | 数组字面量项 , 数组字面量项列表 + +数组字面量项 → 表达式 + +字典字面量 → [ 字典字面量项列表 ] | [ : ] + +字典字面量项列表 → 字典字面量项 , 可选 | 字典字面量项 , 字典字面量项列表 + +字典字面量项 → 表达式 : 表达式 + +####Self 表达式语法 +self表达式 → self + +self表达式 → self . 标识符 + +self表达式 → self [ 表达式 ] + +self表达式 → self . init + +####超类表达式语法 +超类表达式 → 超类方法表达式 | 超类下标表达式 | 超类构造器表达式 + +超类方法表达式 → super . 标识符 + +超类下标表达式 → super [ 表达式 ] + +超类构造器表达式 → super . init + +####闭包表达式语法 + +闭包表达式 → { 闭包签名 可选 多条语句 } + +闭包签名 → 参数子句 函数结果 可选 in + +闭包签名 → 标识符列表 函数结果 可选 in + +闭包签名 → 捕获列表 参数子句 函数结果 可选 in + +闭包签名 → 捕获列表 标识符列表 函数结果 可选 in + +闭包签名 → 捕获列表 in + +捕获列表 → [ 捕获说明符 表达式 ] + +捕获说明符 → weak | unowned | unowned(safe) | unowned(unsafe) + +####隐式成员表达式语法 +隐式成员表达式 → . 标识符 + +圆括号表达式语法 + +圆括号表达式 → ( 表达式元素列表 可选 ) + +表达式元素列表 → 表达式元素 | 表达式元素 , 表达式元素列表 + +表达式元素 → 表达式 | 标识符 : 表达式 + +####通配符表达式语法 +通配符表达式 → _ + +后置表达式语法 + +后置表达式 → 主表达式 + +后置表达式 → 后置表达式 后置运算符 + +后置表达式 → 函数调用表达式 + +后置表达式 → 构造器表达式 + +后置表达式 → 显示成员表达式 + +后置表达式 → 后置self表达式 + +后置表达式 → 动态类型表达式 + +后置表达式 → 下标表达式 + +后置表达式 → 强制取值表达式 + +后置表达式 → 可选链表达式 + +####函数调用表达式语法 +函数调用表达式 → 后置表达式 圆括号表达式 + +函数调用表达式 → 后置表达式 圆括号表达式 可选 后置闭包 + +后置闭包 → 闭包表达式 + +####构造器表达式语法 +构造器表达式 → 后置表达式 . init + +####显式成员表达式语法 +显示成员表达式 → 后置表达式 . 十进制数字 + +显示成员表达式 → 后置表达式 . 标识符 泛型参数子句 可选 + +####后置Self 表达式语法 +后置self表达式 → 后置表达式 . self +####动态类型表达式语法 + +动态类型表达式 → 后置表达式 . dynamicType + +####附属脚本表达式语法 +附属脚本表达式 → 后置表达式 [ 表达式列表 ] + +强制取值语法 + +强制取值表达式 → 后置表达式 ! + +###可选链表达式语法 +可选链表达式 → 后置表达式 ? + +####词法结构 +标识符语法 + +标识符 → 标识符头 标识符字符列表 可选 + +标识符 → ` 标识符头 标识符字符列表 可选 ` + +标识符 → 隐式参数名 + +标识符列表 → 标识符 | 标识符 , 标识符列表 + +标识符头 → Upper- or lowercase letter A through Z + +标识符头 → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA + +标识符头 → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF + +标识符头 → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF + +标识符头 → U+1E00–U+1FFF + +标识符头 → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F + +标识符头 → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793 + +标识符头 → U+2C00–U+2DFF or U+2E80–U+2FFF + +标识符头 → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF + +标识符头 → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44 + +标识符头 → U+FE47–U+FFFD + +标识符头 → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD + +标识符头 → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD + +标识符头 → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD + +标识符头 → U+D0000–U+DFFFD or U+E0000–U+EFFFD + +标识符字符 → 数值 0 到 9 + +标识符字符 → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F + +标识符字符 → 标识符头 + +标识符字符列表 → 标识符字符 标识符字符列表 可选 + +隐式参数名 → $ 十进制数字列表 + +####字面量语法 +字面量 → 整型字面量 | 浮点数字面量 | 字符串字面量 + +####整型字面量语法 +整型字面量 → 二进制字面量 + +整型字面量 → 八进制字面量 + +整型字面量 → 十进制字面量 + +整型字面量 → 十六进制字面量 + +二进制字面量 → 0b 二进制数字 二进制字面量字符列表 可选 + +二进制数字 → 数值 0 到 1 + +二进制字面量字符 → 二进制数字 | _ + +二进制字面量字符列表 → 二进制字面量字符 二进制字面量字符列表 可选 + +八进制字面量 → 0o 八进字数字 八进制字符列表 可选 + +八进字数字 → 数值 0 到 7 + +八进制字符 → 八进字数字 | _ + +八进制字符列表 → 八进制字符 八进制字符列表 可选 + +十进制字面量 → 十进制数字 十进制字符列表 可选 + +十进制数字 → 数值 0 到 9 + +十进制数字列表 → 十进制数字 十进制数字列表 可选 + +十进制字符 → 十进制数字 | _ + +十进制字符列表 → 十进制字符 十进制字符列表 可选 + +十六进制字面量 → 0x 十六进制数字 十六进制字面量字符列表 可选 + +十六进制数字 → 数值 0 到 9, a through f, or A through F + +十六进制字符 → 十六进制数字 | _ + +十六进制字面量字符列表 → 十六进制字符 十六进制字面量字符列表 可选 + +####浮点型字面量语法 +浮点数字面量 → 十进制字面量 十进制分数 可选 十进制指数 可选 + +浮点数字面量 → 十六进制字面量 十六进制分数 可选 十六进制指数 + +十进制分数 → . 十进制字面量 + +十进制指数 → 浮点数e 正负号 可选 十进制字面量 + +十六进制分数 → . 十六进制字面量 可选 + +十六进制指数 → 浮点数p 正负号 可选 十六进制字面量 + +浮点数e → e | E + +浮点数p → p | P + +正负号 → + | - + +####字符型字面量语法 +字符串字面量 → " 引用文本 " + +引用文本 → 引用文本条目 引用文本 可选 + +引用文本条目 → 转义字符 + +引用文本条目 → ( 表达式 ) + +引用文本条目 → 除了"­, \­, U+000A, or U+000D的所有Unicode的字符 + +转义字符 → \0 | \ | \t | \n | \r | \" | \' + +转义字符 → \x 十六进制数字 十六进制数字 + +转义字符 → \u 十六进制数字 十六进制数字 十六进制数字 十六进制数字 + +转义字符 → \U 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 + +####运算符语法语法 + +运算符 → 运算符字符 运算符 可选 + +运算符字符 → / | = | - | + | ! | * | % | < | > | & | | | ^ | ~ | . + +二元运算符 → 运算符 + +前置运算符 → 运算符 + +后置运算符 → 运算符 + +###类型 +####类型语法 +类型 → 数组类型 | 函数类型 | 类型标识 | 元组类型 | 可选类型 | 隐式解析可选类型 | 协议合成类型 | 元型类型 + +####类型注解语法 + +类型注解 → : 属性列表 可选 类型 + +####类型标识语法 +类型标识 → 类型名称 泛型参数子句 可选 | 类型名称 泛型参数子句 可选 . 类型标识 + +类名 → 标识符 + +####元组类型语法 +元组类型 → ( 元组类型主体 可选 ) + +元组类型主体 → 元组类型的元素列表 ... 可选 + +元组类型的元素列表 → 元组类型的元素 | 元组类型的元素 , 元组类型的元素列表 + +元组类型的元素 → 属性列表 可选 inout 可选 类型 | inout 可选 元素名 类型注解 + +元素名 → 标识符 + +####函数类型语法 +函数类型 → 类型 → 类型 +####数组类型语法 +数组类型 → 类型 [ ] | 数组类型 [ ] +####可选类型语法 +可选类型 → 类型 ? + +隐式解析可选类型(Implicitly Unwrapped Optional Type)语法 + +隐式解析可选类型 → 类型 ! + +####协议合成类型语法 +协议合成类型 → protocol < 协议标识符列表 可选 > + +协议标识符列表 → 协议标识符 | 协议标识符 , 协议标识符列表 + +协议标识符 → 类型标识 + +####元类型语法 +元类型 → 类型 . Type | 类型 . Protocol + +####类型继承子句语法 +类型继承子句 → : 类型继承列表 + +类型继承列表 → 类型标识 | 类型标识 , 类型继承列表 + From f3565f040390d9af23d0208de513a5f165f78893 Mon Sep 17 00:00:00 2001 From: bingxi Date: Fri, 20 Jun 2014 11:31:01 +0800 Subject: [PATCH 135/261] =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E7=AC=A6=EF=BC=88=E8=BF=98=E6=B2=A1=E7=BF=BB=E8=AF=91=E5=AE=8C?= =?UTF-8?q?...=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/02_Basic_Operators.md | 74 ++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/chapter2/02_Basic_Operators.md b/src/chapter2/02_Basic_Operators.md index e69de29..fb08b76 100644 --- a/src/chapter2/02_Basic_Operators.md +++ b/src/chapter2/02_Basic_Operators.md @@ -0,0 +1,74 @@ +###基本运算符 + +运算符是用来检查,改变或者合并值的一种提别的符号或者短语。举个例子,加号(+)将2个数字相加(i=1+2).更多复杂的逻辑和运算&&和i++,它是便捷的让i+1的一种方式。 + +Swift 支持大部分标准 C 语言的运算符,且改进许多特性来减少常规编码错误。像等于号(=)不再返回一个值,以减少要判断相等运算符(==)的地方写成赋值符导致的错误。算术运算符(+,-,*,/,%等)会检测并不允许值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用 Swift 的溢出运算符来实现溢出。详情参见溢出运算符。 + +和c不同,Swift允许你对浮点数进行浮点运算,同时还提供C种没有的两数字区间的运算符(a..b 和a...b),以方便我们表达区间内的数值。 + +本章节只描述了 Swift 中的基本运算符,高级运算符包含了高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。 + +###术语 + +运算符有一元,二元,三元。 + +* 一元运算符是对单一操作对象的操作(如-a).一元运算符的前元算符出现在操作对象的前面(如!b),后运算符则出现在操作对象的后面(如i++). +* 二元运算符是对两个操作对象的操作,同时它出现在2个操作对象之间(如2+3) +* 三元运算符就是对三个对象的操作,和C一样,Swift 只有一个三元运算符,就是三元条件运算符(a ? b : c)。 + +受运算符影响的值叫操作数,在表达式1 + 2中,加号+是二元运算符,它的两个操作数是值1和2。 + +###赋值运算符 +赋值运算符(a = b),表示通过b来初始化或更新a; + + let b = 10 + var a = 5 + a = b + // a 现在等于 10 + +如果赋值的右边是一个多元组,它的元素可以马上被分解多个变量或变量: + + let (x, y) = (1, 2) + // 此时 x 等于 1, y 等于 2 + +与 C 语言和 Objective-C 不同,Swift 的赋值操作并不返回任何值。所以以下代码是错误的: + + if x = y { + // 这里是错误的, 因为 x = y 并不返回任何值 + } + +这个特性使你无法把(==)错写成(=),由于if x = y是错误代码,Swift 从底层帮你避免了这些错误代码。 + + +###数值运算 + +Swift 支持基本的四则运算: +* 加法(+) +* 减法(-) +* 乘法(*) +* 除法(/) + + 1 + 2 // 等于 3 + 5 - 3 // 等于 2 + 2 * 3 // 等于 6 + 10.0 / 2.5 // 等于 4.0 + +和C、Object-C不同的是,Swift 默认不允许在数值运算中出现溢出情况。但你可以使用 Swift 的溢出运算符来达到你有目的的溢出(如a &+ b)。详情参见溢出运算符。 + +加法运算符也可用于String的拼接: + + "hello, " + "world" // 等于 "hello, world" + +两个Character值或一个String和一个Character值,相加会生成一个新的String值: + + let dog: Character = "d" + let cow: Character = "c" + let dogCow = dog + cow + + // dogCow 现在是 "dc" + +详情参见字符,字符串的拼接。 + + +###求余运算 + From 0babb92d4c898dac4be76de8f6a7c7c79cdc3fab Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Fri, 20 Jun 2014 13:39:55 +0800 Subject: [PATCH 136/261] Update 06_Functions.md --- src/chapter2/06_Functions.md | 717 ++++++++++++++++++++++++++++++++++- 1 file changed, 709 insertions(+), 8 deletions(-) diff --git a/src/chapter2/06_Functions.md b/src/chapter2/06_Functions.md index f3b459c..b8b72ad 100644 --- a/src/chapter2/06_Functions.md +++ b/src/chapter2/06_Functions.md @@ -1,5 +1,4 @@ -# Functions -# 函数 +# Functions 函数 Functions are self-contained chunks of code that perform a specific task. You give a function a name that identifies what it does, and this name is used to “call” the function to perform its task when needed. @@ -13,9 +12,7 @@ Every function in Swift has a type, consisting of the function’s parameter typ Swift的每个函数都有类型,包含函数参数类型和返回类型。你可以像swift中任何其他类型那样使用,这让函数作为参数传递给其他函数,和从函数返回函数变得十分容易。函数也可以定义在另一个函数中, 在嵌套函数范围内,封装特定功能。 -Defining and Calling Functions - -定义和调用函数 +# Defining and Calling Functions 定义和调用函数 When you define a function, you can optionally define one or more named, typed values that the function takes as input (known as parameters), and/or a type of value that the function will pass back as output when it is done (known as its return type). @@ -45,7 +42,6 @@ The definition describes what the function does, what it expects to receive, and 函数定义描述这个函数是做什么的,期望接收什么和运行结束后返回什么。这个定义使得在代码中任何地方用清晰明白的方式调用函数变得容易。 ```js - println(sayHello("Anna")) // prints "Hello, Anna!" println(sayHello("Brian")) @@ -76,5 +72,710 @@ println(sayHelloAgain("Anna")) // prints "Hello again, Anna!” ``` -Function Parameters and Return Values -函数参数和返回值 +# Function Parameters and Return Values 函数参数和返回值 + + +Function parameters and return values are extremely flexible in Swift. You can define anything from a simple utility function with a single unnamed parameter to a complex function with expressive parameter names and different parameter options. + +Swift 中的函数参数和返回值都十分灵活。你可以定义任何函数,从单个未命名参数的简单工具函数到 具有表达性参数名和不同参数选项的复杂函数。 + +## Multiple Input Parameters 多个输入参数 + +Functions can have multiple input parameters, which are written within the function’s parentheses, separated by commas. + +函数可以有多个输入参数,写在函数的括号内,以逗号分隔。 + +This function takes a start and an end index for a half-open range, and works out how many elements the range contains: + +下面这个函数接收半开区间的开始和结束索引,并计算出该区间范围包含多少个元素: + +```js +func halfOpenRangeLength(start: Int, end: Int) -> Int { + return end - start +} +println(halfOpenRangeLength(1, 10)) +// prints “9" +``` + +## Functions Without Parameters 无参数函数 + +Functions are not required to define input parameters. Here’s a function with no input parameters, which always returns the same String message whenever it is called: + +函数可以不定义输入参数。下面是一个无输入参数的函数,不管何时被调用总是返回相同的字符串信息: + +```js +func sayHelloWorld() -> String { + return "hello, world" +} +println(sayHelloWorld()) +// prints "hello, world” +``` + +The function definition still needs parentheses after the function’s name, even though it does not take any parameters. The function name is also followed by an empty pair of parentheses when the function is called. + +虽然定义这种函数,并不需要任何参数,但在函数名后仍需要括号。所以调用函数时,函数名后总是紧跟一对空括号。 + +## Functions Without Return Values 无返回值的函数 + +Functions are not required to define a return type. Here’s a version of the sayHello function, called waveGoodbye, which prints its own String value rather than returning it: + +函数可以不定义返回类型。下面是sayHello 函数的一个版本,叫做sayGoodbye,这个函数只打印字符串而不返回。 + +```js +func sayGoodbye(personName: String) { + println("Goodbye, \(personName)!") +} +sayGoodbye("Dave") +// prints "Goodbye, Dave!” +``` + +Because it does not need to return a value, the function’s definition does not include the return arrow (->) or a return type. + +由于这个函数不需要返回值,定义函数时不需要返回箭头(->)和返回类型。 + +> NOTE + +> 注意 + +> Strictly speaking, the sayGoodbye function does still return a value, even though no return value is defined. Functions without a defined return type return a special value of type Void. This is simply an empty tuple, in effect a tuple with zero elements, which can be written as (). + +> 严格来说,即使函数sayGoodbye没有定义返回值,但它仍然返回了一个值。没有定义返回类型的函数会返回一个Void类型的特殊值。它仅仅是一个空元组(值组),实际为零个元素的元组,可以写成()。【 + +The return value of a function can be ignored when it is called: + +调用函数时,函数的返回值可以忽略。 + +```js +func printAndCount(stringToPrint: String) -> Int { + println(stringToPrint) + return countElements(stringToPrint) +} +func printWithoutCounting(stringToPrint: String) { + printAndCount(stringToPrint) +} +printAndCount("hello, world") +// prints "hello, world" and returns a value of 12 +printWithoutCounting("hello, world") +// prints "hello, world" but does not return a value +``` + +The first function, printAndCount, prints a string, and then returns its character count as an Int. The second function, printWithoutCounting, calls the first function, but ignores its return value. When the second function is called, the message is still printed by the first function, but the returned value is not used. + +第一个函数printAndCount 打印一个字符串并返回整型的字符个数。第二个函数 printWithoutCounting 调用第一个函数,但忽略其返回值。调用第二个函数时,信息仍由第一个函数打印,但不使用其返回值。 + +> NOTE + +> 注意 + +> Return values can be ignored, but a function that says it will return a value must always do so. A function with a defined return type cannot allow control to fall out of the bottom of the function without returning a value, and attempting to do so will result in a compile-time error. + +> 返回值虽然可以被忽略,但函数必须总是返回一个值。定义返回类型的函数不允许控制函数的底部没有返回值,试图这样做会导致编译时错误。 + +## Functions with Multiple Return Values 多返回值函数 + +You can use a tuple type as the return type for a function to return multiple values as part of one compound return value. + +可以使用元组类型作为函数的返回类型,这个函数可以返回多个值作为复合返回值的一部分。 + +The example below defines a function called count, which counts the number of vowels, consonants, and other characters in a string, based on the standard set of vowels and consonants used in American English: + +下面的例子定义了count的函数,其基于美式英语中使用的元音和辅音的标准集合,来计算字符串中的元音、辅音和其他字符的个数: + +```js +func count(string: String) -> (vowels: Int, consonants: Int, others: Int) { + var vowels = 0, consonants = 0, others = 0 + for character in string { + switch String(character).lowercaseString { + case "a", "e", "i", "o", "u": + ++vowels + case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", + "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": + ++consonants + default: + ++others + } + } + return (vowels, consonants, others) +} +``` + +You can use this count function to count the characters in an arbitrary string, and to retrieve the counted totals as a tuple of three named Int values: + +你可以使用这个 count 函数来计算任意字符串中的字符数,然后得到所有字符总数——含有3个整型值的元组(译者注:元音,辅音,其他)。 + +```js +let total = count("some arbitrary string!") +println("\(total.vowels) vowels and \(total.consonants) consonants") +// prints "6 vowels and 13 consonants” +``` + +Note that the tuple’s members do not need to be named at the point that the tuple is returned from the function, because their names are already specified as part of the function’s return type. + +注意当函数返回时,元组的成员不需要命名,因为成员的名字已经指定作为函数返回类型的一部分。 + +# Function Parameter Names 函数参数名 + +All of the above functions define parameter names for their parameters: + +以上所有的函数都定义了参数名: + +```js +func someFunction(parameterName: Int) { + // function body goes here, and can use parameterName + // to refer to the argument value for that parameter +} +``` + +However, these parameter names are only used within the body of the function itself, and cannot be used when calling the function. These kinds of parameter names are known as local parameter names, because they are only available for use within the function’s body. + +然而,这些参数名只在该函数体内部使用,不能在调用函数时使用。这种参数名被称为本地(是不是应该翻译成 局部)参数名,因为它们只能在函数体内部获得和使用。 + +## External Parameter Names 外部参数名 + +Sometimes it’s useful to name each parameter when you call a function, to indicate the purpose of each argument you pass to the function. + +有时,在调用函数时为每个参数命名十分有用,表明传给函数的每个参数的用途。 + +If you want users of your function to provide parameter names when they call your function, define an external parameter name for each parameter, in addition to the local parameter name. You write an external parameter name before the local parameter name it supports, separated by a space: + +如果希望用户在调用函数时提供参数名,除了定义本地参数名,还要给每个参数定义外部参数名。把外部参数名写在支持的本地(是不是应该翻译成 局部)参数名前,用空格分隔: + +```js +func someFunction(externalParameterName localParameterName: Int) { + // function body goes here, and can use localParameterName + // to refer to the argument value for that parameter +} +``` + +> NOTE 注意 + +> If you provide an external parameter name for a parameter, that external name must always be used when calling the function. + +> 如果为参数提供了外部参数名,那么在调用函数时必须总是带上外部名。 + +As an example, consider the following function, which joins two strings by inserting a third “joiner” string between them: + +例如下面的函数,把第三个名为“joiner”的字符串插入到另外两个字符串之间,进行连接: + +```js +func join(s1: String, s2: String, joiner: String) -> String { + return s1 + joiner + s2 +} +``` + +When you call this function, the purpose of the three strings that you pass to the function is unclear: + +不过,在调用这个函数时,传给函数的三个字符串的用意并不明确: + +```js +join("hello", "world", ", ") +// returns "hello, world” +``` + +To make the purpose of these String values clearer, define external parameter names for each join function parameter: + +为了明确这些字符串值的用途,需要给 join 函数的每个参数定义外部参数名: + +``` +func join(string s1: String, toString s2: String, withJoiner joiner: String) + -> String { + return s1 + joiner + s2 +} +``` + +In this version of the join function, the first parameter has an external name of string and a local name of s1; the second parameter has an external name of toString and a local name of s2; and the third parameter has an external name of withJoiner and a local name of joiner. + +在这个版本的 join 函数中,第一个参数具有外部参数名 string 和 局部参数名 s1;第二个参数具有外部参数名 toString 和 局部参数名 s2;第三个参数具有外部参数名 withJoiner 和 局部参数名 joiner; + +You can now use these external parameter names to call the function in a clear and unambiguous way: + +现在你就可以明确清楚地使用这些外部参数名来调用函数: + +```js +join(string: "hello", toString: "world", withJoiner: ", ") +// returns "hello, world” +``` + +The use of external parameter names enables this second version of the join function to be called in an expressive, sentence-like manner by users of the function, while still providing a function body that is readable and clear in intent. + +利用外部参数使调用第二个版本的join函数更具表达性和语义性,同时也使函数体更可读、更清晰。 + +> NOTE 注意 + +> Consider using external parameter names whenever the purpose of a function’s arguments would be unclear to someone reading your code for the first time. You do not need to specify external parameter names if the purpose of each parameter is clear and unambiguous when the function is called. + +> 初次阅读这些代码的人,可能不清楚函数参数的用途,这时需要考虑使用外部参数名。如果调用函数时,每个参数的用意都很清楚、明确,那就不需要指定外部参数名。 + +## Shorthand External Parameter Names 简写外部参数名 + +If you want to provide an external parameter name for a function parameter, and the local parameter name is already an appropriate name to use, you do not need to write the same name twice for that parameter. Instead, write the name once, and prefix the name with a hash symbol (#). This tells Swift to use that name as both the local parameter name and the external parameter name. + +如果想给函数参数提供外部参数名,而本地(是不是应该翻译成 局部)参数名已经很适合了,那么你不需要给参数写两个相同的名字。而只用写一次,然后在名字前加上前缀符号(#)。这就告诉Swift使用这个名字同时作为本地参数名和外部参数名。 + +This example defines a function called containsCharacter, which defines external parameter names for both of its parameters by placing a hash symbol before their local parameter names: + +下面的例子定义了名为containsCharacter的函数,该函数在本地(是不是应该翻译成 局部)参数名前加上#标识从而给它的两个参数定义外部参数名。 + +```js +func containsCharacter(#string: String, #characterToFind: Character) -> Bool { + for character in string { + if character == characterToFind { + return true + } + } + return false +} +``` + +This function’s choice of parameter names makes for a clear, readable function body, while also enabling the function to be called without ambiguity: + +这个函数选择的参数名使函数体清晰、可读,同时在调用函数时也没有歧义: + +```js +let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v") +// containsAVee equals true, because "aardvark" contains a “v" +``` + +## Default Parameter Values 默认参数值 + +You can define a default value for any parameter as part of a function’s definition. If a default value is defined, you can omit that parameter when calling the function. + +你可以为函数定义中的任何参数定义默认值。如果定义了默认值,在调用函数时可以忽略该参数。 + +> NOTE 注意 + +> Place parameters with default values at the end of a function’s parameter list. This ensures that all calls to the function use the same order for their non-default arguments, and makes it clear that the same function is being called in each case. + +> 在函数参数列表的最后设置参数默认值。这样可以确保对非默认参数,所有的函数调用使用相同的参数顺序,并明确每种情况都会调用相同的函数。 + +Here’s a version of the join function from earlier, which provides a default value for its joiner parameter: + +下面是之前版本的 join 函数,该函数为它的joiner 参数提供了默认值: + +```js +func join(string s1: String, toString s2: String, + withJoiner joiner: String = " ") -> String { + return s1 + joiner + s2 +} +``` + +If a string value for joiner is provided when the join function is called, that string value is used to join the two strings together, as before: + +如果在调用 join 函数时,为 joiner 提供了字符串类型的值,该字符串值用来连接 另外两个字符串,和之前一样: + +```js +join(string: "hello", toString: "world", withJoiner: "-") +// returns "hello-world” +``` + +However, if no value of joiner is provided when the function is called, the default value of a single space (" ") is used instead: + +然而,如果调用函数时没有提供 joiner 值,会使用默认值空格(“ ”)替代: + +```js +join(string: "hello", toString: "world") +// returns "hello world” +``` + +## External Names for Parameters with Default Values 带默认值参数的外部参数名 + +In most cases, it is useful to provide (and therefore require) an external name for any parameter with a default value. This ensures that the argument for that parameter is clear in purpose if a value is provided when the function is called. + +在大多数情况下,给任何带有默认值的参数提供外部参数名十分有用(而且非常必要)。这确保了在给函数调用提供值时,参数的用途是明确的。 + +To make this process easier, Swift provides an automatic external name for any defaulted parameter you define, if you do not provide an external name yourself. The automatic external name is the same as the local name, as if you had written a hash symbol before the local name in your code. + +为了使这个过程更简单,如果你没有提供自定义的外部参数名,Swift 会为你定义的任何默认参数提供自动外部参数名。在代码中,如果你已经在本地参数名前加上 # 标识,那么自动外部参数名和本地参数名相同。 + +Here’s a version of the join function from earlier, which does not provide external names for any of its parameters, but still provides a default value for its joiner parameter: + +下面是之前版本的 join函数,这个函数不为它的任何参数提供外部参数名,但仍然为它的 joiner 参数提供了默认值。 + +```js +func join(s1: String, s2: String, joiner: String = " ") -> String { + return s1 + joiner + s2 +} +``` + +In this case, Swift automatically provides an external parameter name of joiner for the defaulted parameter. The external name must therefore be provided when calling the function, making the parameter’s purpose clear and unambiguous: + +在这个例子中,Swift自动为默认参数joiner提供了外部参数名。因此,在调用该函数时,必须提供外部名,使该参数的用途明确、清晰。 + +```js +join("hello", "world", joiner: "-") +// returns "hello-world” +``` + +> NOTE 注意 + +> You can opt out of this behavior by writing an underscore (_) instead of an explicit external name when you define the parameter. However, external names for defaulted parameters are always preferred where appropriate. + +> 定义参数时,可以使用下划线(_)来避免显式使用参数外部名。不过,在大多情况下,都推荐为有默认值的参数提供外部参数名。 + +## Parameters 可变参数 + +A variadic parameter accepts zero or more values of a specified type. You use a variadic parameter to specify that the parameter can be passed a varying number of input values when the function is called. Write variadic parameters by inserting three period characters (...) after the parameter’s type name. + +可变参数接收指定类型的零个或多个值。调用函数时,参数可以传入不定个数的输入值。这种参数定义为可变参数。通过在参数类型名后插入3个点字符(…)来定义可变参数。 + +The values passed to a variadic parameter are made available within the function’s body as an array of the appropriate type. For example, a variadic parameter with a name of numbers and a type of Double... is made available within the function’s body as a constant array called numbers of type Double[]. + +传给可变参数的值,在函数体内部可以当做相应类型的数组使用。例如,名为 numbers 的 Double...类型的可变参数,可以在函数体内部作为名为numbers的Double[]类型的常量数组使用。 + +The example below calculates the arithmetic mean (also known as the average) for a list of numbers of any length: + +下面的例子是对一个有任意个数的数字列表求算术平均数(也被称为平均数) + +```js +func arithmeticMean(numbers: Double...) -> Double { + var total: Double = 0 + for number in numbers { + total += number + } + return total / Double(numbers.count) +} +arithmeticMean(1, 2, 3, 4, 5) +// returns 3.0, which is the arithmetic mean of these five numbers +arithmeticMean(3, 8, 19) +// returns 10.0, which is the arithmetic mean of these three numbers +``` + +> NOTE 注意 + +> A function may have at most one variadic parameter, and it must always appear last in the parameter list, to avoid ambiguity when calling the function with multiple parameters. + +> 在调用带有多个参数的函数时,为了避免产生歧义,函数最多可以有一个可变参数,而且它必须总是放在参数列表的最后。 + +> If your function has one or more parameters with a default value, and also has a variadic parameter, place the variadic parameter after all the defaulted parameters at the very end of the list. + +> 如果函数有一个或多个参数有默认值,且还有一个可变参数,请把可变参数放在所有默认参数列表的最后。 + +## Constant and Variable Parameters 常量和变量参数 + +Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. This means that you can’t change the value of a parameter by mistake. + +函数参数默认都是常量。试图在函数体内改变参数的值会导致编译时错误。这会防止你意外地改变其参数值。 + +However, sometimes it is useful for a function to have a variable copy of a parameter’s value to work with. You can avoid defining a new variable yourself within the function by specifying one or more parameters as variable parameters instead. Variable parameters are available as variables rather than as constants, and give a new modifiable copy of the parameter’s value for your function to work with. + +然而,有时使用参数的拷贝值对于函数来说十分有用。为了避免在函数内部定义新变量,可以把一个或多个参数定义为变量参数。这时,变量参数可以作为变量而不是常量使用,并且提供一个新的可修改的参数值的拷贝给函数使用。 + +Define variable parameters by prefixing the parameter name with the keyword var: + +可以在参数名前增加前缀关键字 var 来定义变量参数: + +```js +func alignRight(var string: String, count: Int, pad: Character) -> String { + let amountToPad = count - countElements(string) + for _ in 1...amountToPad { + string = pad + string + } + return string +} +let originalString = "hello" +let paddedString = alignRight(originalString, 10, "-") +// paddedString is equal to "-----hello" +// originalString is still equal to “hello" +``` + +This example defines a new function called alignRight, which aligns an input string to the right edge of a longer output string. Any space on the left is filled with a specified padding character. In this example, the string "hello" is converted to the string "-----hello”. + +这个例子定义了名为alignRight的新函数,它把输入的 string 放在一个更长的输出字符串的最右端(译者注:以实现右对齐)。这个字符串的左边将被指定的字符所填充。在这个例子中,字符串“hello” 转换为 字符串“——hello”。 + +The alignRight function defines the input parameter string to be a variable parameter. This means that string is now available as a local variable, initialized with the passed-in string value, and can be manipulated within the body of the function. + +这个alignRight 函数把输入参数 string 定义为变量参数。这意味着在函数体内部可以把string当做本地变量使用,并初始化为传入的字符串值。 + +The function starts by working out how many characters need to be added to the left of string in order to right-align it within the overall string. This value is stored in a local constant called amountToPad. The function then adds amountToPad copies of the pad character to the left of the existing string and returns the result. It uses the string variable parameter for all its string manipulation. + +为了在整个字符串中右对齐 string,首先要算出 string 的左边需要添加多少字符。这个值储存在局部常量 amoutToPad 中。然后,函数在现有 string 的左边添加数量为 amoutToPad 的填充字符并返回结果。所有对 string 的操作均使用了 string 的可变参数。 + +> NOTE + +> The changes you make to a variable parameter do not persist beyond the end of each call to the function, and are not visible outside the function’s body. The variable parameter only exists for the lifetime of that function call. + +> 变量参数的改变持续到每个函数调用的结束(不会超过),并在函数体外不可见。变量参数只存在于函数调用的生命周期中。 + +## In-Out Parameters In-Out参数 + +Variable parameters, as described above, can only be changed within the function itself. If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead. + +变量参数,如前所述,只能在函数自身内部改变。如果希望函数可以修改参数值,且这些变化持续到函数调用结束之后,需要定义该参数为In-Out 参数。 + +You write an in-out parameter by placing the inout keyword at the start of its parameter definition. An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value. + +在定义的参数前添加inout关键字,可以定义in-out参数。in-out参数的值会传入函数,被函数修改,然后传出函数来替换原始值。//TODO + + +You can only pass a variable as the argument for an in-out parameter. You cannot pass a constant or a literal value as the argument, because constants and literals cannot be modified. You place an ampersand (&) directly before a variable’s name when you pass it as an argument to an inout parameter, to indicate that it can be modified by the function. + +in-out参数作为函数参数,只能传入变量,不能传入常量或字面量。因为常量和字面量不能被修改。在变量名前直接加上&,把它作为参数传给inout参数,表明它可以被函数修改。 + +> NOTE 注意 + +> In-out parameters cannot have default values, and variadic parameters cannot be marked as inout. If you mark a parameter as inout, it cannot also be marked as var or let. + +> In-out参数不能有默认值,且可变参数不能标记为inout。如果定义一个参数为inout参数,就不能再定义它为var或let。 + +Here’s an example of a function called swapTwoInts, which has two in-out integer parameters called a and b: + +下面是swapTwoInts函数的例子,它有2个inout 整型参数a和b: + +```js +func swapTwoInts(inout a: Int, inout b: Int) { + let temporaryA = a + a = b + b = temporaryA +} +``` + +The swapTwoInts function simply swaps the value of b into a, and the value of a into b. The function performs this swap by storing the value of a in a temporary constant called temporaryA, assigning the value of b to a, and then assigning temporaryA to b. + +swapTwoInts函数简单地交换a、b值。先把a值存储在临时常量temporaryA中,然后把b值赋给a,最后把temporaryA赋值给b来实现交换。 + +You can call the swapTwoInts function with two variables of type Int to swap their values. Note that the names of someInt and anotherInt are prefixed with an ampersand when they are passed to the swapTwoInts function: + +可以调用 swapTwoInts 函数交换两个 Int 型变量的值。注意把someInt 和anotherInt 传给swapTwoInts函数时,它们的名字前都有&的前缀: + +```js +var someInt = 3 +var anotherInt = 107 +swapTwoInts(&someInt, &anotherInt) +println("someInt is now \(someInt), and anotherInt is now \(anotherInt)") +// prints "someInt is now 107, and anotherInt is now 3” +``` + +The example above shows that the original values of someInt and anotherInt are modified by the swapTwoInts function, even though they were originally defined outside of the function. + +上面的例子说明函数 swapTwoInts 改变了 someInt 和anotherInt 的初始值,尽管它们的初始值是在函数外定义的。 + +> NOTE 注意 + +> In-out parameters are not the same as returning a value from a function. The swapTwoInts example above does not define a return type or return a value, but it still modifies the values of someInt and anotherInt. In-out parameters are an alternative way for a function to have an effect outside of the scope of its function body. + +> In-out参数和从函数中返回的值不一样。虽然上面swapTwoInts的例子没有定义返回类型和返回值,但它仍然修改了someInt 和anotherInt的值。In-out参数是函数对函数体范围外产生影响的另一种方式。 + +# Function Types 函数类型 + +Every function has a specific function type, made up of the parameter types and the return type of the function. + +每个函数都有一个特定的函数类型,由函数参数类型和返回类型组成。 + +For example: + +例如: + +```js +func addTwoInts(a: Int, b: Int) -> Int { + return a + b +} +func multiplyTwoInts(a: Int, b: Int) -> Int { + return a * b +} +``` + +This example defines two simple mathematical functions called addTwoInts and multiplyTwoInts. These functions each take two Int values, and return an Int value, which is the result of performing an appropriate mathematical operation. + +这个例子定义了2个简单的数学函数addTwoInts 和multiplyTwoInts。每个函数都接受两个整型值并返回一个整型值——执行相应数学运算的结果。 + +The type of both of these functions is (Int, Int) -> Int. This can be read as: + +这两个函数的类型都是(Int, Int) -> Int,可以解读为: + +“A function type that has two parameters, both of type Int, and that returns a value of type Int.” + +函数类型是有2个整型参数和一个整型返回值 + +Here’s another example, for a function with no parameters or return value: + +下面是另一个例子,没有参数和返回值的函数。 + +```js +func printHelloWorld() { + println("hello, world") +} +``` + +The type of this function is () -> (), or “a function that has no parameters, and returns Void.” Functions that don’t specify a return value always return Void, which is equivalent to an empty tuple in Swift, shown as (). + +这个函数的类型是() -> (),或”没有参数,且返回Void的函数。“不定义返回值的函数始终返回Void,相当于Swift中的空元组,写作()。 + +## Using Function Types 使用函数类型 + +You use function types just like any other types in Swift. For example, you can define a constant or variable to be of a function type and assign an appropriate function to that variable: + +你可以像使用Swift中任何其他类型那样使用函数类型。例如,可以定义一个函数类型的常量或变量,并且把对应的函数赋给这个变量。 + +```js +var mathFunction: (Int, Int) -> Int = addTwoInts +``` + +This can be read as: + +这可以解读为: + +“Define a variable called mathFunction, which has a type of ‘a function that takes two Int values, and returns an Int value.’ Set this new variable to refer to the function called addTwoInts.” + +”定义名为mathFunction的变量,该变量类型为’可以接收两个整型参数并返回整型值的函数’。设置这个新变量引用addTwoInts函数“ + +The addTwoInts function has the same type as the mathFunction variable, and so this assignment is allowed by Swift’s type-checker. + +addTwoInts 函数和mathFunction 函数有相同的类型,因此Swift的类型检查允许这种赋值。 + +You can now call the assigned function with the name mathFunction: + +可以使用mathFunction名来调用函数: + +```js +println("Result: \(mathFunction(2, 3))") +// prints "Result: 5” +``` + +A different function with the same matching type can be assigned to the same variable, in the same way as for non-function types: + +可以把具有相同类型的不同函数赋值给同一变量,对于无函数类型的函数也适用。 + +```js +mathFunction = multiplyTwoInts +println("Result: \(mathFunction(2, 3))") +// prints "Result: 6” +``` +As with any other type, you can leave it to Swift to infer the function type when you assign a function to a constant or variable: + +与其他类型一样,当把函数赋值给常量或变量时,可以留给Swift来推断函数类型。 + +```js +let anotherMathFunction = addTwoInts +// anotherMathFunction is inferred to be of type (Int, Int) -> Int +``` + +## Function Types as Parameter Types 作为参数类型的函数类型 + +You can use a function type such as (Int, Int) -> Int as a parameter type for another function. This enables you to leave some aspects of a function’s implementation for the function’s caller to provide when the function is called. + +可以使用类似 (Int, Int) -> Int的函数类型作为另一个函数的参数类型。在函数调用时,可以把一个函数的某些实现留给函数调用者来确定。 + +Here’s an example to print the results of the math functions from above: + +下面的例子可以打印上面数学函数的结果。 + +```js +func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) { + println("Result: \(mathFunction(a, b))") +} +printMathResult(addTwoInts, 3, 5) +// prints "Result: 8” +``` + +This example defines a function called printMathResult, which has three parameters. The first parameter is called mathFunction, and is of type (Int, Int) -> Int. You can pass any function of that type as the argument for this first parameter. The second and third parameters are called a and b, and are both of type Int. These are used as the two input values for the provided math function. + +这个例子定义了函数printMathResult,它有三个参数。第一参数是 mathFunction,(Int, Int) -> Int类型的。可以传入任何该类型的函数作为该函数的第一个参数。第二和第三个参数是a和b,都是整形。它们被用来作为所提供的数学函数的两个输入值。 + +When printMathResult is called, it is passed the addTwoInts function, and the integer values 3 and 5. It calls the provided function with the values 3 and 5, and prints the result of 8. + +调用printMathResult 时,传入addTwoInts 函数、整型值3和5作为参数。让后把3和5作为参数调用 addTwoInts ,最后打印出结果8。 + +The role of printMathResult is to print the result of a call to a math function of an appropriate type. It doesn’t matter what that function’s implementation actually does—it matters only that the function is of the correct type. This enables printMathResult to hand off some of its functionality to the caller of the function in a type-safe way. + +printMathResult 的作用是打印相应类型的数学函数的调用结果。与函数的具体实现无关,只与函数具有的正确类型有关。这让函数 printMathResult 以类型安全的方式,把它的部分功能交给其调用者。 + + +## Function Types as Return Types + +## 作为返回类型的函数类型 + +You can use a function type as the return type of another function. You do this by writing a complete function type immediately after the return arrow (->) of the returning function. + +可以使用函数 类型作为另一个函数的返回类型。通过在返回函数的返回箭头(->)后编写完整的函数类型。 + +The next example defines two simple functions called stepForward and stepBackward. The stepForward function returns a value one more than its input value, and the stepBackward function returns a value one less than its input value. Both functions have a type of (Int) -> Int: + +下面的例子定义了stepForward 和stepBackward两个简单函数。stepForward 函数返回值比输入值多1,而stepBackward 函数返回值比输入值少1.这两个函数都是 (Int) -> Int类型: + +```js +func stepForward(input: Int) -> Int { + return input + 1 +} +func stepBackward(input: Int) -> Int { + return input - 1 +} +``` + +Here’s a function called chooseStepFunction, whose return type is “a function of type (Int) -> Int”. chooseStepFunction returns the stepForward function or the stepBackward function based on a Boolean parameter called backwards: + +下面是函数chooseStepFunction,它的返回类型是”类型为(Int) -> Int的函数“。chooseStepFunction 根据布尔参数 backwards 判断是返回 stepForward 函数,还是返回 stepBackward 函数。 + +```js +func chooseStepFunction(backwards: Bool) -> (Int) -> Int { + return backwards ? stepBackward : stepForward +} +``` + +You can now use chooseStepFunction to obtain a function that will step in one direction or the other: + +使用函数chooseStepFunction,可以获得指示前进或后退的返回函数。 + +```js +var currentValue = 3 +let moveNearerToZero = chooseStepFunction(currentValue > 0) +// moveNearerToZero now refers to the stepBackward() function +``` + +The preceding example works out whether a positive or negative step is needed to move a variable called currentValue progressively closer to zero. currentValue has an initial value of 3, which means that currentValue > 0 returns true, causing chooseStepFunction to return the stepBackward function. A reference to the returned function is stored in a constant called moveNearerToZero. + +前面的例子实现了确定 正向或是反向移动使 变量 currentValue 逐步趋向于零的功能。currentValue 初始值为3,这意味着currentValue > 0 返回true,导致chooseStepFunction 返回stepBackward 函数。返回的函数的引用被存储在常量moveNearerToZero中。 + + +Now that moveNearerToZero refers to the correct function, it can be used to count to zero: + +现在 moveNearerToZero 引用了正确的函数,可以用来计数到零: + +```js +println("Counting to zero:") +// Counting to zero: +while currentValue != 0 { + println("\(currentValue)... ") + currentValue = moveNearerToZero(currentValue) +} +println("zero!") +// 3... +// 2... +// 1... +// zero! +``` + +# Nested Functions +# 嵌套函数 + +All of the functions you have encountered so far in this chapter have been examples of global functions, which are defined at a global scope. You can also define functions inside the bodies of other functions, known as nested functions. + +到目前为止,本章所有的全局函数都是在全局范围定义的。也可以在其他函数的内部定义函数,称为嵌套函数。 + +Nested functions are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope. + +嵌套函数默认在外部环境下不可访问,但仍可以被闭包函数调用。闭包函数也可以返回它其中一个嵌套函数,使得这个嵌套函数可以在其他作用域内使用。 + +You can rewrite the chooseStepFunction example above to use and return nested functions: + +可以重写上面的chooseStepFunction 例子来返回嵌套函数: + +```js +func chooseStepFunction(backwards: Bool) -> (Int) -> Int { + func stepForward(input: Int) -> Int { return input + 1 } + func stepBackward(input: Int) -> Int { return input - 1 } + return backwards ? stepBackward : stepForward +} +var currentValue = -4 +let moveNearerToZero = chooseStepFunction(currentValue > 0) +// moveNearerToZero now refers to the nested stepForward() function +while currentValue != 0 { + println("\(currentValue)... ") + currentValue = moveNearerToZero(currentValue) +} +println("zero!") +// -4... +// -3... +// -2... +// -1... +// zero! +``` From 55ba9f491797337d0122d36f0f5fcae52106b42a Mon Sep 17 00:00:00 2001 From: yozomk Date: Fri, 20 Jun 2014 14:50:48 +0800 Subject: [PATCH 137/261] 77% 20 pages were translated by MK. --- .../16_Automatic_Reference_Counting.md | 218 +++++++++++++++++- 1 file changed, 215 insertions(+), 3 deletions(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index f1b1e76..35b6fff 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -188,7 +188,7 @@ Here’s how the strong references look after creating and assigning these two i You can now link the two instances together so that the person has an apartment, and the apartment has a tenant. Note that an exclamation mark (!) is used to unwrap and access the instances stored inside the john and number73 optional variables, so that the properties of those instances can be set: -现在将两个实例连接在一起,让john住进number73公寓,number73公寓也有了一个租客john。注意那个感叹号(!),它用于打开和访问存储于john和number73实例中的可选变量,这样实例的属性才能够被设置: +现在将两个实例连接在一起,让john住进number73公寓,number73公寓也有了一个租客john。注意那个感叹号(!),它用于解析和访问存储于john和number73实例中的可选变量,这样实例的属性才能够被设置: ``` john!.apartment = number73 @@ -340,13 +340,225 @@ Like weak references, an unowned reference does not keep a strong hold on the in Because an unowned reference is non-optional, you don’t need to unwrap the unowned reference each time it is used. An unowned reference can always be accessed directly. However, ARC cannot set the reference to nil when the instance it refers to is deallocated, because variables of a non-optional type cannot be set to nil. -由于无主引用是非可选类型的,你不必在使用的时候展开它,它可以被直接访问。与弱引用不同,当无主引用指向的实例被销毁后,ARC不会将其指向nil。 +由于无主引用是非可选类型的,你不必在使用的时候解析它,它可以被直接访问。与弱引用不同,当无主引用指向的实例被销毁后,ARC不会将其指向nil。 > NOTE > > If you try to access an unowned reference after the instance that it references is deallocated, you will trigger a runtime error. Use unowned references only when you are sure that the reference will always refer to an instance. > > Note also that Swift guarantees your app will crash if you try to access an unowned reference after the instance it references is deallocated. You will never encounter unexpected behavior in this situation. Your app will always crash reliably, although you should, of course, prevent it from doing so. + > 注意 > 在无主引用指向的实例被销毁后,如果依然试图访问该无主引用,你会触发运行时错误。使用无主引用,需要你你能够确保引用指向的实例未被销毁。 -> 需要格外注意的是,在无主引用指向的实例被销毁后,若你依然试图访问该无主引用,Swift保证,你的app会毫无意外地直接崩溃。不是应该而是你必须避免这样的情况发生。 \ No newline at end of file +> 需要格外注意的是,在无主引用指向的实例被销毁后,若你依然试图访问该无主引用,Swift保证,你的app会毫无意外地直接崩溃。不是应该而是你必须避免这样的情况发生。 + +The following example defines two classes, Customer and CreditCard, which model a bank customer and a possible credit card for that customer. These two classes each store an instance of the other class as a property. This relationship has the potential to create a strong reference cycle. + +接下来的例子定义了两个类,Customer和CreditCard,分别为银行客户和信用卡建模。这两个类通过属性互相保存了对方的实例。这种关系,在它们之间潜在地形成了循环强引用。 + +The relationship between Customer and CreditCard is slightly different from the relationship between Apartment and Person seen in the weak reference example above. In this data model, a customer may or may not have a credit card, but a credit card will always be associated with a customer. To represent this, the Customer class has an optional card property, but the CreditCard class has a non-optional customer property. + +Customer 与 CreditCard之间的关系与上文弱引用例子里提到的Apartment 和 Person之间的关系有些许不同。在这个数据模型里,一位客户可能有也可能没有信用卡,但是一张信用卡必然与某位银行客户关联。为了表示这种关系,Customer类声明了一个可选类型的属性card,但CreditCard类声明了一个非可选类型的属性customer。 + +Furthermore, a new CreditCard instance can only be created by passing a number value and a customer instance to a custom CreditCard initializer. This ensures that a CreditCard instance always has a customer instance associated with it when the CreditCard instance is created. + +此外,只能通过向CreditCard类构造器传递一个数值和一个Customer类实例的方式创建新的CreditCard类实例。这是为了保证创建CreditCard类实例的时候总是有一位客户实例与之关联。 + +Because a credit card will always have a customer, you define its customer property as an unowned reference, to avoid a strong reference cycle: + +由于一张信用卡一定会有一位客户实例与之关联,你将其属性customer定义为无主类型以避免循环强引用: + +``` +class Customer { + let name: String + var card: CreditCard? + init(name: String) { + self.name = name + } + deinit { println("\(name) is being deinitialized") } +} + +class CreditCard { + let number: Int + unowned let customer: Customer + init(number: Int, customer: Customer) { + self.number = number + self.customer = customer + } + deinit { println("Card #\(number) is being deinitialized") } +} +``` + +This next code snippet defines an optional Customer variable called john, which will be used to store a reference to a specific customer. This variable has an initial value of nil, by virtue of being optional: + +如下代码片段定义了一个可选Customer类型的变量john,john将用于存储到特定客户的引用。由于是可选类型,这个变量初始值是nil. + +``` +var john: Customer? +``` + +You can now create a Customer instance, and use it to initialize and assign a new CreditCard instance as that customer’s card property: + +现在创建Customer类实例,并用它初始化CreditCard类实例,同时,将CreditCard类实例分配给Customer类实例的客户属性。 + +``` +john = Customer(name: "John Appleseed") +john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!) +``` + +Here’s how the references look, now that you’ve linked the two instances: + +下图展示了两个实例连接起来后的引用关系: + +![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/unownedReference01_2x.png) + +The Customer instance now has a strong reference to the CreditCard instance, and the CreditCard instance has an unowned reference to the Customer instance. + +Customer类实例拥有一个指向CreditCard类实例的强引用,同时CreditCard类实例有一个指向Customer类实例的无主引用。 + +Because of the unowned customer reference, when you break the strong reference held by the john variable, there are no more strong references to the Customer instance: + +由于无主引用customer的存在,当你断开由变量john保持的强引用后,就没有强引用指向Customer类实例了: + +![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/unownedReference02_2x.png) + +Because there are no more strong references to the Customer instance, it is deallocated. After this happens, there are no more strong references to the CreditCard instance, and it too is deallocated: + +由于没有强引用指向Customer类实例了,它被销毁了。在此之后,由于也没有强引用指向CreditCard类实例了,它也被销毁了。 + +``` +john = nil +// prints "John Appleseed is being deinitialized" +// prints "Card #1234567890123456 is being deinitialized" +``` + +The final code snippet above shows that the deinitializers for the Customer instance and CreditCard instance both print their “deinitialized” messages after the john variable is set to nil. + +上面的代码展示了变量john被赋值为nil后,Customer实例和CreditCard实例的析构函数都打印出了“销毁”的信息。 + +## 无主引用与隐式解析可选属性 + +The examples for weak and unowned references above cover two of the more common scenarios in which it is necessary to break a strong reference cycle. + +弱引用和无主引用的例子涵盖了两种常用的需要打破循环强引用的场景。 + +The Person and Apartment example shows a situation where two properties, both of which are allowed to be nil, have the potential to cause a strong reference cycle. This scenario is best resolved with a weak reference. + +Person和Apartment的例子展示了两个属性的值都允许为nil,并会潜在地产生循环强引用。这种场景最适合用弱引用来解决。 + +The Customer and CreditCard example shows a situation where one property that is allowed to be nil and another property that cannot be nil have the potential to cause a strong reference cycle. This scenario is best resolved with an unowned reference. + +Customer和CreditCard的例子展示了一个属性的值允许为nil,而另一个不允许为nil,并会潜在地产生循环强引用。这种场景最适合通过无主引用来解决。 + +However, there is a third scenario, in which both properties should always have a value, and neither property should ever be nil once initialization is complete. In this scenario, it is useful to combine an unowned property on one class with an implicitly unwrapped optional property on the other class. + +但是,还有第三种场景:就是两个属性都一直有值,并且一旦初始化完成他们就永远都不可能是nil的情况。这种情况下,在一个类中使用无主属性,在另一个类中使用隐式解析可选属性,是解决此类循环强引用问题的有效手段。 + +This enables both properties to be accessed directly (without optional unwrapping) once initialization is complete, while still avoiding a reference cycle. This section shows you how to set up such a relationship. + +只要初始化完成,这两个属性都是可以被直接访问的(没有可选类型的解析过程)同时也可以避免循环引用。这部分将向你介绍如何建立这种关系。 + +The example below defines two classes, Country and City, each of which stores an instance of the other class as a property. In this data model, every country must always have a capital city, and every city must always belong to a country. To represent this, the Country class has a capitalCity property, and the City class has a country property: + +下面的例子定义了两个类,Country 和 City,它们彼此通过属性保存了对方的实例引用。在这个数据模型里,国家是必须有首都的,而一个城市也必须是属于某个国家。为了表示这种关系,Country类声明了一个capitalCity属性,City类也声明了一个country属性: + +``` +class Country { + let name: String + let capitalCity: City! + init(name: String, capitalName: String) { + self.name = name + self.capitalCity = City(name: capitalName, country: self) + } +} + +class City { + let name: String + unowned let country: Country + init(name: String, country: Country) { + self.name = name + self.country = country + } +} +``` + +To set up the interdependency between the two classes, the initializer for City takes a Country instance, and stores this instance in its country property. + +为了构建两个类之间的依赖关系,City类的构造器接收一个Country实例并把它存储在country属性里。 + +The initializer for City is called from within the initializer for Country. However, the initializer for Country cannot pass self to the City initializer until a new Country instance is fully initialized, as described in Two-Phase Initialization. + +City的构造器将在Country的构造器里被调用。但是,Country的构造器无法传递自身(`self`)到City的构造器,直到Country实例已完全初始化。这在[两段式构造过程](http://TODO)中有介绍。 + +To cope with this requirement, you declare the capitalCity property of Country as an implicitly unwrapped optional property, indicated by the exclamation mark at the end of its type annotation (City!). This means that the capitalCity property has a default value of nil, like any other optional, but can be accessed without the need to unwrap its value as described in Implicitly Unwrapped Optionals. + +为了满足要求,你将Country类的capitalCity属性声明为隐式解析可选属性(通过在capitalCity类型后加感叹号`City!`来声明)。这意味着,像其他可选类型属性一样,capitalCity属性的默认值为nil, 但是它可以不经解析直接被访问。这在[隐式解析可选类型](http://TODO)中有详细介绍。 + +Because capitalCity has a default nil value, a new Country instance is considered fully initialized as soon as the Country instance sets its name property within its initializer. This means that the Country initializer can start to reference and pass around the implicit self property as soon as the name property is set. The Country initializer can therefore pass self as one of the parameters for the City initializer when the Country initializer is setting its own capitalCity property. + +由于capitalCity默认值为nil, 因此当Country实例的name属性在构造器内被赋值的时候,就认为初始化已经全部完成。这意味着name属性一被赋值,Country类构造器就可以开始引用和传递隐式的`self`。Country构造器也因此可以在为capitalCity属性赋值时把`self`作为参数给City的构造器。 + +All of this means that you can create the Country and City instances in a single statement, without creating a strong reference cycle, and the capitalCity property can be accessed directly, without needing to use an exclamation mark to unwrap its optional value: + +上述这一切,意味着你可以在单一语句中同时创建Country和City的实例,这里没有形成循环强引用,同时capitalCity也可以直接被访问,也不必用感叹号来解析其可选值,如下所示: + +``` +var country = Country(name: "Canada", capitalName: "Ottawa") +println("\(country.name)'s capital city is called \(country.capitalCity.name)") +// prints "Canada's capital city is called Ottawa +``` + +In the example above, the use of an implicitly unwrapped optional means that all of the two-phase class initializer requirements are satisfied. The capitalCity property can be used and accessed like a non-optional value once initialization is complete, while still avoiding a strong reference cycle. + +在上面的例子中,应用“隐式解析可选属性”使得两段式类构造器所需要的条件均得到满足。一旦初始化完成,capitalCity属性可以像非可选值那样被直接访问,同时还避免了循环强引用。 + +## 闭包引起的循环强引用 +You saw above how a strong reference cycle can be created when two class instance properties hold a strong reference to each other. You also saw how to use weak and unowned references to break these strong reference cycles. + +在上文中你已经了解了两个实例属性互相保持彼此的强引用是如何导致循环强引用的。你也知道了可以利用弱引用和无主引用来断开强引用循环。 + +A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of that closure captures the instance. This capture might occur because the closure’s body accesses a property of the instance, such as self.someProperty, or because the closure calls a method on the instance, such as self.someMethod(). In either case, these accesses cause the closure to “capture” self, creating a strong reference cycle. + +如果你将一个闭包分配给一个类实例的属性,同时闭包内部又捕获了该实例,也会形成循环强引用。这种捕获之所以可能发生,是因为闭包内部访问了该实例的属性,如:self.someProperty,或是访问了该实例的方法,如:self.someMethod()。这两种类型的访问,都会导致闭包“捕获”self,造成循环强引用。 + +This strong reference cycle occurs because closures, like classes, are reference types. When you assign a closure to a property, you are assigning a reference to that closure. In essence, it’s the same problem as above—two strong references are keeping each other alive. However, rather than two class instances, this time it’s a class instance and a closure that are keeping each other alive. + +这种因闭包导致的循环强引用,和“类”的情况类似,都是引用类型的问题。 + +Swift provides an elegant solution to this problem, known as a closure capture list. However, before you learn how to break a strong reference cycle with a closure capture list, it is useful to understand how such a cycle can be caused. + +针对这类问题,Swift提供了一种优雅的解决方案:闭包捕获列表。 + +The example below shows how you can create a strong reference cycle when using a closure that references self. This example defines a class called HTMLElement, which provides a simple model for an individual element within an HTML document: + +下面的例子展示了闭包是如何导致循环强引用的。例子定义了一个名为HTMLElement的类,为HTML文档中的一类元素建模: + +``` +class HTMLElement { + + let name: String + let text: String? + + @lazy var asHTML: () -> String = { + if let text = self.text { + return "<\(self.name)>\(text)" + } else { + return "<\(self.name) />" + } + } + + init(name: String, text: String? = nil) { + self.name = name + self.text = text + } + + deinit { + println("\(name) is being deinitialized") + } + +} +``` + +The HTMLElement class defines a name property, which indicates the name of the element, such as "p" for a paragraph element, or "br" for a line break element. HTMLElement also defines an optional text property, which you can set to a string that represents the text to be rendered within that HTML element. + +In addition to these two simple properties, the HTMLElement class defines a lazy property called asHTML. This property references a closure that combines name and text into an HTML string fragment. The asHTML property is of type () -> String, or “a function that takes no parameters, and returns a String From c0966ef1ede05d27bd0d50c2c0ca82aa085151e2 Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Fri, 20 Jun 2014 15:16:40 +0800 Subject: [PATCH 138/261] update 01_the_basics - Type Safety and Type Inference --- src/chapter2/01_The_Basics.md | 38 +++++++++++++++++++++++++++++------ src/words.md | 3 ++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 91c742c..370c762 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -352,30 +352,56 @@ Float represents a 32-bit floating-point number. Use it when floating-point valu Swift is a type safe language. A type safe language encourages you to be clear about the types of values your code can work with. If part of your code expects a String, you can’t pass it an Int by mistake. +Swift是一个类型安全的语言。一个类型安全的语言鼓励你声明代码中使用的值的类型。如果你期望这部分代码是字符串(String),你就不能错误的给它赋一个整型(Int)的值。 + Because Swift is type safe, it performs type checks when compiling your code and flags any mismatched types as errors. This enables you to catch and fix errors as early as possible in the development process. +因为Swift是类型安全的,它会在编译时运行类型检查,并且将所有不匹配的类型标记为错误。这让你可以在开发过程中今早的发现和修复问题。 + Type-checking helps you avoid errors when you’re working with different types of values. However, this doesn’t mean that you have to specify the type of every constant and variable that you declare. If you don’t specify the type of value you need, Swift uses type inference to work out the appropriate type. Type inference enables a compiler to deduce the type of a particular expression automatically when it compiles your code, simply by examining the values you provide. +当你处理不同类型的值的时候,类型检查帮助你避免错误。然而,这并不意味着你需要给每一个声明的常量和变量指定特定的类型。如果你没有指定特定的类型,Swift会使用类型推断来推断出合适的类型。当编译代码时,类型推断特性使得编译器可以简单的通过检查你提供的值来自动推断出特定表达式的类型。 + Because of type inference, Swift requires far fewer type declarations than languages such as C or Objective-C. Constants and variables are still explicitly typed, but much of the work of specifying their type is done for you. +因为有了类型推断,Swift与类似C和Objective-C的语言相比需要更少的类型声明。常量和变量同样会有准确的类型,但是大部分关于指定类型的工作Swift已经帮你做好了。 + Type inference is particularly useful when you declare a constant or variable with an initial value. This is often done by assigning a literal value (or literal) to the constant or variable at the point that you declare it. (A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below.) +当你声明一个有初始值的常量或变量的时候类型推断特别实用。通常是当你声明一个常量和变量的时候你就给它赋一个参数值(literal value)。(参数值是会直接出现在源码里的值,比如下面例子里的42和3.14159。) + For example, if you assign a literal value of 42 to a new constant without saying what type it is, Swift infers that you want the constant to be an Int, because you have initialized it with a number that looks like an integer: -let meaningOfLife = 42 -// meaningOfLife is inferred to be of type Int +举个例子,如果你给一个新的常量赋了一个参数值42,但没有说它的类型,Swift会推断你希望这个常量是一个整数类型(Int),因为你用了一个像是整数的数字来初始化: + + let meaningOfLife = 42 + // meaningOfLife is inferred to be of type Int + // meaningOfLife被推断为整数类型(Int) + Likewise, if you don’t specify a type for a floating-point literal, Swift infers that you want to create a Double: -let pi = 3.14159 -// pi is inferred to be of type Double +类似的,如果你没有特别指定一个浮点型的参数,Swift会推断你需要一个Double类型的浮点数: + + let pi = 3.14159 + // pi is inferred to be of type Double + // pi被推断为Double类型 + Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers. +在推断浮点型的数字时,Swift总是会选择Double型而不是Float。 + If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context: -let anotherPi = 3 + 0.14159 -// anotherPi is also inferred to be of type Double +如果你将整数型和浮点型的参数值相加,这种情况下会推断为Double类型: + + let anotherPi = 3 + 0.14159 + // anotherPi is also inferred to be of type Double + // anotherPi也被推断为Double类型 + The literal value of 3 has no explicit type in and of itself, and so an appropriate output type of Double is inferred from the presence of a floating-point literal as part of the addition. +参数值3本身并没有准确的类型,因此是通过相加的元素中有一个浮点型的参数值推断出合适的输出类型为Double. + Numeric Literals Integer literals can be written as: diff --git a/src/words.md b/src/words.md index cb4ca6e..fe83b49 100644 --- a/src/words.md +++ b/src/words.md @@ -1 +1,2 @@ -Class - 类 - Classes, structures, and enumerations can define subscripts \ No newline at end of file +Class - 类 - Classes, structures, and enumerations can define subscripts +literals - 参数 - A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below. From 2ddcba5ce27bae2c4d162ec7f5e061274747b5c3 Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Thu, 19 Jun 2014 01:11:19 +0800 Subject: [PATCH 139/261] update 01_the_basics - printIn and comment --- src/chapter2/01_The_Basics.md | 87 +++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 890722b..bafd030 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -113,6 +113,7 @@ The welcomeMessage variable can now be set to any string value without error: # 命名常量和变量 You can use almost any character you like for constant and variable names, including Unicode characters: + 你可以使用几乎所有你喜欢的符号来命名常量和变量,包括unicode字符: ``` @@ -153,3 +154,89 @@ Unlike a variable, the value of a constant cannot be changed once it is set. Att let languageName = "Swift" languageName = "Swift++" // this is a compile-time error - languageName cannot be changed + +# Printing Constants and Variables +# 输出常量和变量 + +You can print the current value of a constant or variable with the println function: + +你可以用`printIn`函数输出常量和变量的当前值: + +``` +println(friendlyWelcome) +// prints "Bonjour!" +// 输出 "Bonjour!" +``` + +println is a global function that prints a value, followed by a line break, to an appropriate output. If you are working in Xcode, for example, println prints its output in Xcode’s “console” pane. (A second function, print, performs the same task without appending a line break to the end of the value to be printed.) + +`printIn`是一个输出值的全局函数,为了得到良好的输出结果,输出后会加上一个空行。如果你使用的是Xcode,`printIn`会将结果输出到Xcode的调试信息栏。(另一个函数,`print`,会执行几乎相同的任务,除了不会在输出结果之后加空行以外。) + +The println function prints any String value you pass to it: + +`printIn`函数会输出任何你赋值的字符串: + +``` +println("This is a string") +// prints "This is a string" +``` + +The println function can print more complex logging messages, in a similar manner to Cocoa’s NSLog function. These messages can include the current values of constants and variables. + +`printIn`函数可以输出更复杂的记录信息,和Cocoa的NSlog函数类似。这些信息可以包含常量和变量的当前值。 + +Swift uses string interpolation to include the name of a constant or variable as a placeholder in a longer string, and to prompt Swift to replace it with the current value of that constant or variable. Wrap the name in parentheses and escape it with a backslash before the opening parenthesis: + +Swift使用字符串内插(string interpolation)的方式将常量或变量名以占位符的形式加入一个长的字符串中,并且提示Swift用常量或变量的当前值取代替它。将名字包裹在括号中并在前面加上反斜扛来转义。 + +``` +println("The current value of friendlyWelcome is \(friendlyWelcome)") +// prints "The current value of friendlyWelcome is Bonjour!" +// 输出 "The current value of friendlyWelcome is Bonjour!" +``` + +> NOTE + +> All options you can use with string interpolation are described in String Interpolation. + +> 注意 + +> 关于字符串插值的详细参数,参见[字符串插值](link)。 + +# Comments +# 注释 + +Use comments to include non-executable text in your code, as a note or reminder to yourself. Comments are ignored by the Swift compiler when your code is compiled. + +将代码中不会执行的文本,笔记或者备忘,用注释来表达。注释在编译时会被忽略。 + +Comments in Swift are very similar to comments in C. Single-line comments begin with two forward-slashes (//): + +Swift中的注释和C中的注释十分相似。单行的注释以两个正斜杠 (//)开头: + + // this is a comment + // 这是一个注释 + +You can also write multiline comments, which start with a forward-slash followed by an asterisk (/*) and end with an asterisk followed by a forward-slash (*/): + +你也可以写多行的注释,用一个正斜杠跟着一个星号开头 (/*) ,用一个星号跟着一个正斜杠结束(*/): + + /* this is also a comment, + but written over multiple lines */ + /* 这还是一个注释, + 但是是多行的 */ + +Unlike multiline comments in C, multiline comments in Swift can be nested inside other multiline comments. You write nested comments by starting a multiline comment block and then starting a second multiline comment within the first block. The second block is then closed, followed by the first block: + +和C中的多行注释不同,Swift的多行注释可以嵌套在另一个多行注释内部。你可以这样写嵌套的注释:开始一个多行注释块,在第一块多行注释内部跟着开始第二个多行注释。第二个多行注释块结束,然后第一个多行注释块结束。 + + /* this is the start of the first multiline comment + /* this is the second, nested multiline comment */ + this is the end of the first multiline comment */ + /* 这是第一个多行注释开始 + /* 这是第二个,嵌套的多行注释 */ + 这是第一个多行注释的结束 */ + +Nested multiline comments enable you to comment out large blocks of code quickly and easily, even if the code already contains multiline comments. + +嵌套的多行注释让你可以简单快捷的注释一大段代码,即使这块代码之前已经有多行注释块。 \ No newline at end of file From a217034f14c580cdb9734fb50ea840f350e4493f Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Thu, 19 Jun 2014 01:18:18 +0800 Subject: [PATCH 140/261] update 01_the_basics - all original content and update simicolons --- src/chapter2/01_The_Basics.md | 414 +++++++++++++++++++++++++++++++++- 1 file changed, 413 insertions(+), 1 deletion(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index bafd030..f4b14bb 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -239,4 +239,416 @@ Unlike multiline comments in C, multiline comments in Swift can be nested inside Nested multiline comments enable you to comment out large blocks of code quickly and easily, even if the code already contains multiline comments. -嵌套的多行注释让你可以简单快捷的注释一大段代码,即使这块代码之前已经有多行注释块。 \ No newline at end of file +嵌套的多行注释让你可以简单快捷的注释一大段代码,即使这块代码之前已经有多行注释块。 + +# Semicolons +# 分号 + +Unlike many other languages, Swift does not require you to write a semicolon (;) after each statement in your code, although you can do so if you wish. Semicolons are required, however, if you want to write multiple separate statements on a single line: + +和其他很多语言不同,Swift并不要求你在代码的每一个语句之后写一个分号(;),尽管如果你愿意你可以这么做。然而,如果你想在一行里写多个独立的语句,分号是必要的。 + + let cat = "🐱"; println(cat) + // prints "🐱" + +Integers + +Integers are whole numbers with no fractional component, such as 42 and -23. Integers are either signed (positive, zero, or negative) or unsigned (positive or zero). + +Swift provides signed and unsigned integers in 8, 16, 32, and 64 bit forms. These integers follow a naming convention similar to C, in that an 8-bit unsigned integer is of type UInt8, and a 32-bit signed integer is of type Int32. Like all types in Swift, these integer types have capitalized names. + +Integer Bounds + +You can access the minimum and maximum values of each integer type with its min and max properties: + +let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8 +let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8 +The values of these properties are of the appropriate-sized number type (such as UInt8 in the example above) and can therefore be used in expressions alongside other values of the same type. + +Int + +In most cases, you don’t need to pick a specific size of integer to use in your code. Swift provides an additional integer type, Int, which has the same size as the current platform’s native word size: + +On a 32-bit platform, Int is the same size as Int32. +On a 64-bit platform, Int is the same size as Int64. +Unless you need to work with a specific size of integer, always use Int for integer values in your code. This aids code consistency and interoperability. Even on 32-bit platforms, Int can store any value between -2,147,483,648 and 2,147,483,647, and is large enough for many integer ranges. + +UInt + +Swift also provides an unsigned integer type, UInt, which has the same size as the current platform’s native word size: + +On a 32-bit platform, UInt is the same size as UInt32. +On a 64-bit platform, UInt is the same size as UInt64. +NOTE + +Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference. + +Floating-Point Numbers + +Floating-point numbers are numbers with a fractional component, such as 3.14159, 0.1, and -273.15. + +Floating-point types can represent a much wider range of values than integer types, and can store numbers that are much larger or smaller than can be stored in an Int. Swift provides two signed floating-point number types: + +Double represents a 64-bit floating-point number. Use it when floating-point values must be very large or particularly precise. +Float represents a 32-bit floating-point number. Use it when floating-point values do not require 64-bit precision. +NOTE + +Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. + +Type Safety and Type Inference + +Swift is a type safe language. A type safe language encourages you to be clear about the types of values your code can work with. If part of your code expects a String, you can’t pass it an Int by mistake. + +Because Swift is type safe, it performs type checks when compiling your code and flags any mismatched types as errors. This enables you to catch and fix errors as early as possible in the development process. + +Type-checking helps you avoid errors when you’re working with different types of values. However, this doesn’t mean that you have to specify the type of every constant and variable that you declare. If you don’t specify the type of value you need, Swift uses type inference to work out the appropriate type. Type inference enables a compiler to deduce the type of a particular expression automatically when it compiles your code, simply by examining the values you provide. + +Because of type inference, Swift requires far fewer type declarations than languages such as C or Objective-C. Constants and variables are still explicitly typed, but much of the work of specifying their type is done for you. + +Type inference is particularly useful when you declare a constant or variable with an initial value. This is often done by assigning a literal value (or literal) to the constant or variable at the point that you declare it. (A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below.) + +For example, if you assign a literal value of 42 to a new constant without saying what type it is, Swift infers that you want the constant to be an Int, because you have initialized it with a number that looks like an integer: + +let meaningOfLife = 42 +// meaningOfLife is inferred to be of type Int +Likewise, if you don’t specify a type for a floating-point literal, Swift infers that you want to create a Double: + +let pi = 3.14159 +// pi is inferred to be of type Double +Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers. + +If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context: + +let anotherPi = 3 + 0.14159 +// anotherPi is also inferred to be of type Double +The literal value of 3 has no explicit type in and of itself, and so an appropriate output type of Double is inferred from the presence of a floating-point literal as part of the addition. + +Numeric Literals + +Integer literals can be written as: + +A decimal number, with no prefix +A binary number, with a 0b prefix +An octal number, with a 0o prefix +A hexadecimal number, with a 0x prefix +All of these integer literals have a decimal value of 17: + +let decimalInteger = 17 +let binaryInteger = 0b10001 // 17 in binary notation +let octalInteger = 0o21 // 17 in octal notation +let hexadecimalInteger = 0x11 // 17 in hexadecimal notation +Floating-point literals can be decimal (with no prefix), or hexadecimal (with a 0x prefix). They must always have a number (or hexadecimal number) on both sides of the decimal point. They can also have an optional exponent, indicated by an uppercase or lowercase e for decimal floats, or an uppercase or lowercase p for hexadecimal floats. + +For decimal numbers with an exponent of exp, the base number is multiplied by 10exp: + +1.25e2 means 1.25 × 102, or 125.0. +1.25e-2 means 1.25 × 10-2, or 0.0125. +For hexadecimal numbers with an exponent of exp, the base number is multiplied by 2exp: + +0xFp2 means 15 × 22, or 60.0. +0xFp-2 means 15 × 2-2, or 3.75. +All of these floating-point literals have a decimal value of 12.1875: + +let decimalDouble = 12.1875 +let exponentDouble = 1.21875e1 +let hexadecimalDouble = 0xC.3p0 +Numeric literals can contain extra formatting to make them easier to read. Both integers and floats can be padded with extra zeroes and can contain underscores to help with readability. Neither type of formatting affects the underlying value of the literal: + +let paddedDouble = 000123.456 +let oneMillion = 1_000_000 +let justOverOneMillion = 1_000_000.000_000_1 +Numeric Type Conversion + +Use the Int type for all general-purpose integer constants and variables in your code, even if they are known to be non-negative. Using the default integer type in everyday situations means that integer constants and variables are immediately interoperable in your code and will match the inferred type for integer literal values. + +Use other integer types only when they are are specifically needed for the task at hand, because of explicitly-sized data from an external source, or for performance, memory usage, or other necessary optimization. Using explicitly-sized types in these situations helps to catch any accidental value overflows and implicitly documents the nature of the data being used. + +Integer Conversion + +The range of numbers that can be stored in an integer constant or variable is different for each numeric type. An Int8 constant or variable can store numbers between -128 and 127, whereas a UInt8 constant or variable can store numbers between 0 and 255. A number that will not fit into a constant or variable of a sized integer type is reported as an error when your code is compiled: + +let cannotBeNegative: UInt8 = -1 +// UInt8 cannot store negative numbers, and so this will report an error +let tooBig: Int8 = Int8.max + 1 +// Int8 cannot store a number larger than its maximum value, +// and so this will also report an error +Because each numeric type can store a different range of values, you must opt in to numeric type conversion on a case-by-case basis. This opt-in approach prevents hidden conversion errors and helps make type conversion intentions explicit in your code. + +To convert one specific number type to another, you initialize a new number of the desired type with the existing value. In the example below, the constant twoThousand is of type UInt16, whereas the constant one is of type UInt8. They cannot be added together directly, because they are not of the same type. Instead, this example calls UInt16(one) to create a new UInt16 initialized with the value of one, and uses this value in place of the original: + +let twoThousand: UInt16 = 2_000 +let one: UInt8 = 1 +let twoThousandAndOne = twoThousand + UInt16(one) +Because both sides of the addition are now of type UInt16, the addition is allowed. The output constant (twoThousandAndOne) is inferred to be of type UInt16, because it is the sum of two UInt16 values. + +SomeType(ofInitialValue) is the default way to call the initializer of a Swift type and pass in an initial value. Behind the scenes, UInt16 has an initializer that accepts a UInt8 value, and so this initializer is used to make a new UInt16 from an existing UInt8. You can’t pass in any type here, however—it has to be a type for which UInt16 provides an initializer. Extending existing types to provide initializers that accept new types (including your own type definitions) is covered in Extensions. + +Integer and Floating-Point Conversion + +Conversions between integer and floating-point numeric types must be made explicit: + +let three = 3 +let pointOneFourOneFiveNine = 0.14159 +let pi = Double(three) + pointOneFourOneFiveNine +// pi equals 3.14159, and is inferred to be of type Double +Here, the value of the constant three is used to create a new value of type Double, so that both sides of the addition are of the same type. Without this conversion in place, the addition would not be allowed. + +The reverse is also true for floating-point to integer conversion, in that an integer type can be initialized with a Double or Float value: + +let integerPi = Int(pi) +// integerPi equals 3, and is inferred to be of type Int +Floating-point values are always truncated when used to initialize a new integer value in this way. This means that 4.75 becomes 4, and -3.9 becomes -3. + +NOTE + +The rules for combining numeric constants and variables are different from the rules for numeric literals. The literal value 3 can be added directly to the literal value 0.14159, because number literals do not have an explicit type in and of themselves. Their type is inferred only at the point that they are evaluated by the compiler. + +Type Aliases + +Type aliases define an alternative name for an existing type. You define type aliases with the typealias keyword. + +Type aliases are useful when you want to refer to an existing type by a name that is contextually more appropriate, such as when working with data of a specific size from an external source: + +typealias AudioSample = UInt16 +Once you define a type alias, you can use the alias anywhere you might use the original name: + +var maxAmplitudeFound = AudioSample.min +// maxAmplitudeFound is now 0 +Here, AudioSample is defined as an alias for UInt16. Because it is an alias, the call to AudioSample.min actually calls UInt16.min, which provides an initial value of 0 for the maxAmplitudeFound variable. + +Booleans + +Swift has a basic Boolean type, called Bool. Boolean values are referred to as logical, because they can only ever be true or false. Swift provides two Boolean constant values, true and false: + +let orangesAreOrange = true +let turnipsAreDelicious = false +The types of orangesAreOrange and turnipsAreDelicious have been inferred as Bool from the fact that they were initialized with Boolean literal values. As with Int and Double above, you don’t need to declare constants or variables as Bool if you set them to true or false as soon as you create them. Type inference helps make Swift code more concise and readable when it initializes constants or variables with other values whose type is already known. + +Boolean values are particularly useful when you work with conditional statements such as the if statement: + +if turnipsAreDelicious { + println("Mmm, tasty turnips!") +} else { + println("Eww, turnips are horrible.") +} +// prints "Eww, turnips are horrible." +Conditional statements such as the if statement are covered in more detail in Control Flow. + +Swift’s type safety prevents non-Boolean values from being be substituted for Bool. The following example reports a compile-time error: + +let i = 1 +if i { + // this example will not compile, and will report an error +} +However, the alternative example below is valid: + +let i = 1 +if i == 1 { + // this example will compile successfully +} +The result of the i == 1 comparison is of type Bool, and so this second example passes the type-check. Comparisons like i == 1 are discussed in Basic Operators. + +As with other examples of type safety in Swift, this approach avoids accidental errors and ensures that the intention of a particular section of code is always clear. + +Tuples + +Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other. + +In this example, (404, "Not Found") is a tuple that describes an HTTP status code. An HTTP status code is a special value returned by a web server whenever you request a web page. A status code of 404 Not Found is returned if you request a webpage that doesn’t exist. + +let http404Error = (404, "Not Found") +// http404Error is of type (Int, String), and equals (404, "Not Found") +The (404, "Not Found") tuple groups together an Int and a String to give the HTTP status code two separate values: a number and a human-readable description. It can be described as “a tuple of type (Int, String)”. + +You can create tuples from any permutation of types, and they can contain as many different types as you like. There’s nothing stopping you from having a tuple of type (Int, Int, Int), or (String, Bool), or indeed any other permutation you require. + +You can decompose a tuple’s contents into separate constants or variables, which you then access as usual: + +let (statusCode, statusMessage) = http404Error +println("The status code is \(statusCode)") +// prints "The status code is 404" +println("The status message is \(statusMessage)") +// prints "The status message is Not Found" +If you only need some of the tuple’s values, ignore parts of the tuple with an underscore (_) when you decompose the tuple: + +let (justTheStatusCode, _) = http404Error +println("The status code is \(justTheStatusCode)") +// prints "The status code is 404" +Alternatively, access the individual element values in a tuple using index numbers starting at zero: + +println("The status code is \(http404Error.0)") +// prints "The status code is 404" +println("The status message is \(http404Error.1)") +// prints "The status message is Not Found" +You can name the individual elements in a tuple when the tuple is defined: + +let http200Status = (statusCode: 200, description: "OK") +If you name the elements in a tuple, you can use the element names to access the values of those elements: + +println("The status code is \(http200Status.statusCode)") +// prints "The status code is 200" +println("The status message is \(http200Status.description)") +// prints "The status message is OK" +Tuples are particularly useful as the return values of functions. A function that tries to retrieve a web page might return the (Int, String) tuple type to describe the success or failure of the page retrieval. By returning a tuple with two distinct values, each of a different type, the function provides more useful information about its outcome than if it could only return a single value of a single type. For more information, see Functions with Multiple Return Values. + +NOTE + +Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple. For more information, see Classes and Structures. + +Optionals + +You use optionals in situations where a value may be absent. An optional says: + +There is a value, and it equals x +or + +There isn’t a value at all +NOTE + +The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structs, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there is a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants. + +Here’s an example. Swift’s String type has a method called toInt, which tries to convert a String value into an Int value. However, not every string can be converted into an integer. The string "123" can be converted into the numeric value 123, but the string "hello, world" does not have an obvious numeric value to convert to. + +The example below uses the toInt method to try to convert a String into an Int: + +let possibleNumber = "123" +let convertedNumber = possibleNumber.toInt() +// convertedNumber is inferred to be of type "Int?", or "optional Int" +Because the toInt method might fail, it returns an optional Int, rather than an Int. An optional Int is written as Int?, not Int. The question mark indicates that the value it contains is optional, meaning that it might contain some Int value, or it might contain no value at all. (It can’t contain anything else, such as a Bool value or a String value. It’s either an Int, or it’s nothing at all.) + +If Statements and Forced Unwrapping + +You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to true; if it has no value at all, it evaluates to false. + +Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value: + +if convertedNumber { + println("\(possibleNumber) has an integer value of \(convertedNumber!)") +} else { + println("\(possibleNumber) could not be converted to an integer") +} +// prints "123 has an integer value of 123" +For more on the if statement, see Control Flow. + +NOTE + +Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value. + +Optional Binding + +You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used with if and while statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action. if and while statements are described in more detail in Control Flow. + +Write optional bindings for the if statement as follows: + +if let constantName = someOptional { + statements +} +You can rewrite the possibleNumber example from above to use optional binding rather than forced unwrapping: + +if let actualNumber = possibleNumber.toInt() { + println("\(possibleNumber) has an integer value of \(actualNumber)") +} else { + println("\(possibleNumber) could not be converted to an integer") +} +// prints "123 has an integer value of 123" +This can be read as: + +“If the optional Int returned by possibleNumber.toInt contains a value, set a new constant called actualNumber to the value contained in the optional.” + +If the conversion is successful, the actualNumber constant becomes available for use within the first branch of the if statement. It has already been initialized with the value contained within the optional, and so there is no need to use the ! suffix to access its value. In this example, actualNumber is simply used to print the result of the conversion. + +You can use both constants and variables with optional binding. If you wanted to manipulate the value of actualNumber within the first branch of the if statement, you could write if var actualNumber instead, and the value contained within the optional would be made available as a variable rather than a constant. + +nil + +You set an optional variable to a valueless state by assigning it the special value nil: + +var serverResponseCode: Int? = 404 +// serverResponseCode contains an actual Int value of 404 +serverResponseCode = nil +// serverResponseCode now contains no value +NOTE + +nil cannot be used with non-optional constants and variables. If a constant or variable in your code needs to be able to cope with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type. + +If you define an optional constant or variable without providing a default value, the constant or variable is automatically set to nil for you: + +var surveyAnswer: String? +// surveyAnswer is automatically set to nil +NOTE + +Swift’s nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a non-existent object. In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types. + +Implicitly Unwrapped Optionals + +As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist. + +Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time. + +These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional. + +Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties. + +An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it is accessed. The following example shows the difference in behavior between an optional String and an implicitly unwrapped optional String: + +let possibleString: String? = "An optional string." +println(possibleString!) // requires an exclamation mark to access its value +// prints "An optional string." + +let assumedString: String! = "An implicitly unwrapped optional string." +println(assumedString) // no exclamation mark is needed to access its value +// prints "An implicitly unwrapped optional string." +You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used. Rather than placing an exclamation mark after the optional’s name each time you use it, you place an exclamation mark after the optional’s type when you declare it. + +NOTE + +If you try to access an implicitly unwrapped optional when it does not contain a value, you will trigger a runtime error. The result is exactly the same as if you place an exclamation mark after a normal optional that does not contain a value. + +You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value: + +if assumedString { + println(assumedString) +} +// prints "An implicitly unwrapped optional string." +You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement: + +if let definiteString = assumedString { + println(definiteString) +} +// prints "An implicitly unwrapped optional string." +NOTE + +Implicitly unwrapped optionals should not be used when there is a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable. + +Assertions + +Optionals enable you to check for values that may or may not exist, and to write code that copes gracefully with the absence of a value. In some cases, however, it is simply not possible for your code to continue execution if a value does not exist, or if a provided value does not satisfy certain conditions. In these situations, you can trigger an assertion in your code to end code execution and to provide an opportunity to debug the cause of the absent or invalid value. + +Debugging with Assertions + +An assertion is a runtime check that a logical condition definitely evaluates to true. Literally put, an assertion “asserts” that a condition is true. You use an assertion to make sure that an essential condition is satisfied before executing any further code. If the condition evaluates to true, code execution continues as usual; if the condition evaluates to false, code execution ends, and your app is terminated. + +If your code triggers an assertion while running in a debug environment, such as when you build and run an app in Xcode, you can see exactly where the invalid state occurred and query the state of your app at the time that the assertion was triggered. An assertion also lets you provide a suitable debug message as to the nature of the assert. + +You write an assertion by calling the global assert function. You pass the assert function an expression that evaluates to true or false and a message that should be displayed if the result of the condition is false: + +let age = -3 +assert(age >= 0, "A person's age cannot be less than zero") +// this causes the assertion to trigger, because age is not >= 0 +In this example, code execution will continue only if age >= 0 evaluates to true, that is, if the value of age is non-negative. If the value of age is negative, as in the code above, then age >= 0 evaluates to false, and the assertion is triggered, terminating the application. + +Assertion messages cannot use string interpolation. The assertion message can be omitted if desired, as in the following example: + +assert(age >= 0) +When to Use Assertions + +Use an assertion whenever a condition has the potential to be false, but must definitely be true in order for your code to continue execution. Suitable scenarios for an assertion check include: + +An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high. +A value is passed to a function, but an invalid value means that the function cannot fulfill its task. +An optional value is currently nil, but a non-nil value is essential for subsequent code to execute successfully. +See also Subscripts and Functions. + +NOTE + +Assertions cause your app to terminate and are not a substitute for designing your code in such a way that invalid conditions are unlikely to arise. Nonetheless, in situations where invalid conditions are possible, an assertion is an effective way to ensure that such conditions are highlighted and noticed during development, before your app is published. \ No newline at end of file From 81da1cd72fe77e62b5f77bc1f946160b7568115c Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Thu, 19 Jun 2014 02:33:43 +0800 Subject: [PATCH 141/261] update 01_the_basics - till UInt --- src/chapter2/01_The_Basics.md | 53 +++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index f4b14bb..cc08cb4 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -251,37 +251,74 @@ Unlike many other languages, Swift does not require you to write a semicolon (;) let cat = "🐱"; println(cat) // prints "🐱" -Integers +# Integers +# 整数 Integers are whole numbers with no fractional component, such as 42 and -23. Integers are either signed (positive, zero, or negative) or unsigned (positive or zero). +整数就是没有小数部分的完整的数字,如42和-23.整数可以有符号(正数,0,或负数),也可以没有符号(正数或0)。 + Swift provides signed and unsigned integers in 8, 16, 32, and 64 bit forms. These integers follow a naming convention similar to C, in that an 8-bit unsigned integer is of type UInt8, and a 32-bit signed integer is of type Int32. Like all types in Swift, these integer types have capitalized names. -Integer Bounds +Swift提供8,16,32和64进制的带符号和不带符号的整数类型。这些整数遵从和C类似的命名约定,在这个约定中,8进制的无符号整数的类型为`UInt8`,而一个32进制的有符号整数的类型是`Int32`。和Swift的所有类型一样,这些整数的类型是首字母大写的。 + +# Integer Bounds +# 整数边界 You can access the minimum and maximum values of each integer type with its min and max properties: -let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8 -let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8 +你可以通过整数类型的`max`和`min`属性来访问它的最大值和最小值: + + let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8 + let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8 + let minValue = UInt8.min // 最小值是 0, 类型是 UInt8 + let maxValue = UInt8.max // 最大值是 255, 类型是 UInt8 + The values of these properties are of the appropriate-sized number type (such as UInt8 in the example above) and can therefore be used in expressions alongside other values of the same type. -Int +这些属性值是相应数字类型的合适范围(比如上面例子里的`UInt8`),因此它们可以在其他拥有相同类型值的表达式中沿用。 + +# Int +# 整数 In most cases, you don’t need to pick a specific size of integer to use in your code. Swift provides an additional integer type, Int, which has the same size as the current platform’s native word size: +在大多数情况下,你不需要在代码中指定整数的范围。Swift提供了一个专门的整数类型,`Int`,它和当前平台的原生长度范围相同。 + On a 32-bit platform, Int is the same size as Int32. + +在32位的平台上,`Int`和`Int32`范围相同。 + On a 64-bit platform, Int is the same size as Int64. + +在64位的平台上,`Int`和`Int64`范围相同。 + Unless you need to work with a specific size of integer, always use Int for integer values in your code. This aids code consistency and interoperability. Even on 32-bit platforms, Int can store any value between -2,147,483,648 and 2,147,483,647, and is large enough for many integer ranges. -UInt +如果你不需要处理特定的整数范围,请在代码中的整数值使用`Int`类型。这有助于代码的一致性和可复用性。即使在32位的平台上,`Int`类型可以储存从-2,147,483,648到2,147,483,647的整数,大多数情况下这足够用了。 + +# UInt +# 无符号整数 Swift also provides an unsigned integer type, UInt, which has the same size as the current platform’s native word size: +Swift也提供了无符号整数类型,`UInt`,它和当前平台的原生长度范围相同。 + On a 32-bit platform, UInt is the same size as UInt32. + +在32位的平台上,`UInt`和`UInt32`范围相同。 + On a 64-bit platform, UInt is the same size as UInt64. -NOTE -Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference. +在64位的平台上,`UInt`和`UInt64`范围相同。 + +> NOTE + +> Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference. + +> 注意 + +> 只在你需要特别指定无符号整数与当前平台原生长度范围相同时才使用`UInt`,否则,推荐使用`Int`,即使是你知道不会存储负值的时候。使用一致的`Int`整数类型有助于代码的服用,避免了不同数字类型之间的转换,并且匹配整数的类型推断,详见[类型安全和类型推断](link)。 Floating-Point Numbers From 7e3c289fb4386d2c0912b37071c787b6dbdfd132 Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Thu, 19 Jun 2014 22:18:48 +0800 Subject: [PATCH 142/261] update 01_the_basics - Floating-Point Numbers --- src/chapter2/01_The_Basics.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index cc08cb4..91c742c 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -320,19 +320,35 @@ On a 64-bit platform, UInt is the same size as UInt64. > 只在你需要特别指定无符号整数与当前平台原生长度范围相同时才使用`UInt`,否则,推荐使用`Int`,即使是你知道不会存储负值的时候。使用一致的`Int`整数类型有助于代码的服用,避免了不同数字类型之间的转换,并且匹配整数的类型推断,详见[类型安全和类型推断](link)。 -Floating-Point Numbers +# Floating-Point Numbers +# 浮点型数字 Floating-point numbers are numbers with a fractional component, such as 3.14159, 0.1, and -273.15. +浮点型数字是指有小数部分的数字,比如3.14159, 0.1 和 -273.15。 + Floating-point types can represent a much wider range of values than integer types, and can store numbers that are much larger or smaller than can be stored in an Int. Swift provides two signed floating-point number types: +浮点类型比整数类型范围大很多,它可以储存比整数更大或者更小的数。Swift提供了两种有符号的浮点数类型: + Double represents a 64-bit floating-point number. Use it when floating-point values must be very large or particularly precise. + +`Double`代表64位浮点数。当你需要特别大和特别精确的值的时候使用`Double`类型。 + Float represents a 32-bit floating-point number. Use it when floating-point values do not require 64-bit precision. -NOTE -Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. +`Float`代表32位浮点数。当不需要像64位那么精确的时候使用`Float`就够了。 + +> NOTE + +> Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. + +> 注意 + +> `Double`有至少15位数字的精确度,而`Float`的精确度最少只有6位数字。根据业务需要的值的范围去选择合适的浮点类型。 -Type Safety and Type Inference +# Type Safety and Type Inference +# 类型安全和类型推断 Swift is a type safe language. A type safe language encourages you to be clear about the types of values your code can work with. If part of your code expects a String, you can’t pass it an Int by mistake. From 44129e0e14c9d273bdcb863fa011f49e2c369d2f Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Fri, 20 Jun 2014 15:16:40 +0800 Subject: [PATCH 143/261] update 01_the_basics - Type Safety and Type Inference --- src/chapter2/01_The_Basics.md | 38 +++++++++++++++++++++++++++++------ src/words.md | 3 ++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 91c742c..370c762 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -352,30 +352,56 @@ Float represents a 32-bit floating-point number. Use it when floating-point valu Swift is a type safe language. A type safe language encourages you to be clear about the types of values your code can work with. If part of your code expects a String, you can’t pass it an Int by mistake. +Swift是一个类型安全的语言。一个类型安全的语言鼓励你声明代码中使用的值的类型。如果你期望这部分代码是字符串(String),你就不能错误的给它赋一个整型(Int)的值。 + Because Swift is type safe, it performs type checks when compiling your code and flags any mismatched types as errors. This enables you to catch and fix errors as early as possible in the development process. +因为Swift是类型安全的,它会在编译时运行类型检查,并且将所有不匹配的类型标记为错误。这让你可以在开发过程中今早的发现和修复问题。 + Type-checking helps you avoid errors when you’re working with different types of values. However, this doesn’t mean that you have to specify the type of every constant and variable that you declare. If you don’t specify the type of value you need, Swift uses type inference to work out the appropriate type. Type inference enables a compiler to deduce the type of a particular expression automatically when it compiles your code, simply by examining the values you provide. +当你处理不同类型的值的时候,类型检查帮助你避免错误。然而,这并不意味着你需要给每一个声明的常量和变量指定特定的类型。如果你没有指定特定的类型,Swift会使用类型推断来推断出合适的类型。当编译代码时,类型推断特性使得编译器可以简单的通过检查你提供的值来自动推断出特定表达式的类型。 + Because of type inference, Swift requires far fewer type declarations than languages such as C or Objective-C. Constants and variables are still explicitly typed, but much of the work of specifying their type is done for you. +因为有了类型推断,Swift与类似C和Objective-C的语言相比需要更少的类型声明。常量和变量同样会有准确的类型,但是大部分关于指定类型的工作Swift已经帮你做好了。 + Type inference is particularly useful when you declare a constant or variable with an initial value. This is often done by assigning a literal value (or literal) to the constant or variable at the point that you declare it. (A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below.) +当你声明一个有初始值的常量或变量的时候类型推断特别实用。通常是当你声明一个常量和变量的时候你就给它赋一个参数值(literal value)。(参数值是会直接出现在源码里的值,比如下面例子里的42和3.14159。) + For example, if you assign a literal value of 42 to a new constant without saying what type it is, Swift infers that you want the constant to be an Int, because you have initialized it with a number that looks like an integer: -let meaningOfLife = 42 -// meaningOfLife is inferred to be of type Int +举个例子,如果你给一个新的常量赋了一个参数值42,但没有说它的类型,Swift会推断你希望这个常量是一个整数类型(Int),因为你用了一个像是整数的数字来初始化: + + let meaningOfLife = 42 + // meaningOfLife is inferred to be of type Int + // meaningOfLife被推断为整数类型(Int) + Likewise, if you don’t specify a type for a floating-point literal, Swift infers that you want to create a Double: -let pi = 3.14159 -// pi is inferred to be of type Double +类似的,如果你没有特别指定一个浮点型的参数,Swift会推断你需要一个Double类型的浮点数: + + let pi = 3.14159 + // pi is inferred to be of type Double + // pi被推断为Double类型 + Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers. +在推断浮点型的数字时,Swift总是会选择Double型而不是Float。 + If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context: -let anotherPi = 3 + 0.14159 -// anotherPi is also inferred to be of type Double +如果你将整数型和浮点型的参数值相加,这种情况下会推断为Double类型: + + let anotherPi = 3 + 0.14159 + // anotherPi is also inferred to be of type Double + // anotherPi也被推断为Double类型 + The literal value of 3 has no explicit type in and of itself, and so an appropriate output type of Double is inferred from the presence of a floating-point literal as part of the addition. +参数值3本身并没有准确的类型,因此是通过相加的元素中有一个浮点型的参数值推断出合适的输出类型为Double. + Numeric Literals Integer literals can be written as: diff --git a/src/words.md b/src/words.md index cb4ca6e..fe83b49 100644 --- a/src/words.md +++ b/src/words.md @@ -1 +1,2 @@ -Class - 类 - Classes, structures, and enumerations can define subscripts \ No newline at end of file +Class - 类 - Classes, structures, and enumerations can define subscripts +literals - 参数 - A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below. From 3eec3cd940e0b772f9face48738188aeddb636bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E6=97=B6?= Date: Fri, 20 Jun 2014 17:06:32 +0800 Subject: [PATCH 144/261] =?UTF-8?q?swift=E6=B3=9B=E5=9E=8B=E9=83=A8?= =?UTF-8?q?=E5=88=86=E7=BF=BB=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/22_Generics.md | 565 ++++++++++++++++++++++++++++++++++++ 1 file changed, 565 insertions(+) diff --git a/src/chapter2/22_Generics.md b/src/chapter2/22_Generics.md index e69de29..97c9e25 100644 --- a/src/chapter2/22_Generics.md +++ b/src/chapter2/22_Generics.md @@ -0,0 +1,565 @@ +#Generics +#泛型 + +Generic code enables you to write flexible, reusable functions and types that can work with any type, subject to requirements that you define. You can write code that avoids duplication and expresses its intent in a clear, abstracted manner. + +泛型代码可以让你写出更灵活、复用性更强的的函数或者类型,这种函数或者类型可以是满足你需求的任意类型或者主题。你可以用一种清晰抽象的方式表达出来,避免重复代码。 + +Generics are one of the most powerful features of Swift, and much of the Swift standard library is built with generic code. In fact, you’ve been using generics throughout this Language Guide, even if you didn’t realize it. For example, Swift’s Array and Dictionary types are both generic collections. You can create an array that holds Int values, or an array that holds String values, or indeed an array for any other type that can be created in Swift. Similarly, you can create a dictionary to store values of any specified type, and there are no limitations on what that type can be. + +泛型是Swift中非常强大的特性之一,而且很多Swift中的基础库是用泛型构建的。事实上,不管你有没有意识到,其实在整本swift介绍中你都会用到泛型。例如,Swift中的Array和Dictionary类型都是泛型集合。你可以创建一个int类型的数组,也可以创建String类型的数组,事实上在Swift中你可以创建任意类型的数组。同样地,你也可以创建一个存储任意类型数据的字典类型; + +#The Problem That Generics Solve +#泛型解决的问题 + +Here’s a standard, non-generic function called `swapTwoInts`, which swaps two Int values: + +下边代码是一个标准的、非泛型函数`swapTwoInts`, 用于交换两个int值: + +``` +func swapTwoInts(inout a: Int, inout b: Int) { + let temporaryA = a + a = b + b = temporaryA +} +``` + +This function makes use of in-out parameters to swap the values of a and b, as described in [In-Out Parameters](). + +这个函数使用in-out参数交换a,b值,具体的可以参考[In-Out Parameters](). + +The `swapTwoInts` function swaps the original value of b into a, and the original value of a into b. You can call this function to swap the values in two Int variables: + +`swapTwoInts`函数把b的原始值赋值给a, a的原始值给b.你可以调用这个函数去交换两个整形值: + +``` +var someInt = 3 +var anotherInt = 107 +swapTwoInts(&someInt, &anotherInt) +println("someInt is now \(someInt), and anotherInt is now \(anotherInt)") +// prints "someInt is now 107, and anotherInt is now 3 +``` + +The `swapTwoInts` function is useful, but it can only be used with Int values. If you want to swap two String values, or two Double values, you have to write more functions, such as the `swapTwoStrings` and `swapTwoDoubles `functions shown below: + +`swapTwoInts`函数是有用的,但是这个函数只能交换int值。如果想交换两个NSString、或者是两个Double类型的值,你不得不写更多的代码,比如`swapTwoStrings`,`swapTwoDoublesfunctions`,如下所示: + +``` +func swapTwoStrings(inout a: String, inout b: String) { + let temporaryA = a + a = b + b = temporaryA +} +func swapTwoDoubles(inout a: Double, inout b: Double) { + let temporaryA = a + a = b + b = temporaryA +} +``` + +You may have noticed that the bodies of the `swapTwoInts`, `swapTwoStrings`, and `swapTwoDoubles` functions are identical. The only difference is the type of the values that they accept (Int, String, and Double). + +也许,你已经注意到了,这三个函数的内容基本上是相同的,唯一的区别就是传参类型不一样,分别是Int,String,Double. + +It would be much more useful, and considerably more flexible, to write a single function that could swap two values of any type. This is the kind of problem that generic code can solve. (A generic version of these functions is defined below.) + +你会想,如果可以只写一个函数就可以交换两个任意类型的值,那一定会很强大、相当的灵活。这正是泛型所解决的问题。(泛型版的这种函数如下)。 + +``` +NOTE +In all three functions, it is important that the types of a and b are defined to be the same as each other. If a and b were not of the same type, it would not be possible to swap their values. Swift is a type-safe language, and does not allow (for example) a variable of type String and a variable of type Double to swap values with each other. Attempting to do so would be reported as a compile-time error. +``` + + +#Generic Functions +#泛型函数 + +Generic functions can work with any type. Here’s a generic version of the `swapTwoInts` function from above, called `swapTwoValues`: + +泛型函数可以工作于任何类型。下面就是上边提到的`swapTwoInts`的泛型版本,`swapTwoValues`: + +``` +func swapTwoValues(inout a: T, inout b: T) { + let temporaryA = a + a = b + b = temporaryA +} +``` +The body of the `swapTwoValues` function is identical to the body of the `swapTwoInts` function. However, the first line of `swapTwoValues` is slightly different from `swapTwoInts`. Here’s how the first lines compare: + +除了第一行有一点区别之外,`swapTwoValues`和`swapTwoInts`的主题内容是一样的,如下所示: + +``` +func swapTwoInts(inout a: Int, inout b: Int) +func swapTwoValues(inout a: T, inout b: T) +``` + +The generic version of the function uses a placeholder type name (called T, in this case) instead of an actual type name (such as Int, String, or Double). The placeholder type name doesn’t say anything about what T must be, but it does say that both a and b must be of the same type T, whatever T represents. The actual type to use in place of T will be determined each time the `swapTwoValues` function is called. + +泛型版本使用了节点类型命名(一般都使用字母T)来代替实际的类型名称(比如Int,String,或者Double)。节点类型定义限制a和b必须是相同类型,而不限制到底是什么类型,T可以代表任意类型。只有当`swapTwoValues`真正调用的时候,才会决定T代表什么类型。 + +The other difference is that the generic function’s name (swapTwoValues) is followed by the placeholder type name (T) inside angle brackets (). The brackets tell Swift that T is a placeholder type name within the`swapTwoValues` function definition. Because T is a placeholder, Swift does not look for an actual type called T. + +另一个区别是泛型函数后边跟着的类型(T)是放到尖括号里边的()。尖括号告诉Swift,T是`swapTwoValues`所定义的一个节点类型。由于T表示节点,swift不会查找命名为T的类型。 + +The `swapTwoValues` function can now be called in the same way as `swapTwoInts`, except that it can be passed two values of any type, as long as both of those values are of the same type as each other. Each time `swapTwoValues` is called, the type to use for T is inferred from the types of values passed to the function. + + + +In the two examples below, T is inferred to be Int and String respectively: + +``` +var someInt = 3 +var anotherInt = 107 +swapTwoValues(&someInt, &anotherInt) +// someInt is now 107, and anotherInt is now + +var someString = "hello" +var anotherString = "world" +swapTwoValues(&someString, &anotherString) +// someString is now "world", and anotherString is now "hello" +``` + +``` +NOTE +The swapTwoValues function defined above is inspired by a generic function called swap, which is part of the Swift standard library, and is automatically made available for you to use in your apps. If you need the behavior of the swapTwoValues function in your own code, you can use Swift’s existing swap function rather than providing your own implementation. +``` +#Type Parameters +#参数类型 +In the swapTwoValues example above, the placeholder type T is an example of a type parameter. Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of matching angle brackets (such as ). + +Once specified, a type parameter can be used to define the type of a function’s parameters (such as the a and b parameters of the swapTwoValues function); or as the function’s return type; or as a type annotation within the body of the function. In each case, the placeholder type represented by the type parameter is replaced with an actual type whenever the function is called. (In the swapTwoValues example above, T was replaced with Int the first time the function was called, and was replaced with String the second time it was called.) + +You can provide more than one type parameter by writing multiple type parameter names within the angle brackets, separated by commas. + +‌ +#Naming Type Parameters +#参数类型命名 +In simple cases where a generic function or generic type needs to refer to a single placeholder type (such as the swapTwoValues generic function above, or a generic collection that stores a single type, such as Array), it is traditional to use the single-character name T for the type parameter. However, you are can use any valid identifier as the type parameter name. + +If you are defining more complex generic functions, or generic types with multiple parameters, it can be useful to provide more descriptive type parameter names. For example, Swift’s Dictionary type has two type parameters—one for its keys and one for its values. If you were writing Dictionary yourself, you might name these two type parameters KeyType and ValueType to remind you of their purpose as you use them within your generic code. + +``` +NOTE + +Always give type parameters UpperCamelCase names (such as T and KeyType) to indicate that they are a placeholder for a type, not a value. +``` +#Generic Types +#泛型类型 +n addition to generic functions, Swift enables you to define your own generic types. These are custom classes, structures, and enumerations that can work with any type, in a similar way to Array and Dictionary. + +This section shows you how to write a generic collection type called Stack. A stack is an ordered set of values, similar to an array, but with a more restricted set of operations than Swift’s Array type. An array allows new items to be inserted and removed at any location in the array. A stack, however, allows new items to be appended only to the end of the collection (known as pushing a new value on to the stack). Similarly, a stack allows items to be removed only from the end of the collection (known as popping a value off the stack). + +``` +NOTE +The concept of a stack is used by the UINavigationController class to model the view controllers in its navigation hierarchy. You call the UINavigationController class pushViewController:animated: method to add (or push) a view controller on to the navigation stack, and its popViewControllerAnimated: method to remove (or pop) a view controller from the navigation stack. A stack is a useful collection model whenever you need a strict “last in, first out” approach to managing a collection. +``` + +The illustration below shows the push / pop behavior for a stack: + +下边图表展示的是堆栈的进入、进出特性: + +![stack](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPushPop_2x.png) + + +1. There are currently three values on the stack. +2. A fourth value is “pushed” on to the top of the stack. +3. The stack now holds four values, with the most recent one at the top. +4. The top item in the stack is removed, or “popped”. +5. After popping a value, the stack once again holds three values. + +1.当前堆栈里有3个值 +2.第四个值从堆栈的顶部push进去 +3.现在堆栈中有4个值,其中最先进的在最顶部 +4.堆栈最顶部的值被移除,或者叫“popped” +5.当推出一个值后,堆栈重新变成了三个值 + +Here’s how to write a non-generic version of a “stack, in this case for a stack of Int values + +下边是如何写一个不是泛型版本的堆栈,这个例子中得堆栈是Int类型: + +``` +struct IntStack { + var items = Int[]() + mutating func push(item: Int) { + items.append(item) + } + mutating func pop() -> Int { + return items.removeLast() + } +} +``` +This structure uses an Array property called items to store the values in the stack. Stack provides two methods, push and pop, to push and pop values on and off the stack. These methods are marked as mutating, because they need to modify (or mutate) the structure’s items array. + +这个结构中使用数组属性`items`去存储堆栈中的数据。堆栈提供两个方法`push` 和`pop`,用于推入数据到堆栈,或者从堆栈推出数据。这些方法定义为`mutating`类型,原因是需要修改结构中得items数组的值。 + +The IntStack type shown above can only be +“used with Int values, however. It would be much more useful to define a generic Stack class, that can manage a stack of any type of value. + +上边的这个`IntStack`类型只能用于Int值。然而,定义泛型类型的堆栈类型,可以管理堆栈中得任意类型,是非常有用的。 + +Here’s a generic version of the same code: + +上边是相同代码的泛型版本: + +``` +struct Stack { + var items = T[]() + mutating func push(item: T) { + items.append(item) + } + mutating func pop() -> T { + return items.removeLast() + } +} +``` +Note how the generic version of Stack is essentially the same as the non-generic version, but with a placeholder type parameter called T instead of an actual type of Int. This “type parameter is written within a pair of angle brackets () immediately after the structure’s name. + +可以注意到,除了使用T代替真实int类型之外,下边的泛型版本的堆栈结构和上边非泛型版本的基本上一样的。这种类型参数是在紧接着结构的名称后跟着一对尖括号(). + +T defines a placeholder name for “some type T” to be provided later on. This future type can be referred to as “T” anywhere within the structure’s definition. In this case, T is used as a placeholder in three places: + +`T`定义了一个名称为”某种类型T“的节点提供给后边用。这种将来类型可以在结构体定义中的任何地方表示为`T`。在这个例子中,`T`在如下的几个地方会被使用: + +1. To create a property called items, which is initialized with an empty array of values of type T +2. To specify that the push method has a single parameter called item, which must be of type T +3. To specify that the value returned by the pop method will be a value of type T + +1.创建成员变量`items`,被初始化为包含类型T的空数组 +2.指定`push`方法有一个参数item,类型为T类型 +3.指定`pop`方法返回结果类型为T + +You create instances of Stack in a similar way to Array and Dictionary, by writing the actual type to be used for this specific stack within angle brackets after the type name when creating a new instance with initializer syntax: + +像创建Array和Dictionary一样,创建一个Stack实例,在初始化时,紧随类型名后边尖括号中写出实际用到的类型: + +``` +var stackOfStrings = Stack() +stackOfStrings.push("uno") +stackOfStrings.push("dos") +stackOfStrings.push("tres") +stackOfStrings.push("cuatro") +// the stack now contains 4 strings +``` + +Here’s how stackOfStrings looks after pushing these four values on to the stack: + +下边展示`stackOfStrings`是如何把四个值push进栈: + +![进栈](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPushedFourStrings_2x.png) + + Popping a value from the stack returns and removes the top value, "cuatro": + + 下图是如何从栈中pop一个值的过程,移除栈最顶上结果,“cuatro”,并返回其值: + +``` + let fromTheTop = stackOfStrings.pop() + // fromTheTop is equal to "cuatro", and the stack now contains 3 strings +``` +Here’s how the stack looks after popping its top value: + +下边是推出最顶层数据之后的堆栈效果: + +![移除堆栈效果](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPoppedOneString_2x.png) + + Because it is a generic type, Stack can be used to create a stack of any valid type in Swift, in a similar manner to Array and Dictionary. + + 由于`Stack`是泛型类型,所以在Swift中可以用于创建任何有效类型的栈,方式同`Array`和`Dictionary`。 + +#Type Constraints +#类型约束 + +The swapTwoValues function and the Stack type can work with any type. However, it is sometimes useful to enforce certain type constraints on the types that can be used with generic functions and generic types. Type constraints specify that a type parameter must inherit from a specific class, or conform to a particular protocol or protocol composition. + +`swapTwoValues`函数和`Stack`类型可以作用于任何类型,不过,有的时候对泛型函数和泛型类型上做类型强制约束是非常有用的。类型约束指定参数类型必须继承一个指定类型参数或者遵循一个特定的协议或协议构成。 + +For example, Swift’s Dictionary type places a limitation on the types that can be used as keys for a dictionary. As described in Dictionaries, the type of a dictionary’s keys must be hashable. That is, it must provide a way to make itself uniquely representable. Dictionary needs its keys to be hashable so that it can check whether it already contains a value for a particular key. Without this requirement, Dictionary could not tell whether it should insert or replace a value for a particular key, nor would it be able to find a value for a given key that is already in the dictionary. + +例如,Swift中的`Dictionary`对键值做了约束。在字典的描述中,字典的键值类型必须是可哈希的,就是说他必须有一种方法保证其是唯一的。`Dictionary`约定键值是可哈希的,是为了便于检查其是否已经包含某个特定键的值。如果没有这个约束,就不能告诉是否可以插入或者替换某个特定键的值,也不能查找到某个已经存储在字典中的特定值。 + +This requirement is enforced by a type constraint on the key type for Dictionary, which specifies that the key type must conform to the Hashable protocol, a special protocol defined in the Swift standard library. All of Swift’s basic types (such as String, Int, Double, and Bool) are hashable by default. + +这个需求强制加上一个类型约束作用于Dictionary的键上,而且其键类型必须遵循Hashable协议(Swift 标准库中定义的一个特定协议)。所有的 Swift 基本类型(如String,Int,Double和 Bool)默认都是可哈希。 + +You can define your own type constraints when creating custom generic types, and these constraints provide much of the power of generic programming. Abstract concepts like Hashable characterize types in terms of their conceptual characteristics, rather than their explicit type. + +当你创建自定义泛型类型时,你可以定义你自己的类型约束,当然,这些约束要支持泛型编程的强力特征中的多数。抽象概念如可哈希具有的类型特征是根据它们概念特征来界定的,而不是它们的直接类型特征。 + +##Type Constraint Syntax + +##类型约束语法 + You write type constraints by placing a single class or protocol constraint after a type parameter’s name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types): + + 你可以通过在参数名称的后边以冒号分割,加上类型参数约束。基础的泛型函数的类型约束语法如下(同样的,泛型类型的语法相同) + +``` + func someFunction(someT: T, someU: U) { + // function body goes here + } + ``` +The hypothetical function above has two type parameters. The first type parameter, T, has a type constraint that requires T to be a subclass of SomeClass. The second type parameter, U, has a type constraint that requires U to conform to the protocol SomeProtocol. + +上边函数有两个参数。参数一类型参数为T,需要T必须是`SomeClass`子类;第二个参数类型为U,需要U必须遵循`SomeClass`协议。 + +##Type Constraints in Action +##类型约束行为 + +Here’s a non-generic function called findStringIndex, which is given a String value to find and an array of String values within which to find it. The findStringIndex function returns an optional Int value, which will be the index of the first matching string in the array if it is found, or nil if the string cannot be found: + +这里有个名为findStringIndex的非泛型函数,该函数是去查找包含一指定String值的数组。若查找到匹配的字符串,findStringIndex函数返回该字符串在数组中的索引位置(Int),反之返回nil: + + func findStringIndex(array: String[], valueToFind: String) -> Int? { + for (index, value) in enumerate(array) { + if value == valueToFind { + return index + } + } + return nil + } + +The findStringIndex function can be used to find a string value in an array of strings: + +`findStringIndex`用于查找数组中的指定String值: + + let strings = ["cat", "dog", "llama", "parakeet", "terrapin"] + if let foundIndex = findStringIndex(strings, "llama") { + println("The index of llama is \(foundIndex)") + } + // prints "The index of llama is 2" + +The principle of finding the index of a value in an array isn’t useful only for strings, however. You can write the same functionality as a generic function called findIndex, by replacing any mention of strings with values of some type T instead. + +如果只是查找数组中的指定字符串用处不大,但是你可以写出相同功能的泛型版本`findIndex`,用T代替字符串类型。 + +Here’s how you might expect a generic version of findStringIndex, called findIndex, to be written. Note that the return type of this function is still Int?, because the function returns an optional index number, not an optional value from the array. Be warned, though—this function does not compile, for reasons explained after the example: + +下边是你理想中的`findStringIndex`的泛型版本`findIndex`。注意到函数的返回结果仍然是Int?,这是因为这个函数使用用于返回具体的索引值,而不是搜索值。需要提醒的是,这个函数不会编译,原因后边会说明: + + func findIndex(array: T[], valueToFind: T) -> Int? { + for (index, value) in enumerate(array) { + if value == valueToFind { + return index + } + } + return nil + } + +This function does not compile as written above. The problem lies with the equality check, “if value == valueToFind”. Not every type in Swift can be compared with the equal to operator (==). If you create your own class or structure to represent a complex data model, for example, then the meaning of “equal to” for that class or structure is not something that Swift can guess for you. Because of this, it is not possible to guarantee that this code will work for every possible type T, and an appropriate error is reported when you try to compile the code. + +这个函数按照上边的写法不会编译。原因是因为比较这部分`“if value == valueToFind”. 不是所有的泛型类型都可以用比较操作`==`。如果你创建了自己的函数或者结构代表一个负责的数据模型,那么Swift语言没法猜出这个类或者结果等于的意思。正因为如此,不能保证这个代码可以作用于所有类型T,而且会编译出错。 + +All is not lost, however. The Swift standard library defines a protocol called Equatable, which requires any conforming type to implement the equal to operator (==) and the not equal to operator (!=) to compare any two values of that type. All of Swift’s standard types automatically support the Equatable protocol. + +不过,有解决方法。Swift 标准库中定义了一个Equatable协议,该协议要求任何遵循的类型实现等式符(==)和不等符(!=)对任何两个该类型进行比较。所有的 Swift 标准类型自动支持Equatable协议。 + +Any type that is Equatable can be used safely with the findIndex function, because it is guaranteed to support the equal to operator. To express this fact, you write a type constraint of Equatable as part of the type parameter’s definition when you define the function: + +任何Equatable类型都可以安全的使用在findIndex函数中,它保证可以支持等号操作。为了说明这个事实,你定义函数时,可以写一个Equatable类型约束作为类型参数定义的一部分: + + func findIndex(array: T[], valueToFind: T) -> Int? { + for (index, value) in enumerate(array) { + if value == valueToFind { + return index + } + } + return nil + } + +The single type parameter for findIndex is written as T: Equatable, which means “any type T that conforms to the Equatable protocol. + +`findIndex`的类型参数可以写成`T: Equatable`,表示任意实现` Equatable`协议的类型。 + +The findIndex function now compiles successfully and can be used with any type that is Equatable, such as Double or String: + +`findIndex`类型现在可以成功编译,并且可以用于任意实现了` Equatable`协议的类型,比如`Doubl`e 或者`String`: + + let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3) + // doubleIndex is an optional Int with no value, because 9.3 is not in the array + let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea") + // stringIndex is an optional Int containing a value of 2 + +#Associated Types +#关联类型 +When defining a protocol, it is sometimes useful to declare one or more associated types as part of the protocol’s definition. An associated type gives a placeholder name (or alias) to a type that is used as part of the protocol. The actual type to use for that associated type is not specified until the protocol is adopted. Associated types are specified with the typealias keyword. + +当定义一个协议时,有时声明一个或多个关联类型作为协议的一部分非常有用。一个关联类型给定作用于协议部分的类型一个节点名(或别名)。作用于关联类型实际类型不需要指定,直到协议接受。关联类型被指定为typealias关键字。 + +##Associated Types in Action +##关联类型行为 + +Here’s an example of a protocol called Container, which declares an associated type called ItemType: + +下边是一个协议`Container`,定义了关联类型`ItemType`: + + protocol Container { + typealias ItemType + mutating func append(item: ItemType) + var count: Int { get } + subscript(i: Int) -> ItemType { get } + } + +The Container protocol defines three required capabilities that any container must provide: + +上述协议定义了三个必须支持的兼容协议: + +1. It must be possible to add a new item to the container with an append method. + +2. It must be possible to access a count of the items in the container through a count property that returns an Int value. + +3. It must be possible to retrieve each item in the container with a subscript that takes an Int index value. + +1. 必须可以通过append方法添加新的元素到容器中。 +2. 必须提供一个属性方法可以获取容器中的元素数目,并返回一个Int值。 +3. 必须可以通过Int索引下标检索每个值。 + +This protocol doesn’t specify how the items in the container should be stored or what type they are allowed to be. The protocol only specifies the three bits of functionality that any type must provide in order to be considered a Container. A conforming type can provide additional functionality, as long as it satisfies these three requirements. + + + +Any type that conforms to the Container protocol must be able to specify the type of values it stores. Specifically, it must ensure that only items of the right type are added to the container, and it must be clear about the type of the items returned by its subscript. + +To define these requirements, the Container protocol needs a way to refer to the type of the elements that a container will hold, without knowing what that type is for a specific container. The Container protocol needs to specify that any value passed to the append method must have the same type as the container’s element type, and that the value returned by the container’s subscript will be of the same type as the container’s element type. + +To achieve this, the Container protocol declares an associated type called ItemType, written as typealias ItemType. The protocol does not define what ItemType is an alias for—that information is left for any conforming type to provide. Nonetheless, the ItemType alias provides a way to refer to the type of the items in a Container, and to define a type for use with the append method and subscript, to ensure that the expected behavior of any Container is enforced. + +Here’s a version of the non-generic IntStack type from earlier, adapted to conform to the Container protocol: + + struct IntStack: Container { + // original IntStack implementation + var items = Int[]() + mutating func push(item: Int) { + items.append(item) + } + mutating func pop() -> Int { + return items.removeLast() + } + // conformance to the Container protocol + typealias ItemType = Int + mutating func append(item: Int) { + self.push(item) + } + var count: Int { + return items.count + } + subscript(i: Int) -> Int { + return items[i] + } + } + +The IntStack type implements all three of the Container protocol’s requirements, and in each case wraps part of the IntStack type’s existing functionality to satisfy these requirements. + +Moreover, IntStack specifies that for this implementation of Container, the appropriate ItemType to use is a type of Int. The definition of typealias ItemType = Int turns the abstract type of ItemType into a concrete type of Int for this implementation of the Container protocol. + +Thanks to Swift’s type inference, you don’t actually need to declare a concrete ItemType of Int as part of the definition of IntStack. Because IntStack conforms to all of the requirements of the Container protocol, Swift can infer the appropriate ItemType to use, simply by looking at the type of the append method’s item parameter and the return type of the subscript. Indeed, if you delete the typealias ItemType = Int line from the code above, everything still works, because it is clear what type should be used for ItemType. + +You can also make the generic Stack type conform to the Container protocol: + + struct Stack: Container { + // original Stack implementation + var items = T[]() + mutating func push(item: T) { + items.append(item) + } + mutating func pop() -> T { + return items.removeLast() + } + // conformance to the Container protocol + mutating func append(item: T) { + self.push(item) + } + var count: Int { + return items.count + } + subscript(i: Int) -> T { + return items[i] + } + } + +This time, the placeholder type parameter T is used as the type of the append method’s item parameter and the return type of the subscript. Swift can therefore infer that T is the appropriate type to use as the ItemType for this particular container. +Extending an Existing Type to Specify an Associated Type + +You can extend an existing type to add conformance to a protocol, as described in Adding Protocol Conformance with an Extension. This includes a protocol with an associated type. + +Swift’s Array type already provides an append method, a count property, and a subscript with an Int index to retrieve its elements. These three capabilities match the requirements of the Container protocol. This means that you can extend Array to conform to the Container protocol simply by declaring that Array adopts the protocol. You do this with an empty extension, as described in Declaring Protocol Adoption with an Extension: + + extension Array: Container {} + +Array’s existing append method and subscript enable Swift to infer the appropriate type to use for ItemType, just as for the generic Stack type above. After defining this extension, you can use any Array as a Container. + +Where Clauses + +Type constraints, as described in Type Constraints, enable you to define requirements on the type parameters associated with a generic function or type. + +It can also be useful to define requirements for associated types. You do this by defining where clauses as part of a type parameter list. A where clause enables you to require that an associated type conforms to a certain protocol, and/or that certain type parameters and associated types be the same. You write a where clause by placing the where keyword immediately after the list of type parameters, followed by one or more constraints for associated types, and/or one or more equality relationships between types and associated types. + +The example below defines a generic function called allItemsMatch, which checks to see if two Container instances contain the same items in the same order. The function returns a Boolean value of true if all items match and a value of false if they do not. + +The two containers to be checked do not have to be the same type of container (although they can be), but they do have to hold the same type of items. This requirement is expressed through a combination of type constraints and where clauses: + + func allItemsMatch< + C1: Container, C2: Container + where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> + (someContainer: C1, anotherContainer: C2) -> Bool { + // check that both containers contain the same number of items + if someContainer.count != anotherContainer.count { + return false + } + // check each pair of items to see if they are equivalent + for i in 0..someContainer.count { + if someContainer[i] != anotherContainer[i] { + return false + } + } + // all items match, so return true + return true + } + +This function takes two arguments called someContainer and anotherContainer. The someContainer argument is of type C1, and the anotherContainer argument is of type C2. Both C1 and C2 are placeholder type parameters for two container types to be determined when the function is called. + +The function’s type parameter list places the following requirements on the two type parameters: + + C1 must conform to the Container protocol (written as C1: Container). + + C2 must also conform to the Container protocol (written as C2: Container). + + The ItemType for C1 must be the same as the ItemType for C2 (written as C1.ItemType == C2.ItemType). + + The ItemType for C1 must conform to the Equatable protocol (written as C1.ItemType: Equatable). + +The third and fourth requirements are defined as part of a where clause, and are written after the where keyword as part of the function’s type parameter list. + +These requirements mean: + + someContainer is a container of type C1. + + anotherContainer is a container of type C2. + + someContainer and anotherContainer contain the same type of items. + + The items in someContainer can be checked with the not equal operator (!=) to see if they are different from each other. + +The third and fourth requirements combine to mean that the items in anotherContainer can also be checked with the != operator, because they are exactly the same type as the items in someContainer. + +These requirements enable the allItemsMatch function to compare the two containers, even if they are of a different container type. + +The allItemsMatch function starts by checking that both containers contain the same number of items. If they contain a different number of items, there is no way that they can match, and the function returns false. + +After making this check, the function iterates over all of the items in someContainer with a for-in loop and the half-closed range operator (..). For each item, the function checks whether the item from someContainer is not equal to the corresponding item in anotherContainer. If the two items are not equal, then the two containers do not match, and the function returns false. + +If the loop finishes without finding a mismatch, the two containers match, and the function returns true. + +Here’s how the allItemsMatch function looks in action: + + var stackOfStrings = Stack() + stackOfStrings.push("uno") + stackOfStrings.push("dos") + stackOfStrings.push("tres") + var arrayOfStrings = ["uno", "dos", "tres"] + if allItemsMatch(stackOfStrings, arrayOfStrings) { + println("All items match.") + } else { + println("Not all items match.") + } + // prints "All items match." + +The example above creates a Stack instance to store String values, and pushes three strings onto the stack. The example also creates an Array instance initialized with an array literal containing the same three strings as the stack. Even though the stack and the array are of a different type, they both conform to the Container protocol, and both contain the same type of values. You can therefore call the allItemsMatch function with these two containers as its arguments. In the example above, the allItemsMatch function correctly reports that all of the items in the two containers match. From c74d79b0ffe845339a5f475052562e28778ed819 Mon Sep 17 00:00:00 2001 From: yozomk Date: Fri, 20 Jun 2014 17:21:29 +0800 Subject: [PATCH 145/261] 85% 22/26 pages were translated by MK. --- .../16_Automatic_Reference_Counting.md | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index 35b6fff..362d123 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -561,4 +561,70 @@ class HTMLElement { The HTMLElement class defines a name property, which indicates the name of the element, such as "p" for a paragraph element, or "br" for a line break element. HTMLElement also defines an optional text property, which you can set to a string that represents the text to be rendered within that HTML element. -In addition to these two simple properties, the HTMLElement class defines a lazy property called asHTML. This property references a closure that combines name and text into an HTML string fragment. The asHTML property is of type () -> String, or “a function that takes no parameters, and returns a String +HTMLElement类定义了一个name属性,用于标明元素的名称,如:“p”是段落元素的名称,或“br”是换行元素的名称。同时定义了一个可选类型的text属性,用于设置元素内需要渲染的内容。 + +In addition to these two simple properties, the HTMLElement class defines a lazy property called asHTML. This property references a closure that combines name and text into an HTML string fragment. The asHTML property is of type () -> String, or “a function that takes no parameters, and returns a String “value”. + +除了这两个普通的属性之外,HTMLElement类还定义了一个懒属性asHTML。这个属性引用了一个用于将name和text合并为HTML片段的闭包。asHTML属性的类型是 `() -> String` 或描述为“一个返回字符串的无参函数”。 + +By default, the asHTML property is assigned a closure that returns a string representation of an HTML tag. This tag contains the optional text value if it exists, or no text content if text does not exist. For a paragraph element, the closure would return "<p>some text</p>" or "<p />", depending on whether the text property equals "some text" or nil. + +默认情况下,asHTML属性被分配了一个闭包,这个闭包返回一个字符串形式的HTML标签。如果text的值存在就返回包含text值的标签,如果text的值不存在就返回不包含text值的标签。比如:一个段落标签,闭包会返回"<p>some text</p>" 或 "<p />",这取决于text属性的值是"some text"还是nil。 + +The asHTML property is named and used somewhat like an instance method. However, because asHTML is a closure property rather than an instance method, you can replace the default value of the asHTML property with a custom closure, if you want to change the HTML rendering for a particular HTML element. + +尽管asHTML是命名属性且用法类似实例方法,但是,由于asHTML是闭包属性而不是实例方法,因此如果你想渲染一个特定的HTML元素你可以用自定义闭包替换asHTML属性的默认值。 + +> +> NOTE +> +> The asHTML property is declared as a lazy property, because it is only needed if and when the element actually needs to be rendered as a string value for some HTML output target. The fact that asHTML is a lazy property means that you can refer to self within the default closure, because the lazy property will not be accessed until after initialization has been completed and self is known to exist. +> 注意 +> asHTML之所以被声明为懒属性,是为了满足某些HTML输出需要,并且该元素确实需要渲染为字符串的情况下才被调用。事实上,声明asHTML为懒属性是为了在默认闭包内部引用self,因为懒属性只有在初始化完成且self已存在的情况下才能被访问。 + +The HTMLElement class provides a single initializer, which takes a name argument and (if desired) a text argument to initialize a new element. The class also defines a deinitializer, which prints a message to show when an HTMLElement instance is deallocated. + +HTMLElement类提供了单一的构造器,它需要传递两个参数来初始化一个新元素:name(若需要) 和 text。同时定义了析构函数,当HTMLElement的实例被销毁的时候会打印出一条提示信息。 + +Here’s how you use the HTMLElement class to create and print a new instance: + +这里展示了如何创建和打印HTMLElement类的新实例: + +``` +var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") +println(paragraph!.asHTML()) +// prints "

hello, world

+``` +> +> NOTE +> +> The paragraph variable above is defined as an optional HTMLElement, so that it can be set to nil below to demonstrate the presence of a strong reference cycle. +> 注意 +> 上面的paragraph变量被定义为可选类型是为了便于接下来可以设置为nil演示循环强引用。 + +Unfortunately, the HTMLElement class, as written above, creates a strong reference cycle between an HTMLElement instance and the closure used for its default asHTML value. Here’s how the cycle looks: + +不幸的是,上面的HTMLElement类,在其类实例和做为asHTML默认值的闭包之间形成了循环强引用,如下所示: + +![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/closureReferenceCycle01_2x.png) + +The instance’s asHTML property holds a strong reference to its closure. However, because the closure refers to self within its body (as a way to reference self.name and self.text), the closure captures self, which means that it holds a strong reference back to the HTMLElement instance. A strong reference cycle is created between the two. (For more information about capturing values in a closure, see Capturing Values.) + +实例的asHTML属性保持了一个指向它闭包的强引用。由于在闭包内部引用了self(作为访问self.name和self.text的途径),闭包捕获了self, 这意味着闭包也保持了指回HTMLElement的强引用。二者之间形成了循环强引用。(了解更多关于闭包值捕获有关的信息,请查看[值捕获](HTMLElement)有关的内容) + +> NOTE +> +> Even though the closure refers to self multiple times, it only captures one strong reference to the HTMLElement instance. +> 注意 +> 尽管闭包引用了self多次,但只会捕获一个指向HTMLElement实例的强引用。 + +If you set the paragraph variable to nil and break its strong reference to the HTMLElement instance, neither the HTMLElement instance nor its closure are deallocated, because of the strong reference cycle: + +即使将paragraph变量设置为nil来断开其与HTMLElement实例间的强引用,HTMLElement实例与其闭包也不会被销毁,因为它们之间存在循环强引用: + +> paragraph = nil + +Note that the message in the HTMLElement deinitializer is not printed, which shows that the HTMLElement instance is not deallocated. + +注意到HTMLElement析构函数的信息并没有打印出来,这说明HTMLElement实例并未被销毁。 + From 9cd5d4607849a1e6a6067a183504c5ccd04d7623 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Fri, 20 Jun 2014 19:25:46 +0800 Subject: [PATCH 146/261] =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/09_Classes_and_Structures.md | 204 +++++++++++++++++++++- 1 file changed, 203 insertions(+), 1 deletion(-) diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md index b98214e..c3a543a 100644 --- a/src/chapter2/09_Classes_and_Structures.md +++ b/src/chapter2/09_Classes_and_Structures.md @@ -457,4 +457,206 @@ The behavior described for Array and Dictionary below is different again from th Whenever you assign a Dictionary instance to a constant or variable, or pass a Dictionary instance as an argument to a function or method call, the dictionary is copied at the point that the assignment or call takes place. This process is described in Structures and Enumerations Are Value Types. -只要将一个Dictionary实例进行赋值或者传参操作,就会产生拷贝行为,在[结构体和枚举都是值类型](#)小节中有详细描述过。 +只要将一个字典实例进行赋值或者传参操作,就会产生拷贝行为,在[结构体和枚举都是值类型](#)小节中有详细描述过。 + +If the keys and/or values stored in the Dictionary instance are value types (structures or enumerations), they too are copied when the assignment or call takes place. Conversely, if the keys and/or values are reference types (classes or functions), the references are copied, but not the class instances or functions that they refer to. This copy behavior for a dictionary’s keys and values is the same as the copy behavior for a structure’s stored properties when the structure is copied. + +如果字典实例中所储存的键值是结构体或枚举类型,那么赋值的时候也是拷贝赋值。相反,如果键值是引用类型,那么赋值操作只传递会引用,而不是实例本身的拷贝。在结构体中的键值也具有相同特性。 + +The example below defines a dictionary called ages, which stores the names and ages of four people. The ages dictionary is then assigned to a new variable called copiedAges and is copied when this assignment takes place. After the assignment, ages and copiedAges are two separate dictionaries. + +下面的示例定义了一个名为ages的字典实例,存储了四个人的名字和年龄。ages被赋值给了一个名为copiedAges的新变量时字典实例被重新复制了一份。赋值结束后,ages和copiedAges成为两个相互独立的字典实例。 + +``` +var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19] +var copiedAges = ages +``` + +The keys for this dictionary are of type String, and the values are of type Int. Both types are value types in Swift, and so the keys and values are also copied when the dictionary copy takes place. + +这个字典的键是字符串型,值是整型。这两种类型在Swift 中都是值类型,所以当字典被拷贝时,它们也都会被一起拷贝。 + +You can prove that the ages dictionary has been copied by changing an age value in one of the dictionaries and checking the corresponding value in the other. If you set the value for "Peter" in the copiedAges dictionary to 24, the ages dictionary still returns the old value of 23 from before the copy took place: + +我们可以通过改变一个字典中的年龄,然后检查另一个字典中所对应的值,来证明ages字典确实是被拷贝了。如果在copiedAges字典中将Peter的值设为24,那么ages字典中Peter值仍然会返回23: + +``` +copiedAges["Peter"] = 24 +println(ages["Peter"]) +// prints "23" +``` + +### Assignment and Copy Behavior for Arrays +### 数组的赋值与拷贝 + +The assignment and copy behavior for Swift’s Array type is more complex than for its Dictionary type. Array provides C-like performance when you work with an array’s contents and copies an array’s contents only when copying is necessary. + +在Swift 中,数组(Arrays)类型的赋值和拷贝行为要比字典(Dictionary)类型的复杂的多。当操作数组内容时,数组(Array)能提供接近C语言的的性能,并且拷贝行为只有在必要时才会发生。 + +If you assign an Array instance to a constant or variable, or pass an Array instance as an argument to a function or method call, the contents of the array are not copied at the point that the assignment or call takes place. Instead, both arrays share the same sequence of element values. When you modify an element value through one array, the result is observable through the other. + +如果你将一个数组(Arrays)实例赋给一个变量或常量,或者将其作为参数传递给函数或方法,在事件发生时数组的内容不会被拷贝。而且两个数组使用的还是同一套序列。只有当你在一个数组内修改某一元素,修改结果才c会在另一数组显示。 + +For arrays, copying only takes place when you perform an action that has the potential to modify the length of the array. This includes appending, inserting, or removing items, or using a ranged subscript to replace a range of items in the array. If and when array copying does take place, the copy behavior for an array’s contents is the same as for a dictionary’s keys and values, as described in Assignment and Copy Behavior for Dictionaries. + +对数组来说,拷贝行为仅仅当操作有可能修改数组长度时才会发生。这种行为包括了附加(appending),插入(inserting),删除(removing)或者使用范围下标(ranged subscript)去替换这一范围内的元素。只有当数组拷贝确要发生时,数组内容的行为规则与字典中键值的相同,详见[Dictionary的赋值与拷贝](#)。 + +The example below assigns a new array of Int values to a variable called a. This array is also assigned to two further variables called b and c: + +下面的示例将一个整数数组赋给了一个名为a的变量,继而又被赋给了变量b和c: + +``` +var a = [1, 2, 3] +var b = a +var c = a +``` + +You can retrieve the first value in the array with subscript syntax on either a, b, or c: + +我们可以在a,b,c上使用下标语法以得到数组的第一个元素: + +``` +println(a[0]) +// 1 +println(b[0]) +// 1 +println(c[0]) +// 1 +``` + +If you set an item in the array to a new value with subscript syntax, all three of a, b, and c will return the new value. Note that the array is not copied when you set a new value with subscript syntax, because setting a single value with subscript syntax does not have the potential to change the array’s length: + +如果通过下标语法修改数组中某一元素的值,那么a,b,c中的相应值都会发生改变。请注意当你用下标语法修改某一值时,并没有拷贝行为伴随发生,因为下表语法修改值时没有改变数组长度的可能: + +``` +a[0] = 42 +println(a[0]) +// 42 +println(b[0]) +// 42 +println(c[0]) +// 42 +``` + +However, if you append a new item to a, you do modify the array’s length. This prompts Swift to create a new copy of the array at the point that you append the new value. Henceforth, a is a separate, independent copy of the array. + +然而,当你给a附加新元素时,数组的长度发生改变。 Swift 会创建这个数组的一个拷贝。此后,a将会是一个独立拷贝。 + +If you change a value in a after the copy is made, a will return a different value from b and c, which both still reference the original array contents from before the copy took place: + +拷贝发生后,如果再修改a中元素值的话,a将会返回与b,c不同的结果,因为后两者引用的是原来的数组: + +``` +a.append(4) +a[0] = 777 +println(a[0]) +// 777 +println(b[0]) +// 42 +println(c[0]) +// 42 +``` + +#### Ensuring That an Array Is Unique + +#### 确保数组的唯一性 + +It can be useful to ensure that you have a unique copy of an array before performing an action on that array’s contents, or before passing that array to a function or method. You ensure the uniqueness of an array reference by calling the unshare method on a variable of array type. (The unshare method cannot be called on a constant array.) + +在操作一个数组,或将其传递给函数以及方法调用之前是很有必要先确定这个数组是有一个唯一拷贝的。通过在数组变量上调用unshare方法来确定数组引用的唯一性。(当数组赋给常量时,不能调用unshare方法) + +If multiple variables currently refer to the same array, and you call the unshare method on one of those variables, the array is copied, so that the variable has its own independent copy of the array. However, no copying takes place if the variable is already the only reference to the array. + +如果一个数组被多个变量引用,在其中的一个变量上调用unshare方法,则会拷贝此数组,此时这个变量将会有属于它自己的独立数组拷贝。当数组仅被一个变量引用时,则不会有拷贝发生。 + +At the end of the previous example, b and c both reference the same array. Call the unshare method on b to make it become a unique copy: + +在上一个示例的最后,b和c都引用了同一个数组。此时在b上调用unshare方法则会将b变成一个唯一个拷贝: + +``` +b.unshare() +``` + +If you change the first value in b after calling the unshare method, all three arrays will now report a different value: + +在unshare方法调用后再修改b中第一个元素的值,这三个数组(a,b,c)会返回不同的三个值: + +``` +b[0] = -105 +println(a[0]) +// 777 +println(b[0]) +// -105 +println(c[0]) +// 42 +``` + +#### Checking Whether Two Arrays Share the Same Elements + +#### 判定两个数组是否共用相同元素 + +Check whether two arrays or subarrays share the same storage and elements by comparing them with the identity operators (=== and !==). + +我们通过使用恒等运算符(identity operators) (=== 和 !==)来判定两个数组或子数组共用相同的储存空间或元素。 + +The example below uses the “identical to” operator (===) to check whether b and c still share the same array elements: + +下面这个示例使用了“等同(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.") +} +// prints "b and c now refer to two independent sets of array elements." +``` + +Alternatively, use the identity operators to check whether two subarrays share the same elements. The example below compares two identical subarrays from b and confirms that they refer to the same 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.") +} +// prints "These two subarrays share the same elements." +``` + +#### Forcing a Copy of an Array + +#### 强制复制数组 + +Force an explicit copy of an array by calling the array’s copy method. This method performs a shallow copy of the array and returns a new array containing the copied items. + +我们通过调用数组的copy方法进行强制显式复制。这个方法对数组进行了浅拷贝(shallow copy),并且返回一个包含此拷贝数组的新数组。 + +The example below defines an array called names, which stores the names of seven people. A new variable called copiedNames is set to the result of calling the copy method on the names array: + +下面这个示例中定义了一个names数组,其包含了七个人名。还定义了一个copiedNames变量,用以储存在names上调用copy方法所返回的结果: + +``` +var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"] +var copiedNames = names.copy() +``` + +You can prove that the names array has been copied by changing an item in one of the arrays and checking the corresponding item in the other. If you set the first item in the copiedNames array to "Mo" rather than "Mohsen", the names array still returns the old value of "Mohsen" from before the copy took place: + +我们可以通过修改数组中某一个元素,并且检查另一个数组中对应元素的方法来判定names数组确已被复制。如果你将copiedNames中第一个元素从"Mohsen"修改为"Mo",则names数组返回的仍是拷贝发生前的"Mohsen": + +``` +copiedNames[0] = "Mo" +println(names[0]) +// prints "Mohsen" +``` + + +> NOTE +> +> If you simply need to be sure that your reference to an array’s contents is the only reference in existence, call the unshare method, not the copy method. The unshare method does not make a copy of the array unless it is necessary to do so. The copy method always copies the array, even if it is already unshared. + +> 提示: +> +> 如果你仅需要确保你对数组的引用是唯一引用,请调用unshare方法,而不是copy方法。unshare方法只在必要时才会创建数组拷贝。copy方法会在任何时候都创建一个新的拷贝,即使已经标记为唯一。 \ No newline at end of file From 17a5f209f8688e0f5e8c1ceb1813773f367dd730 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Fri, 20 Jun 2014 19:28:05 +0800 Subject: [PATCH 147/261] =?UTF-8?q?=E7=B1=BB=E5=92=8C=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E4=BD=93=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c4ee7de..1385047 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The Swift Programming Language 中文化项目 * 函数 [认领 by 紫溪] * 闭包 [认领 by 闻西] * 枚举 [已完成 by 灵吾] - * 类和结构体 [认领 by 晓毒] + * 类和结构体 [已完成 by 晓毒] * 属性 [认领 by 周源] * 方法 [已完成 by 米尔] * 下标 [已完成 by 递归] From cee6e2d4314d314f78b3f2bcb3d2bf5470ec19d5 Mon Sep 17 00:00:00 2001 From: yozomk Date: Fri, 20 Jun 2014 20:19:10 +0800 Subject: [PATCH 148/261] 100% 26/26 pages were translated by MK. oh yeah! --- .../16_Automatic_Reference_Counting.md | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index 362d123..ac9e810 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -628,3 +628,117 @@ Note that the message in the HTMLElement deinitializer is not printed, which sho 注意到HTMLElement析构函数的信息并没有打印出来,这说明HTMLElement实例并未被销毁。 +## 解决闭包引起的循环强引用 +You resolve a strong reference cycle between a closure and a class instance by defining a capture list as part of the closure’s definition. A capture list defines the rules to use when capturing one or more reference types within the closure’s body. As with strong reference cycles between two class instances, you declare each captured reference to be a weak or unowned reference rather than a strong reference. The appropriate choice of weak or unowned depends on the relationships between the different parts of your code. + +你可以在闭包的定义内附加定义捕获列表来解决闭包和类实例间的循环强引用问题。捕获列表为在闭包内使用一个或多个引用类型定义了一套规则。与解决两个类实例之间形成循环强引用方式一样,你应声明每个捕获的引用为弱类型或无主类型,而不是强引用类型。到底选择那种类型要看你代码不同部分之间的关系。 + +> NOTE +> +> Swift requires you to write self.someProperty or self.someMethod (rather than just someProperty or someMethod) whenever you refer to a member of self within a closure. This helps you remember that it’s possible to capture self by accident. +> 注意 +> 在闭包内引用self成员时,Swift要求以self.someProperty或self.someMethod的方式来引用,而不是以直接使用属性或方法名的方式引用(如:someProperty 或 someMethod)。这帮你记得闭包内引用self可能意外导致self被捕获。 + +### 定义捕获列表 +Each item in a capture list is a pairing of the weak or unowned keyword with a reference to a class instance (such as self or someInstance). These pairings are written within a pair of square braces, separated by commas. + +捕获列表的每一项都是weak或unown关键字和需引用的类实例(如:self或someInstance)成对组成。每一对由方括号包裹,以逗号分隔。 + + +Place the capture list before a closure’s parameter list and return type if they are provided: + +将捕获列表放在闭包参数列表和返回类型声明(若有返回值)之前: + +``` +@lazy var someClosure: (Int, String) -> String = { + [unowned self] (index: Int, stringToProcess: String) -> String in + // closure body goes here +} +``` + +If a closure does not specify a parameter list or return type because they can be inferred from context, place the capture list at the very start of the closure, followed by the in keyword: + +若闭包没有确切的参数列表或返回类型(因为参数或返回类型可通过上下文推断),请将捕获列表放在闭包的最前面,并在后面加上in关键字。 + +``` +@lazy var someClosure: () -> String = { + [unowned self] in + // closure body goes here +} +``` + +### 弱引用与无主引用 +Define a capture in a closure as an unowned reference when the closure and the instance it captures will always refer to each other, and will always be deallocated at the same time. + +当闭包和它捕获的实例总是互相引用且同时被销毁的时候,将闭包内的捕获定义为无主引用。 + +Conversely, define a capture as a weak reference when the captured reference may become nil at some point in the future. Weak references are always of an optional type, and automatically become nil when the instance they reference is deallocated. This enables you to check for their existence within the closure’s body. + +相反的,如果捕获的实例在将来的某一时刻会变为nil,就将捕获定义为弱引用。弱引用总是可选类型,而且如果它们引用的实例被销毁了,它们会自动变为nil。因此可以很容易的在闭包内检查他们是否存在。 + +> NOTE +> +> If the captured reference will never become nil, it should always be captured as an unowned reference, rather than a weak reference. +> 注意 +> 如果捕获的引用永远不会变为nil,就要将该捕获定义为无主引用,而不是弱引用。 + +An unowned reference is the appropriate capture method to use to resolve the strong reference cycle in the HTMLElement example from earlier. Here’s how you write the HTMLElement class to avoid the cycle: + +根据上述的判断原则,无主引用就是解决先前HTMLElement例子里循环强引用问题的合适方式。 +这是改写后的HTMLElement类,避免了引用循环: + +``` +class HTMLElement { + + let name: String + let text: String? + + @lazy var asHTML: () -> String = { + [unowned self] in + if let text = self.text { + return "<\(self.name)>\(text)" + } else { + return "<\(self.name) />" + } + } + + init(name: String, text: String? = nil) { + self.name = name + self.text = text + } + + deinit { + println("\(name) is being deinitialized") + } + +} +``` + +This implementation of HTMLElement is identical to the previous implementation, apart from the addition of a capture list within the asHTML closure. In this case, the capture list is [unowned self], which means “capture self as an unowned reference rather than a strong reference”. + +这次HTMLElement类的实现与之前的一样,除了在asHTML闭包内增加了一个捕获列表。在这个例子里,捕获列表是[unowned self],意思是:“用无主引用而不是强引用来捕获self” + +You can create and print an HTMLElement instance as before: +你依然可以想之前那样创建并打印HTMLElement实例: + +``` +var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") +println(paragraph!.asHTML()) +// prints "<p>hello, world</p>" +``` + +Here’s how the references look with the capture list in place: + +这是使用了捕获列表后的引用关系: + +![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/closureReferenceCycle02_2x.png) + + +This time, the capture of self by the closure is an unowned reference, and does not keep a strong hold on the HTMLElement instance it has captured. If you set the strong reference from the paragraph variable to nil, the HTMLElement instance is deallocated, as can be seen from the printing of its deinitializer message in the example below: + +这次闭包的self捕获是无主引用,不会强制保持闭包捕获的HTMLElement实例。如果你将paragraph变量设为nil,HTMLElement实例会被销毁并会看到由其析构函数打印出的销毁信息,如下所示: + +``` +paragraph = nil +// prints "p is being deinitialized +``` \ No newline at end of file From 024092c6940feaa3dc48722c80373ce12472f0ff Mon Sep 17 00:00:00 2001 From: yozomk Date: Fri, 20 Jun 2014 22:00:17 +0800 Subject: [PATCH 149/261] fix mistakes --- .../16_Automatic_Reference_Counting.md | 92 ++++++++++--------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index ac9e810..2b71e9d 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -6,7 +6,7 @@ However, in a few cases ARC requires more information about the relationships be Swift 使用自动引用计数(ARC)机制跟踪和管理APP的内存使用,大部分情况下,此机制是自动工作的,你没有必要考虑内存管理的事情。当一个类实例不再需要的时候,ARC会自动释放其占用的内存。 -但少数情况下,ARC需要更多关于你代码之间的关系信息来帮你管理内存。本章介绍了这些情况,并向你示范如何启用ARC来管理你的APP的全部内存。 +但少数情况下,ARC需要更多关于你代码之间的关系信息来帮你管理内存。本章介绍了这些情况,并向你示范如何启用ARC来管理APP的全部内存。 > NOTE > @@ -21,7 +21,7 @@ Every time you create a new instance of a class, ARC allocates a chunk of memory Additionally, when an instance is no longer needed, ARC frees up the memory used by that instance so that the memory can be used for other purposes instead. This ensures that class instances do not take up space in memory when they are no longer needed. -当你创建一个类实例的时候,ARC会为之分配一块内存来存储该实例的相关信息。这些信息包括:该实例的类型及其相关的属性和值。当该实例不再需要的时候,ARC会释放其占用的内存留作他用。这种机制保证了不需要的类实例占用的内存会及时得到释放。 +当创建一个类实例的时候,ARC会为之分配一块内存来存储该实例的相关信息。这些信息包括:该实例的类型及相关的属性和值。当该实例不再需要的时候,ARC会释放其占用的内存留作他用。这种机制保证了不需要的类实例占用的内存会及时得到释放。 However, if ARC were to deallocate an instance that was still in use, it would no longer be possible to access that instance’s properties, or call that instance’s methods. Indeed, if you tried to access the instance, your app would most likely crash. @@ -80,7 +80,7 @@ reference1 = Person(name: "John Appleseed") Note that the message "John Appleseed is being initialized" is printed at the point that you call the Person class’s initializer. This confirms that initialization has taken place. -注意,当你调用Person类的构造函数的时候,此消息:"John Appleseed is being initialized"将会被打印出来。这表明初始化已经完成。 +注意,当调用Person类的构造函数的时候,此消息:"John Appleseed is being initialized"将会被打印出来。这表明初始化已经完成。 Because the new Person instance has been assigned to the reference1 variable, there is now a strong reference from reference1 to the new Person instance. Because there is at least one strong reference, ARC makes sure that this Person is kept in memory and is not deallocated. @@ -102,7 +102,7 @@ There are now three strong references to this single Person instance. If you break two of these strong references (including the original reference) by assigning nil to two of the variables, a single strong reference remains, and the Person instance is not deallocated: -如果你通过给任意两个变量赋值nil的方式断开两个强引用(包括原始引用),留下一个强引用,该Person实例不会被销毁: +如果你通过给任意两个变量赋值nil的方式断开两个强引用(包括原始引用),留下一个强引用,该Person实例也不会被销毁: ``` reference2 = nil @@ -134,7 +134,7 @@ You resolve strong reference cycles by defining some of the relationships betwee Here’s an example of how a strong reference cycle can be created by accident. This example defines two classes called Person and Apartment, which model a block of apartments and its residents: -这是一个意外导致循环强引用的例子。例子定义了名为Person和Apartment的两个类,用来模拟公寓和公寓里的居民: +这是一个意外导致循环强引用的例子。例子定义了名为Person和Apartment的两个类,用来建立公寓和公寓居民的数据模型: ``` class Person { @@ -188,7 +188,7 @@ Here’s how the strong references look after creating and assigning these two i You can now link the two instances together so that the person has an apartment, and the apartment has a tenant. Note that an exclamation mark (!) is used to unwrap and access the instances stored inside the john and number73 optional variables, so that the properties of those instances can be set: -现在将两个实例连接在一起,让john住进number73公寓,number73公寓也有了一个租客john。注意那个感叹号(!),它用于解析和访问存储于john和number73实例中的可选变量,这样实例的属性才能够被设置: +现在将两个实例连接在一起,让john住进number73公寓,number73公寓也有了一个租客john。注意那个感叹号(!),它用于解析和访问存储于john和number73实例中的可选变量,这样做实例的属性才能被设置: ``` john!.apartment = number73 @@ -228,15 +228,15 @@ Person类实例与Apartment类实例之间的强引用关系将保持且无法 Swift provides two ways to resolve strong reference cycles when you work with properties of class type: weak references and unowned references. -Swift提供了两种方式来解决你在处理类属性时遇到的循环强引用问题:弱引用和无主引用。 +Swift提供了两种方式:弱引用和无主引用,来解决你在处理类属性时遇到的循环强引用问题。 Weak and unowned references enable one instance in a reference cycle to refer to the other instance without keeping a strong hold on it. The instances can then refer to each other without creating a strong reference cycle. -弱引用和无主引用允许循环引用中的一个实例引用另外一个实例而不保持强引用。这样实例能够互相引用而不产生循环强引用。 +弱引用和无主引用允许循环引用中的一个实例引用另外一个实例而不强制保持。这样实例就能够互相引用而不产生循环强引用。 Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialization. -对于生命周期中会变为nil的实例使用弱引用。相反的,对于初始化赋值后再也不会被赋值为nil的实例,使用无主引用。 +对于生命周期中会变为nil的引用使用弱引用。相反的,对于初始化赋值后再也不会被赋值为nil的引用,使用无主引用。 ### 弱引用 @@ -251,16 +251,17 @@ Use a weak reference to avoid reference cycles whenever it is possible for that > NOTE > > Weak references must be declared as variables, to indicate that their value can change at runtime. A weak reference cannot be declared as a constant. +> > 注意 > 弱引用必须声明为变量而不能声明为常量,以表明它们的值在运行时是可以改变的。 Because weak references are allowed to have “no value”, you must declare every weak reference as having an optional type. Optional types are the preferred way to represent the possibility for “no value” in Swift. -由于弱引用类型允许没有值,因此你必须声明所有弱引用变量为可选类型。在Swift里,可选类型是表示可能没有值的变量的首选方式。 +由于弱引用类型允许没有值,因此你必须声明所有弱引用为可选类型。在Swift里,可选类型是表示可能没有值的引用的首选方式。 Because a weak reference does not keep a strong hold on the instance it refers to, it is possible for that instance to be deallocated while the weak reference is still referring to it. Therefore, ARC automatically sets a weak reference to nil when the instance that it refers to is deallocated. You can check for the existence of a value in the weak reference, just like any other optional value, and you will never end up with a reference to an invalid instance that no longer exists. -由于弱引用与其指向的实例之间不会保持强引用关系,因此即使有弱引用指向实例,实例也有可能被销毁。弱引用指向的实例被销毁后,ARC会将该弱引用指向nil。像其他可选类型变量一样,你可以检查弱引用类型的变量是否存在值来避免引用一个不存在的实例。 +由于弱引用与其引用的实例之间不会保持强引用关系,因此即使有弱引用指向实例,实例也有可能被销毁。弱引用指向的实例被销毁后,ARC会将该弱引用指向nil。像其他可选类型一样,你可以检查弱引用是否存在值来避免引用一个不存在的实例。 The example below is identical to the Person and Apartment example from above, with one important difference. This time around, the Apartment type’s tenant property is declared as a weak reference: @@ -297,6 +298,7 @@ number73!.tenant = john ``` Here’s how the references look now that you’ve linked the two instances together: + 下图展示了现在的引用关系: ![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/weakReference01_2x.png) @@ -308,6 +310,7 @@ Person实例依然保持对Apartment实例的强引用,但是Apartment实例 ![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/weakReference02_2x.png) Because there are no more strong references to the Person instance, it is deallocated: + 由于没有指向Person实例的强引用了,所以它被销毁了: ``` @@ -321,6 +324,7 @@ The only remaining strong reference to the Apartment instance is from the number ![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/weakReference03_2x.png) Because there are no more strong references to the Apartment instance, it too is deallocated: + 由于也没有指向Apartment类实例的强引用了,它也被销毁了: ``` @@ -330,13 +334,13 @@ number73 = nil The final two code snippets above show that the deinitializers for the Person instance and Apartment instance print their “deinitialized” messages after the john and number73 variables are set to nil. This proves that the reference cycle has been broken. -上面的两段代码展示了变量john和number73在被赋值为nil后,Person实例和Apartment实例的析构函数都打印出“销毁”的信息。这证明了引用循环被打破了。 +上面的两段代码展示了变量john和number73在被赋值为nil后,Person实例和Apartment实例的析构函数都打印出“销毁”的信息。这证明引用循环被打破了。 ### 无主引用 Like weak references, an unowned reference does not keep a strong hold on the instance it refers to. Unlike a weak reference, however, an unowned reference is assumed to always have a value. Because of this, an unowned reference is always defined as a non-optional type. You indicate an unowned reference by placing the unowned keyword before a property or variable declaration. -与弱引用类似,无主引用也不会与其指向的类实例间保持强引用关系。不同的是,无主引用假定一直都是有值的。因此,无主引用总是被定义为非可选类型。你可以在属性和变量之前加上unowned关键词来声明这是无主引用。 +与弱引用类似,无主引用也不会与其引用的类实例间保持强引用关系。不同的是,无主引用假定一直都是有值的。因此,无主引用总是被定义为非可选类型。在属性和变量之前加上unowned关键词来声明这是无主引用。 Because an unowned reference is non-optional, you don’t need to unwrap the unowned reference each time it is used. An unowned reference can always be accessed directly. However, ARC cannot set the reference to nil when the instance it refers to is deallocated, because variables of a non-optional type cannot be set to nil. @@ -349,12 +353,12 @@ Because an unowned reference is non-optional, you don’t need to unwrap the uno > Note also that Swift guarantees your app will crash if you try to access an unowned reference after the instance it references is deallocated. You will never encounter unexpected behavior in this situation. Your app will always crash reliably, although you should, of course, prevent it from doing so. > 注意 -> 在无主引用指向的实例被销毁后,如果依然试图访问该无主引用,你会触发运行时错误。使用无主引用,需要你你能够确保引用指向的实例未被销毁。 +> 在无主引用指向的实例被销毁后,如果依然试图访问该无主引用,你会触发运行时错误。使用无主引用,你需要确保引用指向的实例未被销毁。 > 需要格外注意的是,在无主引用指向的实例被销毁后,若你依然试图访问该无主引用,Swift保证,你的app会毫无意外地直接崩溃。不是应该而是你必须避免这样的情况发生。 The following example defines two classes, Customer and CreditCard, which model a bank customer and a possible credit card for that customer. These two classes each store an instance of the other class as a property. This relationship has the potential to create a strong reference cycle. -接下来的例子定义了两个类,Customer和CreditCard,分别为银行客户和信用卡建模。这两个类通过属性互相保存了对方的实例。这种关系,在它们之间潜在地形成了循环强引用。 +接下来的例子定义了两个类,Customer和CreditCard,分别为银行客户和信用卡建立数据模型。这两个类将对方的实例保存为自己的属性。这在它们之间潜在地形成了循环强引用。 The relationship between Customer and CreditCard is slightly different from the relationship between Apartment and Person seen in the weak reference example above. In this data model, a customer may or may not have a credit card, but a credit card will always be associated with a customer. To represent this, the Customer class has an optional card property, but the CreditCard class has a non-optional customer property. @@ -362,11 +366,11 @@ Customer 与 CreditCard之间的关系与上文弱引用例子里提到的Apartm Furthermore, a new CreditCard instance can only be created by passing a number value and a customer instance to a custom CreditCard initializer. This ensures that a CreditCard instance always has a customer instance associated with it when the CreditCard instance is created. -此外,只能通过向CreditCard类构造器传递一个数值和一个Customer类实例的方式创建新的CreditCard类实例。这是为了保证创建CreditCard类实例的时候总是有一位客户实例与之关联。 +此外,只能通过向CreditCard类构造器传递一个数值和一个Customer实例的方式创建新的CreditCard实例。这是为了保证创建CreditCard实例的时候总是有一位客户实例与之关联。 Because a credit card will always have a customer, you define its customer property as an unowned reference, to avoid a strong reference cycle: -由于一张信用卡一定会有一位客户实例与之关联,你将其属性customer定义为无主类型以避免循环强引用: +由于一张信用卡一定会有一位客户与之关联,将属性customer定义为无主类型以避免循环强引用: ``` class Customer { @@ -391,7 +395,7 @@ class CreditCard { This next code snippet defines an optional Customer variable called john, which will be used to store a reference to a specific customer. This variable has an initial value of nil, by virtue of being optional: -如下代码片段定义了一个可选Customer类型的变量john,john将用于存储到特定客户的引用。由于是可选类型,这个变量初始值是nil. +如下代码片段定义了一个可选Customer类型的变量john,john将用于存储指向特定客户的引用。由于是可选类型,这个变量初始值是nil. ``` var john: Customer? @@ -399,7 +403,7 @@ var john: Customer? You can now create a Customer instance, and use it to initialize and assign a new CreditCard instance as that customer’s card property: -现在创建Customer类实例,并用它初始化CreditCard类实例,同时,将CreditCard类实例分配给Customer类实例的客户属性。 +现在创建Customer实例,并用它初始化CreditCard实例,同时,将CreditCard实例分配给Customer实例的card属性。 ``` john = Customer(name: "John Appleseed") @@ -414,17 +418,17 @@ Here’s how the references look, now that you’ve linked the two instances: The Customer instance now has a strong reference to the CreditCard instance, and the CreditCard instance has an unowned reference to the Customer instance. -Customer类实例拥有一个指向CreditCard类实例的强引用,同时CreditCard类实例有一个指向Customer类实例的无主引用。 +Customer实例拥有一个指向CreditCard实例的强引用,同时CreditCard实例有一个指向Customer实例的无主引用。 Because of the unowned customer reference, when you break the strong reference held by the john variable, there are no more strong references to the Customer instance: -由于无主引用customer的存在,当你断开由变量john保持的强引用后,就没有强引用指向Customer类实例了: +由于无主引用customer的存在,当你断开由变量john保持的强引用后,就没有强引用指向Customer实例了: ![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/unownedReference02_2x.png) Because there are no more strong references to the Customer instance, it is deallocated. After this happens, there are no more strong references to the CreditCard instance, and it too is deallocated: -由于没有强引用指向Customer类实例了,它被销毁了。在此之后,由于也没有强引用指向CreditCard类实例了,它也被销毁了。 +由于没有强引用指向Customer实例了,它被销毁了。在此之后,由于也没有强引用指向CreditCard实例了,它也被销毁了。 ``` john = nil @@ -460,7 +464,7 @@ This enables both properties to be accessed directly (without optional unwrappin The example below defines two classes, Country and City, each of which stores an instance of the other class as a property. In this data model, every country must always have a capital city, and every city must always belong to a country. To represent this, the Country class has a capitalCity property, and the City class has a country property: -下面的例子定义了两个类,Country 和 City,它们彼此通过属性保存了对方的实例引用。在这个数据模型里,国家是必须有首都的,而一个城市也必须是属于某个国家。为了表示这种关系,Country类声明了一个capitalCity属性,City类也声明了一个country属性: +下面的例子定义了两个类,Country 和 City,它们彼此通过属性保存了对方的实例引用。在这个数据模型里,国家是必须有首都的,而一个城市也必须是属于某个国家的。为了表示这种关系,Country类声明了一个capitalCity属性,City类也声明了一个country属性: ``` class Country { @@ -488,19 +492,19 @@ To set up the interdependency between the two classes, the initializer for City The initializer for City is called from within the initializer for Country. However, the initializer for Country cannot pass self to the City initializer until a new Country instance is fully initialized, as described in Two-Phase Initialization. -City的构造器将在Country的构造器里被调用。但是,Country的构造器无法传递自身(`self`)到City的构造器,直到Country实例已完全初始化。这在[两段式构造过程](http://TODO)中有介绍。 +City的构造器将在Country的构造器里被调用。但是,在Country实例已完全初始化之前,Country的构造器无法传递自身(`self`)到City的构造器。这在[两段式构造过程](http://TODO)中有介绍。 To cope with this requirement, you declare the capitalCity property of Country as an implicitly unwrapped optional property, indicated by the exclamation mark at the end of its type annotation (City!). This means that the capitalCity property has a default value of nil, like any other optional, but can be accessed without the need to unwrap its value as described in Implicitly Unwrapped Optionals. -为了满足要求,你将Country类的capitalCity属性声明为隐式解析可选属性(通过在capitalCity类型后加感叹号`City!`来声明)。这意味着,像其他可选类型属性一样,capitalCity属性的默认值为nil, 但是它可以不经解析直接被访问。这在[隐式解析可选类型](http://TODO)中有详细介绍。 +为了满足要求,将Country类的capitalCity属性声明为隐式解析可选属性(通过在capitalCity类型后加感叹号来声明)。像其他可选类型属性一样,capitalCity属性的默认值为nil, 但是它可以不经解析直接被访问。这在[隐式解析可选类型](http://TODO)中有详细介绍。 Because capitalCity has a default nil value, a new Country instance is considered fully initialized as soon as the Country instance sets its name property within its initializer. This means that the Country initializer can start to reference and pass around the implicit self property as soon as the name property is set. The Country initializer can therefore pass self as one of the parameters for the City initializer when the Country initializer is setting its own capitalCity property. -由于capitalCity默认值为nil, 因此当Country实例的name属性在构造器内被赋值的时候,就认为初始化已经全部完成。这意味着name属性一被赋值,Country类构造器就可以开始引用和传递隐式的`self`。Country构造器也因此可以在为capitalCity属性赋值时把`self`作为参数给City的构造器。 +由于capitalCity默认值为nil, 因此只要Country实例的name属性在构造器内被赋值,就认为初始化已全部完成。这意味着name属性一旦被赋值,Country类构造器就可以引用和传递隐式的`self`。Country构造器也因此可以在为capitalCity属性赋值时把`self`作为参数给City的构造器。 All of this means that you can create the Country and City instances in a single statement, without creating a strong reference cycle, and the capitalCity property can be accessed directly, without needing to use an exclamation mark to unwrap its optional value: -上述这一切,意味着你可以在单一语句中同时创建Country和City的实例,这里没有形成循环强引用,同时capitalCity也可以直接被访问,也不必用感叹号来解析其可选值,如下所示: +上述这一切意味着可以在单一语句中同时创建Country和City的实例,并且没有形成循环强引用,同时capitalCity可以直接被访问,不必用感叹号来解析其可选值,如下所示: ``` var country = Country(name: "Canada", capitalName: "Ottawa") @@ -515,23 +519,23 @@ In the example above, the use of an implicitly unwrapped optional means that all ## 闭包引起的循环强引用 You saw above how a strong reference cycle can be created when two class instance properties hold a strong reference to each other. You also saw how to use weak and unowned references to break these strong reference cycles. -在上文中你已经了解了两个实例属性互相保持彼此的强引用是如何导致循环强引用的。你也知道了可以利用弱引用和无主引用来断开强引用循环。 +在上文中,你已经了解了两个实例互相保持彼此的强引用是如何导致循环强引用的。你也知道了可以利用弱引用和无主引用来断开强引用循环。 A strong reference cycle can also occur if you assign a closure to a property of a class instance, and the body of that closure captures the instance. This capture might occur because the closure’s body accesses a property of the instance, such as self.someProperty, or because the closure calls a method on the instance, such as self.someMethod(). In either case, these accesses cause the closure to “capture” self, creating a strong reference cycle. -如果你将一个闭包分配给一个类实例的属性,同时闭包内部又捕获了该实例,也会形成循环强引用。这种捕获之所以可能发生,是因为闭包内部访问了该实例的属性,如:self.someProperty,或是访问了该实例的方法,如:self.someMethod()。这两种类型的访问,都会导致闭包“捕获”self,造成循环强引用。 +如果将一个闭包分配给一个类实例的属性,同时在闭包内部又捕获了该实例,也会形成循环强引用。这种捕获之所以可能发生,是因为闭包内部访问了该实例的属性,如:self.someProperty,或是访问了该实例的方法,如:self.someMethod()。这两种类型的访问,都会导致闭包“捕获”self,造成循环强引用。 This strong reference cycle occurs because closures, like classes, are reference types. When you assign a closure to a property, you are assigning a reference to that closure. In essence, it’s the same problem as above—two strong references are keeping each other alive. However, rather than two class instances, this time it’s a class instance and a closure that are keeping each other alive. -这种因闭包导致的循环强引用,和“类”的情况类似,都是引用类型的问题。 +这种因闭包导致的循环强引用,和“类”的情况相似,都是引用类型的问题。当将闭包分配给属性时,你就为闭包分配了一个引用。本质上,这与上文中讲述的两个强引用互相保持对方存活的例子是同一问题。然而,与两个类实例情况不同的是:这次是类实例和闭包互相保持对方存活。 Swift provides an elegant solution to this problem, known as a closure capture list. However, before you learn how to break a strong reference cycle with a closure capture list, it is useful to understand how such a cycle can be caused. -针对这类问题,Swift提供了一种优雅的解决方案:闭包捕获列表。 +针对这类问题,Swift提供了一种优雅的解决方案:闭包捕获列表。然而,在学会如何利用捕获列表断开循环强引用之前,理解这种循环是如何导致的过程是很有用的。 The example below shows how you can create a strong reference cycle when using a closure that references self. This example defines a class called HTMLElement, which provides a simple model for an individual element within an HTML document: -下面的例子展示了闭包是如何导致循环强引用的。例子定义了一个名为HTMLElement的类,为HTML文档中的一类元素建模: +下面的例子展示了使用闭包是如何导致循环强引用的。例子定义了一个名为HTMLElement的类,为HTML文档中的一类元素建模: ``` class HTMLElement { @@ -561,7 +565,7 @@ class HTMLElement { The HTMLElement class defines a name property, which indicates the name of the element, such as "p" for a paragraph element, or "br" for a line break element. HTMLElement also defines an optional text property, which you can set to a string that represents the text to be rendered within that HTML element. -HTMLElement类定义了一个name属性,用于标明元素的名称,如:“p”是段落元素的名称,或“br”是换行元素的名称。同时定义了一个可选类型的text属性,用于设置元素内需要渲染的内容。 +HTMLElement类定义了一个name属性,用于表示元素名,如:“p”是段落元素的名称,“br”是换行元素的名称。同时定义了一个可选类型的text属性,用于设置元素内需要渲染的内容。 In addition to these two simple properties, the HTMLElement class defines a lazy property called asHTML. This property references a closure that combines name and text into an HTML string fragment. The asHTML property is of type () -> String, or “a function that takes no parameters, and returns a String “value”. @@ -569,18 +573,18 @@ In addition to these two simple properties, the HTMLElement class defines a lazy By default, the asHTML property is assigned a closure that returns a string representation of an HTML tag. This tag contains the optional text value if it exists, or no text content if text does not exist. For a paragraph element, the closure would return "<p>some text</p>" or "<p />", depending on whether the text property equals "some text" or nil. -默认情况下,asHTML属性被分配了一个闭包,这个闭包返回一个字符串形式的HTML标签。如果text的值存在就返回包含text值的标签,如果text的值不存在就返回不包含text值的标签。比如:一个段落标签,闭包会返回"<p>some text</p>" 或 "<p />",这取决于text属性的值是"some text"还是nil。 +默认情况下,asHTML属性被分配了一个闭包,这个闭包返回一个字符串形式的HTML标签。根据text的值是否存在来返回一个包含内容的标签或一个空标签。比如:一个段落标签,闭包会返回"<p>some text</p>" 或 "<p />",这取决于text属性的值是"some text"还是nil。 The asHTML property is named and used somewhat like an instance method. However, because asHTML is a closure property rather than an instance method, you can replace the default value of the asHTML property with a custom closure, if you want to change the HTML rendering for a particular HTML element. -尽管asHTML是命名属性且用法类似实例方法,但是,由于asHTML是闭包属性而不是实例方法,因此如果你想渲染一个特定的HTML元素你可以用自定义闭包替换asHTML属性的默认值。 +尽管asHTML是命名属性且用法类似实例方法,但由于asHTML是闭包属性而不是实例方法,因此若你想渲染一个特定的HTML元素,你也可以用自定义闭包替换asHTML属性的默认值。 > > NOTE > > The asHTML property is declared as a lazy property, because it is only needed if and when the element actually needs to be rendered as a string value for some HTML output target. The fact that asHTML is a lazy property means that you can refer to self within the default closure, because the lazy property will not be accessed until after initialization has been completed and self is known to exist. > 注意 -> asHTML之所以被声明为懒属性,是为了满足某些HTML输出需要,并且该元素确实需要渲染为字符串的情况下才被调用。事实上,声明asHTML为懒属性是为了在默认闭包内部引用self,因为懒属性只有在初始化完成且self已存在的情况下才能被访问。 +> asHTML之所以被声明为懒属性,是因为它只有在满足特定输出要求且确实需要将元素渲染为字符串时才需要。事实上,声明asHTML为懒属性是为了在默认闭包内部引用self,因为懒属性只有在初始化完成且self已存在的情况下才能被访问。 The HTMLElement class provides a single initializer, which takes a name argument and (if desired) a text argument to initialize a new element. The class also defines a deinitializer, which prints a message to show when an HTMLElement instance is deallocated. @@ -600,17 +604,17 @@ println(paragraph!.asHTML()) > > The paragraph variable above is defined as an optional HTMLElement, so that it can be set to nil below to demonstrate the presence of a strong reference cycle. > 注意 -> 上面的paragraph变量被定义为可选类型是为了便于接下来可以设置为nil演示循环强引用。 +> 上面的paragraph变量被定义为可选类型是为了接下来可以将其设置为nil,以便演示循环强引用。 Unfortunately, the HTMLElement class, as written above, creates a strong reference cycle between an HTMLElement instance and the closure used for its default asHTML value. Here’s how the cycle looks: -不幸的是,上面的HTMLElement类,在其类实例和做为asHTML默认值的闭包之间形成了循环强引用,如下所示: +不幸的是,上面的HTMLElement实例和做为asHTML默认值的闭包之间形成了循环强引用,如下所示: ![](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/closureReferenceCycle01_2x.png) The instance’s asHTML property holds a strong reference to its closure. However, because the closure refers to self within its body (as a way to reference self.name and self.text), the closure captures self, which means that it holds a strong reference back to the HTMLElement instance. A strong reference cycle is created between the two. (For more information about capturing values in a closure, see Capturing Values.) -实例的asHTML属性保持了一个指向它闭包的强引用。由于在闭包内部引用了self(作为访问self.name和self.text的途径),闭包捕获了self, 这意味着闭包也保持了指回HTMLElement的强引用。二者之间形成了循环强引用。(了解更多关于闭包值捕获有关的信息,请查看[值捕获](HTMLElement)有关的内容) +实例的asHTML属性保持了一个指向它闭包的强引用。由于在闭包内部引用了self(作为访问self.name和self.text的途径),闭包捕获了self, 这意味着闭包也保持了指回HTMLElement的强引用。二者之间形成了循环强引用。(了解更多关于闭包值捕获有关的信息,请查看[值捕获](http://TODO)有关的内容) > NOTE > @@ -637,12 +641,12 @@ You resolve a strong reference cycle between a closure and a class instance by d > > Swift requires you to write self.someProperty or self.someMethod (rather than just someProperty or someMethod) whenever you refer to a member of self within a closure. This helps you remember that it’s possible to capture self by accident. > 注意 -> 在闭包内引用self成员时,Swift要求以self.someProperty或self.someMethod的方式来引用,而不是以直接使用属性或方法名的方式引用(如:someProperty 或 someMethod)。这帮你记得闭包内引用self可能意外导致self被捕获。 +> 在闭包内引用self成员时,Swift要求以self.someProperty或self.someMethod的方式来引用,而不是以直接使用属性或方法名的方式引用(如:someProperty 或 someMethod)。这提醒你self可能意外被捕获。 ### 定义捕获列表 Each item in a capture list is a pairing of the weak or unowned keyword with a reference to a class instance (such as self or someInstance). These pairings are written within a pair of square braces, separated by commas. -捕获列表的每一项都是weak或unown关键字和需引用的类实例(如:self或someInstance)成对组成。每一对由方括号包裹,以逗号分隔。 +捕获列表项都是由weak或unown关键字和需引用的类实例(如:self或someInstance)成对组成。每一对由方括号包裹,以逗号分隔。 Place the capture list before a closure’s parameter list and return type if they are provided: @@ -716,10 +720,10 @@ class HTMLElement { This implementation of HTMLElement is identical to the previous implementation, apart from the addition of a capture list within the asHTML closure. In this case, the capture list is [unowned self], which means “capture self as an unowned reference rather than a strong reference”. -这次HTMLElement类的实现与之前的一样,除了在asHTML闭包内增加了一个捕获列表。在这个例子里,捕获列表是[unowned self],意思是:“用无主引用而不是强引用来捕获self” +这里HTMLElement类的实现与之前的一样,除了在asHTML闭包内增加了一个捕获列表。在这个例子里,捕获列表是[unowned self],意思是:“用无主引用而不是强引用来捕获self” You can create and print an HTMLElement instance as before: -你依然可以想之前那样创建并打印HTMLElement实例: +你依然可以像之前那样创建并打印HTMLElement实例: ``` var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") @@ -736,7 +740,7 @@ Here’s how the references look with the capture list in place: This time, the capture of self by the closure is an unowned reference, and does not keep a strong hold on the HTMLElement instance it has captured. If you set the strong reference from the paragraph variable to nil, the HTMLElement instance is deallocated, as can be seen from the printing of its deinitializer message in the example below: -这次闭包的self捕获是无主引用,不会强制保持闭包捕获的HTMLElement实例。如果你将paragraph变量设为nil,HTMLElement实例会被销毁并会看到由其析构函数打印出的销毁信息,如下所示: +这次,被闭包捕获的self是无主引用,它不会强制保持闭包捕获的HTMLElement实例。如果你将paragraph变量设为nil,HTMLElement实例会被销毁并会看到由其析构函数打印出的销毁信息,如下所示: ``` paragraph = nil From 5c3d43758037b6ac67af4cdf1c4cd3b96890f204 Mon Sep 17 00:00:00 2001 From: Adams Date: Sat, 21 Jun 2014 00:05:29 +0800 Subject: [PATCH 150/261] Update 21_Protocols.md --- src/chapter2/21_Protocols.md | 432 +++++++++++++++++++++++++++++++++++ 1 file changed, 432 insertions(+) diff --git a/src/chapter2/21_Protocols.md b/src/chapter2/21_Protocols.md index e69de29..29931bf 100644 --- a/src/chapter2/21_Protocols.md +++ b/src/chapter2/21_Protocols.md @@ -0,0 +1,432 @@ +http://numbbbbb.github.io/the-swift-programming-language-in-chinese/chapter2/21_Protocols.html + +https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_345 + +#Protocols +A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol doesn’t actually provide an implementation for any of these requirements—it only describes what an implementation will look like. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol. + + +#协议 + +一个协议(protocol)定义了适合特定的任务或功能的方法、属性和其他需求。协议并不提供这些需求的实现,只描述了这个实现应该是怎样的。 + +协议能够被类(class),结构体(structure),枚举(enumeration)适配(adopted),同时,这些类型如果了满足一个协议需求,则被称为遵循(conform to)协议 + +Protocols can require that conforming types have specific instance properties, instance methods, type methods, operators, and subscripts. + +协议可以要求遵循(conforming)的类型有特定的实例属性(instance properties),实例方法(instance methods),类型方法(type methods),操作符(operators)和下标(subscripts)。 + + +##Protocol Syntax +##协议语法 +You define protocols in a very similar way to classes, structures, and enumerations: + +定义协议,与定义类,结构体,枚举的方式非常相似,如下所示: + + protocol SomeProtocol { + // protocol definition goes here + } + +Custom types state that they adopt a particular protocol by placing the protocol’s name after the type’s name, separated by a colon, as part of their definition. Multiple protocols can be listed, and are separated by commas: +在类型名称后添加协议名称,并以冒号`:`分割,表示自定义类型(Custom types)适配一个特定协议;实现多个协议时,各协议之间用逗号`,`分隔,如下所示: + + struct SomeStructure: FirstProtocol, AnotherProtocol { + // structure definition goes here + } +If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma: +若某个类有父类,要把父类放在所有其适配的协议之前,且用逗号`,`分割,如下所示: + + class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol { + // class definition goes here + } + +Property Requirements +##属性要求 + +A protocol can require any conforming type to provide an instance property or type property with a particular name and type. The protocol doesn’t specify whether the property should be a stored property or a computed property—it only specifies the required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable. + +协议可以要求任何遵循(conforming)类型,提供一个特定名称和类型的实例属性(instance property)或类型属性(type property)。协议不指定属性是存储型属性(stored property)还是计算型属性(calculate property)。 +协议同时指定了每个属性是否是可读(gettable)或可读写(gettable and settable) + + +If a protocol requires a property to be gettable and settable, that property requirement cannot be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for it also to be settable if this is useful for your own code. +如果协议要求属性可读写(gettable and settable),那常量存储属性(constant stored property)或者只读计算属性(read-only computed property)都无法满足此要求。如果协议只要求属性可读(gettable),那任何类型的属性都满足这个要求,即使这些属性是可写(settable)的。 + +Property requirements are always declared as variable properties, prefixed with the var keyword. Gettable and settable properties are indicated by writing { get set } after their type declaration, and gettable properties are indicated by writing { get }. + +协议里的属性要求,通常都是通过使用`var`关键字来声明的变量属性。 +在类型声明之后用{ get set }表示属性为可读写的。{ get }表示属性为可读的。 + + protocol SomeProtocol { + var mustBeSettable: Int { get set } + var doesNotNeedToBeSettable: Int { get } + } + +Always prefix type property requirements with the class keyword when you define them in a protocol. This is true even though type property requirements are prefixed with the static keyword when implemented by a structure or enumeration: + +当你在一个协议中定义一个某种类型的属性要求,总要前置`class` 关键字。同样某类型属性要求使用`static`关键字前缀,来定义结构体(structure)或枚举类型(enumeration) + +> 这样翻译正确么? + + protocol AnotherProtocol { + class var someTypeProperty: Int { get set } + } + +Here’s an example of a protocol with a single instance property requirement: + +下面是协议的一个例子,这个协议只有一个实例属性(instance property)要求: + + + protocol FullyNamed { + var fullName: String { get } + } + +The FullyNamed protocol defines any kind of thing that has a fully-qualified name. It doesn’t specify what kind of thing it must be—it only specifies that the thing must be able to provide a full name for itself. It specifies this requirement by stating that any FullyNamed type must have a gettable instance property called fullName, which is of type String. + +FullyNamed协议可以定义任何需要一个完整name的类型(方法,属性或者其他需求)。这个协议并不指定什么,只有一个需求:这个类型本身必须提供一个完整的名称。这个需求通过声明一个String类型的实例属性fullName,且这个属性必须是可读的(gettable)来指定。 + + + +Here’s an example of a simple structure that adopts and conforms to the FullyNamed protocol: + +下面的例子中,一个简单的结构体适配且遵循FullyNamed协议 + + struct Person: FullyNamed { + var fullName: String + } + let john = Person(fullName: "John Appleseed") + // john.fullName is "John Appleseed" + +This example defines a structure called Person, which represents a specific named person. It states that it adopts the FullyNamed protocol as part of the first line of its definition. +这个例子中定义了一个名为Person的结构体,代表一个有名字的人。它在第一行的结构体定义中,声明了其适配FullyNamed协议。 + +Each instance of Person has a single stored property called fullName, which is of type String. This matches the single requirement of the FullyNamed protocol, and means that Person has correctly conformed to the protocol. (Swift reports an error at compile-time if a protocol requirement is not fulfilled.) + +每个Person实例都有一个单独存储的,String类型的属性fullName。拥有这个属性代表满足了FullyNamed协议的要求,这意味着Person遵循协议。(在编译时如果不满足协议要求,swift会报告一个错误)。 + + +Here’s a more complex class, which also adopts and conforms to the FullyNamed protocol: +下面有一个更复杂的类,同样适配且遵循FullyNamed协议 + + class Starship: FullyNamed { + var prefix: String? + var name: String + init(name: String, prefix: String? = nil) { + self.name = name + self.prefix = prefix + } + var fullName: String { + return (prefix ? prefix! + " " : "") + name + } + } + var ncc1701 = Starship(name: "Enterprise", prefix: "USS") + // ncc1701.fullName is "USS Enterprise" + +This class implements the fullName property requirement as a computed read-only property for a starship. Each Starship class instance stores a mandatory name and an optional prefix. The fullName property uses the prefix value if it exists, and prepends it to the beginning of name to create a full name for the starship. +这个类提供了fullName属性,这个属性是starship这个类的一个只读的计算属性。 +每个starship类的实例存储一个强制性的名称和一个可选的前缀。当存在前缀时,fullName属性会把前缀添加到名称前面,从而创建了一个starship的全名。 + + +Method Requirements + +Protocols can require specific instance methods and type methods to be implemented by conforming types. These methods are written as part of the protocol’s definition in exactly the same way as for normal instance and type methods, but without curly braces or a method body. Variadic parameters are allowed, subject to the same rules as for normal methods. + + + +方法需求 + +若某种类型遵循协议,协议可以要求指定特定的实例方法和类型方法。这些方法作为协议定义的一部分,跟通常定义实例与类型方法的途径完全一样,但不需要书写大括号或方法的主体。方法允许含有可变参数,且与通常的方法遵循同样的规则。 + +NOTE + +Protocols use the same syntax as normal methods, but are not allowed to specify default values for method parameters. + +注意 + +协议与通常的方法语法相同,但不允许指定方法中参数的默认值 + +As with type property requirements, you always prefix type method requirements with the class keyword when they are defined in a protocol. This is true even though type method requirements are prefixed with the static keyword when implemented by a structure or enumeration: + + protocol SomeProtocol { + class func someTypeMethod() + } + +当你在一个协议中定义一个某种类型的方法要求,要前置`class` 关键字。同样某类型方法要求使用`static`关键字前缀,来定义结构体(structure)或枚举类型(enumeration) + +The following example defines a protocol with a single instance method requirement: +下面的例子中,定义了一个协议,协议要求一个实例方法。 + + protocol RandomNumberGenerator { + func random() -> Double + } +This protocol, RandomNumberGenerator, requires any conforming type to have an instance method called random, which returns a Double value whenever it is called. (Although it is not specified as part of the protocol, it is assumed that this value will be a number between 0.0 and 1.0 inclusive.) + +RandomNumberGenerator,该协议要求任何遵循协议的类型调用一个名为random的实例方法,这个方法无论何时调用,都会返回一个Double类型的值。(这个值在0.0与1.0之间,这一点没有在协议中指出)。 + + +The RandomNumberGenerator protocol does not make any assumptions about how each random number will be generated—it simply requires the generator to provide a standard way to generate a new random number. + +Here’s an implementation of a class that adopts and conforms to the RandomNumberGenerator protocol. This class implements a pseudorandom number generator algorithm known as a linear congruential generator: + + RandomNumberGenerator协议不会描述如何建立一个随机数,只需要指定一个随机数生成器,从而提供一种标准的方式来生成一个新随机数。 +   + 下面是一个类的实现,遵循RandomNumberGenerator协议。这个类实现了一种伪随机数发生器算法,称为线性同余(linear congruential)发生器: + + + class LinearCongruentialGenerator: RandomNumberGenerator { + var lastRandom = 42.0 + let m = 139968.0 + let a = 3877.0 + let c = 29573.0 + func random() -> Double { + lastRandom = ((lastRandom * a + c) % m) + return lastRandom / m + } + } + let generator = LinearCongruentialGenerator() + println("Here's a random number: \(generator.random())") + // prints "Here's a random number: 0.37464991998171" + println("And another one: \(generator.random())") + // prints "And another one: 0.729023776863283" + +Mutating Method Requirements + +突变方法要求 + +It is sometimes necessary for a method to modify (or mutate) the instance it belongs to. For instance methods on value types (that is, structures and enumerations) you place the mutating keyword before a method’s func keyword to indicate that the method is allowed to modify the instance it belongs to and/or any properties of that instance. This process is described in Modifying Value Types from Within Instance Methods. + +有时,实例的一个方法需要修改(或突变)实例的类型。对值类型(value types)(即结构体和枚举类型)的实例方法中,使用`mutating`关键字,写在方法的函数关键字`fun`前面,来表明实例中该方法允许修改其类型及任何属性。这个过程在 `在实例方法中修改值类型`章节中有详细的描述。 + +If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement. + +如果你定义的协议中,某个实例适配此协议,而实例方法需要改变其类型,协议定义时要在此方法前加上关键字`mutating`。这样可以让结构体及枚举类型适配协议,且满足实例方法的需求。 + +NOTE +注意 +If you mark a protocol instance method requirement as mutating, you do not need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations. + + +如果你在一个协议中实现的突变方法是为一个类服务的,不需要为其加上mutating关键字。 +mutating关键字只用在结构体与枚举类型中。 + + +The example below defines a protocol called Togglable, which defines a single instance method requirement called toggle. As its name suggests, the toggle method is intended to toggle or invert the state of any conforming type, typically by modifying a property of that type. +下面的例子中定义了一个togglable协议,包含一个名为togger的突变实例方法。正如名称所表达的,适配此协议的某实例中,toggle方法通常会通过改变实例的某个属性,来切换或恢复其类型。 + +The toggle method is marked with the mutating keyword as part of the Togglable protocol definition, to indicate that the method is expected to mutate the state of a conforming instance when it is called: +toggle方法前面加上了mutating关键字,作为Togglabel协议定义的一部分,则表示一个适配toggleabel协议的实例中,这个方法会在调用时改变实例的类型。 + + protocol Togglable { + mutating func toggle() + } + +If you implement the Togglable protocol for a structure or enumeration, that structure or enumeration can conform to the protocol by providing an implementation of the toggle method that is also marked as mutating. + +当你提供的枚举或结构体遵循Togglabl协议时,需要提供一个带有`mutating`前缀的toggle方法。 + + +The example below defines an enumeration called OnOffSwitch. This enumeration toggles between two states, indicated by the enumeration cases On and Off. The enumeration’s toggle implementation is marked as mutating, to match the Togglable protocol’s requirements: + + enum OnOffSwitch: Togglable { + case Off, On + mutating func toggle() { + switch self { + case Off: + self = On + case On: + self = Off + } + } + } + var lightSwitch = OnOffSwitch.Off + lightSwitch.toggle() + // lightSwitch is now equal to .On +Protocols as Types +协议类型 + +Protocols do not actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use in your code. +尽管协议本身并不实现任何功能,但协议可以作为完整的类型来使用。 +Because it is a type, you can use a protocol in many places where other types are allowed, including: +你可以把协议类型用在其他类型适用的场景里,比如: + +As a parameter type or return type in a function, method, or initializer + +在函数,方法或构造方法中作为形参类型(parameter type)或返回值类型(return type) +As the type of a constant, variable, or property +作为常量、变量或属性这三种类型之一 +As the type of items in an array, dictionary, or other container +作为数组,字典或其他容器中的元素类型 + +NOTE +注意 +Because protocols are types, begin their names with a capital letter (such as FullyNamed and RandomNumberGenerator) to match the names of other types in Swift (such as Int, String, and Double). +注意: 协议是一种类型,因此协议类型的名称应与Swift中其他类型(Int,Double,String)的写法相同,每一个单字的首字母都采用大写字母(大驼峰写法) + +Here’s an example of a protocol used as a type: +下面的例子中,协议被当作类型使用: + + class Dice { + let sides: Int + let generator: RandomNumberGenerator + init(sides: Int, generator: RandomNumberGenerator) { + self.sides = sides + self.generator = generator + } + func roll() -> Int { + return Int(generator.random() * Double(sides)) + 1 + } + } +This example defines a new class called Dice, which represents an n-sided dice for use in a board game. Dice instances have an integer property called sides, which represents how many sides they have, and a property called generator, which provides a random number generator from which to create dice roll values. +例子中定义了一个Dice类,用来表示桌游中的拥有N个面的骰子。Dice的实例包含sides和generator两个属性,前者是整型(integer),用来表示骰子有几个面,后者提供了一个随机数生成器,来表示骰子掷出的值。 + +The generator property is of type RandomNumberGenerator. Therefore, you can set it to an instance of any type that adopts the RandomNumberGenerator protocol. Nothing else is required of the instance you assign to this property, except that the instance must adopt the RandomNumberGenerator protocol. +generator属性的类型为RandomNumberGenerator,因此任何类型,若适配RandomNumberGenerator协议,其实例都可以赋值给generator,除此以外没有其他要求。 + +Dice also has an initializer, to set up its initial state. This initializer has a parameter called generator, which is also of type RandomNumberGenerator. You can pass a value of any conforming type in to this parameter when initializing a new Dice instance. +Dice类也包含一个构造方法,用于设置其初始状态。这个方法包含一个同样是RandomNumberGenerator类型的参数generator。在构造一个新的Dice的实例时,可以传入任何遵循RandomNumberGenerator协议的类型作为generator。 + +Dice provides one instance method, roll, which returns an integer value between 1 and the number of sides on the dice. This method calls the generator’s random method to create a new random number between 0.0 and 1.0, and uses this random number to create a dice roll value within the correct range. Because generator is known to adopt RandomNumberGenerator, it is guaranteed to have a random method to call. +Dice类提供了一个实例方法,roll,此方法会返回一个整型值,介于1和骰子面的数量之间。这个方法调用generator的随机�数方法来创建一在0.0和1.0之间的随机数,并使用这个随机数来确保骰子的滚动值在正确的范围内。因为generator适配RandomNumberGenerator协议,因此它可以保证有一个random方法供调用。 + +Here’s how the Dice class can be used to create a six-sided dice with a LinearCongruentialGenerator instance as its random number generator: + +下面的例子中,展示了如何使用线性同余发生器(LinearCongruentialGenerator)的实例作为随机数生成器,从而创建一个六面的骰子: + + + var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator()) + for _ in 1...5 { + println("Random dice roll is \(d6.roll())") + } + // Random dice roll is 3 + // Random dice roll is 5 + // Random dice roll is 4 + // Random dice roll is 5 + // Random dice roll is 4 + +Delegation +代理 +Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source. +代理(Delegation)是一种设计模式,它允许类或结构体将一些他们负责的功能转交(代理)给其他类型的实例。 +委托模式的实现需要定义一个协议,这个协议封装了那些需要被代理的功能,而一个遵循此协议的实例则拥有这些功能 + +The example below defines two protocols for use with dice-based board games: +下面的例子中定义了两个基于骰子游戏的协议: + + protocol DiceGame { + var dice: Dice { get } + func play() + } + protocol DiceGameDelegate { + func gameDidStart(game: DiceGame) + func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) + func gameDidEnd(game: DiceGame) + } + +The DiceGame protocol is a protocol that can be adopted by any game that involves dice. The DiceGameDelegate protocol can be adopted by any type to track the progress of a DiceGame. + +DiceGame协议可以被任意含有骰子的游戏所适配,DiceGameDelegate协议可以被任意用来追踪DiceGame过程的类型所适配 + +Here’s a version of the Snakes and Ladders game originally introduced in Control Flow. This version is adapted to use a Dice instance for its dice-rolls; to adopt the DiceGame protocol; and to notify a DiceGameDelegate about its progress: + +这里有一个,Snakes and Ladders游戏的新版本(之前的版本在流程控制这一节中介绍过)。新版本使用Dice类的实例作为掷骰子的需求,并且适配了DiceGame协议。同时通知(notify)DiceGameDelegate协议,用来记录游戏过程: + + class SnakesAndLadders: DiceGame { + let finalSquare = 25 + let dice = Dice(sides: 6, generator: LinearCongruentialGenerator()) + var square = 0 + var board: Int[] + init() { + board = Int[](count: finalSquare + 1, repeatedValue: 0) + board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 + board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 + } + var delegate: DiceGameDelegate? + func play() { + square = 0 + delegate?.gameDidStart(self) + gameLoop: while square != finalSquare { + let diceRoll = dice.roll() + delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll) + switch square + diceRoll { + case finalSquare: + break gameLoop + case let newSquare where newSquare > finalSquare: + continue gameLoop + default: + square += diceRoll + square += board[square] + } + } + delegate?.gameDidEnd(self) + } + } +For a description of the Snakes and Ladders gameplay, see the Break section of the Control Flow chapter. +你可以参考流程控制章节中对此游戏的介绍 + +This version of the game is wrapped up as a class called SnakesAndLadders, which adopts the DiceGame protocol. It provides a gettable dice property and a play method in order to conform to the protocol. (The dice property is declared as a constant property because it does not need to change after initialization, and the protocol only requires that it is gettable.) + +这个版本的游戏封装为SnakesAndLadders类,该类适配DiceGame协议。这个类还提供了可读的dice属性和play方法,从而遵循了DiceGame协议。(dice属性声明为常量,因为构造之后dice属性就不在改变,且协议只要求dice为只读) + + + +The Snakes and Ladders game board setup takes place within the class’s init() initializer. All game logic is moved into the protocol’s play method, which uses the protocol’s required dice property to provide its dice roll values. + +Snakes And Ladders游戏通过构造方法(initializer)init初始化游戏。所有的游戏逻辑移到了play方法中,play方法使用协议要求的dice属性,来提供骰子掷出的值。 + +Note that the delegate property is defined as an optional DiceGameDelegate, because a delegate isn’t required in order to play the game. Because it is of an optional type, the delegate property is automatically set to an initial value of nil. Thereafter, the game instantiator has the option to set the property to a suitable delegate. +注意,delegate并不是玩游戏所必须的,因此delegate被定义为DiceGameDelegate协议类型的可选属性,delegate使用nil作为初始值。此后,游戏实例可以选择将其设置为一个合适的代理。 + + + +DiceGameDelegate provides three methods for tracking the progress of a game. These three methods have been incorporated into the game logic within the play method above, and are called when a new game starts, a new turn begins, or the game ends. + +DicegameDelegate协议提供了三个方法来跟踪游戏过程。这三个方法存在于游戏的逻辑中,即上面的play()方法内。分别在游戏开始时,新一轮开始时,游戏结束时被调用。 + + +Because the delegate property is an optional DiceGameDelegate, the play method uses optional chaining each time it calls a method on the delegate. If the delegate property is nil, these delegate calls fail gracefully and without error. If the delegate property is non-nil, the delegate methods are called, and are passed the SnakesAndLadders instance as a parameter. +因为delegate属性是一个遵循DiceGameDelegate的可选属性,因此在play()方法中使用了可选链(optional chaining )来在代理时调用方法。 若delegate属性为nil, 则delegate所调用的方法正常失败(fail gracefully)且不报错。若delegate不为nil,则方法能够被调用,且作为一个参数传入SnakesAndLadders实例中 +This next example shows a class called DiceGameTracker, which adopts the DiceGameDelegate protocol: +下一个例子展示了一个名为DiceGameTracker的类,适配DiceGameDelegate协议。 + + class DiceGameTracker: DiceGameDelegate { + var numberOfTurns = 0 + func gameDidStart(game: DiceGame) { + numberOfTurns = 0 + if game is SnakesAndLadders { + println("Started a new game of Snakes and Ladders") + } + println("The game is using a \(game.dice.sides)-sided dice") + } + func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) { + ++numberOfTurns + println("Rolled a \(diceRoll)") + } + func gameDidEnd(game: DiceGame) { + println("The game lasted for \(numberOfTurns) turns") + } + } +DiceGameTracker implements all three methods required by DiceGameDelegate. It uses these methods to keep track of the number of turns a game has taken. It resets a numberOfTurns property to zero when the game starts; increments it each time a new turn begins; and prints out the total number of turns once the game has ended. + +DiceGameTracker提供了DiceGameDelegate所要求的三个方法。它使用这三个方法来跟踪游戏进行的轮数。当游戏开始时,将numberOfTurns属性重置为0。每轮开始后递增这个值。当游戏结束时打印游戏进行的总轮数 + +The implementation of gameDidStart shown above uses the game parameter to print some introductory information about the game that is about to be played. The game parameter has a type of DiceGame, not SnakesAndLadders, and so gameDidStart can access and use only methods and properties that are implemented as part of the DiceGame protocol. However, the method is still able to use type casting to query the type of the underlying instance. In this example, it checks whether game is actually an instance of SnakesAndLadders behind the scenes, and prints an appropriate message if so. + +在如上所示的gameDidStart实现中,游戏即将开始时使用了game参数来打印一些介绍性信息。game参数拥有一个DiceGame类型,而不是SnakesAndLadders,所以gameDidStart只能访问和使用DiceGame协议中的方法和属性。然而,该方法仍然能够使用类型追溯(type casting)查询底层实例的类型。在这个例子中,它在幕后检查游戏是否是SnakesAndLadders的一个实例,当确认后打印一个适当的消息。 + +gameDidStart also accesses the dice property of the passed game parameter. Because game is known to conform to the DiceGame protocol, it is guaranteed to have a dice property, and so the gameDidStart method is able to access and print the dice’s sides property, regardless of what kind of game is being played. + +gameDidStart也能够访问dice属性,这个属性在被传递为参数的game中。因为game遵循DiceGame协议,因此被赋予了dice属性,不管运行何种游戏,gameDidStart方法都可以访问且打印骰子的边数。 +下面是DiceGameTracker的运行过程: +Here’s how DiceGameTracker looks in action: + + let tracker = DiceGameTracker() + let game = SnakesAndLadders() + game.delegate = tracker + game.play() + // Started a new game of Snakes and Ladders + // The game is using a 6-sided dice + // Rolled a 3 + // Rolled a 5 + // Rolled a 4 + // Rolled a 5 + // The game lasted for 4 turns From f1863b01539dd757015f7987e85d84c53ae7ecbe Mon Sep 17 00:00:00 2001 From: Adams Date: Sat, 21 Jun 2014 00:08:18 +0800 Subject: [PATCH 151/261] Update 21_Protocols.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 校订ing --- src/chapter2/21_Protocols.md | 433 +---------------------------------- 1 file changed, 1 insertion(+), 432 deletions(-) diff --git a/src/chapter2/21_Protocols.md b/src/chapter2/21_Protocols.md index 29931bf..33fc849 100644 --- a/src/chapter2/21_Protocols.md +++ b/src/chapter2/21_Protocols.md @@ -1,432 +1 @@ -http://numbbbbb.github.io/the-swift-programming-language-in-chinese/chapter2/21_Protocols.html - -https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_345 - -#Protocols -A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol doesn’t actually provide an implementation for any of these requirements—it only describes what an implementation will look like. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol. - - -#协议 - -一个协议(protocol)定义了适合特定的任务或功能的方法、属性和其他需求。协议并不提供这些需求的实现,只描述了这个实现应该是怎样的。 - -协议能够被类(class),结构体(structure),枚举(enumeration)适配(adopted),同时,这些类型如果了满足一个协议需求,则被称为遵循(conform to)协议 - -Protocols can require that conforming types have specific instance properties, instance methods, type methods, operators, and subscripts. - -协议可以要求遵循(conforming)的类型有特定的实例属性(instance properties),实例方法(instance methods),类型方法(type methods),操作符(operators)和下标(subscripts)。 - - -##Protocol Syntax -##协议语法 -You define protocols in a very similar way to classes, structures, and enumerations: - -定义协议,与定义类,结构体,枚举的方式非常相似,如下所示: - - protocol SomeProtocol { - // protocol definition goes here - } - -Custom types state that they adopt a particular protocol by placing the protocol’s name after the type’s name, separated by a colon, as part of their definition. Multiple protocols can be listed, and are separated by commas: -在类型名称后添加协议名称,并以冒号`:`分割,表示自定义类型(Custom types)适配一个特定协议;实现多个协议时,各协议之间用逗号`,`分隔,如下所示: - - struct SomeStructure: FirstProtocol, AnotherProtocol { - // structure definition goes here - } -If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma: -若某个类有父类,要把父类放在所有其适配的协议之前,且用逗号`,`分割,如下所示: - - class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol { - // class definition goes here - } - -Property Requirements -##属性要求 - -A protocol can require any conforming type to provide an instance property or type property with a particular name and type. The protocol doesn’t specify whether the property should be a stored property or a computed property—it only specifies the required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable. - -协议可以要求任何遵循(conforming)类型,提供一个特定名称和类型的实例属性(instance property)或类型属性(type property)。协议不指定属性是存储型属性(stored property)还是计算型属性(calculate property)。 -协议同时指定了每个属性是否是可读(gettable)或可读写(gettable and settable) - - -If a protocol requires a property to be gettable and settable, that property requirement cannot be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for it also to be settable if this is useful for your own code. -如果协议要求属性可读写(gettable and settable),那常量存储属性(constant stored property)或者只读计算属性(read-only computed property)都无法满足此要求。如果协议只要求属性可读(gettable),那任何类型的属性都满足这个要求,即使这些属性是可写(settable)的。 - -Property requirements are always declared as variable properties, prefixed with the var keyword. Gettable and settable properties are indicated by writing { get set } after their type declaration, and gettable properties are indicated by writing { get }. - -协议里的属性要求,通常都是通过使用`var`关键字来声明的变量属性。 -在类型声明之后用{ get set }表示属性为可读写的。{ get }表示属性为可读的。 - - protocol SomeProtocol { - var mustBeSettable: Int { get set } - var doesNotNeedToBeSettable: Int { get } - } - -Always prefix type property requirements with the class keyword when you define them in a protocol. This is true even though type property requirements are prefixed with the static keyword when implemented by a structure or enumeration: - -当你在一个协议中定义一个某种类型的属性要求,总要前置`class` 关键字。同样某类型属性要求使用`static`关键字前缀,来定义结构体(structure)或枚举类型(enumeration) - -> 这样翻译正确么? - - protocol AnotherProtocol { - class var someTypeProperty: Int { get set } - } - -Here’s an example of a protocol with a single instance property requirement: - -下面是协议的一个例子,这个协议只有一个实例属性(instance property)要求: - - - protocol FullyNamed { - var fullName: String { get } - } - -The FullyNamed protocol defines any kind of thing that has a fully-qualified name. It doesn’t specify what kind of thing it must be—it only specifies that the thing must be able to provide a full name for itself. It specifies this requirement by stating that any FullyNamed type must have a gettable instance property called fullName, which is of type String. - -FullyNamed协议可以定义任何需要一个完整name的类型(方法,属性或者其他需求)。这个协议并不指定什么,只有一个需求:这个类型本身必须提供一个完整的名称。这个需求通过声明一个String类型的实例属性fullName,且这个属性必须是可读的(gettable)来指定。 - - - -Here’s an example of a simple structure that adopts and conforms to the FullyNamed protocol: - -下面的例子中,一个简单的结构体适配且遵循FullyNamed协议 - - struct Person: FullyNamed { - var fullName: String - } - let john = Person(fullName: "John Appleseed") - // john.fullName is "John Appleseed" - -This example defines a structure called Person, which represents a specific named person. It states that it adopts the FullyNamed protocol as part of the first line of its definition. -这个例子中定义了一个名为Person的结构体,代表一个有名字的人。它在第一行的结构体定义中,声明了其适配FullyNamed协议。 - -Each instance of Person has a single stored property called fullName, which is of type String. This matches the single requirement of the FullyNamed protocol, and means that Person has correctly conformed to the protocol. (Swift reports an error at compile-time if a protocol requirement is not fulfilled.) - -每个Person实例都有一个单独存储的,String类型的属性fullName。拥有这个属性代表满足了FullyNamed协议的要求,这意味着Person遵循协议。(在编译时如果不满足协议要求,swift会报告一个错误)。 - - -Here’s a more complex class, which also adopts and conforms to the FullyNamed protocol: -下面有一个更复杂的类,同样适配且遵循FullyNamed协议 - - class Starship: FullyNamed { - var prefix: String? - var name: String - init(name: String, prefix: String? = nil) { - self.name = name - self.prefix = prefix - } - var fullName: String { - return (prefix ? prefix! + " " : "") + name - } - } - var ncc1701 = Starship(name: "Enterprise", prefix: "USS") - // ncc1701.fullName is "USS Enterprise" - -This class implements the fullName property requirement as a computed read-only property for a starship. Each Starship class instance stores a mandatory name and an optional prefix. The fullName property uses the prefix value if it exists, and prepends it to the beginning of name to create a full name for the starship. -这个类提供了fullName属性,这个属性是starship这个类的一个只读的计算属性。 -每个starship类的实例存储一个强制性的名称和一个可选的前缀。当存在前缀时,fullName属性会把前缀添加到名称前面,从而创建了一个starship的全名。 - - -Method Requirements - -Protocols can require specific instance methods and type methods to be implemented by conforming types. These methods are written as part of the protocol’s definition in exactly the same way as for normal instance and type methods, but without curly braces or a method body. Variadic parameters are allowed, subject to the same rules as for normal methods. - - - -方法需求 - -若某种类型遵循协议,协议可以要求指定特定的实例方法和类型方法。这些方法作为协议定义的一部分,跟通常定义实例与类型方法的途径完全一样,但不需要书写大括号或方法的主体。方法允许含有可变参数,且与通常的方法遵循同样的规则。 - -NOTE - -Protocols use the same syntax as normal methods, but are not allowed to specify default values for method parameters. - -注意 - -协议与通常的方法语法相同,但不允许指定方法中参数的默认值 - -As with type property requirements, you always prefix type method requirements with the class keyword when they are defined in a protocol. This is true even though type method requirements are prefixed with the static keyword when implemented by a structure or enumeration: - - protocol SomeProtocol { - class func someTypeMethod() - } - -当你在一个协议中定义一个某种类型的方法要求,要前置`class` 关键字。同样某类型方法要求使用`static`关键字前缀,来定义结构体(structure)或枚举类型(enumeration) - -The following example defines a protocol with a single instance method requirement: -下面的例子中,定义了一个协议,协议要求一个实例方法。 - - protocol RandomNumberGenerator { - func random() -> Double - } -This protocol, RandomNumberGenerator, requires any conforming type to have an instance method called random, which returns a Double value whenever it is called. (Although it is not specified as part of the protocol, it is assumed that this value will be a number between 0.0 and 1.0 inclusive.) - -RandomNumberGenerator,该协议要求任何遵循协议的类型调用一个名为random的实例方法,这个方法无论何时调用,都会返回一个Double类型的值。(这个值在0.0与1.0之间,这一点没有在协议中指出)。 - - -The RandomNumberGenerator protocol does not make any assumptions about how each random number will be generated—it simply requires the generator to provide a standard way to generate a new random number. - -Here’s an implementation of a class that adopts and conforms to the RandomNumberGenerator protocol. This class implements a pseudorandom number generator algorithm known as a linear congruential generator: - - RandomNumberGenerator协议不会描述如何建立一个随机数,只需要指定一个随机数生成器,从而提供一种标准的方式来生成一个新随机数。 -   - 下面是一个类的实现,遵循RandomNumberGenerator协议。这个类实现了一种伪随机数发生器算法,称为线性同余(linear congruential)发生器: - - - class LinearCongruentialGenerator: RandomNumberGenerator { - var lastRandom = 42.0 - let m = 139968.0 - let a = 3877.0 - let c = 29573.0 - func random() -> Double { - lastRandom = ((lastRandom * a + c) % m) - return lastRandom / m - } - } - let generator = LinearCongruentialGenerator() - println("Here's a random number: \(generator.random())") - // prints "Here's a random number: 0.37464991998171" - println("And another one: \(generator.random())") - // prints "And another one: 0.729023776863283" - -Mutating Method Requirements - -突变方法要求 - -It is sometimes necessary for a method to modify (or mutate) the instance it belongs to. For instance methods on value types (that is, structures and enumerations) you place the mutating keyword before a method’s func keyword to indicate that the method is allowed to modify the instance it belongs to and/or any properties of that instance. This process is described in Modifying Value Types from Within Instance Methods. - -有时,实例的一个方法需要修改(或突变)实例的类型。对值类型(value types)(即结构体和枚举类型)的实例方法中,使用`mutating`关键字,写在方法的函数关键字`fun`前面,来表明实例中该方法允许修改其类型及任何属性。这个过程在 `在实例方法中修改值类型`章节中有详细的描述。 - -If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement. - -如果你定义的协议中,某个实例适配此协议,而实例方法需要改变其类型,协议定义时要在此方法前加上关键字`mutating`。这样可以让结构体及枚举类型适配协议,且满足实例方法的需求。 - -NOTE -注意 -If you mark a protocol instance method requirement as mutating, you do not need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations. - - -如果你在一个协议中实现的突变方法是为一个类服务的,不需要为其加上mutating关键字。 -mutating关键字只用在结构体与枚举类型中。 - - -The example below defines a protocol called Togglable, which defines a single instance method requirement called toggle. As its name suggests, the toggle method is intended to toggle or invert the state of any conforming type, typically by modifying a property of that type. -下面的例子中定义了一个togglable协议,包含一个名为togger的突变实例方法。正如名称所表达的,适配此协议的某实例中,toggle方法通常会通过改变实例的某个属性,来切换或恢复其类型。 - -The toggle method is marked with the mutating keyword as part of the Togglable protocol definition, to indicate that the method is expected to mutate the state of a conforming instance when it is called: -toggle方法前面加上了mutating关键字,作为Togglabel协议定义的一部分,则表示一个适配toggleabel协议的实例中,这个方法会在调用时改变实例的类型。 - - protocol Togglable { - mutating func toggle() - } - -If you implement the Togglable protocol for a structure or enumeration, that structure or enumeration can conform to the protocol by providing an implementation of the toggle method that is also marked as mutating. - -当你提供的枚举或结构体遵循Togglabl协议时,需要提供一个带有`mutating`前缀的toggle方法。 - - -The example below defines an enumeration called OnOffSwitch. This enumeration toggles between two states, indicated by the enumeration cases On and Off. The enumeration’s toggle implementation is marked as mutating, to match the Togglable protocol’s requirements: - - enum OnOffSwitch: Togglable { - case Off, On - mutating func toggle() { - switch self { - case Off: - self = On - case On: - self = Off - } - } - } - var lightSwitch = OnOffSwitch.Off - lightSwitch.toggle() - // lightSwitch is now equal to .On -Protocols as Types -协议类型 - -Protocols do not actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use in your code. -尽管协议本身并不实现任何功能,但协议可以作为完整的类型来使用。 -Because it is a type, you can use a protocol in many places where other types are allowed, including: -你可以把协议类型用在其他类型适用的场景里,比如: - -As a parameter type or return type in a function, method, or initializer - -在函数,方法或构造方法中作为形参类型(parameter type)或返回值类型(return type) -As the type of a constant, variable, or property -作为常量、变量或属性这三种类型之一 -As the type of items in an array, dictionary, or other container -作为数组,字典或其他容器中的元素类型 - -NOTE -注意 -Because protocols are types, begin their names with a capital letter (such as FullyNamed and RandomNumberGenerator) to match the names of other types in Swift (such as Int, String, and Double). -注意: 协议是一种类型,因此协议类型的名称应与Swift中其他类型(Int,Double,String)的写法相同,每一个单字的首字母都采用大写字母(大驼峰写法) - -Here’s an example of a protocol used as a type: -下面的例子中,协议被当作类型使用: - - class Dice { - let sides: Int - let generator: RandomNumberGenerator - init(sides: Int, generator: RandomNumberGenerator) { - self.sides = sides - self.generator = generator - } - func roll() -> Int { - return Int(generator.random() * Double(sides)) + 1 - } - } -This example defines a new class called Dice, which represents an n-sided dice for use in a board game. Dice instances have an integer property called sides, which represents how many sides they have, and a property called generator, which provides a random number generator from which to create dice roll values. -例子中定义了一个Dice类,用来表示桌游中的拥有N个面的骰子。Dice的实例包含sides和generator两个属性,前者是整型(integer),用来表示骰子有几个面,后者提供了一个随机数生成器,来表示骰子掷出的值。 - -The generator property is of type RandomNumberGenerator. Therefore, you can set it to an instance of any type that adopts the RandomNumberGenerator protocol. Nothing else is required of the instance you assign to this property, except that the instance must adopt the RandomNumberGenerator protocol. -generator属性的类型为RandomNumberGenerator,因此任何类型,若适配RandomNumberGenerator协议,其实例都可以赋值给generator,除此以外没有其他要求。 - -Dice also has an initializer, to set up its initial state. This initializer has a parameter called generator, which is also of type RandomNumberGenerator. You can pass a value of any conforming type in to this parameter when initializing a new Dice instance. -Dice类也包含一个构造方法,用于设置其初始状态。这个方法包含一个同样是RandomNumberGenerator类型的参数generator。在构造一个新的Dice的实例时,可以传入任何遵循RandomNumberGenerator协议的类型作为generator。 - -Dice provides one instance method, roll, which returns an integer value between 1 and the number of sides on the dice. This method calls the generator’s random method to create a new random number between 0.0 and 1.0, and uses this random number to create a dice roll value within the correct range. Because generator is known to adopt RandomNumberGenerator, it is guaranteed to have a random method to call. -Dice类提供了一个实例方法,roll,此方法会返回一个整型值,介于1和骰子面的数量之间。这个方法调用generator的随机�数方法来创建一在0.0和1.0之间的随机数,并使用这个随机数来确保骰子的滚动值在正确的范围内。因为generator适配RandomNumberGenerator协议,因此它可以保证有一个random方法供调用。 - -Here’s how the Dice class can be used to create a six-sided dice with a LinearCongruentialGenerator instance as its random number generator: - -下面的例子中,展示了如何使用线性同余发生器(LinearCongruentialGenerator)的实例作为随机数生成器,从而创建一个六面的骰子: - - - var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator()) - for _ in 1...5 { - println("Random dice roll is \(d6.roll())") - } - // Random dice roll is 3 - // Random dice roll is 5 - // Random dice roll is 4 - // Random dice roll is 5 - // Random dice roll is 4 - -Delegation -代理 -Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source. -代理(Delegation)是一种设计模式,它允许类或结构体将一些他们负责的功能转交(代理)给其他类型的实例。 -委托模式的实现需要定义一个协议,这个协议封装了那些需要被代理的功能,而一个遵循此协议的实例则拥有这些功能 - -The example below defines two protocols for use with dice-based board games: -下面的例子中定义了两个基于骰子游戏的协议: - - protocol DiceGame { - var dice: Dice { get } - func play() - } - protocol DiceGameDelegate { - func gameDidStart(game: DiceGame) - func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) - func gameDidEnd(game: DiceGame) - } - -The DiceGame protocol is a protocol that can be adopted by any game that involves dice. The DiceGameDelegate protocol can be adopted by any type to track the progress of a DiceGame. - -DiceGame协议可以被任意含有骰子的游戏所适配,DiceGameDelegate协议可以被任意用来追踪DiceGame过程的类型所适配 - -Here’s a version of the Snakes and Ladders game originally introduced in Control Flow. This version is adapted to use a Dice instance for its dice-rolls; to adopt the DiceGame protocol; and to notify a DiceGameDelegate about its progress: - -这里有一个,Snakes and Ladders游戏的新版本(之前的版本在流程控制这一节中介绍过)。新版本使用Dice类的实例作为掷骰子的需求,并且适配了DiceGame协议。同时通知(notify)DiceGameDelegate协议,用来记录游戏过程: - - class SnakesAndLadders: DiceGame { - let finalSquare = 25 - let dice = Dice(sides: 6, generator: LinearCongruentialGenerator()) - var square = 0 - var board: Int[] - init() { - board = Int[](count: finalSquare + 1, repeatedValue: 0) - board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 - board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 - } - var delegate: DiceGameDelegate? - func play() { - square = 0 - delegate?.gameDidStart(self) - gameLoop: while square != finalSquare { - let diceRoll = dice.roll() - delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll) - switch square + diceRoll { - case finalSquare: - break gameLoop - case let newSquare where newSquare > finalSquare: - continue gameLoop - default: - square += diceRoll - square += board[square] - } - } - delegate?.gameDidEnd(self) - } - } -For a description of the Snakes and Ladders gameplay, see the Break section of the Control Flow chapter. -你可以参考流程控制章节中对此游戏的介绍 - -This version of the game is wrapped up as a class called SnakesAndLadders, which adopts the DiceGame protocol. It provides a gettable dice property and a play method in order to conform to the protocol. (The dice property is declared as a constant property because it does not need to change after initialization, and the protocol only requires that it is gettable.) - -这个版本的游戏封装为SnakesAndLadders类,该类适配DiceGame协议。这个类还提供了可读的dice属性和play方法,从而遵循了DiceGame协议。(dice属性声明为常量,因为构造之后dice属性就不在改变,且协议只要求dice为只读) - - - -The Snakes and Ladders game board setup takes place within the class’s init() initializer. All game logic is moved into the protocol’s play method, which uses the protocol’s required dice property to provide its dice roll values. - -Snakes And Ladders游戏通过构造方法(initializer)init初始化游戏。所有的游戏逻辑移到了play方法中,play方法使用协议要求的dice属性,来提供骰子掷出的值。 - -Note that the delegate property is defined as an optional DiceGameDelegate, because a delegate isn’t required in order to play the game. Because it is of an optional type, the delegate property is automatically set to an initial value of nil. Thereafter, the game instantiator has the option to set the property to a suitable delegate. -注意,delegate并不是玩游戏所必须的,因此delegate被定义为DiceGameDelegate协议类型的可选属性,delegate使用nil作为初始值。此后,游戏实例可以选择将其设置为一个合适的代理。 - - - -DiceGameDelegate provides three methods for tracking the progress of a game. These three methods have been incorporated into the game logic within the play method above, and are called when a new game starts, a new turn begins, or the game ends. - -DicegameDelegate协议提供了三个方法来跟踪游戏过程。这三个方法存在于游戏的逻辑中,即上面的play()方法内。分别在游戏开始时,新一轮开始时,游戏结束时被调用。 - - -Because the delegate property is an optional DiceGameDelegate, the play method uses optional chaining each time it calls a method on the delegate. If the delegate property is nil, these delegate calls fail gracefully and without error. If the delegate property is non-nil, the delegate methods are called, and are passed the SnakesAndLadders instance as a parameter. -因为delegate属性是一个遵循DiceGameDelegate的可选属性,因此在play()方法中使用了可选链(optional chaining )来在代理时调用方法。 若delegate属性为nil, 则delegate所调用的方法正常失败(fail gracefully)且不报错。若delegate不为nil,则方法能够被调用,且作为一个参数传入SnakesAndLadders实例中 -This next example shows a class called DiceGameTracker, which adopts the DiceGameDelegate protocol: -下一个例子展示了一个名为DiceGameTracker的类,适配DiceGameDelegate协议。 - - class DiceGameTracker: DiceGameDelegate { - var numberOfTurns = 0 - func gameDidStart(game: DiceGame) { - numberOfTurns = 0 - if game is SnakesAndLadders { - println("Started a new game of Snakes and Ladders") - } - println("The game is using a \(game.dice.sides)-sided dice") - } - func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) { - ++numberOfTurns - println("Rolled a \(diceRoll)") - } - func gameDidEnd(game: DiceGame) { - println("The game lasted for \(numberOfTurns) turns") - } - } -DiceGameTracker implements all three methods required by DiceGameDelegate. It uses these methods to keep track of the number of turns a game has taken. It resets a numberOfTurns property to zero when the game starts; increments it each time a new turn begins; and prints out the total number of turns once the game has ended. - -DiceGameTracker提供了DiceGameDelegate所要求的三个方法。它使用这三个方法来跟踪游戏进行的轮数。当游戏开始时,将numberOfTurns属性重置为0。每轮开始后递增这个值。当游戏结束时打印游戏进行的总轮数 - -The implementation of gameDidStart shown above uses the game parameter to print some introductory information about the game that is about to be played. The game parameter has a type of DiceGame, not SnakesAndLadders, and so gameDidStart can access and use only methods and properties that are implemented as part of the DiceGame protocol. However, the method is still able to use type casting to query the type of the underlying instance. In this example, it checks whether game is actually an instance of SnakesAndLadders behind the scenes, and prints an appropriate message if so. - -在如上所示的gameDidStart实现中,游戏即将开始时使用了game参数来打印一些介绍性信息。game参数拥有一个DiceGame类型,而不是SnakesAndLadders,所以gameDidStart只能访问和使用DiceGame协议中的方法和属性。然而,该方法仍然能够使用类型追溯(type casting)查询底层实例的类型。在这个例子中,它在幕后检查游戏是否是SnakesAndLadders的一个实例,当确认后打印一个适当的消息。 - -gameDidStart also accesses the dice property of the passed game parameter. Because game is known to conform to the DiceGame protocol, it is guaranteed to have a dice property, and so the gameDidStart method is able to access and print the dice’s sides property, regardless of what kind of game is being played. - -gameDidStart也能够访问dice属性,这个属性在被传递为参数的game中。因为game遵循DiceGame协议,因此被赋予了dice属性,不管运行何种游戏,gameDidStart方法都可以访问且打印骰子的边数。 -下面是DiceGameTracker的运行过程: -Here’s how DiceGameTracker looks in action: - - let tracker = DiceGameTracker() - let game = SnakesAndLadders() - game.delegate = tracker - game.play() - // Started a new game of Snakes and Ladders - // The game is using a 6-sided dice - // Rolled a 3 - // Rolled a 5 - // Rolled a 4 - // Rolled a 5 - // The game lasted for 4 turns +##协议 From 6131f9ff8703ffdc129c2545f2a8316c859fdfcc Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Sat, 21 Jun 2014 11:46:55 +0800 Subject: [PATCH 152/261] modify the literal translation --- src/chapter2/01_The_Basics.md | 12 ++++++------ src/words.md | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 370c762..8a63d8f 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -107,7 +107,7 @@ The welcomeMessage variable can now be set to any string value without error: > 注意 -> 在实践中你需要写类型批注的很少见。如果你在定义一个常量或变量的时候给了它一个初始值,Swift几乎总是可以推断出这个常量或变量使用的类型,参见类型安全(Type Safety)和类型推断(Type Inference)。在上面这个welcomeMessage的例子里,没有提供初始值,所以welcomeMessage这个变量的类型是通过类型批注的形式来指定,而不是通过初始值推断而来。 +> 在实践中你需要写类型批注的很少见。如果你在定义一个常量或变量的时候给了它一个初始值,Swift几乎总是可以推断出这个常量或变量使用的类型,参见[类型安全和类型推断](link)。在上面这个welcomeMessage的例子里,没有提供初始值,所以welcomeMessage这个变量的类型是通过类型批注的形式来指定,而不是通过初始值推断而来。 # Naming Constants and Variables # 命名常量和变量 @@ -368,11 +368,11 @@ Because of type inference, Swift requires far fewer type declarations than langu Type inference is particularly useful when you declare a constant or variable with an initial value. This is often done by assigning a literal value (or literal) to the constant or variable at the point that you declare it. (A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below.) -当你声明一个有初始值的常量或变量的时候类型推断特别实用。通常是当你声明一个常量和变量的时候你就给它赋一个参数值(literal value)。(参数值是会直接出现在源码里的值,比如下面例子里的42和3.14159。) +当你声明一个有初始值的常量或变量的时候类型推断特别实用。通常是当你声明一个常量和变量的时候你就给它赋一个字面值(literal value)。(字面值是会直接出现在源码里的值,比如下面例子里的42和3.14159。) For example, if you assign a literal value of 42 to a new constant without saying what type it is, Swift infers that you want the constant to be an Int, because you have initialized it with a number that looks like an integer: -举个例子,如果你给一个新的常量赋了一个参数值42,但没有说它的类型,Swift会推断你希望这个常量是一个整数类型(Int),因为你用了一个像是整数的数字来初始化: +举个例子,如果你给一个新的常量赋了一个字面值42,但没有说它的类型,Swift会推断你希望这个常量是一个整数类型(Int),因为你用了一个像是整数的数字来初始化: let meaningOfLife = 42 // meaningOfLife is inferred to be of type Int @@ -380,7 +380,7 @@ For example, if you assign a literal value of 42 to a new constant without sayin Likewise, if you don’t specify a type for a floating-point literal, Swift infers that you want to create a Double: -类似的,如果你没有特别指定一个浮点型的参数,Swift会推断你需要一个Double类型的浮点数: +类似的,如果你没有特别指定一个浮点型的字面值,Swift会推断你需要一个Double类型的浮点数: let pi = 3.14159 // pi is inferred to be of type Double @@ -392,7 +392,7 @@ Swift always chooses Double (rather than Float) when inferring the type of float If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context: -如果你将整数型和浮点型的参数值相加,这种情况下会推断为Double类型: +如果你将整数型和浮点型的字面值相加,这种情况下会推断为Double类型: let anotherPi = 3 + 0.14159 // anotherPi is also inferred to be of type Double @@ -400,7 +400,7 @@ If you combine integer and floating-point literals in an expression, a type of D The literal value of 3 has no explicit type in and of itself, and so an appropriate output type of Double is inferred from the presence of a floating-point literal as part of the addition. -参数值3本身并没有准确的类型,因此是通过相加的元素中有一个浮点型的参数值推断出合适的输出类型为Double. +字面值3本身并没有准确的类型,因此是通过相加的元素中有一个浮点型的字面值推断出合适的输出类型为Double. Numeric Literals diff --git a/src/words.md b/src/words.md index 0f936f8..56954f4 100644 --- a/src/words.md +++ b/src/words.md @@ -10,4 +10,4 @@ - override 覆盖 - adopt - 适配。但是一般用于被动。如 `a protocol can be adopted by a class`: 协议可以被类适配。 - conform - 遵循。如果一个类适配了一个协议,我们就说这个类遵循这个协议。`this class conforms to that protocol`。 -- literals - 参数 - A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below. \ No newline at end of file +- literal value - 字面量 - A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below. \ No newline at end of file From 60cd1f8f877ebf9fcac8f909a6cf6169f6bd5e51 Mon Sep 17 00:00:00 2001 From: LionQ Date: Sat, 21 Jun 2014 20:25:18 +0800 Subject: [PATCH 153/261] Update 02_A_Swift_Tour.md A Swift Tour --- src/chapter1/02_A_Swift_Tour.md | 211 ++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) diff --git a/src/chapter1/02_A_Swift_Tour.md b/src/chapter1/02_A_Swift_Tour.md index e69de29..b2d2ede 100644 --- a/src/chapter1/02_A_Swift_Tour.md +++ b/src/chapter1/02_A_Swift_Tour.md @@ -0,0 +1,211 @@ +A Swift Tour + +Tradition suggests that the first program in a new language should print the words “Hello, world” on the screen. In Swift, this can be done in a single line: +通常学习一门新语言都会输出一行“Hello,world”.在swift里只需要一行代码 + +“If you have written code in C or Objective-C, this syntax looks familiar to you—in Swift, this line of code is a complete program. You don’t need to import a separate library for functionality like input/output or string handling. Code written at global scope is used as the entry point for the program, so you don’t need a main function. You also don’t need to write semicolons at the end of every statement.” +如果你之前写过C或者Objective-C的代码,你会很熟悉这种语法。在swift里,这一行代码就是一个完整的程序,你不需要再去引入一个完成类似输入输出,字符串处理等操作的类库。在全局范围内编写的代码就是程序的入口,因此你不再需要main函数了,也不需要在每一条语句末尾写分号。 + +“This tour gives you enough information to start writing code in Swift by showing you how to accomplish a variety of programming tasks. Don’t worry if you don’t understand something—everything introduced in this tour is explained in detail in the rest of this book.” +这篇文章会充分向你展示如何用swift完成各种编程任务。不用担心一些细节不太理解,在这本书之后的章节中会详细的为你介绍。 + + +“Simple Values +Use let to make a constant and var to make a variable. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once. This means you can use constants to name a value that you determine once but use in many places.” +简单值 +使用let声明常量,var声明变量。在编译的时候不需要知道常量的值,但是你只能给常量显式地赋值一次。也就是说你可以给常量赋一次值然后在其他一些地方来使用。 + +“A constant or variable must have the same type as the value you want to assign to it. However, you don’t always have to write the type explicitly. Providing a value when you create a constant or variable lets the compiler infer its type. In the example above, the compiler infers that myVariable is an integer because its initial value is a integer.” +不管是常量还是变量必须与其所赋的值类型保持一致。你不一定要把常量或者变量的类型显式地写出来。因为编译器可以根据值来自动推断常量或者变量的类型。如上面的例子,编译器根据myVariable的初始值类型推断出它是一个整型变量。 + +“If the initial value doesn’t provide enough information (or if there is no initial value), specify the type by writing it after the variable, separated by a colon.” +如果初始值没有提供足够的信息或者没有初始值,可以在变量后面写上它的类型,变量和类型用冒号隔开。 + +“Values are never implicitly converted to another type. If you need to convert a value to a different type, explicitly make an instance of the desired type.” +值的类型不会自动转换,如果你需要把一个值转换成另外一种类型,需要强制转换。 + +“There’s an even simpler way to include values in strings: Write the value in parentheses, and write a backslash (\) before the parentheses. For example:” +有一种更简单的把值转换成字符串的方法:把值写在括号里,然后在括号前加一个反斜杠。例如: + +“Create arrays and dictionaries using brackets ([]), and access their elements by writing the index or key in brackets.” +用中括号创建数组和字典,通过中括号里的索引和键来访问集合中的元素。 + +“To create an empty array or dictionary, use the initializer syntax.” +用下面的初始化语法来创建一个空的数组或字典 + +“If type information can be inferred, you can write an empty array as [] and an empty dictionary as [:]—for example, when you set a new value for a variable or pass an argument to a function.” +如果类型可以被推断出来,你可以用[]来创建一个空数组,用[:]来创建一个空字典。例如,当你给一个变量赋值或者给一个函数传参 + +“Control Flow +Use if and switch to make conditionals, and use for-in, for, while, and do-while to make loops. Parentheses around the condition or loop variable are optional. Braces around the body are required.” +流控制 +使用if和switch来进行条件控制,使用for-in、for、while和do-while来进行循环控制。条件和循环变量外面的括号可以省略,但是语句体的大括号是必须的。 + +“In an if statement, the conditional must be a Boolean expression—this means that code such as if score { ... } is an error, not an implicit comparison to zero.” +在if语句里,条件必须是一个Boolean表达式。所以if score { ... }这种写法是错误的,score不会隐式地和0来比较。 + +“You can use if and let together to work with values that might be missing. These values are represented as optionals. An optional value either contains a value or contains nil to indicate that the value is missing. Write a question mark (?) after the type of a value to mark the value as optional.” +你可以一起使用if和let来处理值缺失的情况。有些变量的值是可选的。一个可选的值可能是一个具体的值或者是nil,表示值缺失。在类型后面加一个问号来标记这个变量的值是可选的。 + +“If the optional value is nil, the conditional is false and the code in braces is skipped. Otherwise, the optional value is unwrapped and assigned to the constant after let, which makes the unwrapped value available inside the block of code.” +如果变量的可选值是nil,则判断条件为false,大括号中的代码被略过。如果不为nil,可选值会赋值给let后的常量,并且该常量可以在代码块中使用。 + +“Switches support any kind of data and a wide variety of comparison operations—they aren’t limited to integers and tests for equality.” +Switch支持各种类型的数据以及大量的比较操作-它们不仅限于整数和比较大小。 + +“After executing the code inside the switch case that matched, the program exits from the switch statement. Execution doesn’t continue to the next case, so there is no need to explicitly break out of the switch at the end of each case’s code.” +与switch的case相匹配的代码执行完之后,程序不会继续执行下一个case中的代码,而是会自动退出switch语句,所以不需要在每一个case的代码后面显式的调用break。 + +“You use for-in to iterate over items in a dictionary by providing a pair of names to use for each key-value pair.” +你可以使用for-in来遍历字典,用两个变量来表示每对键值。 + +“Use while to repeat a block of code until a condition changes. The condition of a loop can be at the end instead, ensuring that the loop is run at least once.” +使用while来重复执行一段代码直到条件改变。循环条件也可也在末尾,以保证循环至少可执行一次。 + +“You can keep an index in a loop—either by using .. to make a range of indexes or by writing an explicit initialization, condition, and increment. These two loops do the same thing:” +在循环中可以使用..来表示索引范围或者使用传统的方式。两者是等价的。 + +“Use .. to make a range that omits its upper value, and use ... to make a range that includes both values.” +使用..会忽略范围中的上限值,使用...则不会忽略。 + +“Functions and Closures +Use func to declare a function. Call a function by following its name with a list of arguments in parentheses. Use -> to separate the parameter names and types from the function’s return type.” +函数和闭包 +使用func来声明一个函数。在函数名后的括号里加入参数来调用函数。使用->分隔开函数的参数和函数的返回值类型。 + +“Use a tuple to return multiple values from a function.” +使用元组来返回一组值。 + +“Functions can also take a variable number of arguments, collecting them into an array.” +函数可以有一组可变个数的参数,由array来表示。 + +“Functions can be nested. Nested functions have access to variables that were declared in the outer function. You can use nested functions to organize the code in a function that is long or complex.” +函数可以嵌套,被嵌套的函数可以访问外部函数中声明的变量。你可以使用嵌套函数来重构一段很长很复杂的函数。 + +“Functions are a first-class type. This means that a function can return another function as its value.” +函数是first-class类型,因此它可以作为另一个函数的返回值。 + +“A function can take another function as one of its arguments.” +函数可以作为另一个函数的参数。 + +“Functions are actually a special case of closures. You can write a closure without a name by surrounding code with braces ({}). Use in to separate the arguments and return type from the body.” +函数实际上是一个特殊的闭包。你可以把一段代码写在大括号{}中来表示一个匿名闭包,参数和返回类型与闭包体之间用in来分隔。 + +“You have several options for writing closures more concisely. When a closure’s type is already known, such as the callback for a delegate, you can omit the type of its parameters, its return type, or both. Single statement closures implicitly return the value of their only statement.” +有一些简洁表示闭包的方式。当一个闭包的类型已知,例如作为委托的回调,可以省略它的参数和返回类型。单个语句闭包会把它语句的值当做结果返回。 + +“You can refer to parameters by number instead of by name—this approach is especially useful in very short closures. A closure passed as the last argument to a function can appear immediately after the parentheses.” +你可以使用参数位置替代参数名来引用参数-这个方法特别是在很短的闭包里很好用。闭包作为函数最后一个参数的时候,可以直接跟在小括号后面。 + +“Objects and Classes +Use class followed by the class’s name to create a class. A property declaration in a class is written the same way as a constant or variable declaration, except that it is in the ” +“context of a class. Likewise, method and function declarations are written the same way.” +对象和类 +使用class和类名来创建一个类。类中的属性声明是和常量或者变量的声明方式一样的,唯一的区别是属性声明是在类的上下文之中的。同样的,方法和函数的声明也是一样的。 + +“Create an instance of a class by putting parentheses after the class name. Use dot syntax to access the properties and methods of the instance.” +类名后面跟小括号来创建一个类的实例。使用点语法来访问该实例的属性和方法。 + +“This version of the Shape class is missing something important: an initializer to set up the class when an instance is created. Use init to create one.” +这个版本的Shape类缺少了一个重要的东西:类实例化时候的一个构造器。使用init来创造一个构造器。 + +“Notice how self is used to distinguish the name property from the name argument to the initializer. The arguments to the initializer are passed like a function call when you create an instance of the class. Every property needs a value assigned—either in its declaration (as with numberOfSides) or in the initializer (as with name).” +注意用self来区分name属性和传递给构造器的name参数。像函数调用一样,把参数传递给构造器来创建一个类实例。每一个属性都需要赋值,在属性的声明中(如numberOfSides),或者在构造器中(如name) + +“Use deinit to create a deinitializer if you need to perform some cleanup before the object is deallocated.” +“Subclasses include their superclass name after their class name, separated by a colon. There is no requirement for classes to subclass any standard root class, so you can include or omit a superclass as needed.” +使用deinit来创建一个析构器来执行对象销毁前的清理工作。 +定义子类的时候是在类名后加上父类的名字,中间用冒号隔开。因为类不需要继承任何标准的基类,所以你可以省略父类。 + +“Methods on a subclass that override the superclass’s implementation are marked with override—overriding a method by accident, without override, is detected by the compiler as an error. The compiler also detects methods with override that don’t actually override any method in the superclass.” +子类方法重写父类方法的时候标记为override-这是为了防止意外的重写,如果没有override关键字,编译器会报错。编译器同样会检测在子类标记为override的方法是否真的重写了父类的某个方法。 + +“In addition to simple properties that are stored, properties can have a getter and a setter.” +属性也可以有getter和setter方法。 + +“In the setter for perimeter, the new value has the implicit name newValue. You can provide an explicit name in parentheses after set.” +在setter方法中,新的属性值被隐式地命名为newValue。你可以在set后的括号里显式地给属性值命名。 + +“Notice that the initializer for the EquilateralTriangle class has three different steps: +Setting the value of properties that the subclass declares. +Calling the superclass’s initializer. +Changing the value of properties defined by the ” +“superclass. Any additional setup work that uses methods, getters, or setters can also be done at this point.” +注意创建EquilateralTriangle类的构造器包含三个不同的步骤。 +1.在子类声明的时候设置属性值。 +2.调用父类的构造器。 +3.改变定义在父类中的属性值,还有调用方法,getter和setter方法都可以在这个步骤完成。 + +“If you don’t need to compute the property but still need to provide code that is run before and after setting a new value, use willSet and didSet. For example, the class below ensures that the side length of its triangle is always the same as the side length of its square.” +如果你不需要计算属性,但仍需要在给属性设置新值的前后运行一些代码,使用willSet和didSet。例如,下面的类会确保三角形的边长和方形的边长相等。 + +“Methods on classes have one important difference from functions. Parameter names in functions are used only within the function, but parameters names in methods are also used when you call the method (except for the first parameter). By default, a method has the same name for its parameters when you call it and within the method itself. You can specify a second name, which is used inside the method.” +类中的方法和函数有一个很重要的区别。函数中的参数只会在函数内部使用,但是方法中的参数还可以在方法调用的时候使用(除了第一个参数)。默认情况下,方法调用时候的参数名和方法内部使用的参数名保持一致。在方法内部使用的时候你也可以定义一个不同的名字。 + +“When working with optional values, you can write ? before operations like methods, properties, and subscripting. If the value before the ? is nil, everything after the ? is ignored and the value of the whole expression is nil. Otherwise, the optional value is unwrapped, and everything after the ? acts on the unwrapped value. In both cases, the value of the whole expression is an optional value.” +处理可选值的时候,你可以在?后面跟上方法,属性,子脚本等操作。如果?之前的值是nil,?后面的代码会被忽略,然后整个表达式的值返回nil。否则,?之后的代码会执行。在这两种情况下,整个表达式就是一个可选值。 + +“Enumerations and Structures +Use enum to create an enumeration. Like classes and all other named types, enumerations can have methods associated with them.” +枚举和结构体 +使用enum来创建一个枚举。像类和其他命名类型一样,枚举可以有方法。 + +“In the example above, the raw value type of the enumeration is Int, so you only have to specify the first raw value. The rest of the raw values are assigned in order. You can also use strings or floating-point numbers as the raw type of an enumeration.” +在上面的例子中,枚举的原始值类型是Int,所以你只需要指定第一个值,其余的会按照顺序进行赋值。你同样可以使用字符串和浮点数作为枚举的原始类型。 + +“Use the toRaw and fromRaw functions to convert between the raw value and the enumeration value.” +使用toRaw和fromRaw这两个函数用于在原始值和枚举值之间转换。 + +“The member values of an enumeration are actual values, not just another way of writing their raw values. In fact, in cases where there isn’t a meaningful raw value, you don’t have to provide one.” +枚举的成员值是实际值,并不是原始值的另一种表示方式。实际上,如果原始值没有意义,你就不需要提供。 + +“Notice the two ways that the Hearts member of the ” +“enumeration is referred to above: When assigning a value to the hearts constant, the enumeration member Suit.Hearts is referred to by its full name because the constant doesn’t have an explicit type specified. Inside the switch, the enumeration is referred to by the abbreviated form .Hearts because the value of self is already known to be a suit. You can use the abbreviated form anytime the value’s type is already known.” +注意,有两种方式可以引用Hearts成员:当给hearts常量赋值时,通过Suit.Hearts全名来引用枚举成员,因为常量没有显式指定其类型。在switch语句内部,因为已知self是一个suit,所以可以通过.Hearts这种简写的方式来引用枚举。在已知值类型的情况下你都可以采用简写的方式。 + +“Use struct to create a structure. Structures support many of the same behaviors as classes, including methods and initializers. One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.” +使用struct来创建一个结构体。结构体支持很多和类同样的操作,包括方法和构造器。两者之间最重要的差别是结构体在代码中传递采用的是拷贝的方式,但是类采用的是传递引用的方式。 + +“An instance of an enumeration member can have values associated with the instance. Instances of the same enumeration member can have different values associated with them. You provide the associated values when you create the instance. Associated values and raw values are different: The raw value of an enumeration member is the ”“same for all of its instances, and you provide the raw value when you define the enumeration.” +一个枚举成员的实例可以有对应的实例值。相同枚举成员的实例可以有不同的实例值。当你创建一个实例的时候提供对应的实例值。实例值和原始值是不同的:枚举成员所有的实例的原始值都是相同的,而且你是在定义枚举的时候提供原始值。 + +“For example, consider the case of requesting the sunrise and sunset time from a server. The server either responds with the information or it responds with some error information.” +例如,考虑从服务端获取日出和日落的时间。服务端要么返回正常信息,要么返回错误信息。 + +“Notice how the sunrise and sunset times are extracted from the ServerResponse value as part of matching the value against the switch cases.” +注意,如何从ServerResponse中提去日出和日落时间。 + +Protocols and Extensions +“Use protocol to declare a protocol.” +协议和扩展 +使用protocol来声明一个协议 + +“Classes, enumerations, and structs can all adopt protocols.” +类,枚举,结构体都可以遵循协议 + +“Notice the use of the mutating keyword in the declaration of SimpleStructure to mark a method that modifies the structure. The declaration of SimpleClass doesn’t need any of its methods marked as mutating because methods on a class can always modify the class.” +注意,在SimpleStructure的声明中使用关键字mutating来标记一个会修改结构体的方法。在SimpleClass的声明中不需要用关键字mutating来标记类中的方法,因为类中的方法总是可以修改类。 + +“Use extension to add functionality to an existing type, such as new methods and computed properties. You can use an extension to add protocol conformance to a type that is declared elsewhere, or even to a type that you imported from a library or framework.” +使用扩展给一个已存在的类型增加功能,例如一些新方法和计算过的属性。你可以使用扩展给一个在别处声明的类型增加协议,甚至是给一个从库和框架中引入的类型增加协议。 + +“You can use a protocol name just like any other named type—for example, to create a collection of objects that have different types but that all conform to a single protocol. When you work with values whose type is a protocol type, methods outside the protocol definition are not available.” +你可以像使用其他命名类型一样使用协议名-例如,创建一个具有不同类型但是遵循同一协议的对象集合。当你处理一些协议类型的值的时候,协议定义之外的方法是不可用的。 + +“Even though the variable protocolValue has a runtime type of SimpleClass, the compiler treats it as the given type of ExampleProtocol. This means that you can’t accidentally access methods or properties that the class implements in addition to its protocol conformance.” +虽然变量protocolValue具有一个运行时类型SimpleClass,编译器是把它当做一个协议类型来处理的。这意味着你不能够访问协议没有指定的方法和属性。 + +Generics +“Write a name inside angle brackets to make a generic function or type.” +泛型 +在尖括号中写一个名字来创建一个泛型函数或类型。 + +“You can make generic forms of functions and methods, as well as classes, enumerations, and structures.” +你可以使用泛型来创建函数,方法,类,枚举和结构体。 + +“Use where after the type name to specify a list of ” +“requirements—for example, to require the type to implement a protocol, to require two types to be the same, or to require a class to have a particular superclass.” +在类型名之后使用where来指定一些条件-例如,要求类型遵循某个协议,要求两个类型相同,或者要求一个类有一个特定的父类。 + +“In the simple cases, you can omit where and simply write the protocol or class name after a colon. Writing is the same as writing .” +在简单情况下,你可以省略where,然后在协议和类名之间用冒号隔开。 是等价的。 From f03415413eaa5f20197b23db9189983016e8a940 Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Sat, 21 Jun 2014 22:48:21 +0800 Subject: [PATCH 154/261] update 01_the_basics - Page 65 --- src/chapter2/01_The_Basics.md | 86 ++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 8a63d8f..71fa0b4 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -368,11 +368,11 @@ Because of type inference, Swift requires far fewer type declarations than langu Type inference is particularly useful when you declare a constant or variable with an initial value. This is often done by assigning a literal value (or literal) to the constant or variable at the point that you declare it. (A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below.) -当你声明一个有初始值的常量或变量的时候类型推断特别实用。通常是当你声明一个常量和变量的时候你就给它赋一个字面值(literal value)。(字面值是会直接出现在源码里的值,比如下面例子里的42和3.14159。) +当你声明一个有初始值的常量或变量的时候类型推断特别实用。通常是当你声明一个常量和变量的时候你就给它赋一个字面量(literal value)。(字面量是会直接出现在源码里的值,比如下面例子里的42和3.14159。) For example, if you assign a literal value of 42 to a new constant without saying what type it is, Swift infers that you want the constant to be an Int, because you have initialized it with a number that looks like an integer: -举个例子,如果你给一个新的常量赋了一个字面值42,但没有说它的类型,Swift会推断你希望这个常量是一个整数类型(Int),因为你用了一个像是整数的数字来初始化: +举个例子,如果你给一个新的常量赋了一个字面量42,但没有说它的类型,Swift会推断你希望这个常量是一个整数类型(Int),因为你用了一个像是整数的数字来初始化: let meaningOfLife = 42 // meaningOfLife is inferred to be of type Int @@ -380,7 +380,7 @@ For example, if you assign a literal value of 42 to a new constant without sayin Likewise, if you don’t specify a type for a floating-point literal, Swift infers that you want to create a Double: -类似的,如果你没有特别指定一个浮点型的字面值,Swift会推断你需要一个Double类型的浮点数: +类似的,如果你没有特别指定一个浮点型的字面量,Swift会推断你需要一个Double类型的浮点数: let pi = 3.14159 // pi is inferred to be of type Double @@ -392,7 +392,7 @@ Swift always chooses Double (rather than Float) when inferring the type of float If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context: -如果你将整数型和浮点型的字面值相加,这种情况下会推断为Double类型: +如果你将整数型和浮点型的字面量相加,这种情况下会推断为Double类型: let anotherPi = 3 + 0.14159 // anotherPi is also inferred to be of type Double @@ -400,68 +400,130 @@ If you combine integer and floating-point literals in an expression, a type of D The literal value of 3 has no explicit type in and of itself, and so an appropriate output type of Double is inferred from the presence of a floating-point literal as part of the addition. -字面值3本身并没有准确的类型,因此是通过相加的元素中有一个浮点型的字面值推断出合适的输出类型为Double. +字面量3本身并没有准确的类型,因此是通过相加的元素中有一个浮点型的字面量推断出合适的输出类型为Double. -Numeric Literals +# Numeric Literals +# 数字字面量 Integer literals can be written as: +整数字面量可以写成: + A decimal number, with no prefix A binary number, with a 0b prefix An octal number, with a 0o prefix A hexadecimal number, with a 0x prefix All of these integer literals have a decimal value of 17: -let decimalInteger = 17 -let binaryInteger = 0b10001 // 17 in binary notation -let octalInteger = 0o21 // 17 in octal notation -let hexadecimalInteger = 0x11 // 17 in hexadecimal notation +十进制的数字,不需要任何前缀 +二进制的数字,前缀是0b +八进制的数字,前缀是0o +十六进制的数字,前缀是0x +下面所有的整数字面量在十进制下的值都是17: + + let decimalInteger = 17 + let binaryInteger = 0b10001 // 17 in binary notation + let octalInteger = 0o21 // 17 in octal notation + let hexadecimalInteger = 0x11 // 17 in hexadecimal notation + + let decimalInteger = 17 + let binaryInteger = 0b10001 // 二进制声明中的17 + let octalInteger = 0o21 // 八进制声明中的17 + let hexadecimalInteger = 0x11 // 十六进制声明中的17 + + Floating-point literals can be decimal (with no prefix), or hexadecimal (with a 0x prefix). They must always have a number (or hexadecimal number) on both sides of the decimal point. They can also have an optional exponent, indicated by an uppercase or lowercase e for decimal floats, or an uppercase or lowercase p for hexadecimal floats. +浮点型的字面量可以是十进制的(没有前缀),或者十六进制(前缀是0x)。在小数点两边都必须有数字(或十六进制数字符号)。它们也可以有一个可选的指数,在十进制中用大写或小写的e来表示,或者在十六进制中用大写或小写的p来表示。 + For decimal numbers with an exponent of exp, the base number is multiplied by 10exp: +在十进制数字中有一个指数`exp`,表示基数乘以`10^exp`: + +``` 1.25e2 means 1.25 × 102, or 125.0. 1.25e-2 means 1.25 × 10-2, or 0.0125. +``` + For hexadecimal numbers with an exponent of exp, the base number is multiplied by 2exp: +在十六进制的数字中有一个指数`exp`,表示基数乘以`2^exp` + +``` 0xFp2 means 15 × 22, or 60.0. 0xFp-2 means 15 × 2-2, or 3.75. +``` + All of these floating-point literals have a decimal value of 12.1875: +以下这些浮点字面量在十进制下的值都是12.1875: +``` let decimalDouble = 12.1875 let exponentDouble = 1.21875e1 let hexadecimalDouble = 0xC.3p0 +``` + Numeric literals can contain extra formatting to make them easier to read. Both integers and floats can be padded with extra zeroes and can contain underscores to help with readability. Neither type of formatting affects the underlying value of the literal: +数字字面量可以使用额外的格式让它们更易读。不论整数还是浮点数都可以添加额外的0,也可以增加下划线来增加可读性。这些格式都不会影响到这些字面量原本的值: + +``` let paddedDouble = 000123.456 let oneMillion = 1_000_000 let justOverOneMillion = 1_000_000.000_000_1 -Numeric Type Conversion +``` + +# Numeric Type Conversion +# 数字类型转换 Use the Int type for all general-purpose integer constants and variables in your code, even if they are known to be non-negative. Using the default integer type in everyday situations means that integer constants and variables are immediately interoperable in your code and will match the inferred type for integer literal values. +在一般情况下对整数的常量或变量使用`Int`类型,即使是你知道不会存储负值的时候。总是使用默认的整数类型意味着你的代码中整数的常量和变量是可以很好的协作的,并且可以和整数字面量推断出的类型一致。 + Use other integer types only when they are are specifically needed for the task at hand, because of explicitly-sized data from an external source, or for performance, memory usage, or other necessary optimization. Using explicitly-sized types in these situations helps to catch any accidental value overflows and implicitly documents the nature of the data being used. -Integer Conversion +只在当前工作中有特殊的需要的时候,才使用其他的整数类型,比如是从外部来源的需要指定精确度的数据,或者为了性能,内存使用量,或者其他必要的优化。在这些情况下使用指定精确度的数字类型可以帮助我们发现溢出值和暗示这个数据的特性。 + +## Integer Conversion +## 整数类型转换 The range of numbers that can be stored in an integer constant or variable is different for each numeric type. An Int8 constant or variable can store numbers between -128 and 127, whereas a UInt8 constant or variable can store numbers between 0 and 255. A number that will not fit into a constant or variable of a sized integer type is reported as an error when your code is compiled: +不同整数类型的常量或变量可以储存不同范围的数字。一个`Int8`的常量或变量可以储存-128到127之间的数字,然而一个`UInt8`型的常量或变量可以储存从0到255之间的数字。如果一个数字不符合常量或变量的储值范围,编译的时候会报错: + +``` let cannotBeNegative: UInt8 = -1 // UInt8 cannot store negative numbers, and so this will report an error +// UInt8不能储存负数,所以这里会报错 let tooBig: Int8 = Int8.max + 1 // Int8 cannot store a number larger than its maximum value, // and so this will also report an error +// Int8不能储存一个大于其最大值的数字 +// 所以这里同样会报错 +``` + Because each numeric type can store a different range of values, you must opt in to numeric type conversion on a case-by-case basis. This opt-in approach prevents hidden conversion errors and helps make type conversion intentions explicit in your code. +因为每一种数字类型可以储存不同范围的值,你必须根据具体的案例选择合适的数字类型转换。这种选择方式组织了隐式的转换报错,并且让你的代码中的类型转换意图更明确。 + To convert one specific number type to another, you initialize a new number of the desired type with the existing value. In the example below, the constant twoThousand is of type UInt16, whereas the constant one is of type UInt8. They cannot be added together directly, because they are not of the same type. Instead, this example calls UInt16(one) to create a new UInt16 initialized with the value of one, and uses this value in place of the original: +要将一种特定类型转换成另一种,你需要用一个你想要的类型的新的数字来重新初始化。在下面的例子里,常量twoThousand是UInt16类型的,然而常量one是UInt8类型的。它们不能直接相加,因为i它们类型不同。因此,这个例子调用了UInt16(one)来对常量one创建一个新的UInt16初始值,然后用这个值来代替原来的值: + +``` let twoThousand: UInt16 = 2_000 let one: UInt8 = 1 let twoThousandAndOne = twoThousand + UInt16(one) +``` + Because both sides of the addition are now of type UInt16, the addition is allowed. The output constant (twoThousandAndOne) is inferred to be of type UInt16, because it is the sum of two UInt16 values. +因为相加的两个数现在都是UInt16类型了,这样相加是允许的。输出结果的常量(twoThousandAndOne)被推断为UInt16类型,因为它是两个UInt16的类型的值的和。 + SomeType(ofInitialValue) is the default way to call the initializer of a Swift type and pass in an initial value. Behind the scenes, UInt16 has an initializer that accepts a UInt8 value, and so this initializer is used to make a new UInt16 from an existing UInt8. You can’t pass in any type here, however—it has to be a type for which UInt16 provides an initializer. Extending existing types to provide initializers that accept new types (including your own type definitions) is covered in Extensions. +SomeType(ofInitialValue)是Swift初始化并赋予一个初值的默认方法。在语言内部,UInt16类型有一个初始值设定项会接受一个UInt8的值,然后这个初始值设定项是用来从已知的UInt8中创建一个新的UInt16的值。你不能传递任意类型,只能传入UInt16提供初始化的类型。扩展已有的类型来提供更多的初始化选项,来接受新的类型(包括自定义类型),见[扩展](link)。 + Integer and Floating-Point Conversion Conversions between integer and floating-point numeric types must be made explicit: From a1ff47b1dd8f8e89107f20d202038fc55de1f61b Mon Sep 17 00:00:00 2001 From: Mengyuan Wu Date: Sun, 22 Jun 2014 03:00:57 +0800 Subject: [PATCH 155/261] update 01_the_basics - till Tuples --- src/chapter2/01_The_Basics.md | 99 ++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 13 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 71fa0b4..9fea829 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -2,15 +2,15 @@ # 基础部分 Swift is a new programming language for iOS and OS X app development. Nonetheless, many parts of Swift will be familiar from your experience of developing in C and Objective-C. - + Swift是一个用于iOS和OS X平台开发的新的编程语言。尽管如此,Swift在很多地方都会和你以往用C语言和Objective-C开发的经验类似。 Swift provides its own versions of all fundamental C and Objective-C types, including Int for integers; Double and Float for floating-point values; Bool for Boolean values; and String for textual data. Swift also provides powerful versions of the two primary collection types, Array and Dictionary, as described in Collection Types. - + Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值Int,浮点值Double和Float,布尔值Bool,以及文本值String。Swift还提供了两个强大的常见集合类型,数组和字典,见[集合类型](link to 集合类型)。 Like C, Swift uses variables to store and refer to values by an identifying name. Swift also makes extensive use of variables whose values cannot be changed. These are known as constants, and are much more powerful than constants in C. Constants are used throughout Swift to make code safer and clearer in intent when you work with values that do not need to change. - + 和C一样,Swift使用具有唯一名称的变量(variables)来储存和指向特定值。Swift还对那些值不能改变的变量进行了扩展,他们也被称为常量(Constants),Swift中的常量比C中的常量更加强大。在Swift中当你需要处理一些恒定不变的值的时候,使用常量(Constants)可以让代码更加安全和整洁。 In addition to familiar types, Swift introduces advanced types not found in Objective-C. These include tuples, which enable you to create and pass around groupings of values. Tuples can return multiple values from a function as a single compound value. @@ -18,11 +18,11 @@ In addition to familiar types, Swift introduces advanced types not found in Obje 除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,包括:元组(tuples),你可以创建和传递一组数值。元组(tuples)可以在函数中以一个复合值的形式返回多个数值。 Swift also introduces optional types, which handle the absence of a value. Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”. Optionals are similar to using nil with pointers in Objective-C, but they work for any type, not just classes. Optionals are safer and more expressive than nil pointers in Objective-C and are at the heart of many of Swift’s most powerful features. - + Swift还有可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用nil,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的nil,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大的特性的核心。 Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This enables you to catch and fix errors as early as possible in the development prObjective Cess. - + 可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(String),类型安全性会阻止你错误的给它赋一个整型(Int)的值。这让你在开发的过程中尽早的发现问题。 # Constants and Variables @@ -485,7 +485,7 @@ Use other integer types only when they are are specifically needed for the task 只在当前工作中有特殊的需要的时候,才使用其他的整数类型,比如是从外部来源的需要指定精确度的数据,或者为了性能,内存使用量,或者其他必要的优化。在这些情况下使用指定精确度的数字类型可以帮助我们发现溢出值和暗示这个数据的特性。 ## Integer Conversion -## 整数类型转换 +## 整数类型转换 The range of numbers that can be stored in an integer constant or variable is different for each numeric type. An Int8 constant or variable can store numbers between -128 and 127, whereas a UInt8 constant or variable can store numbers between 0 and 255. A number that will not fit into a constant or variable of a sized integer type is reported as an error when your code is compiled: @@ -524,83 +524,156 @@ SomeType(ofInitialValue) is the default way to call the initializer of a Swift t SomeType(ofInitialValue)是Swift初始化并赋予一个初值的默认方法。在语言内部,UInt16类型有一个初始值设定项会接受一个UInt8的值,然后这个初始值设定项是用来从已知的UInt8中创建一个新的UInt16的值。你不能传递任意类型,只能传入UInt16提供初始化的类型。扩展已有的类型来提供更多的初始化选项,来接受新的类型(包括自定义类型),见[扩展](link)。 -Integer and Floating-Point Conversion +## Integer and Floating-Point Conversion +## 整数和浮点数转换 Conversions between integer and floating-point numeric types must be made explicit: +整数和浮点数之间的类型转换必须是显性的: +``` let three = 3 let pointOneFourOneFiveNine = 0.14159 let pi = Double(three) + pointOneFourOneFiveNine // pi equals 3.14159, and is inferred to be of type Double +// pi等于3.14159,它被推断为Double类型 +``` Here, the value of the constant three is used to create a new value of type Double, so that both sides of the addition are of the same type. Without this conversion in place, the addition would not be allowed. +在这里,常量three的值被用来创建一个新的Double型的值,所以相加的两个数都是同样的类型了,无须转换,这个加法是允许的。 + The reverse is also true for floating-point to integer conversion, in that an integer type can be initialized with a Double or Float value: +相对的,由浮点数到证书的转换也是可行的,也就是说一个整数类型可以被初始化为一个Double或者Float型的值: + +``` let integerPi = Int(pi) // integerPi equals 3, and is inferred to be of type Int +// integerPi等于3,它被推断为整数(Int)类型 +``` + Floating-point values are always truncated when used to initialize a new integer value in this way. This means that 4.75 becomes 4, and -3.9 becomes -3. -NOTE +当浮点型的值初始化为一个新的整数型的值时,它的数值总是被截断的。这意味着4.75会成为4,而-3.9会成为-3。 -The rules for combining numeric constants and variables are different from the rules for numeric literals. The literal value 3 can be added directly to the literal value 0.14159, because number literals do not have an explicit type in and of themselves. Their type is inferred only at the point that they are evaluated by the compiler. +> NOTE + +> The rules for combining numeric constants and variables are different from the rules for numeric literals. The literal value 3 can be added directly to the literal value 0.14159, because number literals do not have an explicit type in and of themselves. Their type is inferred only at the point that they are evaluated by the compiler. + +> 注意 -Type Aliases +> 数字的常量和变量相加的规则和数字字面量的规则是不一样的。字面量3可以和字面量0.14159直接相加,因为数字字面量本身并没有一个显式的类型声明。他们的类型是在编译器运行时被推断的。 + +# Type Aliases +# 类型别名 Type aliases define an alternative name for an existing type. You define type aliases with the typealias keyword. +类型别名给已经存在的类型定义另一个名字。你用关键字`typealias`来定义类型别名。 + Type aliases are useful when you want to refer to an existing type by a name that is contextually more appropriate, such as when working with data of a specific size from an external source: +当你想用一个更合适的名字来命名一个已有的类型的时候,类型别名是很有用的,比如当你处理一个外部来源的需要指定精确度的数据时: + +``` typealias AudioSample = UInt16 +``` + Once you define a type alias, you can use the alias anywhere you might use the original name: +一旦你定义了类型别名,你就可以在任何你可以使用原始名字的地方使用这个别名 +``` var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound is now 0 +``` + Here, AudioSample is defined as an alias for UInt16. Because it is an alias, the call to AudioSample.min actually calls UInt16.min, which provides an initial value of 0 for the maxAmplitudeFound variable. -Booleans +在这里,`AudioSample`定义为`UInt16`的一个别名。因为这是一个别名,调用`AudioSample.min`实际上是调用`UInt16.min`给变量maxAmplitudeFound赋了一个0的初始值。 + +# Booleans +# 布尔值 Swift has a basic Boolean type, called Bool. Boolean values are referred to as logical, because they can only ever be true or false. Swift provides two Boolean constant values, true and false: +Swift有一个基本的布尔值类型,叫做Bool。布尔值可以当作逻辑判断,因为它们只有true或false两个值。Swift提供两种布尔值常量,true和false。 + +``` let orangesAreOrange = true let turnipsAreDelicious = false +``` + The types of orangesAreOrange and turnipsAreDelicious have been inferred as Bool from the fact that they were initialized with Boolean literal values. As with Int and Double above, you don’t need to declare constants or variables as Bool if you set them to true or false as soon as you create them. Type inference helps make Swift code more concise and readable when it initializes constants or variables with other values whose type is already known. +因为orangesAreOrange和turnipsAreDelicious有一个布尔的字面量作为初值,它们的类型被推断为Bool。如果你在创建常量或变量的时候就把它们的值设为true或者false,你不需要声明它们的类型是Bool。当你赋予常量或变量一个类型已知的初值时,类型推断让Swift的代码更加准确和可读。 + Boolean values are particularly useful when you work with conditional statements such as the if statement: +在条件声明比如if语句中,布尔值特别有用: + +``` if turnipsAreDelicious { println("Mmm, tasty turnips!") } else { println("Eww, turnips are horrible.") } // prints "Eww, turnips are horrible." +``` + Conditional statements such as the if statement are covered in more detail in Control Flow. +关于条件声明比如if语句的更多细节会在Control Flow这一章节中详细讲解。 + Swift’s type safety prevents non-Boolean values from being be substituted for Bool. The following example reports a compile-time error: +Swift的类型安全会阻止一个非布尔值替换了Bool值。下面的例子会在编译时报错: +``` let i = 1 if i { // this example will not compile, and will report an error + // 这个例子不会顺利编译,会报错 } +``` + However, the alternative example below is valid: +然而,下面这个例子是有效的: +``` let i = 1 if i == 1 { // this example will compile successfully + // 这个例子会成功编译 } +``` + The result of the i == 1 comparison is of type Bool, and so this second example passes the type-check. Comparisons like i == 1 are discussed in Basic Operators. +`i == 1`比较的结果是一个Bool类型的值,因此第二个例子通过了类型检查。类似`i == 1`的比较我们会在[Basic Operators](link)更深入讨论。 + As with other examples of type safety in Swift, this approach avoids accidental errors and ensures that the intention of a particular section of code is always clear. -Tuples +和其他Swift的类型安全的例子一样,这个例子避免了意外的错误并且保证了特定的某块代码的意图始终是明确的。 + +# Tuples +# 元组 Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other. +元组将多个数值组合成一个单独的复合值。一个元组中的值可以是任何类型,不必是同一种类型。 + In this example, (404, "Not Found") is a tuple that describes an HTTP status code. An HTTP status code is a special value returned by a web server whenever you request a web page. A status code of 404 Not Found is returned if you request a webpage that doesn’t exist. +在这个例子里, (404, "Not Found") 是一个用来形容Http状态码的元组。一个Http状态码是当你请求一个网页的时候网页服务器的返回值。当你请求的网页不存在的时候会返回`404找不到网页`的状态码。 + +``` let http404Error = (404, "Not Found") // http404Error is of type (Int, String), and equals (404, "Not Found") +// http404Error的类型是(Int, String),值等于(404, "Not Found") +``` + The (404, "Not Found") tuple groups together an Int and a String to give the HTTP status code two separate values: a number and a human-readable description. It can be described as “a tuple of type (Int, String)”. +元组`(404, "Not Found")`将一个整数值Int和一个字符串组合起来,给http状态码赋予两个独立的值:一个机器语言的数字和一句人类语言的描述。它可以描述为”一个类型为 (Int, String)的元组“。 + You can create tuples from any permutation of types, and they can contain as many different types as you like. There’s nothing stopping you from having a tuple of type (Int, Int, Int), or (String, Bool), or indeed any other permutation you require. You can decompose a tuple’s contents into separate constants or variables, which you then access as usual: @@ -735,7 +808,7 @@ An implicitly unwrapped optional is a normal optional behind the scenes, but can let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string." - + let assumedString: String! = "An implicitly unwrapped optional string." println(assumedString) // no exclamation mark is needed to access its value // prints "An implicitly unwrapped optional string." From 45421f437eb66afcc133ce2de92dc1eb6a2eaf3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E6=97=B6?= Date: Sun, 22 Jun 2014 09:47:29 +0800 Subject: [PATCH 156/261] =?UTF-8?q?swift=E6=B3=9B=E5=9E=8B=E9=83=A8?= =?UTF-8?q?=E5=88=86=E7=BF=BB=E8=AF=91=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/22_Generics.md | 133 +++++++++++++++++++++++++++++++----- 1 file changed, 116 insertions(+), 17 deletions(-) diff --git a/src/chapter2/22_Generics.md b/src/chapter2/22_Generics.md index 97c9e25..14ed065 100644 --- a/src/chapter2/22_Generics.md +++ b/src/chapter2/22_Generics.md @@ -69,7 +69,10 @@ It would be much more useful, and considerably more flexible, to write a single NOTE In all three functions, it is important that the types of a and b are defined to be the same as each other. If a and b were not of the same type, it would not be possible to swap their values. Swift is a type-safe language, and does not allow (for example) a variable of type String and a variable of type Double to swap values with each other. Attempting to do so would be reported as a compile-time error. ``` - +``` +注意 +在上边的三个函数中,a和b的类型必须是一样的。如果不一样,就不能交互两者的值。Swift是类型安全的语言,不允许一个`String`和`Double`类型变量互相交互值。如果试图操作,会有编译错误。 +``` #Generic Functions #泛型函数 @@ -104,9 +107,11 @@ The other difference is that the generic function’s name (swapTwoValues) is fo The `swapTwoValues` function can now be called in the same way as `swapTwoInts`, except that it can be passed two values of any type, as long as both of those values are of the same type as each other. Each time `swapTwoValues` is called, the type to use for T is inferred from the types of values passed to the function. - +除了要求传入的两个任何类型值是同一类型外,`swapTwoValues`函数,也可以作为`swapTwoInts`函数被调用。每次`swapTwoValues`被调用,T所代表的类型值都会传给函数。 In the two examples below, T is inferred to be Int and String respectively: + +在下边的例子中,T分别指定为Int和String类型。 ``` var someInt = 3 @@ -123,36 +128,61 @@ swapTwoValues(&someString, &anotherString) ``` NOTE The swapTwoValues function defined above is inspired by a generic function called swap, which is part of the Swift standard library, and is automatically made available for you to use in your apps. If you need the behavior of the swapTwoValues function in your own code, you can use Swift’s existing swap function rather than providing your own implementation. +``` +``` +注意 +上边定义的`swapTwoValues`函数是受`swap`函数的启发而实现的,存在Swift的基础库中,可以在其它类中任意使用。如果你需要`swapTwoValues`类似的功能,可以直接使用Swift中已存在的`swap`方法。 ``` #Type Parameters #参数类型 -In the swapTwoValues example above, the placeholder type T is an example of a type parameter. Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of matching angle brackets (such as ). +In the swapTwoValues example above, the placeholder type T is an example of a type parameter. Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of matching angle brackets (such as ). + +在上边的`swapTwoValues`例子中,T占位符是一种参数类型实例。参数类型实例指定相同的占位符类型,紧跟在函数名称之后尖括号内(例如)。 -Once specified, a type parameter can be used to define the type of a function’s parameters (such as the a and b parameters of the swapTwoValues function); or as the function’s return type; or as a type annotation within the body of the function. In each case, the placeholder type represented by the type parameter is replaced with an actual type whenever the function is called. (In the swapTwoValues example above, T was replaced with Int the first time the function was called, and was replaced with String the second time it was called.) +Once specified, a type parameter can be used to define the type of a function’s parameters (such as the a and b parameters of the swapTwoValues function); or as the function’s return type; or as a type annotation within the body of the function. In each case, the placeholder type represented by the type parameter is replaced with an actual type whenever the function is called. (In the swapTwoValues example above, T was replaced with Int the first time the function was called, and was replaced with String the second time it was called.) + +一旦被指定,参数类型可以用作函数的参数值类型(例如`swapTwoValues`参数中的a和b参数);或者也可以作为函数的返回值类型。这每个例子中,占位符类型可以代表类型参数,当在函数被调用时,会以真实类型代替,在`swapTwoValues`的例子中,当第一次调用时,T会被Int代替,第二次调用中T会被String代替。 You can provide more than one type parameter by writing multiple type parameter names within the angle brackets, separated by commas. - + +你可支持多个类型参数,命名在尖括号中,用逗号分开。 ‌ #Naming Type Parameters #参数类型命名 -In simple cases where a generic function or generic type needs to refer to a single placeholder type (such as the swapTwoValues generic function above, or a generic collection that stores a single type, such as Array), it is traditional to use the single-character name T for the type parameter. However, you are can use any valid identifier as the type parameter name. +In simple cases where a generic function or generic type needs to refer to a single placeholder type (such as the swapTwoValues generic function above, or a generic collection that stores a single type, such as Array), it is traditional to use the single-character name T for the type parameter. However, you are can use any valid identifier as the type parameter name. + +在一般的情况下,如果泛型函数或者泛型类型需要指定一个占位符(像上边的`swapTwoValues`泛型函数或者只包含单个类型的泛型集合,比如数组),通常会用一个字符T来代表参数类型。不过,你也可以用任意有效的标示符来表示参数类型。 If you are defining more complex generic functions, or generic types with multiple parameters, it can be useful to provide more descriptive type parameter names. For example, Swift’s Dictionary type has two type parameters—one for its keys and one for its values. If you were writing Dictionary yourself, you might name these two type parameters KeyType and ValueType to remind you of their purpose as you use them within your generic code. + +如果你定义了复杂的泛型函数或者泛型类型,需要多个参数,使用更多的描述类型是有必要的。比如Swift中的字典类型就有两个参数,其中一个键,一个值。如果你自己写字典类型,你也许会定义两个类型`KeyType`和`ValueType`,用来记住在泛型代码中的作用。 ``` NOTE - Always give type parameters UpperCamelCase names (such as T and KeyType) to indicate that they are a placeholder for a type, not a value. +``` +``` +注意 +请始终使用大写字母开头的驼峰式命名法(例如T和KeyType)来给类型参数命名,以表明它们是类型的占位符,而非类型值。 ``` #Generic Types #泛型类型 -n addition to generic functions, Swift enables you to define your own generic types. These are custom classes, structures, and enumerations that can work with any type, in a similar way to Array and Dictionary. +In addition to generic functions, Swift enables you to define your own generic types. These are custom classes, structures, and enumerations that can work with any type, in a similar way to Array and Dictionary. + +除了泛型函数,Swift可以定义自己的泛型类型。可以是自定义的类、结构、枚举类作用于任何类型。和数组及字段的方式相同。 -This section shows you how to write a generic collection type called Stack. A stack is an ordered set of values, similar to an array, but with a more restricted set of operations than Swift’s Array type. An array allows new items to be inserted and removed at any location in the array. A stack, however, allows new items to be appended only to the end of the collection (known as pushing a new value on to the stack). Similarly, a stack allows items to be removed only from the end of the collection (known as popping a value off the stack). +This section shows you how to write a generic collection type called Stack. A stack is an ordered set of values, similar to an array, but with a more restricted set of operations than Swift’s Array type. An array allows new items to be inserted and removed at any location in the array. A stack, however, allows new items to be appended only to the end of the collection (known as pushing a new value on to the stack). Similarly, a stack allows items to be removed only from the end of the collection (known as popping a value off the stack). + +这部分展示如何写泛型版本的堆栈。堆栈是一系类值域的集合,和数组类似,但是比数据的有更多的限制的集合。数组允许元素可以从任何位置插入或者删除。堆栈,只允许从集合的顶部插入元素(如同push一个值到堆栈)。同样的,堆栈只允许从集合的顶部删除一个元素(记为从堆栈pop出一个值)。 ``` NOTE The concept of a stack is used by the UINavigationController class to model the view controllers in its navigation hierarchy. You call the UINavigationController class pushViewController:animated: method to add (or push) a view controller on to the navigation stack, and its popViewControllerAnimated: method to remove (or pop) a view controller from the navigation stack. A stack is a useful collection model whenever you need a strict “last in, first out” approach to managing a collection. +``` + +``` +注意 +堆栈的概念被用在`UINavigationController`类中,模拟试图控制器的导航结构。你调用`UINavigationController`的`pushViewController:animated: `方法添加一个视图到堆栈中,调用` popViewControllerAnimated:`方法从堆栈中删除一个试图。堆栈是非常有用的,当你需要一个严格的“先进先出”的方式来管理集合时。 ``` The illustration below shows the push / pop behavior for a stack: @@ -403,9 +433,7 @@ The Container protocol defines three required capabilities that any container mu 上述协议定义了三个必须支持的兼容协议: 1. It must be possible to add a new item to the container with an append method. - 2. It must be possible to access a count of the items in the container through a count property that returns an Int value. - 3. It must be possible to retrieve each item in the container with a subscript that takes an Int index value. 1. 必须可以通过append方法添加新的元素到容器中。 @@ -414,16 +442,24 @@ The Container protocol defines three required capabilities that any container mu This protocol doesn’t specify how the items in the container should be stored or what type they are allowed to be. The protocol only specifies the three bits of functionality that any type must provide in order to be considered a Container. A conforming type can provide additional functionality, as long as it satisfies these three requirements. - +这个协议没有指定容器中items该如何存储,也没有指定数据是什么类型。协议只是指定了三个任意遵循Container类型所必须的功能点。只要满足这三个条件,遵循协议的类型也可以添加额外的功能。 Any type that conforms to the Container protocol must be able to specify the type of values it stores. Specifically, it must ensure that only items of the right type are added to the container, and it must be clear about the type of the items returned by its subscript. +任意遵循Container协议的类型必须指定所存储的数据值类型。必须保证指定的数据类型可以存储到Container中,而且必须明确可以通过其下标返回结果值。 + To define these requirements, the Container protocol needs a way to refer to the type of the elements that a container will hold, without knowing what that type is for a specific container. The Container protocol needs to specify that any value passed to the append method must have the same type as the container’s element type, and that the value returned by the container’s subscript will be of the same type as the container’s element type. +为了定义这些条件,Container协议需要一个方法指定容器里的元素将会保留,不需要知道特定容器的类型。Container协议需要定义任何append方法添加至容器中的值和容器中的元素是相同类型,并且通过容器下标返回的容器元素值的类型是相同的。 + To achieve this, the Container protocol declares an associated type called ItemType, written as typealias ItemType. The protocol does not define what ItemType is an alias for—that information is left for any conforming type to provide. Nonetheless, the ItemType alias provides a way to refer to the type of the items in a Container, and to define a type for use with the append method and subscript, to ensure that the expected behavior of any Container is enforced. +为了达到这个目的,container协议声明了一个相关类型ItemType,记为`typealias ItemType`。该协议不会定义ItemType是谁的别名,这个信息留给任何遵循协议的类型来提供。尽管如此,ItemType别名支持一种方法识别在一个容器里的items类型,并定义一种使用在append方法和下标中的类型,保证任何期望的Container行为是强制性的。 + Here’s a version of the non-generic IntStack type from earlier, adapted to conform to the Container protocol: +下边是之前的IntStack结构的非泛型版本,适用于遵循Container协议: + struct IntStack: Container { // original IntStack implementation var items = Int[]() @@ -448,12 +484,20 @@ Here’s a version of the non-generic IntStack type from earlier, adapted to con The IntStack type implements all three of the Container protocol’s requirements, and in each case wraps part of the IntStack type’s existing functionality to satisfy these requirements. +`IntStack`类型实现了`Container`协议的所有需求,每个包含部分的功能都满足这些要求。 + Moreover, IntStack specifies that for this implementation of Container, the appropriate ItemType to use is a type of Int. The definition of typealias ItemType = Int turns the abstract type of ItemType into a concrete type of Int for this implementation of the Container protocol. +此外, `IntStack`指定了`Container`的实现,合适的`ItemType`被用作Int类型。对于Container协议实现来说,定义 `typealias ItemType = Int`,将抽象的`ItemType`类型转换为具体的Int类型。 + Thanks to Swift’s type inference, you don’t actually need to declare a concrete ItemType of Int as part of the definition of IntStack. Because IntStack conforms to all of the requirements of the Container protocol, Swift can infer the appropriate ItemType to use, simply by looking at the type of the append method’s item parameter and the return type of the subscript. Indeed, if you delete the typealias ItemType = Int line from the code above, everything still works, because it is clear what type should be used for ItemType. +感谢Swift类型参考,你实际上不用在IntStack定义部分声明具体的Int的ItemType。由于IntStack满足Container协议的所有要求,只需通过简单的查找append方法中的item参数类型和下标返回的类型,Swift就可以推断出合适的ItemType来使用。实际上,如果你删除了上述代码中的 typealias ItemType = Int,仍可以正常运行,因为它清楚的知道ItemType使用的是何种类型。 + You can also make the generic Stack type conform to the Container protocol: +你同样可以生成遵循Containner协议的泛型Stack类型: + struct Stack: Container { // original Stack implementation var items = T[]() @@ -476,26 +520,45 @@ You can also make the generic Stack type conform to the Container protocol: } This time, the placeholder type parameter T is used as the type of the append method’s item parameter and the return type of the subscript. Swift can therefore infer that T is the appropriate type to use as the ItemType for this particular container. -Extending an Existing Type to Specify an Associated Type + +这个时候,占位符T被用作append方法的item参数类型和下标的返回类型。Swift因此也就可以推断出用作ItemType的T的合适类型。 + +#Extending an Existing Type to Specify an Associated Type +#扩展一个存在的类型为一指定关联类型 You can extend an existing type to add conformance to a protocol, as described in Adding Protocol Conformance with an Extension. This includes a protocol with an associated type. +你可以用[使用扩展来添加协议兼容性](../chapter2/21_Protocols.html)的方法,扩展一个已存在的类型遵循指定协议。这包含一个关联类型的协议。 + Swift’s Array type already provides an append method, a count property, and a subscript with an Int index to retrieve its elements. These three capabilities match the requirements of the Container protocol. This means that you can extend Array to conform to the Container protocol simply by declaring that Array adopts the protocol. You do this with an empty extension, as described in Declaring Protocol Adoption with an Extension: +Swift中的数据类型已经提供了`append`方法、`count`属性方法和下标索引方法。这三个功能满足`Container`协议。也就是说你可以扩展数组方法遵循Container协议,只需简单声明Array适用于该协议。你用一个空的扩展来这么做,就像[通过扩展补充协议声明](../chapter2/21_Protocols.html)中描述的一样。 + extension Array: Container {} Array’s existing append method and subscript enable Swift to infer the appropriate type to use for ItemType, just as for the generic Stack type above. After defining this extension, you can use any Array as a Container. -Where Clauses +数组存在的append方法和下标索引方法使Swift可以推断出ItemType的实际类型,像上边的泛型版`Stack`一样。当定义了这个扩展之后,你可以用这个数组作为容器。 + +#Where Clauses +#Where语句 Type constraints, as described in Type Constraints, enable you to define requirements on the type parameters associated with a generic function or type. +类型约束确保相关的泛型函数和类型的指定参数满足需求。 + It can also be useful to define requirements for associated types. You do this by defining where clauses as part of a type parameter list. A where clause enables you to require that an associated type conforms to a certain protocol, and/or that certain type parameters and associated types be the same. You write a where clause by placing the where keyword immediately after the list of type parameters, followed by one or more constraints for associated types, and/or one or more equality relationships between types and associated types. +定义关联类型的满足条件也是非常有用的。你可以通过定义where语句作为类型参数的一部分。通过where语句指定一个关联类型遵循一个特定的协议,以及(或)那个特定的类型参数和关联类型可以是相同的。可以在类型参数后,紧跟着where语句,where语句中跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型的等于关系。 + The example below defines a generic function called allItemsMatch, which checks to see if two Container instances contain the same items in the same order. The function returns a Boolean value of true if all items match and a value of false if they do not. +下边的例子定义了泛型函数`allItemsMatch`,用于判断两个`Container`实例是否包含相同的元素并具有相同的顺序。如果所有元素满足条件,函数返回true,否则返回false。 + The two containers to be checked do not have to be the same type of container (although they can be), but they do have to hold the same type of items. This requirement is expressed through a combination of type constraints and where clauses: +需要检查的两个`containers`,不需要是相同类型的`container`(当然也可以是相同的),但是他们的元素必须相同。这个需求通过一个类型约束和where语句相结合来表示: + func allItemsMatch< C1: Container, C2: Container where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> @@ -514,10 +577,14 @@ The two containers to be checked do not have to be the same type of container (a return true } -This function takes two arguments called someContainer and anotherContainer. The someContainer argument is of type C1, and the anotherContainer argument is of type C2. Both C1 and C2 are placeholder type parameters for two container types to be determined when the function is called. +This function takes two arguments called `someContainer` and `anotherContainer`. The `someContainer` argument is of type `C1`, and the `anotherContainer` argument is of type `C2`. Both `C1` and `C2` are placeholder type parameters for two container types to be determined when the function is called. + +这个函数有两个参数`someContainer`和`anotherContainer`。`someContainer`参数是`C1`类型,`anotherContainer`参数是`C2`类型。`C1`和`C2`都是占位符,真正的参数类型等函数运行时决定。 The function’s type parameter list places the following requirements on the two type parameters: +这个函数的类型参数列紧随在两个类型参数需求的后面: + C1 must conform to the Container protocol (written as C1: Container). C2 must also conform to the Container protocol (written as C2: Container). @@ -526,10 +593,21 @@ The function’s type parameter list places the following requirements on the tw The ItemType for C1 must conform to the Equatable protocol (written as C1.ItemType: Equatable). +``` + C1必须遵循`Container`协议(写法`C1: Container`) + C2必须遵循`Container`协议(写法`C2: Container`) + C1的ItemType必须和C2的ItemType相等(写法C1.ItemType == C2.ItemType) + C1的ItemType必须遵循`Equatable`协议 +``` + The third and fourth requirements are defined as part of a where clause, and are written after the where keyword as part of the function’s type parameter list. +第三四个要求在where语句中定义,并作为参数类型值部分内容放到where语句后。 + These requirements mean: +这几个要求意义是: + someContainer is a container of type C1. anotherContainer is a container of type C2. @@ -537,18 +615,37 @@ These requirements mean: someContainer and anotherContainer contain the same type of items. The items in someContainer can be checked with the not equal operator (!=) to see if they are different from each other. + +``` +someContainer是C1类型的anotherContainer +anotherContainer是C2类型的anotherContainer +someContainer和anotherContainer包含相同类型的元素 +someContainer中的元素可以通过调用不等于操作(!=)判断他们是否不同 +``` The third and fourth requirements combine to mean that the items in anotherContainer can also be checked with the != operator, because they are exactly the same type as the items in someContainer. +第三四个需求结合起来标示`anotherContainer`的元素同样可以调用`!=`操作,因为他们和`someContainer`中的类型是一样的。 + These requirements enable the allItemsMatch function to compare the two containers, even if they are of a different container type. +这些要求使得`allItemsMatch`函数可以比较两个`containers`,即便他们具有不同的`containers`类型。 + The allItemsMatch function starts by checking that both containers contain the same number of items. If they contain a different number of items, there is no way that they can match, and the function returns false. +`allItemsMatch`函数会先检查`containers`是否包含相同数目的元素。如果包含内容不相同,他们互相也就不相等,结果返回`false`。 + After making this check, the function iterates over all of the items in someContainer with a for-in loop and the half-closed range operator (..). For each item, the function checks whether the item from someContainer is not equal to the corresponding item in anotherContainer. If the two items are not equal, then the two containers do not match, and the function returns false. -If the loop finishes without finding a mismatch, the two containers match, and the function returns true. +如果具有相同的元素个数,函数通过`for-in`循环和半闭区间操作(..)来迭代`someContainer`中的所有元素。循环中,`someContainer`中的元素是否和`anotherContainer`中的对应元素相同。如果有不相同的,函数返回`false`。 + +If the loop finishes without finding a mismatch, the two match, and the function returns true. -Here’s how the allItemsMatch function looks in action: +如果循环过程中没有一个不相同的,则`containers`相等,结果返回`true`。 + +Here’s how the `allItemsMatch` function looks in action: + +这里演示了`allItemsMatch`函数运算的过程: var stackOfStrings = Stack() stackOfStrings.push("uno") @@ -563,3 +660,5 @@ Here’s how the allItemsMatch function looks in action: // prints "All items match." The example above creates a Stack instance to store String values, and pushes three strings onto the stack. The example also creates an Array instance initialized with an array literal containing the same three strings as the stack. Even though the stack and the array are of a different type, they both conform to the Container protocol, and both contain the same type of values. You can therefore call the allItemsMatch function with these two containers as its arguments. In the example above, the allItemsMatch function correctly reports that all of the items in the two containers match. + +上边的例子中创建一个`Stack`实例存储字符串值,然后`push`三个字符串到堆栈中。同样创建一个数组实例初始化为包含三个字符串,和堆栈元素相同。尽管堆栈和数组是不同的数据类型,但是他们遵循相同的协议,并且包含相同的数据类型,相同的数据值。所以你可以调用`allItemsMatch`去比较两者。在上边的例子中,`allItemsMatch`函数会返回两者包含的所有元素相匹配。 From ac6dcff604dd5e01e5ad8a531eb808256df14a07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=B4=E6=97=B6?= Date: Sun, 22 Jun 2014 09:48:51 +0800 Subject: [PATCH 157/261] =?UTF-8?q?swift=E6=B3=9B=E5=9E=8B=E9=83=A8?= =?UTF-8?q?=E5=88=86=E7=BF=BB=E8=AF=91=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1385047..dfb6182 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ The Swift Programming Language 中文化项目 * 嵌套类型 [认领 by 祁涛] * 扩展 [已完成 by 袁鹏] * 协议 [认领 by 姜天意] - * 泛型 [认领 by 晴时 & 胡衍明] + * 泛型 [已完成 by 晴时] * 高级操作符 [认领 by 林晚] * 语言参考 * 关于语言参考 [认领 by 筱强] From 389b6a613a662f670fef0110a535d2689ce4a1f3 Mon Sep 17 00:00:00 2001 From: "playman.me" Date: Sun, 22 Jun 2014 15:15:08 +0800 Subject: [PATCH 158/261] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E8=AF=AD=E5=8F=A5?= =?UTF-8?q?=E7=AB=A0=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter3/05_Statements.md | 578 +++++++++++++++++++++++++++++++++- 1 file changed, 577 insertions(+), 1 deletion(-) diff --git a/src/chapter3/05_Statements.md b/src/chapter3/05_Statements.md index 6075542..3d8a638 100644 --- a/src/chapter3/05_Statements.md +++ b/src/chapter3/05_Statements.md @@ -1 +1,577 @@ -Statements \ No newline at end of file +> 翻译:玩家 + + +#Statements# +--------- +# 语句章节 # +---------- + +本页包含内容 + - [循环语句](#loop_statements) + - [分支语句](#branch_statements) + - [带标签的语句](#labeled_statement) + - [控制传递语句](#control_transfer_statements) + +In Swift, there are two kinds of statements: simple statements and control flow statements. Simple statements are the most common and consist of either an expression or a declaration. Control flow statements are used to control the flow of execution in a program. There are three types of control flow statements in Swift: loop statements, branch statements, and control transfer statements. + +swift和其他语言一样,语句可大致分为简单语句和控制流语句,控制流语句也可分为循环语句:用来重复的执行代码块;分支语句:用来执行满足特定条件的代码块;控制语句用来决定代码的执行顺序。后续会详细阐述各控制流语句的使用。 + +Loop statements allow a block of code to be executed repeatedly, branch statements allow a certain block of code to be executed only when certain conditions are met, and control transfer statements provide a way to alter the order in which code is executed. Each type of control flow statement is described in detail below. + +A semicolon (;) can optionally appear after any statement and is used to separate multiple statements if they appear on the same line. + +和javascript类似,在一行语句的结束尾可以不添加分号(;),但是如果一行有多个独立语句必须要添加。在语法上讲,在语句末尾是否添加分好都是可以的,但是从团队协助以及减少错误方面来讲,最好统一加上,一般而言大公司的svn服务器上都会添加一个钩子,用来减少出错的可能,所以最好还是养成添加的习惯。 + +> statement -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression);opt +> statement -> [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration);opt +> statement -> [loop-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement);opt +> statement -> [branch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/branch-statement);opt +> statement -> [labeled-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/branch-statement) +> statement -> [control-transfer-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/control-transfer-statement);opt +> statement -> [statement statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/control-transfer-statement);opt + + + --------- + + +> 语句语法 +> *语句* → [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) **;** _可选_ +> *语句* → [*声明*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) **;** _可选_ +> *语句* → [*循环语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement) **;** _可选_ +> *语句* → [*分支语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/branch-statement) **;** _可选_ +> *语句* → [*标记语句(Labeled Statement)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/labeled-statement) +> *语句* → [*控制转移语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/control-transfer-statement) **;** _可选_ +> *多条语句(Statements)* → [*语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement) [*多条语句(Statements)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) _可选_ + + + +##Loop Statements## +##循环语句## + +Loop statements allow a block of code to be executed repeatedly, depending on the conditions specified in the loop. Swift has four loop statements: a for statement, a for-in statement, a while statement, and a do-while statement. + +Control flow in a loop statement can be changed by a break statement and a continue statement and is discussed in Break Statement and Continue Statement below. + +> loop-statement -> [for-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-statement) +> loop-statement -> [for-in-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-in-statement) +> loop-statement -> [while-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-statement) +> loop-statement -> [do-while-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/do-while-statement) + +各个编程语言从语法上讲,基本的变量,语句都是类似的,swift循环语句也提供四种方式来循环语句:`for`语句 `for in`语句 `while`语句 `do-shile`语句 +通过`break`和`continue`可以改变循环语句的控制流,和其他语言类似,具体可参考break和continue + +> 循环语句语法 +> *循环语句* → [*for语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-statement) +> *循环语句* → [*for-in语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-in-statement) +> *循环语句* → [*while语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-statement) +> *循环语句* → [*do-while语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/do-while-statement) + + +##For Statement## +##for语句## + +A for statement allows a block of code to be executed repeatedly while incrementing a counter, as long as a condition remains true. + +A for statement has the following form: + + for initialization; condition; increment { + statements + } + +`for`语句可以重复的执行一端代码,并且可以递增一个计数器 +`for`语句的形式如下 + + for `initialzation`; `condition`; `increment` { + `statements` + } + +The semicolons between the initialization, condition, and increment are required. The braces around the statements in the body of the loop are also required. + +A for statement is executed as follows: + +The initialization is evaluated only once. It is typically used to declare and initialize any variables that are needed for the remainder of the loop. +The condition expression is evaluated. +If true, the program executes the statements, and execution continues to step 3. If false, the program does not execute the statements or the increment expression, and the program is finished executing the for statement. +The increment expression is evaluated, and execution returns to step 2. +Variables defined within the initialization are valid only within the scope of the for statement itself. + +The value of the condition expression must have a type that conforms to the LogicValue protocol. + +> for-statement -> for [for-init](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init);[expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt; [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) +> for-statement -> for ([for-init](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init)opt;[expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt; [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) +> for-init -> [variable-declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/variable-declaration) | [expression-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression-list) + + +`initialzation` `condition`和`increment`之间的分号 不可少,`{`也不可少 + + 1. `initialzation`只是被执行一次,通常用于声明和初始化在接下来循环中需要的变量 + 2. `condition`:如果为真(`true`)`statements`将会执行,进行第3步,如果为`false`则`statements`和`increment`都不会被执行,for至此执行完毕 + 3. 计算`increment`表达式,然后转到第2步。 + +定义在`initialzation`中的变量仅在`for`语句的作用域以内有效。`condition`表达式的值的类型必须遵循LogicValue协议。 + +> For 循环语法 +> *for语句* → for [*for初始条件*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ [*代码块*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) +> for语句 → for [*for初始条件*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ **)** [*代码块*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) +> *for初始条件* → [*变量声明*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/variable-declaration) | [*表达式列表*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression-list) + + +##For-In Statement## +##For-In 语句## + +A for-in statement allows a block of code to be executed once for each item in a collection (or any type) that conforms to the Sequence protocol. + +A for-in statement has the following form: + + for item in collection { + statements + } + +`for-in`语句允许在重复执行代码块的同时,迭代集合(或遵循Sequence协议的任意类型)中的每一项。 + +`for-in`语句的形式如下: + + for `item` in `collection` { + `statements` + } + +The generate method is called on the collection expression to obtain a value of a generator type—that is, a type that conforms to the Generator protocol. The program begins executing a loop by calling the next method on the stream. If the value returned is not None, it is assigned to the item pattern, the program executes the statements, and then continues execution at the beginning of the loop. Otherwise, the program does not perform assignment or execute the statements, and it is finished executing the for-in statement + +> GRAMMAR OF A FOR-IN STATEMENT +> for-in-statement -> for [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) in [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) + +`for-in`语句在循环开始前会调用`collection`表达式的`generate`方法来获取一个生成器类型(这是一个遵循Generator协议的类型)的值。接下来循环开始,调用`collection`表达式的`next`方法。如果其返回值不是`None`,它将会被赋给`item`,然后执行`statements`,执行完毕后回到循环开始处;否则,将不会赋值给`item`也不会执行`statements`,`for-in`至此执行完毕。这和`javascript`中的`for in`语句是一样的,可以理解为循环`collection`,如果有key的取出,去执行接下来的`statements` + +`For-In`循环语法 +> *for-in语句* → **for** [*模式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) **in** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) [*代码块*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) + + +##While Statement## +##While语句## + +A while statement allows a block of code to be executed repeatedly, as long as a condition remains true. + +A while statement has the following form: + + while condition { + statements + } + +`while`语句允许重复执行代码块 +`while`语句的形式如下: + + while `condition` { + `statements` + } + +A while statement is executed as follows: + + 1. The condition is evaluated. +If true, execution continues to step 2. If false, the program is finished executing the while statement. + 2. The program executes the statements, and execution returns to step 1. + +Because the value of the condition is evaluated before the statements are executed, the statements in a while statement can be executed zero or more times. + +The value of the condition must have a type that conforms to the LogicValue protocol. The condition can also be an optional binding declaration, as discussed in [Optional Bindind](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_432) + +> GRAMMAR OF A WHILE STATEMENT +> while-statement -> whild [while-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-condition) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) +> while-condition -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) | [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) + + +`while`语句的执行流程为判断`condition`,如果为真(`true`),这会执行`statements`,否则`while`语句执行到此结束 +由于`condition`的值在`statements`执行前就已计算出,因此`while`语句中的`statements`可能会被执行若干次,也可能不会被执行。 +`condition`表达式的值的类型必须遵循LogicValue协议。同时,`condition`表达式也可以使用可选绑定,请参考可选绑定待添加链接。 + +> While 循环语法 +> *while语句* → **while** [*while-condition*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-condition) [*code-block*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) +> *while条件* → [*expression*](..\chapter3\04_Expressions.html#expression) | [*declaration*](..\chapter3\05_Declarations.html#declaration) + + +##Do-While Statement## +##Do-While 语句## + +A do-while statement allows a block of code to be executed one or more times, as long as a condition remains true. + +A do-while statement has the following form: + + do { + statements + } while condition + +`do-while`语句允许代码块被执行一次或多次。 +`do-while`语句的形式如下: + + do { + `statements` + } while `condition` + +A do-while statement is executed as follows: + + 1. The program executes the statements, and execution continues to step 2 + 2. The condition is evaluated.If true, execution returns to step 1. If false, the program is finished executing the do-while statement. + +`do-while`语句的执行流程如下: + + 1. 执行`statements`,完后钻到2 + 2. 计算condition表达式,如果返回(`true`)继续回到1新一轮执行,否则`do-while`至此执行完毕 + +Because the value of the condition is evaluated after the statements are executed, the statements in a do-while statement are executed at least once. + +The value of the condition must have a type that conforms to the LogicValue protocol. The condition can also be an optional binding declaration, as discussed in [Optional Binding](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_432) + + 由于`condition`是在`statements`执行之后才会计算,因此可见,相比较`while`而言,`do-while`至少会执行一次 +`condition`表达式的值的类型必须遵循`LogicValue`协议。同时,`condition`表达式也可以使用可选绑定,请参考可选绑定。 +> do-while-statement→ do [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) while [while-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-condition) + + + +##Branch Statements## +##分支语句## + +Branch statements allow the program to execute certain parts of code depending on the value of one or more conditions. The values of the conditions specified in a branch statement control how the program branches and, therefore, what block of code is executed. Swift has two branch statements: an if statement and a switch statement. + +Control flow in a switch statement can be changed by a break statement and is discussed in Break Statement below + +> GRAMMAR OF A BRANCH STAREMENT +> branch-statement -> [if-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) +> brach-statement -> [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) + +通过一个或者多个条件的值,来决定语句允许程序执行指定部分的代码,swift和其他语言类似提供了`if`语句和`switch`语句 +`switch`语句中的控制流可以用`break`语句修改,请参考[Break](http://chinaz.com/swift/chapter3/10_Statements.html#break_statement) 语句。 +>branch-statement → [if-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) +>branch-statement → [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) + + +##If Statement## +##if语句## + +An if statement is used for executing code based on the evaluation of one or more conditions. + +There are two basic forms of an if statement. In each form, the opening and closing braces are required. + +The first form allows code to be executed only when a condition is true and has the following form: + + if condition { + statements + } + +通过一个或多个条件的值来决定执行哪一块的代码,if语句主要有三种使用方式,但无乱哪种方式都需要添加`{`和`}` +第一种形式是当且仅当条件为真时执行代码,像下面这样: + + if `condition` { + `statements` + } + +The second form of an if statement provides an additional else clause (introduced by the else keyword) and is used for executing one part of code when the condition is true and another part code when the same condition is false. When a single else clause is present, an if statement has the following form: + + + if condition { + statements to execute if condition is true + } else { + statements to execute if condition is false + } + +The else clause of an if statement can contain another if statement to test more than one condition. An if statement chained together in this way has the following form: + + if condition 1 { + statements to execute if condition 1 is true + } else if condition 2 { + statements to execute if condition 2 is true + } else { + statements to execute if both conditions are false + } + + +第二种形式是在第一种形式的基础上添加else语句,当只有一个else语句时,像下面这样: + + if `condition` { + `statements to execute if condition is true` + } else { + `statements to execute if condition is false` + } + +第三种则是else中又需要进行判断,即有多种判断情况: + + if `condition 1` { + `statements to execute if condition 1 is true` + } else if `condition 2` { + `statements to execute if condition 2 is true` + } + else { + `statements to execute if both conditions are false` + } + +The value of any condition in an if statement must have a type that conforms to the LogicValue protocol. The condition can also be an optional binding declaration, as discussed in[Option Binding](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_432) + +> GRAMMAR OF AN IF STATEMENT +> if-statement -> if [if-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-condition) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) [else-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/else-clause) opt +> if-condition -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) | [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) +> else-clause -> else [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) | else [if-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) + + +`if`语句中条件的值的类型必须遵循`LogicValue`协议。同时,条件也可以使用可选绑定,请参考可选绑定`待添加链接` +>if-statement → if [if-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-condition) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-condition) [else-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/else-clause) opt + +>if-condition → [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) | [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) + +>else-clause → else [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) | else [if-statement opt](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) + + +##Switch Statement## +##Switch 语句## + +A switch statement allows certain blocks of code to be executed depending on the value of a control expression. +A switch statement has the following form: + + switch control expression { + case pattern 1: + statements + case pattern 2 where condition: + statements + case pattern 3 where condition, + pattern 4 where condition: + statements + default: + statements + } + +取决于`switch~语句的控制表达式(control expression),`switch`语句将决定执行哪一块代码。 + +switch语句的形式如下: + + switch `control expression` { + case `pattern 1`: + `statements` + case `pattern 2` where `condition`: + `statements` + case `pattern 3` where `condition`, + `pattern 4` where `condition`: + `statements` + default: + `statements` + } +The control expression of the switch statement is evaluated and then compared with the patterns specified in each case. If a match is found, the program executes the statements listed within the scope of that case. The scope of each case can’t be empty. As a result, you must include at least one statement following the colon (:) of each case label. Use a single break statement if you don’t intend to execute any code in the body of a matched case. + +`switch`语句的表达式`control expression`会首选被计算,然后与下面的每个`case`的模式进行匹配,如果匹配成功,程序将会执行对应`case`中的`statements`,需要注意的是每个case不能为空,也就是说在case中至少有一条语句,如果在相应case中不想执行代码,只需要在程序中写个`break`即可 + + +The values of expressions your code can branch on is very flexible. For instance, in addition to the values of scalar types, such as integers and characters, your code can branch on the values of any type, including floating-point numbers, strings, tuples, instances of custom classes, and optionals. The value of the control expression can even be matched to the value of a case in an enumeration and checked for inclusion in a specified range of values. For examples of how to use these various types of values in switch statements, see Switch in the Control Flow chapter. + +A switch case can optionally contain a guard expression after each pattern. A guard expression is introduced by the keyword where followed by an expression, and is used to provide an additional condition before a pattern in a case is considered matched to the control expression. If a guard expression is present, the statements within the relevant case are executed only if the value of the control expression matches one of the patterns of the case and the guard expression evaluates to true. For instance, a control expression matches the case in the example below only if it is a tuple that contains two elements of the same value, such as (1, 1). + +case let (x, y) where x == y: + +可以用作控制表达式的值是什么灵活的,除了标量类型(scalartypes,如`Int`、`Character`)之外,你还可以使用其他任何类型的值,包括浮点数,字符串,远组,自定义类的实例以及可选(`optional`)类型,甚至是枚举类型中的成员和指定的范围(`range`)等。关于在`switch`语句中使用这些类型,请参考控制流章节的Switch. + +你可以在模式后端添加一个保护作用的表达式(guard expression),构成是这样的:关键字`where`后面跟着一个作为额外测试条件的表达式,因此当且仅当表达式匹配的一个case的某个模式在保护作用的表达式为真时,对应case中的`statements`才会被执行,在下面例子中,控制表达式只会匹配含有两个相等元素的元组 + + case let (x, y) where x == y: + } + + +As the above example shows, patterns in a case can also bind constants using the keyword let (they can also bind variables using the keyword var). These constants (or variables) can then be referenced in a corresponding guard expression and throughout the rest of the code within the scope of the case. That said, if the case contains multiple patterns that match the control expression, none of those patterns can contain constant or variable bindings. + + +正如上面的例子,也可以在模式中使用let(或var)语句来绑定常量(或变量)。这些常量(或变量)可以在其对应的起保护作用的表达式和其对应的case块里的代码中引用。但是,如果case中有多个模式匹配控制表达式,那么这些模式都不能绑定常量(或变量)。 + +A switch statement can also include a default case, introduced by the keyword default. The code within a default case is executed only if no other cases match the control expression. A switch statement can include only one default case, which must appear at the end of the switch statement. + +Although the actual execution order of pattern-matching operations, and in particular the evaluation order of patterns in cases, is unspecified, pattern matching in a switch statement behaves as if the evaluation is performed in source order—that is, the order in which they appear in source code. As a result, if multiple cases contain patterns that evaluate to the same value, and thus can match the value of the control expression, the program executes only the code within the first matching case in source order. + +switch语句也可以包含默认(default)块,只有其它case块都无法匹配控制表达式时,默认块中的代码才会被执行。一个switch语句只能有一个默认块,而且必须在switch语句的最后面。 + +尽管模式匹配操作的实际执行顺序,并且计算顺序是不可知的,但是Swift规定能够了swift中的语句中的模式匹配顺序和书写源码的顺序保持一致。因此,当多个模式含有相通的值并且能够匹配控制表达式时,程序只会执行源码中第一个匹配`case`中的代码 + +##Switch Statements Must Be Exhaustive## +##Switch 语句必须是完备的## + +In Swift, every possible value of the control expression’s type must match the value of at least one pattern of a case. When this simply isn’t feasible (for instance, when the control expression’s type is Int), you can include a default case to satisfy the requirement + +`switch`语句中包含多个`case`,每个`case`都是`switch`的一个分支,由`switch`来决定执行哪一个分支代码,`switch`语句必须是完整的,也就是值必须与`case`中的某一个对应,可以通过`default`来指定默认就不符合`case`条件时执行的代码块,并且这个`default`分支必须在最后。 + +##Execution Does Not Fall Through Cases Implicitly## +##不存在隐式的贯穿(fall through)## + +After the code within a matched case has finished executing, the program exits from the switch statement. Program execution does not continue or “fall through” to the next case or default case. That said, if you want execution to continue from one case to the next, explicitly include a fallthrough statement, which simply consists of the keyword fallthrough, in the case from which you want execution to continue. For more information about the fallthrough statement, see Fallthrough Statement below + +> switch-statement -> switch [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) {[switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt} +> switch-cases -> [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-case) [switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt +> switch-case -> [case-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) +> switch-case [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label): | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label): +> case-label -> case [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list): +> case-item-list -> [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause) opt | [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause)opt , [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list) +> default-label -> default +> guard-clause -> where [guard-expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-expression) +> guard-expression -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) + +当匹配的`case`代码在执行完毕后,程序会终止`switch`语句,而不会继续执行下一个`case`语句,这就意味着,如果你想执行下一个case块,需要显式地在你需要的case块里使用fallthrough语句。关于fallthrough语句的更多信息,请参考Fallthrough 语句。 + +> switch-statement -> switch [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) {[switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt} +> switch-cases -> [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-case) [switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt +> switch-case -> [case-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) +> switch-case [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label): | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label): +> case-label -> case [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list): +> case-item-list -> [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause) opt | [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause)opt , [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list) +> default-label -> default +> guard-clause -> where [guard-expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-expression) +> guard-expression -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) + + +##Labeled Statement## +##带标签的语句## + +You can prefix a loop statement or a switch statement with a statement label, which consists of the name of the label followed immediately by a colon (:). Use statement labels with break and continue statements to be explicit about how you want to change control flow in a loop statement or a switch statement, as discussed in Break Statement and Continue Statement below. + +你可以在循环语句和`switch`语句前面加上标签,它由标签名和`:`组成,在`break`和`continue`后面跟上标签名可以显式的在循环语句和switch语句中更改控制流,把控制权传递给指定标签标记的语句。关于这两条语句用法,请参考[Break](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-XID_976) 语句和[Continue](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-XID_976) 语句 + +The scope of a labeled statement is the entire statement following the statement label. You can nest labeled statements, but the name of each statement label must be unique. + +For more information and to see examples of how to use statement labels, see Labeled Statements in the Control Flow chapter + +> labeld-statement -> [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [loop-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement) | [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) +> statement-label -> [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name): +> label-name -> [identifier](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier) + + + +标签的作用域是该标签所标记的语句之后的所有语句。你可以不使用带标签的语句,但只要使用它,标签名就必唯一。 + +关于使用带标签的语句的例子,请参考控制流一章的带标签的语句 + +> labeld-statement -> [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [loop-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement) | [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) +> statement-label -> [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name): +> label-name -> [identifier](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier) + + +##Control Transfer Statements## +##控制传递语句## + +Control transfer statements can change the order in which code in your program is executed by unconditionally transferring program control from one piece of code to another. Swift has four control transfer statements: a break statement, a continue statement, a fallthrough statement, and a return statement. + +> control-transfer-statement -> [break-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/break-statement) +> control-transfer-statement -> [continue-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/continue-statement) +> continue-statement -> [fallthrougth-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/fallthrough-statement) +> continue-statement -> [return-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/return-statement) + +能够无条件的把控制权从一片代码传递到另一片代码,控制传递语句能够改变代码的执行顺序,Swift 提供四种类型的控制传递语句: `break`语句,`continue`语句,`fallthrough`语句和`return`语句 + +> control-transfer-statement -> [break-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/break-statement) +> control-transfer-statement -> [continue-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/continue-statement) +> continue-statement -> [fallthrougth-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/fallthrough-statement) +> continue-statement -> [return-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/return-statement) + +##Break Statement## +##bream语句## +A break statement ends program execution of a loop or a switch statement. A break statement can consist of only the keyword break, or it can consist of the keyword break followed by the name of a statement label, as shown below. + + break + break label name + +`break`用于终止循环或是`switch`语句,用break语句时,可以只写break这个关键词,也可以在break后面跟上标签名(label name),像下面这样: + + break + break label name + +When a break statement is followed by the name of a statement label, it ends program execution of the loop or switch statement named by that label. + +When a break statement is not followed by the name of a statement label, it ends program execution of the switch statement or the innermost enclosing loop statement in which it occurs. + +当`break`后面带有标签名时,可用于终止这个标签标记的循环或`switch`语句的执行 + +而当只有`break`关键词时,则会终止`switch`语句或上下文中包含`break` +的最内层的循环的执行 + +In both cases, program control is then transferred to the first line of code following the enclosing loop or switch statement, if any. + +For examples of how to use a break statement, see Break and Labeled Statements in the Control Flow chapter. + +> break-statement -> break [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name) opt + +在这两种情况下,控制权都会被传递给循环或switch语句外面的第一行语句 + +关于使用break语句的例子,请参考控制流一章的Break和带标签的语句 + +> break-statement -> break [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name) opt + +##Continue Statement## +##Continue 语句## +A continue statement ends program execution of the current iteration of a loop statement but does not stop execution of the loop statement. A continue statement can consist of only the keyword continue, or it can consist of the keyword continue followed by the name of a statement label, as shown below. + + continue + continue label name + +continue语句用于终止循环中当前迭代的执行,但不会终止该循环的执行。使用continue语句时,和break一样,可以只写continue这个关键词,也可以在continue后面跟上标签名(label name),像下面这样: + + continue + continue label name + +When a continue statement is followed by the name of a statement label, it ends program execution of the current iteration of the loop statement named by that label. + +When a continue statement is not followed by the name of a statement label, it ends program execution of the current iteration of the innermost enclosing loop statement in which it occurs. + +当continue语句后面带标签名时,可用于终止由这个标签标记的循环中当前迭代的执行 + +而当只写break时,可用于终止上下文中包含continue语句的最内层循环中当前迭代的执行 + +In both cases, program control is then transferred to the condition of the enclosing loop statement. + +In a for statement, the increment expression is still evaluated after the continue statement is executed, because the increment expression is evaluated after the execution of the loop’s body. + +For examples of how to use a continue statement, see Continue and Labeled Statements in the Control Flow chapter + +> continue-statement -> continue [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name)opt + +在这两种情况下,控制权都会被传递给循环外面的第一行语句。 + +在for语句中,continue语句执行后,increment表达式还是会被计算,这是因为每次循环体执行完毕后increment表达式都会被计算。 + +关于使用continue语句的例子,请参考控制流一章的Continue和带标签的语句 + +> continue-statement -> continue [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name)opt + + +##Fallthrough Statement## +##Fallthrough 语句## + +A fallthrough statement consists of the fallthrough keyword and occurs only in a case block of a switch statement. A fallthrough statement causes program execution to continue from one case in a switch statement to the next case. Program execution continues to the next case even if the patterns of the case label do not match the value of the switch statement’s control expression. + +A fallthrough statement can appear anywhere inside a switch statement, not just as the last statement of a case block, but it can’t be used in the final case block. It also cannot transfer control into a case block whose pattern contains value binding patterns. + +`fallthrough`语句用于在`switch`语句中传递控制权。`fallthrough`语句会把控制权从`switch`语句中的一个`case`无条件的传递给下一个case,即使下一个`case`的值与`switch`语句的控制表达式的值不匹配 + +For an example of how to use a fallthrough statement in a switch statement, see Control Transfer Statements in the Control Flow chapter. + +> fallthrough-statement -> fallthrough + +关于在switch语句中使用fallthrough语句的例子,请参考控制流一章的控制传递语句 + +> fallthrough-statement -> fallthrough + +##Return Statement## +##Return 语句## + +A return statement occurs only in the body of a function or method definition and causes program execution to return to the calling function or method. Program execution continues at the point immediately following the function or method call. + +A return statement can consist of only the keyword return, or it can consist of the keyword return followed by an expression, as shown below. + + return + return expression + +`return`用于在函数或是方法中,将控制权传递给调用者,接着程序将会从调用者的位置继续的往下执行 +使用return语句时,可以只写return这个关键词,也可以在return后面跟上表达式,像下面这样 + + return + return `expression` + +When a return statement is followed by an expression, the value of the expression is returned to the calling function or method. If the value of the expression does not match the value of the return type declared in the function or method declaration, the expression’s value is converted to the return type before it is returned to the calling function or method. + +当`return`后面跟有表达式时,会把表达式的值返回给调用者,如果表达式值的类型与调用者期望的类型不匹配,swift会在返回表达式的值之前把表达式值的类型转为调用者期望的类型 + +When a return statement is not followed by an expression, it can be used only to return from a function or method that does not return a value (that is, when the return type of the function or method is Void or ()). + +> return-statement -> return [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt + +而当只写return时,仅仅是将控制权从该函数或方法传递给调用者,而不返回一个值。(这就是说,该函数或方法的返回类型为Void或()) + +> return-statement -> return [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt From a87e9ad4974a167ef3f3fa176334444a08bcac9d Mon Sep 17 00:00:00 2001 From: "playman.me" Date: Sun, 22 Jun 2014 15:17:30 +0800 Subject: [PATCH 159/261] =?UTF-8?q?=E4=BF=AE=E6=94=B9break=E8=AF=AD?= =?UTF-8?q?=E5=8F=A5=E6=96=87=E6=A1=88=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter3/05_Statements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter3/05_Statements.md b/src/chapter3/05_Statements.md index 3d8a638..8d982e9 100644 --- a/src/chapter3/05_Statements.md +++ b/src/chapter3/05_Statements.md @@ -462,7 +462,7 @@ Control transfer statements can change the order in which code in your program i > continue-statement -> [return-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/return-statement) ##Break Statement## -##bream语句## +##break语句## A break statement ends program execution of a loop or a switch statement. A break statement can consist of only the keyword break, or it can consist of the keyword break followed by the name of a statement label, as shown below. break From 5a90b6db0b7cc18aae254ba9ce7ccd8aae2e61d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Sun, 22 Jun 2014 16:02:04 +0800 Subject: [PATCH 160/261] add file --- .../01_About_the_Language_Reference.md | 64 + src/chapter3/02_Lexical_Structure.md | 423 +++++++ src/chapter3/03_Types.md | 533 +++++++++ src/chapter3/04_Expressions.md | 1061 +++++++++++++++++ 4 files changed, 2081 insertions(+) diff --git a/src/chapter3/01_About_the_Language_Reference.md b/src/chapter3/01_About_the_Language_Reference.md index e69de29..a95d021 100644 --- a/src/chapter3/01_About_the_Language_Reference.md +++ b/src/chapter3/01_About_the_Language_Reference.md @@ -0,0 +1,64 @@ +# Language Reference + +## About the Language Reference +## 关于语言参考 + +This part of the book describes the formal grammar of the Swift programming language.The grammar described here is intended to help you understand the language in more detail, rather than to allow you to directly implement a parser or compiler. + + +本书的该部分描述了Swift编程语言的正式语法。在此描述语法的目的是为了帮助你更详细的理解该语言,而不是让你直接实现一个解析器或编译器。 + +The Swift language is relatively small, because many common types, functions, and operators that appear virtually everywhere in Swift code are actually defined in the Swift standard library. Although these types, functions, and operators are not part of the Swift language itself, they are used extensively in the discussions and code examples in this +part of the book. + +Swift语言相对较小,因为那些无处不在出现在Swift代码中的很多常见的类型,函数,和运算符实际上已经定义在了Swift的标准库中。虽然这些类型,函数,和运算符本身不是Swift语言的一部分,但它们被广泛应用于该书本部分的探讨和代码示例中。 + +## How to Read the Grammar +## 如何阅读语法 +The notation used to describe the formal grammar of the Swift programming language follows a few conventions: + +用于描述Swift编程语言正规语法的标记有如下几个约定: + + * An arrow (→) is used to mark grammar productions and can be read as “can consist of.“ + +* 箭头(→)用于标记语法生产和可以理解为“可包括” + +* Syntactic categories are indicated by italic text and appear on both sides of a grammar production rule. + +* 语法范围以斜体文字表示,显示在语法规范的两侧。 + +* Literal words and punctuation are indicated by boldface constant width text and appear only on the right-hand side of a grammar production rule. + +* 文字和标点由固定宽度的粗体文字显示,并只出现在一个语法生产规范的右侧. +* Alternative grammar productions are separated by vertical bars (|). When alternative productions are too long to read easily, they are broken into multiple grammar production rules on new lines. + +* 替代语法产生式由竖线(|)分隔。当替代产生式过长而不易阅读时,它们将在新行中变换为多个语法产生式规范。 + +* In a few cases, regular font text is used to describe the right-hand side of a grammar production rule. + +* 在一些案例中,常规字体文本将用于描述右侧的语法产生式规则。 + +* Optional syntactic categories and literals are marked by a trailing subscript, opt. + +* 可选的句法范围和文字为在尾部以opt标识描述。 + +As an example, the grammar of a getter-setter block is defined as follows: + +比如,getter-setter 区的语法定义如下: + +> G R A M M A R O F A G E T T E R- S E T T E R B L O C K + +> getter-setter-block → { getter-clause setter-clause opt } |{ setter-clause getter clause +} + +This definition indicates that a getter-setter block can consist of a getter clause followed by an optional setter clause, enclosed in braces, or a setter clause followed by a getter clause, enclosed in braces. The grammar production above is equivalent to the following two productions, where the alternatives are spelled out explicitly: + +该定义表示,一个getter-setter方法块可由一个getter子句后跟一个可选的setter语句,括在大括号中。或者一个setter子句后跟一个getter子句,括在大括号中。上述语法产生式等价于下面的两个替代处已经明确拼写出的产生式。 + +> G R A M M A R O F A G E T T E R S E T T E R B L O C K + +> getter-setter-block → { getter-clause setter-clause opt } + +> getter-setter-block → { setter-clause getter-clause } + + diff --git a/src/chapter3/02_Lexical_Structure.md b/src/chapter3/02_Lexical_Structure.md index e69de29..4d6f61f 100644 --- a/src/chapter3/02_Lexical_Structure.md +++ b/src/chapter3/02_Lexical_Structure.md @@ -0,0 +1,423 @@ +# Lexical Structure +# 词法结构 + +The lexical structure of Swift describes what sequence of characters form valid tokens of the language. These valid tokens form the lowest-level building blocks of the language and are used to describe the rest of the language in subsequent chapters. + +Swift的词法结构描述了如何在该语言中用字符序列构建合法标记。这些合法标识构成了该语言最底层的基石,并将会被用于描述后续章节的剩余部分。 + +In most cases, tokens are generated from the characters of a Swift source file by considering the longest possible substring from the input text, within the constraints of the grammar that are specified below. This behavior is referred to as longest match or maximal munch. + +通常,标识将从Swift源文件的输入文本中提取可能的最长子字符串生成。这种方法称为“最长匹配项(longest match)”,或者“最大适合”(maximal munch)。 + +## Whitespace and Comments +## 空白与注释 + +Whitespace has two uses: to separate tokens in the source file and to help determine whether an operator is a prefix or postfix (see Operators), but is otherwise ignored. The following characters are considered whitespace: space (U+0020), line feed (U+000A),carriage return (U+000D), horizontal tab (U+0009), vertical tab (U+000B), form feed (U+000C) and null (U+0000). + +空白(whitespace)有两个用途:区分源文件中的标识符和帮助确定一个操作符是前缀还是后缀(参见:运算符),否则忽略。以下字符会被认为是空白:s空格(space)(U+0020)、换行符(line feed)(U+000A)、回车符(carriage return)(U+000D)、水平 tab(horizontal tab)(U+0009)、垂直 tab(vertical tab)(U+000B)、换页符(form feed)(U+000C)以及空(null)(U+0000)。 + +Comments are treated as whitespace by the compiler. Single line comments begin with // and continue until the end of the line. Multiline comments begin with /* and end with */.Nesting is allowed, but the comment markers must be balanced. + +注释(comments)被编译器当作空白处理。单行注释以//开始直到该行结束。多行注释由/\*开始,以*/结束。注释允许嵌套,但注释标记必须相匹配。 + + +## Identifiers +## 标识符 + +Identifiers begin with an upper case or lower case letter A through Z, an underscore (_), a noncombining alphanumeric Unicode character in the Basic Multilingual Plane, or a character outside the Basic Multilingual Plan that isn’t in a Private Use Area. After the first character, digits and combining Unicode characters are also allowed. + +标识符以大写或小写字母A到Z,下划线(_),基本多语言面(Basic Multilingual Plane)中的非组合Unicode字符或者基本多语言面(Basic Multilingual Plane)以外的非专用区(Private Use Area)的字符开始。首字符之后,可以使用数字和 Unicode 字符组合。 + +To use a reserved word as an identifier, put a backtick (\`) before and after it. For example, class is not a valid identifier, but \`class\` is valid. The backticks are not considered part of the identifier; \`x\` and x have the same meaning. + +要使用保留字作为标识符,需要在其前后增加一个反引号(\`)。例如:类不是一个有效的标识符,但`class`是有效的。反引号不会被当做标识符的一部分;`x` 和 x 意义相同。 + +Inside a closure with no explicit parameter names, the parameters are implicitly named $0, $1, $2, and so on. These names are valid identifiers within the scope of the closure. + +闭包(closure)中如果没有明确指定参数名称,参数将被隐式命名为 $0、$1、$2... 这些命名在闭包作用域内是合法的标识符。 + +> G R A M M A R O F A N I D E N T I F I E R +> 标识符语法 + +> identifier → identifier-head identifier-characters[opt] + +> 标识符 → 标识符头(Head) 标识符字符列表 可选 + +> identifier → \` identifier-head > identifier-characters[opt] ` + +> 标识符 → ` 标识符头(Head) 标识符字符列表 可选 ` +> + +> identifier → implicit-parameter-name +> 标识符 → 隐式参数名 + +> identifier-list → identifier identifier , identifier-list + +> 标识符列表 → 标识符 | 标识符 , 标识符列表 + +> identifier-head → Upper- or lowercase letter A through Z + +> 标识符头(Head) → Upper- or lowercase letter A through Z + +> identifier-head → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or +U+00B7–U+00BA + +> 标识符头(Head) → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA + +> identifier-head → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or +U+00F8–U+00FF + +> 标识符头(Head) → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF + + +> identifier-head → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F– +U+1DBF + +> 标识符头(Head) → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF + +> identifier-head → U+1E00–U+1FFF + +>标识符头(Head) → U+1E00–U+1FFF + +> identifier-head → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or +U+2060–U+206F + +> 标识符头(Head) → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F + + +> identifier-head → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776– +U+2793 + +>标识符头(Head) → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793 + +> identifier-head → U+2C00–U+2DFF or U+2E80–U+2FFF + +> 标识符头(Head) → U+2C00–U+2DFF or U+2E80–U+2FFF + +> identifier-head → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040– +U+D7FF + +> 标识符头(Head) → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF + +> identifier-head → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or +U+FE30–U+FE44 + +> 标识符头(Head) → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44 + +> identifier-head → U+FE47–U+FFFD +> 标识符头(Head) → U+FE47–U+FFFD + + +> identifier-head → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or +U+40000–U+4FFFD + +> 标识符头(Head) → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD + +> identifier-head → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or +U+80000–U+8FFFD + +> 标识符头(Head) → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD + +> identifier-head → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or +U+C0000–U+CFFFD + +> 标识符头(Head) → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD + +> identifier-head → U+D0000–U+DFFFD or U+E0000–U+EFFFD +> 标识符头(Head) → U+D0000–U+DFFFD or U+E0000–U+EFFFD + +> identifier-character → Digit 0 through 9 + +> 标识符字符 → 数值 0 到 9 + +> identifier-character → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or +U+FE20–U+FE2F + +> 标识符字符 → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F + +> identifier-character → identifier-head +> 标识符字符 → 标识符头(Head) + +> identifier-characters → identifier-character identifier-characters[opt] +> 标识符字符列表 → 标识符字符 标识符字符列表 可选 + +> implicit-parameter-name → $ decimal- +> 隐式参数名 → $ 十进制数字列表 + + +## Keywords +## 关键字 +The following keywords are reserved and may not be used as identifiers, unless they’re escaped with backticks, as described above in Identifiers. + +下述被保留的关键字不允许用作标识符,除非它们被反引号转义,参见标识符。 + +* Keywords used in declarations: class, deinit, enum, extension, func, import, init, let, protocol,static, struct, subscript, typealias, and var. +* 用作声明的关键字:class、deinit、enum、extension、func、import、init、let、protocol、static、struct、subscript、typealias、var + +* Keywords used in statements: break, case, continue, default, do, else, fallthrough, if, in, for,return, switch, where, and while. + +* 用作语句的关键字:break、case、continue、default、do、else、fallthrough、if、in、for、return、switch、where、while + +* Keywords used in expressions and types: as, dynamicType, is, new, super, self, Self, Type,__COLUMN__, __FILE__, __FUNCTION__, and __LINE__. + +* 用作表达和类型的关键字:as、dynamicType、is、new、super、self、Self、Type、__COLUMN__、__FILE__、__FUNCTION__、__LINE__ + +* Keywords reserved in particular contexts: associativity, didSet, get, infix, inout, left, mutating,none, nonmutating, operator, override, postfix, precedence, prefix, right, set, unowned, unowned(safe),unowned(unsafe), weak and willSet. Outside the context in which they appear in the grammar, they can be used as identifiers. + +* 特定上下文中被保留的关键字:associativity、didSet、get、infix、inout、left、mutating、none、nonmutating、operator、override、postfix、precedence、prefix、right、set、unowned、unowned(safe)、unowned(unsafe)、weak、willSet,这些关键字在特定上下文之外可以被用于标识符。 + +## Literals +## 字面量 +A literal is the source code representation of a value of an integer, floating-point number, or string type. The following are examples of literals: + +字面量在源代码中表示一个整数,浮点数或字符串类型的值。以下是示例: + +> 42 // Integer literal + +> 3.14159 // Floating-point literal + +> "Hello, world!" // String literal + +> G R A M M A R O F A L I T E R A L + +> literal → integer-literal floating-point-literal string-literal + +> 字面量 → 整型字面量 | 浮点数字面量 | 字符串字面量 + +## Integer Literals +## 整型字面量 + +Integer literals represent integer values of unspecified precision. By default, integer literals are expressed in decimal; you can specify an alternate base using a prefix. Binary literals begin with 0b, octal literals begin with 0o, and hexadecimal literals begin with 0x. + +整型字面量(integer literals)表示未指定精度整型数的值。整型字面量默认为十进制;你可以通过加前缀来改变其数。二进制字面量以 0b 开始,八进制字面量以 0o 开始,十六进制字面量以 0x 开始。 + +Decimal literals contain the digits 0 through 9. Binary literals contain 0 and 1, octal literalscontain 0 through 7, and hexadecimal literals contain 0 through 9 as well as A through F in upper- or lowercase. + +十进制字面量包含数字 0 至 9。二进制字面量只包含 0 或 1,八进制字面量包含数字 0 至 7,十六进制字面量包含数字 0 至 9 以及大写或小写的字母 A 至 F。 + +Negative integers literals are expressed by prepending a minus sign (-) to an integer literal, as in -42. + +负整型字面量的字面量需要在整型字量面前加减号 -,比如 -42。 + +Underscores (_) are allowed between digits for readability, but are ignored and therefore don’t affect the value of the literal. Integer literals can begin with leading zeros (0), but are likewise ignored and don’t affect the base or value of the literal. + +数字间允许使用下划线 _ 来增加可读性,但下划线会被忽略而不会影响字面量的值。整型字面量也可以以0开始,但同样会被忽略而不会影响其基数及字面量的值。 + +Unless otherwise specified, the default type of an integer literal is the Swift standard library type Int. The Swift standard library also defines types for various sizes of signed and unsigned integers, as described in Integers. + +除非特殊指定,整型字面量的默认类型为 Swift 标准库类型中的 Int。Swift 标准库还定义了各种不同长度的是否带符号的整数类型,请参考 整数类型。 + +> 整型字面量语法 +> 整型字面量 → 二进制字面量 +> 整型字面量 → 八进制字面量 +> 整型字面量 → 十进制字面量 +> 整型字面量 → 十六进制字面量 +> 二进制字面量 → 0b 二进制数字 二进制字面量字符列表 可选 +> 二进制数字 → 数值 0 到 1 +> 二进制字面量字符 → 二进制数字 | _ +> 二进制字面量字符列表 → 二进制字面量字符 二进制字面量字符列表 可选 +> 八进制字面量 → 0o 八进字数字 八进制字符列表 可选 +> 八进字数字 → 数值 0 到 7 +> 八进制字符 → 八进字数字 | _ +> 八进制字符列表 → 八进制字符 八进制字符列表 可选 +> 十进制字面量 → 十进制数字 十进制字符列表 可选 +> 十进制数字 → 数值 0 到 9 +> 十进制数字列表 → 十进制数字 十进制数字列表 可选 +> 十进制字符 → 十进制数字 | _ +> 十进制字符列表 → 十进制字符 十进制字符列表 可选 +> 十六进制字面量 → 0x 十六进制数字 十六进制字面量字符列表 可选 +> 十六进制数字 → 数值 0 到 9, a through f, or A through F +> 十六进制字符 → 十六进制数字 | _ +> 十六进制字面量字符列表 → 十六进制字符 十六进制字面量字符列表 可选 + + +## Floating-Point Literals +## 浮点型字面量 + +Floating-point literals represent floating-point values of unspecified precision. + +浮点型字面量(floating-point literals)表示未指定精度浮点数的值。 + +By default, floating-point literals are expressed in decimal (with no prefix), but they can also be expressed in hexadecimal (with a 0x prefix). + +浮点型字面量默认用十进制表示(无前缀),但也可以用十六进制表示(加前缀 0x)。 + +Decimal floating-point literals consist of a sequence of decimal digits followed by either a decimal fraction, a decimal exponent, or both. The decimal fraction consists of a decimal point (.) followed by a sequence of decimal digits. The exponent consists of an upper- or lowercase e prefix followed by sequence of decimal digits that indicates what power of 10 the value preceding the e is multiplied by. For example, 1.25e2 represents 1.25 ⨉ 102, which evaluates to 125.0. Similarly, 1.25e-2 represents 1.25 ⨉ 10-2, which evaluates to 0.0125. + +十进制浮点型字面量(decimal floating-point literals)由十进制数字后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点 . 后跟十进制数字组成。指数部分由大写或小写字母的前缀e 后跟十进制数字组成,这串数字表示 e 之前的数量乘以 10 的几次方。例如:1.25e2 表示 1.25 ⨉ 10^2,也就是 125.0;同样,1.25e-2 表示 1.25 ⨉ 10^-2,也就是 0.0125。 + +Hexadecimal floating-point literals consist of a 0x prefix, followed by an optional hexadecimal fraction, followed by a hexadecimal exponent. The hexadecimal fraction consists of a decimal point followed by a sequence of hexadecimal digits. The exponent consists of an upper- or lowercase p prefix followed by sequence of decimal digits that indicates what power of 2 the value preceding the p is multiplied by. For example, 0xFp2 represents 15 ⨉ 22, which evaluates to 60. Similarly, 0xFp-2 represents 15 ⨉ 2-2, which evaluates to 3.75. +十六进制浮点型字面量(hexadecimal floating-point literals)由前缀 0x 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字组成。指数部分由大写或小写字母的前缀p 后跟十进制数字串组成,这串数字表示 p 之前的数量乘以 2 的几次方。例如:0xFp2 表示15 ⨉ 2^2,也就是 60;同样,0xFp-2 表示 15 ⨉ 2^-2,也就是 3.75。 + +Unlike with integer literals, negative floating-point numbers are expressed by applying the unary minus operator (-) to a floating-point literal, as in -42.0. The result is an expression, not a floating-point integer literal. + +与整型字面量不同,负的浮点型字面量由一元运算符减号 - 和浮点型字面量组成,例如 -42.0。这代表一个表达式,而不是一个浮点整型字面量。 + +Underscores (_) are allowed between digits for readability, but are ignored and therefore don’t affect the value of the literal. Floating-point literals can begin with leading zeros (0),but are likewise ignored and don’t affect the base or value of the literal. + +下划线 _ 允许被用于增强可读性,但会被忽略而不影响字面量的值。浮点型字面量也可以在数字前加 0,但同样会被忽略而不影响字面量的值。 + +Unless otherwise specified, the default type of a floating-point literal is the Swift standard library type Double, which represents a 64-bit floating-point number. The Swift standard library also defines a Float type, which represents a 32-bit floating-point number. + +除非特殊指定,浮点型字面量的默认类型为 Swift 标准库类型中的 Double,表示64位浮点数。Swift 标准库也定义 Float 类型,表示32位浮点数。 + +> 浮点型字面量语法 +> 浮点数字面量 → 十进制字面量 十进制分数 可选 十进制指数 可选 +> 浮点数字面量 → 十六进制字面量 十六进制分数 可选 十六进制指数 +> 十进制分数 → . 十进制字面量 +> 十进制指数 → 浮点数e 正负号 可选 十进制字面量 +> 十六进制分数 → . 十六进制字面量 可选 +> 十六进制指数 → 浮点数p 正负号 可选 十六进制字面量 +> 浮点数e → e | E +> 浮点数p → p | P +> 正负号 → + | - + +## String Literals +## 字符串型字面量 + +A string literal is a sequence of characters surrounded by double quotes, with the following form: +字符串型字面量是双引号括起来的一个字符序列,形式如下: + + " characters " + +String literals cannot contain an unescaped double quote ("), an unescaped backslash (\), a carriage return, or a line feed. + +字符串型字面量中不能包含未转义的双引号 "、未转义的反斜线\、回车符(carriage return)或换行符(line feed)。 + +Special characters can be included in string literals using the following escape sequences: +* Null Character (\0) +* Backslash (\\) +* Horizontal Tab (\t) +* Line Feed (\n) +* Carriage Return (\r) +* Double Quote (\") +* Single Quote (\') + +特殊符号可以经如下转义后在字符串型字面量中使用: + +* 空字符(Null Character)\0 +* 反斜线(Backslash)\\ +* 水平Tab (Horizontal Tab)\t +* 换行符(Line Feed)\n +* 回车符(Carriage Return)\r +* 双引号(Double Quote)\" +* 单引号(Single Quote)\' + +Characters can also be expressed by \x followed by two hexadecimal digits, \u followed by four hexadecimal digits, or \U followed by eight hexadecimal digits. The digits in these escape sequences identify a Unicode codepoint. + +字符也可以用以下方式表示:\x 后跟两位十六进制数字,\u 后跟四位十六进制数字,\U 后跟八位十六进制数字。在这些转义序列后跟的数字表示一个Unicode码。 + +The value of an expression can be inserted into a string literal by placing the expression in parentheses after a backslash (\). The interpolated expression must not contain an unescaped double quote ("), an unescaped backslash (\), a carriage return, or a line feed. + +字符串字面量可以在反斜线后面的小括号中插入表达式\()。插入的表达式必须不能包含未的双引号(”),反斜线(\),回车符或换行符。 + +The expression must evaluate to a value of a type that the String class has an initializer for. + +表达式的计算结果必须是String类的一个有初始化的类型的值。 + +For example, all the following string literals have the same value: +1. “1 2 3" +2. "1 2 \(3)" +3. "1 2 \(1 + 2)" +4. “var x = 3; "1 2 \(x)” + +摘录来自: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/cn/jEUH0.l + +比如,下面所有的字符串型字面量拥有同样的值: + +"1 2 3" +"1 2 \(3)" +"1 2 \(1 + 2)" +var x = 3; "1 2 \(x)" + +The default type of a string literal is String. The characters that make up a string are of type Character. For more information about the String and Character types, see Strings and Characters. + +字符串型字面量的默认类型为 String。组成字符串的字符的类型为 Character,更多关于String和Character类型,请参考 字符串和字符。 + +> 字符型字面量语法 +> 字符串型字面量 → " 引用文本 " +> 引用文本 → 引用文本条目 引用文本 可选 +> 引用文本条目 → 转义字符 +> 引用文本条目 → ( 表达式 ) +> 引用文本条目 → 除了"¬, \¬, U+000A, or U+000D的所有Unicode的字符 +> 转义字符 → \0 | \ | \t | \n | \r | \" | \' +> 转义字符 → \x 十六进制数字 十六进制数字 +> 转义字符 → \u 十六进制数字 十六进制数字 十六进制数字 十六进制数字 +> 转义字符 → \U 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 + +## Operators +## 运算符 + +The Swift standard library defines a number of operators for your use, many of which are discussed in Basic Operators and Advanced Operators. The present section describes which characters can be used as operators. + +Swift标准库定义了许多供你使用的运算符,其中大部分将在 基础运算符 和 高级运算符 中进行阐述。本章节将描述了哪些字符可被用作运算符。 + +Operators are made up of one or more of the following characters: /, =, -, +, !, *, %, <, >,&, |, ^, ~, and .. That said, the tokens =, ->, //, /*, */, ., and the unary prefix operator & are reserved. These tokens can’t be overloaded, nor can they be used to define custom operators. + +运算符由一个或多个如下字符组成:/、=、-、+、!、*、%、<、>、&、|、^、~、.。也就是说,标记 =,->、//、/*、*/、. 以及一元前缀运算符 & 属于保留字,这些标记不能被重写或用于定义自定义的运算符。 + +The whitespace around an operator is used to determine whether an operator is used as a prefix operator, a postfix operator, or a binary operator. This behavior is summarized in the following rules: + +运算符两侧的空白被用来区分一个运算符是否被用为前缀运算符(prefix operator)、后缀运算符(postfix operator)或二元运算符(binary operator)。规则总结如下: + +* If an operator has whitespace around both sides or around neither side, it is +treated as a binary operator. As an example, the + operator in a+b and a + b is +treated as a binary operator. + +* 如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:a+b 和 a + b 中的运算符+ 被看作二元运算符。 + +* If an operator has whitespace on the left side only, it is treated as a prefix unary operator. As an example, the ++ operator in a ++b is treated as a prefix unary operator. +* 如果运算符只有左侧空白,将被看作前缀一元运算符。例如 a ++b 中的 ++ 被看作前缀一元运算符。 + +* If an operator has whitespace on the right side only, it is treated as a postfix +unary operator. As an example, the ++ operator in a++ b is treated as a postfix unary operator. +* 如果运算符只有右侧空白,将被看作后缀一元运算符。例如 a++ b 中的 ++ 被看作后缀一元运算符。 + + +* If an operator has no whitespace on the left but is followed immediately by a dot (.), it is treated as a postfix unary operator. As an example, the ++ operator in a++.b is treated as a postfix unary operator (a++ . b rather than a ++ .b). + +* 如果运算符左侧没有空白并紧跟 .,将被看作后缀一元运算符。例如 a++.b 中的 ++ 被看作后缀一元运算符(同理, a++ . b 中的 ++ 是后缀一元运算符而 a ++ .b 中的 ++ 不是). + + +For the purposes of these rules, the characters (, [, and { before an operator, the +characters ), ], and } after an operator, and the characters ,, ;, and : are also considered whitespace. + +鉴于这些规则的目的,运算符前的字符 (、[ 和 { ;运算符后的字符 )、] 和 } 以及字符 ,、; 和: 同样被认为空白。 + +There is one caveat to the rules above. If the ! or ? operator has no whitespace on the left, it is treated as a postfix operator, regardless of whether it has whitespace on the right. To use the ? operator as syntactic sugar for the Optional type, it must not have whitespace on the left. To use it in the conditional (? :) operator, it must have whitespace around both sides. + +以上规则有一点需要注意。如果运算符 ! 或 ? 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 ? 用作修饰可选类型(optional type),左侧必须无空白。如果用于条件运算符 ? :,必须两侧都有空白。 + +In certain constructs, operators with a leading < or > may be split into two or more tokens. The remainder is treated the same way and may be split again. As a result, there is no need to use whitespace to disambiguate between the closing > characters in constructs like Dictionary>. In this example, the closing > characters are not treated as a single token that may then be misinterpreted as a bit shift >> operator. + +在特定构成中 ,以 < 或 > 开头的运算符会被分离成两个或多个标记,剩余部分以同样的方式会被再次分离。因此,在 Dictionary> 中没有必要添加空白来消除闭合字符 > 的歧义。在这个例子中, 闭合字符 > 被看作单字符标记,而不会被误解为移位运算符 >>。 + +To learn how to define new, custom operators, see Custom Operators and Operator Declaration.To learn how to overload existing operators, see Operator Functions. + +要学习如何自定义新的,自定义的运算符,请参考 自定义操作符 和 运算符声明。学习如何重写现有运算符,请参考 运算符方法。 + +> GRAMMAR OF OPERATORS + +> 运算符语法语法 +> +> operator → operator-characteroperatoropt + +> 运算符 → 运算符字符 运算符 可选 + +> operator-character → / = - + ! * % < > & | ^ ~ . + +> 运算符字符 → / | = | - | + | ! | * | % | < | > | & | | | ^ | ~ | . + +> binary-operator → operator + +> 二元运算符 → 运算符 + +> prefix-operator → operator + +> 前置运算符 → 运算符 + +> postfix-operator → operator +> 后置运算符 → 运算符 + + + diff --git a/src/chapter3/03_Types.md b/src/chapter3/03_Types.md index e69de29..18c168e 100644 --- a/src/chapter3/03_Types.md +++ b/src/chapter3/03_Types.md @@ -0,0 +1,533 @@ +# Types +# 类型 + +In Swift, there are two kinds of types: named types and compound types. A named type is a type that can be given a particular name when it is defined. Named types include classes, structures, enumerations, and protocols. For example, instances of a user-defined class named MyClass have the type MyClass. In addition to user-defined named types, the Swift standard library defines many commonly used named types, including those that represent arrays, dictionaries, and optional values. + +在swift里,有两种类型:命名类型和复合类型。命名类型是指当它被定义的时候能够给一个指定名字的类型。命名类型包含类、结构、枚举和协议。例如,用户定义的类的实例MyClass,其类型就是MyClass。除了用户定义的命名类型,swift标准库还定义了很多常用命名类型,包含的代表有数组,字典,可选值。 + + +Data types that are normally considered basic or primitive in other languages—such as types that represent numbers, characters, and strings—are actually named types, defined and implemented in the Swift standard library using structures. Because they are named types, you can extend their behavior to suit the needs of your program, using an extension declaration, discussed in Extensions and Extension Declaration. + + +通常被其它语言视为是最基础或最原始的数据类型,例如数字、字符、字符串,实际上都是命名类型,swift标准库使用结构去定义和实现他们。因为他们是命名类型,你可以用扩展声明来扩展他们的行为,以满足你的程序需求,详细讨论请参考‘扩展和扩展声明’。 + + +A compound type is a type without a name, defined in the Swift language itself. There are two compound types: function types and tuple types. A compound type may contain named types and other compound types. For instance, the tuple type (Int, (Int, Int)) contains two elements: The first is the named type Int, and the second is another compound type (Int, Int). + +复合类型是一个没有名字的类型,由swift内部自己定义。swift有两种复合类型:函数类型和元组类型。一个复合数据类型可以包含命名类型和其他复合类型。例如,一个元组类型(Int, (Int, Int))包含两个元素:第一个是命名类型Int,第二个是复合类型(Int, Int)。 + +This chapter discusses the types defined in the Swift language itself and describes the type inference behavior of Swift. + +本章讨论swif语言本身定义的类型,描述在swift中类型推断的方式。 + +> GRAMMAR OF A TYPE +> +> 类型的语法 + +> type → array-type function-type type-identifier tuple-type optional-type implicitly-unwrapped-optional-type protocol-composition-type metatype-type +> +> type -> 数组类型|函数类型|类型标识|元组类型|可选类型|隐式去包装可选类型|协议构成类型|元型类型 + + +## Type Annotation + +## 类型注释 +A type annotation explicitly specifies the type of a variable or expression. Type annotations begin with a colon (:) and end with a type, as the following examples show: + +类型标注明确的指定一个变量或者表达式的类型。类型注释以冒号(:)开始,类型结束,如下面的列子: + + + 1. let someTuple:(Double, Double) = (3.14159, 2.71828) + + 2. func someFunction(a:Int) { /**/} + +In the first example, the expression someTuple is specified to “have the tuple type (Double, Double). In the second example, the parameter a to the function someFunction is specified to have the type Int. + +在第一个例子中,表达式someTuple是被指定为元组类型(Double, Double)。在第二个例子中,函数someFuncion的参数a被指定为Int类型。 + +Type annotations can contain an optional list of type attributes before the type. + +类型注释可以在类型前面包含一个类型属性的可选列表。 + +> GRAMMAR OF A TYPE ANNOTATION + +> 类型注释的语法 + +> type-annotation → :attributesopttyp +> type-annotation -> :属性[可选]类型 + + +## Type Identifier +## 类型标识符 + +A type identifier refers to either a named type or a type alias of a named or compound type. + +类型标识符是指一个命名类型、命名类型的别名或复合类型。 + +Most of the time, a type identifier directly refers to a named type with the same name as the identifier. For example, Int is a type identifier that directly refers to the named type Int, and the type identifier Dictionary directly refers to the named type Dictionary. + +大多数情况下,类型标识符是指向相同名字的命名类型。例如,类型标识符Int指向命名类型Int,类型标识符Dictionary指向命名类型Dictionary。 + +There are two cases in which a type identifier does not refer to a type with the same name. In the first case, a type identifier refers to a type alias of a named or compound type. For instance, in the example below, the use of Point in the “type annotation refers to the tuple type (Int, Int). + +命名标识符和类型不同名的情况有两种。第一种情况,命名标识符指向命名类型的别名或者复合类型。例如下面的例子,类型标识符使用Point指向元组类型(Int, Int)。 + + typealias Point = (Int, Int); + let origin: Point = (0, 0); + + +In the second case, a type identifier uses dot (.) syntax to refer to named types declared in other modules or nested within other types. For example, the type identifier in the following code references the named type MyType that is declared in the ExampleModule module. + +第二种情况,类型标识符用点(.)的语法指向声明在其它模块或在其它类型中嵌套的命名类型。例如,在下面的代码中,类型标识符引用在模块ExampleModule中声明的命名类型MyType。 + + var someValue: ExampleModule.MyType + + +> GRAMMAR OF A TYPE IDENTIFIER +> +> 命名标识符的语法 + +‌> type-identifier → type-namegeneric-argument-clauseopt type-namegeneric-argument-clauseopt.type-identifier + +> 命名标识符 -> 类型名称 泛型参数子句[可选]|类型名称 泛型参数子句[可选].类型标识符 +> +> type-name → identifier” + +> 类型标识符 -> 标识符 + + +## Tuple Type +## 元组类型 + +A tuple type is a comma-separated list of zero or more types, enclosed in parentheses. + +元组类型是指在括号中,以逗号分隔的零到多个类型的列表。 + +You can use a tuple type as the return type of a function to enable the function to return a single tuple containing “multiple values. You can also name the elements of a tuple type and use those names to refer to the values of the individual elements. An element name consists of an identifier followed immediately by a colon (:). For an example that demonstrates both of these features, see Functions with Multiple Return Values. + +你可以用元组类型作为函数的返回值类型,这样函数就能返回包含多个值的单元组。你也可以给元组类型中的元素命名,用这些名字来引用单个元素的值。元素的名字由标识符和紧跟着的冒号(:)组成。这两种特性的例子演示,请看 ‘多个返回值的函数’。 + + +Void is a typealias for the the empty tuple type, (). If there is only one element inside the parentheses, the type is simply the type of that element. For example, the type of (Int) is Int, not (Int). As a result, you can label a tuple element only when the tuple type has two or more elements. + + +Void是空元组类型的别名,()。如果在括号里面只有一个元素,那么这个类型就是元素的类型。例如,(Int)的类型是Int,不是(Int)。因此,你可以认为仅当元组类型包含两个或者更多元素的时候才是元组元素。 + + +> GRAMMAR OF A TUPLE TYPE +> +> 元组类型的语法 +> +> tuple-type → (tuple-type-bodyopt) + +> 元组类型 -> (元组类型体[可选]) + +> tuple-type-body → tuple-type-element-list...opt + +> 元组类型体 -> 元组类型元素列表...[可选] + +> tuple-type-element-list → tuple-type-element tuple-type-element,tuple-type-element-list + +> 元组类型元素列表 -> 元组类型元素|元组类型元素,元组类型元素列表 + +> tuple-type-element → attributesoptinoutopttype inoutoptelement-nametype-annotation + +> 元组类型元素 -> 属性[可选]inout[可选]类型|inout[可选]元素名称 类型注释 + +> element-name → identifier + +> 元素名称 -> 标识符 + + +## Function Type +## 函数类型 + +A function type represents the type of a function, method, or closure and consists of a parameter and return type separated by an arrow (->): + +函数类型表示一个函数,方法,闭包的类型,它由参数和返回类型组成,中间通过箭头(->)分隔: + + parameter type -> return type + +Because the parameter type and the return type can be a tuple type, function types support functions and methods that take multiple paramaters and return multiple values. + +因为参数类型和返回类型都可以为元组类型,所以函数类型支持函数和方法有多个参数和多个返回值。 + +You can apply the auto_closure attribute to a function type that has a parameter type of () and that returns the type of an expression (see Type Attributes). An autoclosure function captures an implicit closure over the specified expression, instead of the expression itself. The following example uses the auto_closure attribute in defining a very simple assert function: + + +你可以为参数类型为(),返回值为表达式类型的函数类型申请auto_closure属性(请看 ’类型属性‘)。一个自动闭包函数捕获的是指定表达式上的隐式闭包而不是表达式本身。下面的例子用auto_closure属性定义一个简单的assert函数: + + func simpleAssert(condition: @auto_closure () -> Bool, message: String){ + if !condition(){ + println(message) + } + } + let testNumber = 5 + simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.") + // prints "testNumber isn't an even number." + + +A function type can have a variadic parameter as the last parameter in its parameter type. Syntactically, a variadic parameter consists of a base type name followed immediately by three dots (...), as in Int.... A variadic parameter is treated as an array that contains elements of the base type name. For instance, the variadic parameter Int... is treated as Int[]. For an example that uses a variadic parameter, see Variadic Parameters. + +一个函数类型的参数类型里可以让一个可变参数作为其最后一个参数。 从语法上来说,可变参数可以由一个基础类型名称和紧跟着的三个点(...)组成,例如Int...。可变参数被认为是一个包含基础类型名称的数组。例如,可变参数Int... 被认为是Int[]。使用可变参数的例子,请参考 ‘可变参数’。 + +To specify an in-out parameter, prefix the parameter type with the inout keyword. You can’t mark a variadic parameter or a return type with the inout keyword. In-out parameters are discussed in In-Out Parameters. + +指定一个in-out参数,需要给参数类型加上inout的前缀。可变参数和返回类型不能使用inout标记。in-out参数在’In-Out参数‘中有讨论。 + +The type of a curried function is equivalent to a nested function type. For example, the type of the curried function addTwoNumbers()() below is Int -> Int -> Int: + +柯里化函数(curried function)类型相当于嵌套函数类型。例如,下面的柯里化函数addTwoNumbers()()的类型是Int -> Int -> Int: + + + func addTwoNumbers(a: Int)(b: Int) -> Int{ + return a + b + } + + addTwoNumbers(4)(5) // returns 9 + + +The function types of a curried function are grouped from right to left. For instance, the function type Int -> Int -> Int is understood as Int -> (Int -> Int)—that is, a function that takes an Int and returns another function that takes and return an Int. For example, you can rewrite the curried function addTwoNumbers()() as the following nested function: + +柯里化函数的函数类型从右到左形成一组。例如,函数类型Int -> Int -> Int被理解为Int -> (Int -> Int) -- 指函数传入一个Int,然后返回另外一个输入输出都是Int的函数。 + + func addTwoNumbers(a: Int) -> (Int -> Int){ + func addTheSecondNumber(b: Int) -> Int{ + return a + b + } + return addTheSecondNumber + } + + addTwoNumbers(4)(5) // Returns 9 + + +> GRAMMAR OF A FUNCTION TYPE + +> 函数类型的语法 + +> function-type → type->type” + +> 函数类型 → 类型 -> 类型 + + +## Array Type +## 数组类型 + +The Swift language uses square brackets ([]) immediately after the name of a type as syntactic sugar for the named type Array, which is defined in the Swift standard library. In other words, the following two declarations are equivalent: + +在swift中类型紧跟着[]作为标准库定义的命名类型Array的简写。换句话说,下面两个声明是相等的: + + let someArray: String[] = ["Alex", "Brian", "Dave"] + let someArray: Array = ["Alex", "Brian", "Dave"] + +In both cases, the constant someArray is declared as an array of strings. The elements of an array can be accessed using square brackets as well: someArray[0] refers to the element at index 0, "Alex". + +在这两种情况下,常量someArray被定义为字符串数组。数组元素也可以用中括号访问:someArray[0] 指向index为0的元素,即‘Alex’。 + +As the above example also shows, you can use square brackets to create an array using an array literal. Empty array literals are written using an empty pair of square brackets and can be used to create an empty array of a specified type. + +如上面的例子显示,你可以利用数组自变量通过[]创建一个数组。空数组自变量用[]表示,也可以创建制定类型的空数组。 + + var emptyArray: Double[] = [] + +You can create multidimensional arrays by chaining multiple sets of square brackets to the name of the base type of the elements. For example, you can create a three-dimensional array of integers using three sets of square brackets: + + +你可以链接多组中括号创建多维数组。例如,你可以创建一个三维整数数组,通过三组中括号: + + var array3D: Int[][][] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] + +When accessing the elements in a multidimensional array, the left-most subscript index refers to the element at that index in the outermost array. The next subscript index to the right refers to the element at that index in the array that’s nested one level in. And so on. This means that in the example above, array3D[0] refers to [[1, 2], [3, 4]], array3D[0][1] refers to [3, 4], and array3D[0][1][1] refers to the value 4. + +当访问多维数组里面的元素时,最左边的下标指向最外层数组的对应位置,接下来往右的下标指向第一层嵌套的数组的位置。依此类推。根据上面的例子,array3D[0]指向[[1, 2], [3, 4]],array3D[0][1]指向[3, 4],array3D[0][1][1]的值是4。 + +For a detailed discussion of the Swift standard library Array type, see Arrays. + +数组类型在swift标准库中的详细讨论,请看“数组“。 + + +> GRAMMAR OF AN ARRAY TYPE + +> 数组类型的语法 +‌ +> array-type → type[] array-type[] + +> 数组类型 → 类型[] 数组类型[] + + +## Optional Type +## 可选类型 + +The Swift language defines the postfix ? as syntactic sugar for the named type Optional, which is defined in the Swift standard library. In other words, the following two declarations are equivalent: + +在swift中定义后缀?为标准库定义的命名类型Optional的简写。换句话说,以下两种声明是相等的: + + var optionalInteger: Int? + var optionalInteger: Optional + + +In both cases, the variable optionalInteger is declared to have the type of an optional integer. Note that no whitespace may appear between the type and the ?. + +在这两种情况下,变量optionalInteger被声明是可选整数类型。注意,在类型和?之间没有空格。 + +The type Optional is an enumeration with two cases, None and Some(T), which are used to represent values that may or may not be present. Any type can be explicitly declared to be (or implicitly converted to) an optional type. When declaring an optional type, be sure to use parentheses to properly scope the ? operator. As an example, to declare an optional array of integers, write the type annotation as (Int[])?; writing Int[]? produces an error. + +Optional 是一个含有两种情况的枚举,None和Some(T),用来表示可能有也可能没有值。任何类型都可以声明为(或者隐式转换)可选类型。当声明一个可选类型的时候,要确保用括号给?操作符提供确定的范围。例如,声明可选整数数组,应该写成(Int[])?;写成Int[]?会报错。 + +If you don’t provide an initial value when you declare an optional variable or property, its value automatically defaults to nil. + +当你声明一个可选变量或者可选属性的时候没有提供初始值,它的值会默认设置为nil。 + +Optionals conform to the LogicValue protocol and therefore may occur in a Boolean context. In that context, if an instance of an optional type T? contains any value of type T (that is, it’s value is Optional.Some(T)), the optional type evaluates to true. Otherwise, it evaluates to false. + +可选遵照LogicValue协议,因此可以出现在布尔环境中。在这种情况下,可选类型T?包含类型为T的任何值(也就是说它的值是Optional.Some(T)),这个可选类型等于true,反之为false。 + +If an instance of an optional type contains a value, you can access that value using the postfix operator !, as shown below: + +如果可选类型包含一个值,你可以用后缀!访问,如下所示: + + optionalInteger = 42 + optionalInteger! // 42 + +Using the ! operator to unwrap an optional that has a value of nil results in a runtime error. + +用操作符!去获取值为nil的可选变量回有运行错误。 + + +You can also use optional chaining and optional binding to conditionally perform an operation on an optional expression. If the value is nil, no operation is performed and therefore no runtime error is produced. + +你可以用可选链接和可选绑定选择性执行可选表达式上的操作。如果值为nil,任何操作都不会执行,也不会有运行报错。 + + +For more information and to see examples that show how to use optional types, see Optionals. + + +更过关于可选类型的信息和例子,请看“可选“。 + +> GRAMMAR OF AN OPTIONAL TYPE + +> 可选类型语法 + +> optional-type → type? + +> 可选类型 → 类型 ? + + + +## Implicitly Unwrapped Optional Type +## 隐式解析可选类型 + +The Swift language defines the postfix ! as syntactic sugar for the named type ImplicitlyUnwrappedOptional, which is defined in the Swift standard library. In other words, the following two declarations are equivalent: + + +在swift中定义后缀!为标准库定义的名类型ImplicitlyUnwrappedOptional的简写。换句话说,以下两种声明是相等的: + + var implicitlyUnwrappedString: String! + var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional + +In both cases, the variable implicitlyUnwrappedString is declared to have the type of an implicitly unwrapped optional string. Note that no whitespace may appear between the type and the !. + +在这两种情况下,变量implicitlyUnwrappedString被声明为隐式可选类型字符串。注意,在类型和!之间没有空格。 + +You can use implicitly unwrapped optionals in all the same places in your code that you can use optionals. For instance, you can assign values of implicitly unwrapped optionals to variables, constants, and properties of optionals, and vice versa. + +你代码中用到可选的地方都可以用隐式解析可选。例如,你可以设置隐式可选类型的值为变量、常量、可选属性,反之亦然。 + +As with optionals, if you don’t provide an initial value when you declare an implicitly unwrapped optional variable or property, it’s value automatically defaults to nil. + +有了可选,当你声明一个隐式解析可选变量或者属性的时候没有赋初始值,它的值默认为nil。 + + +Because the value of an implicitly unwrapped optional is automatically unwrapped when you use it, there’s no need to use the ! operator to unwrap it. That said, if you try to use an implicitly unwrapped optional that has a value of nil, you’ll get a runtime error. + +隐式解析可选的值会在使用的时候自动解析,所以不需要用!去解析它。也就是说,如果你用值为nil的隐式解析可选,那么会会导致运行错误。 + +Use optional chaining to conditionally perform an operation on an implicitly unwrapped optional expression. If the value is nil, no operation is performed and therefore no runtime error is produced. + +使用可选链能够选择性的执行隐式解析可选表达式上的操作。用可选链接在隐式解析可选的表达式上做一定的操作。如果值是nil,没有操作会被执行,也不会有运行错误。 + +For more information about implicitly unwrapped optional types, see Implicitly Unwrapped Optionals. + +更多关于隐式解析可选类型,请看 “隐式解析可选”。 + +> GRAMMAR OF AN IMPLICITLY UNWRAPPED OPTIONAL TYPE + +> 隐式解析可选类型语法 + +> implicitly-unwrapped-optional-type → type! + +> 隐式解析可选类型 -> 类型! + + + +## Protocol Composition Type +## 协议组合类型 + +A protocol composition type describes a type that conforms to each protocol in a list of specified protocols. Protocol composition types may be used in type annotations and in generic parameters. + +协议组合类型是指符合指定协议列表里每个协议的类型。协议组合类型可以用在类型注释和泛型参数中。 + + +Protocol composition types have the following form: + +协议组合类型的格式如下: + + protocol + +A protocol composition type allows you to specify a value whose type conforms to the requirements of multiple protocols without having to explicitly define a new, named protocol that inherits from each protocol you want the type to conform to. For example, specifying a protocol composition type protocol is effectively the same as defining a new protocol ProtocolD that inherits from ProtocolA, ProtocolB, and ProtocolC, but without having to introduce a new name. + +它的类型符合多个协议的要求,不需定义新的命名协议,它继承了从每个协议符合的类型。。例如,指定一个协议组合类型protocol相当于定义一个新的协议ProtocolD,它继承了ProtocolA, ProtocolB和 ProtocolC,但是没有引入一个新的名字。 + +Each item in a protocol composition list must be either the name of protocol or a type alias of a protocol composition type. If the list is empty, it specifies the empty protocol composition type, which every type conforms to. + +协议组合列表中的每一项必须是协议名或者是协议组合类型的别名。如果列表是空的,它会指定一个空的协议组合类型,任何类型都可以匹配。 + + +> GRAMMAR OF A PROTOCOL COMPOSITION TYPE +> +> 协议组合类型语法 + +> protocol-composition-type → protocol +> +> 协议组合类型 -> 协议<协议标示符列表[可选]> + +> protocol-identifier-list → protocol-identifier | protocol-identifier,protocol-identifier-list + +> 协议标示符列表 -> 协议标示符 | 协议标示符,协议标示符列表 +> +> protocol-identifier → type-identifier + +> 协议标示符 -> 类型标示符 + + +## Metatype Type +## 元类型 + +A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types. + +元类型是指所有类型的类型,包括类、结构、枚举、协议。 + +The metatype of a class, structure, or enumeration type is the name of that type followed by .Type. The metatype of a protocol type—not the concrete type that conforms to the protocol at runtime—is the name of that protocol followed by .Protocol. For example, the metatype of the class type SomeClass is SomeClass.Type and the metatype of the protocol SomeProtocol is SomeProtocol.Protocol. + + +类、结构、枚举的元类型是相应的类型名称后面跟着.Type。协议类型的元类型 -- 不是具体的类型,根据协议运行时来适配 -- 是该协议名字后面跟着.Protocol。例如,类SomeClass的元类型是SomeClass.Type,协议SomeProtocol的元类型是SomeProtocol.Protocol。 + +You can use the postfix self expression to access a type as a value. For example, SomeClass.self returns SomeClass itself, not an instance of SomeClass. And SomeProtocol.self returns SomeProtocol itself, not an instance of a type that conforms to SomeProtocol at runtime. You can use a dynamicType expression with an instance of a type to access that instance’s runtime type as a value, as the following example shows: + + +你可以用后缀self的方式获取类型。例如,SomeClass.self返回 SomeClass本身,不是SomeClass的实例。SomeProtocol.self返回SomeProtocol本身, 不是运行时SomeProtocol的实例。你可以用dynamicType表达式类获取实例运行时的类型,如下面的例子所示: + + class SomeBaseClass { + class func printClassName() { + println("SomeBaseClass") + } + } + class SomeSubClass:SomeBaseClass { + override class func printClassName() { + println("SomeSubClass") + } + } + let someInstance: SomeBaseClass = SomeSubClass() + // someInstance is of type SomeBaseClass at compile time, but + // someInstance is of type SomeSubClass at runtime + + someInstance.dynamicType.printClassName() + + // prints "SomeSubClass" + + +> GRAMMAR OF A METATYPE TYPE + +> 元类型语法 + +> metatype-type → type.Type | type.Protocol + +> 元类型 → 类型.Type | 类型.Protocol +> + +## Type Inheritance Clause +## 类型继承子句 + +A type inheritance clause is used to specify which class a named type inherits from and which protocols a named type conforms to. A type inheritance clause begins with a colon (:), followed by a comma-separated list of type identifiers. + +类型继承子句被用来指定一个命名类型继承哪个类,适配哪些协议。类型继承子句以冒号(:)开始,紧跟着以逗号分割的类型标示符列表。 + + +Class types may inherit from a single superclass and conform to any number of protocols. When defining a class, the name of the superclass must appear first in the list of type identifiers, followed by any number of protocols the class must conform to. If the class does not inherit from another class, the list may begin with a protocol instead. For an extended discussion and several examples of class inheritance, see Inheritance. + +类类型可能继承单个超类,适配多个协议。当定义一个类的时候,超类的名称必须出现在类型标示符列表首位,接着类必须适配的一些协议。如果类不继承其他类,那么列表就是以协议开头。类机继承的扩展讨论和例子,请看 “继承”。 + + +Other named types may only inherit from or conform to a list of protocols. Protocol types may inherit from any number of other protocols. When a protocol type inherits from other protocols, the set of requirements from those other protocols are aggregated together, and any type that inherits from the current protocol must conform to all of those requirements. + +其他命名协议可能仅继承或适配一个协议列表。协议类型可能继承一些其它协议。当一个协议类型继承其它协议的时候,其它协议的条件会被集合在一起,任何继承当前协议的类型必须适配所有的这些条件。 + +A type inheritance clause in an enumeration definition may be either a list of protocols, or in the case of an enumeration that assigns raw values to its cases, a single, named type that specifies the type of those raw values. For an example of an enumeration definition that uses a type inheritance clause to specify the type of its raw values, see Raw Values. + + +在枚举类型里面定义的类型继承子句可以是一个协议列表,或者指定原始值的枚举实例,一个单独的指定原始值类型的命名型类型。在枚举定义中用类型继承子句来指定原始值类型的列子,请看 “原始类型”。 + +> GRAMMAR OF A TYPE INHERITANCE CLAUSE + +> 类型继承子句语法 + +> type-inheritance-clause → :type-inheritance-list +> +> 类型继承子句 → : 类型继承列表 +> +> type-inheritance-list → type-identifier | type-identifier,type-inheritance-list + +> 类型继承列表 → 类型标示符 | 类型表示符,类型继承列表 + + +## Type Inference +## 类型推断 + +Swift uses type inference extensively, allowing you to omit the type or part of the type of many variables and expressions in your code. For example, instead of writing var x: Int = 0, you can omit the type completely and simply write var x = 0—the compiler correctly infers that x names a value of type Int. Similarly, you can omit part of a type when the full type can be inferred from context. For instance, if you write let dict: Dictionary = ["A": 1], the compiler infers that dict has the type Dictionary. + + +swift广泛使用类型推断,允许你在代码里忽略很多变量和表达式的类型或者部分类型。例如,var x: Int = 0可以完全忽略类型,简写成 var x = 0 -- 编译器能够正确的推测出x的类型名称是Int。同样,当完整的类型能够通过上下文推断出来的时候,你可以忽略部分类型。例如, +dict: Dictionary = ["A": 1],编译器推断出dict的类型是Dictionary。 + +In both of the examples above, the type information is passed up from the leaves of the expression tree to its root. That is, the type of x in var x: Int = 0 is inferred by first checking the type of 0 and then passing this type information up to the root (the variable x). + + +在上面的两个例子中,类型信息从表达树的叶子传向根。也就是说,x在var x: Int = 0的类型通过首先判断0的类型,然后再传递类型信息到根(即变量x)。 + + +In Swift, type information can also flow in the opposite direction—from the root down to the leaves. In the following example, for instance, the explicit type annotation (: Float) on the constant eFloat causes the numeric literal 2.71828 to have type Float instead of type Double. + +在swift里面,类型推断可以反方向推断 -- 从根传递到叶子。下面这个例子就是这种情况,常量eFloat显示类型注释(:Float)导致数字2.71828的类型是Float而不是Double。 + + let e = 2.71828 // The type of e is inferred to be Double. + let eFloat: Float = 2.71828 // The type of eFloat is Float. + + +Type inference in Swift operates at the level of a single expression or statement. This means that all of the information needed to infer an omitted type or part of a type in an expression must be accessible from type-checking the expression or one of its subexpressions. + +swift中的类型推断在单个表达式或者语句上操作。这意味着推测忽略类型或者部分类型信息必须从表达式或者其子表达式类型检测中获取。 + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/chapter3/04_Expressions.md b/src/chapter3/04_Expressions.md index e69de29..67367ed 100644 --- a/src/chapter3/04_Expressions.md +++ b/src/chapter3/04_Expressions.md @@ -0,0 +1,1061 @@ +# Expressions +# 表达式 + +In Swift, there are four kinds of expressions: prefix expressions, binary expressions, primary expressions, and postfix expressions. Evaluating an expression returns a value, causes a side effect, or both. + +在swift中有四种表达式:前缀表达式,二元表达式,主表达式和后缀表达式。对表达式求值可以得到一个返回值、或完成某些逻辑运算,或同时完成这两件事。 + +Prefix and binary expressions let you apply operators to smaller expressions. Primary expressions are conceptually the simplest kind of expression, and they provide a way to access values. Postfix expressions, like prefix and binary expressions, let you build up more complex expressions using postfixes such as function calls and member access. Each kind of expression is described in detail in the sections below. + +前缀和二元表达式可以让我们在更短小的表达式中运算符。主表达式从概念上来看是最简单短小的表达式,同时又提供了一种求值的途径。后缀表达式,与前缀表达式和二元表达式相似,都可以让你建立更为复杂的表达方式,比如函数调用和成员访问。我们将在本节中详细解释每种表达式。 + +> GRAMMAR OF AN EXPRESSION + +> expression → prefix-expressionbinary-expressionsopt + +> expression-list → expression expression,expression-list + + +## Prefix Expressions +## 前缀表达式 + +Prefix expressions combine an optional prefix operator with an expression. Prefix operators take one argument, the expression that follows them. + +前缀表达式由一个任意前缀运算符接表达式构成。前缀表达式只接受一个参数。 + +The Swift standard library provides the following prefix operators: + +* ++ Increment +* -- Decrement +* ! Logical NOT +* ~ Bitwise NOT +* \+ Unary plus +* \- Unary minus + + +Swift标准库提供了如下前缀运算符: + +* ++ 自增 +* -- 自减 +* ! 逻辑否 +* ~ 按位否 +* \+ 一元加 +* \- 一元负 + + +For information about the behavior of these operators, see Basic Operators and Advanced Operators. + +关于这些运算符的信息,请参见:“Basic Operators and Advanced Operators.”两节。 + + +In addition to the standard library operators listed above, you use & immediately before the name of a variable that’s being passed as an in-out argument to a function call expression. For more information and to see an example, see In-Out Parameters. + + +作为对上述运算符的补充,你可以在作为某个函数参数的变量名前使用‘&’运算符。更多信息和实例,参见:In-Out Parameters一节。 + +> “GRAMMAR OF A PREFIX EXPRESSION + +> 前缀表达式语法 + +> prefix-expression → prefix-operatoroptpostfix-expression + +> prefix-expression → in-out-expression +‌ in-out-expression → &identifier + + +## Binary Expressions + +## 二元表达式 + + +Binary expressions combine an infix binary operator with the expression that it takes as its left-hand and right-hand arguments. It has the following form: + +二元表达式由中缀二元运算符和“左边参数”与“右边参数”组成。形式如下: + + left-hand argument operator right-hand argument + + +The Swift standard library provides the following binary operators: + +Swift标准库提供了如下的二元运算符: + + +* Exponentiative (No associativity, precedence level 160) + * << Bitwise left shift + * \>> Bitwise right shift + +* 指数(无结合性,优先级160) + * << 按位左移 + * \>> 按位右移 + + +* Multiplicative (Left associative, precedence level 150) + * Multiply + * / Divide + * % Remainder + * &* Multiply, ignoring overflow + * &/ Divide, ignoring overflow + * &% Remainder, ignoring overflow + * & Bitwise AND + +* 乘法(左结合,优先级150) + * \* 乘 + * / 除 + * % 求余 + * &* 乘,ignoring overflow + * &/ 除,ignoring overflow + * &% 求余,ignoring overflow + * & 按位与 + + +* Additive (Left associative, precedence level 140) + * \+ Add + * \- Subtract + * &+ Add with overflow + * &- Subtract with overflow + * | Bitwise OR + * ^ Bitwise XOR + +* 加法(左结合,优先级140) + * \+ 加 + * \- 减 + * &+ 加,with overflow + * &- 减,with overflow + * | 按位或 + * ^ 按位异或 + +* Range (No associativity, precedence level 135) + * .. Half-closed range + * ... Closed range + +* 值域(无结合性,优先级135) + * .. 半闭值域 + * ... 闭值域 + +* Cast (No associativity, precedence level 132) + * is Type check + * as Type cast + +* 类型转换(无结合性,优先级132) + * is 类型检查 + * as 类型转换 + +* Comparative (No associativity, precedence level 130) + * < Less than + * <= Less than or equal + * \> Greater than + * \>= Greater than or equal + * == Equal + * != Not equal + * === Identical + * !== Not identical + * ~= Pattern match + +* 比较(无结合性,优先级130) + * < 小于 + * <= 小于等于 + * \> 大于 + * \>= 大于等于 + * == 等于 + * != 不等于 + * === 恒等于 + * !== 不恒等 + * ~= 模式匹配 + +* Conjunctive (Left associative, precedence level 120) + * && Logical AND + +* 合取性(conjunctive)(左结合,优先级120) + * && 逻辑与 + +* Disjunctive (Left associative, precedence level 110) + * || Logical OR + +* 析取性(disjunction)(左结合,优先级110) + * || 逻辑或 + + +* Ternary Conditional (Right associative, precedence level 100) + * ?: Ternary conditional + +* 三元条件(右结合,优先级100) + * ?: 三元条件 + +* Assignment (Right associative, precedence level 90) + * = Assign + * *= Multiply and assign + * /= Divide and assign + * %= Remainder and assign + * += Add and assign + * -= Subtract and assign + * <<= Left bit shift and assign + * \>>= Right bit shift and assign + * &= Bitwise AND and assign + * ^= Bitwise XOR and assign + * |= Bitwise OR and assign + * &&= Logical AND and assign + * ||= Logical OR and assign + + +* 赋值(右结合,优先级90) + * = 赋值 + * *= 乘等 + * /= 除等 + * %= 余等 + * += 加等 + * -= 减等 + * <<= 左移等 + * \>>= 右移等 + * &= 按位与等 + * ^= 按位异或等 + * |= 按位非等 + * &&= 逻辑与等 + * ||= 逻辑或等 + +For information about the behavior of these operators, see Basic Operators and Advanced Operators. + + +关于这些运算符的信息,请参见:Basic Operators and Advanced Operators两节。 + +> NOTE +> 注解 + +> At parse time, an expression made up of binary operators is represented as a flat list. This list is transformed into a tree by applying operator precedence For example, the expression 2 + 3 * 5 is initially understood as a flat list of five items, 2, +, `` 3``, *, and 5. This process transforms it into the tree (2 + (3 * 5)). + +> 在解析时,由二元操作符构成的表达式被表达为一个简单列表。这个列表按照运算符的优先级被转换成树(tree),比如“2 + 3 * 5”首先被认为是'2'、'+'、'3'、'+'、'5'这5个元素,随后被转换成树(2 + (3 * 5))。 + + + +> 二元表达式语法 + +> GRAMMAR OF A BINARY EXPRESSION + +‌> binary-expression → binary-operatorprefix-expression + +‌> binary-expression → assignment-operatorprefix-expression + +‌> binary-expression → conditional-operatorprefix-expression + +‌> binary-expression → type-casting-operator + +‌> binary-expressions → binary-expressionbinary-expressionsopt + + +## Assignment Operator +## 赋值运算符 + +The assigment operator sets a new value for a given expression.It has the following form: + +赋值运算符会给某个给定的表达式赋值。如下面的例子: + + expression = value + +The value of the expression is set to the value obtained by evaluating the value. If the expression is a tuple, the value must be a tuple with the same number of elements. (Nested tuples are allowed.) Assignment is performed from each part of the value to the corresponding part of the expression. For example: + + +上面语句的意思就是计算`value`的值并赋给`expression`。如果`expression`是个元组,那么`value`必须是含有同等数量元素的元祖。(嵌套元祖也是可以直接赋值滴。)元祖赋值会把`value`中相对应的部分分别赋给`expression`。例如: + + > (a, _, (b, c)) = ("test", 9.45, (12, 3)) + + > // a is "test", b is 12, c is 3, and 9.45 is ignored + + +The assignment operator does not return any value. + +赋值运算符不返回任何值。 + +> GRAMMAR OF AN ASSIGNMENT OPERATOR + +> 赋值运算符的语法 + +> assignment-operator → = + + +## Ternary Conditional Operator + +## 三元条件运算符 + +The ternary conditional operator evaluates to one of two given values based on the value of a condition. It has the following form: + + +三元条件运算符是根据一个条件判断来求值。形式如下: + + condition ? expression used if true : expression used if false + + +If the condition evaluates to true, the conditional operator evaluates the first expression and returns its value. Otherwise, it evaluates the second expression and returns its value. The unused expression is not evaluated. + +上面例子中,当condition的值为true时,那么将对第一个表达式求值并返回。否则将对第二个表达式求值并返回。期间没有用到的那个表达式将不会被调用。 + +For an example that uses the ternary conditional operator, see Ternary Conditional Operator. + +更多三元条件运算符的例子,请参见Ternary Conditional Operator。 + +> GRAMMAR OF A CONDITIONAL OPERATOR + +> 条件运算符语法: + +> conditional-operator → ?expression: + + +## Type-Casting Operators +## 类型转换运算符 + +There are two type-casting operators, the as operator and the is operator. They have the following form: + +类型转换运算符有两种:as运算符合is运算符。形式如下: + + + expression as type + + expression as? type + + expression is type + + +The as operator performs a cast of the expression to the specified type. It behaves as follows: + +上面例子中,as 运算符会把目标表达式`expression`转换成指定的类型`type`。过程如下: + +* If conversion to the specified type is guaranteed to succeed, the value of the expression is returned as an instance of the specified type. An example is casting from a subclass to a superclass. + +* 如果转换为`type`类型保证能够成功,那么目标表达式`expression`就会返回指定类型的实例。一个显而易见的例子就是子类类型转换成父类类型。 + +* If conversion to the specified type is guaranteed to fail, a compile-time error is raised. + +* 如果转换失败,则抛出编译错误。 + +* Otherwise, if it’s not known at compile time whether the conversion will succeed, the type of the cast expresion is an optional of the specified type. At runtime, if the cast succeeds, the value of expression is wrapped in an optional and returned; otherwise, the value returned is nil. An example is casting from a superclass to a subclass. + +* 如果不是以上两种情况,那么目标表达式`expression`就会被转换成指定类型的optional。在运行时,如果转换成功,那么`expression`会返回一个optional的包装类型;否则返回nil。举个例子: + +> class SomeSuperType {} + +> class SomeType: SomeSuperType {} + +> class SomeChildType: SomeType {} + +> let s = SomeType() + +> let x = s as SomeSuperType // known to succeed; type is SomeSuperType + +> let y = s as Int // known to fail; compile-time error + +> let z = s as SomeChildType // might fail at runtime; type is SomeChildType? + + +Specifying a type with as provides the same information to the compiler as a type annotation, as shown in the following example: + +使用as指定类型与使用类型注释效果相同,看下面这个例子: + +> let y1 = x as SomeType // Type information from 'as' + +> let y2: SomeType = x // Type information from an annotation + + +The is operator checks at runtime to see whether the expression is of the specified type. If so, it returns true; otherwise, it returns false. + + +is运算符会在运行时检查`expression`是否指定了类型。成功会返回true, 否则 false。上述检查在编译时不可用,下面例子就是无效的: + +> "hello" is String +> + "hello" is Int + + +For more information about type casting and to see more examples that use the type-casting operators, see Type Casting. + +关于类型转换的更多内容和例子,请参见: Type Casting. + +> GRAMMAR OF A TYPE-CASTING OPERATOR + +> 类型转换的语法 + +> type-casting-operator → is­ type­| as­?(opt)­ type + + +## Primary Expressions +## 主表达式 + +Primary expressions are the most basic kind of expression. They can be used as expressions on their own, and they can be combined with other tokens to make prefix expressions, binary expressions, and postfix expressions. + +主表达式是种最基本的表达式。它可以单独使用,也可以和其他表达式组合使用。 + +> GRAMMAR OF A PRIMARY EXPRESSION + +> 主表达式的语法 + +> primary-expression → identifiergeneric-argument-clauseopt +> primary-expression → literal-expression +> primary-expression → self-expression +> primary-expression → superclass-expression +> primary-expression → closure-expression +> primary-expression → parenthesized-expression +> primary-expression → implicit-member-expression +> primary-expression → wildcard-expression + + +## Literal Expression +## 字面量表达式 + +A literal expression consists of either an ordinary literal (such as a string or a number), an array or dictionary literal, or one of the following special literals: + +一个字面量表达式可以由普通文本(比如一个字符串或者一个数字)、一个数组或字典字面量或以下指定的文本组成: + + +Literal | Type | Value +------------ | --------| ------------ +\__FILE__ | String | The name of the file in which it appears. +\__LINE__ | Int | The line number on which it appears. +\__COLUMN__ | Int | The column number in which it begins. +\__FUNCTION__| String | The name of the declaration in which it appears. + +Literal | Type | Value +------------ | --------| ------------ +\__FILE__ | String | 当前文件的文件名 +\__LINE__ | Int | 当前行数 +\__COLUMN__ | Int | 当前列数 +\__FUNCTION__| String | 当前声明的名字 + + +Inside a function, the value of __FUNCTION__ is the name of that function, inside a method it is the name of that method, inside a property getter or setter it is the name of that property, inside special members like init or subscript it is the name of that keyword, and at the top level of a file it is the name of the current module. + + +在函数中,__FUNCTION__的值为当前函数的名字。在方法中,它的值为当前方法的名字。在某个属性的getter/setter中为这个属性的名字。在像init和subscript这样的特殊成员中,它的值为那个关键字的名字。在文件顶层(at the top level of a file)则是当前模块的名字。 + + +An array literal is an ordered collection of values. It has the following form: + + +数组字面量是有序的值的集合。形式如下: + + [value 1, value 2, ...] + + +The last expression in the array can be followed by an optional comma. An empty array literal is written as an empty pair of brackets ([]). The value of an array literal has type T[], where T is the type of the expressions inside it. If there are expressions of multiple types, T is their closest common supertype. + +数组中的最后一个表达式后面可以接一个逗号。一对空的中括号([])组成了一个空的数组字面量。数组字面量的类型是T[],这个T就是数组中表达式的类型。如果数组含多个类型的表达式,T则是他们的最近公共父类型(closest common supertype)。 + +A dictionary literal is an unordered collection of key-value pairs. It has the following form: + +字典字面量是无序键值对的集合。形式如下: + + [key 1: value 1, key 2: value 2, ...] + + +The last expression in the dictionary can be followed by an optional comma. An empty dictionary literal is written as a colon inside a pair of brackets ([:]) to distinguish it from an empty array literal. The value of a dictionary literal has type Dictionary, where KeyType is the type of its key expressions and ValueType is the type of its value expressions. If there are expressions of multiple types, KeyType and ValueType are the closest common supertype for their respective values. + + +字典中的最后一个表达式后面也可以接一个逗号。一对空的中括号包含一个冒号([:])组成了一个空的字典字面量。字典字面量的类型是Dictionary,这里KeyType、ValueType就是key和value的类型。如果包含多个类型,则分别取他们相应的最近的公共父类型(closest common supertype)。 + +> GRAMMAR OF A LITERAL EXPRESSION + +> 字面量表达式的语法 + +> literal-expression → literal + +> literal-expression → array-literal | dictionary-literal + +> literal-expression → __FILE__ | __LINE__ __COLUMN__ | __FUNCTION__ + +> array-literal → [array-literal-itemsopt] + +> array-literal-items → array-literal-item,opt | array-literal-item,array-literal-items + +> array-literal-item → expression + +> dictionary-literal → [dictionary-literal-items] | [:] | dictionary-literal-items → dictionary-literal-item,opt dictionary-literal-item,dictionary-literal-items + +> dictionary-literal-item → expression:expression + + +## Self Expression +## self表达式 + + +The self expression is an explicit reference to the current type or instance of the type in which it occurs. It has the following forms: + +self表达式是对当前类型或当前实例的直接引用。形式如下: + + self + + self.member name + + self[subscript index] + + self(initializer arguments) + + self.init(initializer arguments) + + +In an initializer, subscript, or instance method, self refers to the current instance of the type in which it occurs. In a static or class method, self refers to the current type in which it occurs. + + +如果在初始设定式、子脚本、实例方法中,self为当前类型实例的引用。在静态方法和类方法中,self为当前类型的引用。 + + +The self expression is used to specify scope when accessing members, providing disambiguation when there is another variable of the same name in scope, such as a function parameter. For example: + +self表达式被用于在访问成员变量时指定作用域,当作用域中有重名变量时,它还用来消除歧义(例如函数的参数)。例如: + + class SomeClass { + var greeting: String + init(greeting: String) { + self.greeting = greeting + } + } + + +In a mutating method of value type, you can assign a new instance of that value type to self. For example: + + +在派生方法中,你可以把一个那个类型的新实例赋值给self。例如: + + struct Point { + var x = 0.0, y = 0.0 + mutating func moveByX(deltaX: Double, y deltaY: Double) { + self = Point(x: x + deltaX, y: y + deltaY) + } + } + + +> GRAMMAR OF A SELF EXPRESSION + +> self表达式的语法 + +> self-expression → self + +> self-expression → self.identifier + +> self-expression → self[expression] + +> self-expression → self.init + + +## Superclass Expression +## 超类表达式 + + +A superclass expression lets a class interact with its superclass. It has one of the following forms: + + +超类表达式可以让我们在某个class中访问它的超类,形式如下: + + super.`member name` + + super[`subscript index`] + + super.init(`initializer arguments`) + + +The first form is used to access a member of the superclass. The second form is used to access the superclass’s subscript implementation. The third form is used to access an initializer of the superclass. + +第一种形式用来访问超类的某个成员。第二种形式用来访问超类的子脚本实现(subscript implementation)。第三种用来访问该超类的初始设定式。 + + +Subclasses can use a superclass expression in their implementation of members, subscripting, and initializers to make use of the implementation in their superclass. + + +子类可以利用超类的实现,并通过使用超类表达式来实现它们的成员、子脚本和初始值。 + +> GRAMMAR OF A SUPERCLASS EXPRESSION + +> 超类表达式的语法 + +> superclass-expression → superclass-method-expression | superclass-subscript-expression | superclass-initializer-expression + +> superclass-method-expression → super.identifier + +> superclass-subscript-expression → super[expression] + +> superclass-initializer-expression → super.init + + +## Closure Expression +## 闭包表达式 + +A closure expression creates a closure, also known as a lambda or an anonymous function in other programming languages. Like function declarations, closures contain statements which they execute, and they capture values from their enclosing scope. It has the following form: + +闭包表达式可以创建一个闭包,就好像其他语言中的lambda或者匿名函数。与函数声明相同,闭包包含了要执行的语句,接收作用域中的变量。形式如下: + + { (parameters) -> return type in + statements + } + +The parameters have the same form as the parameters in a function declaration, as described in Function Declaration. + +闭包的参数声明跟函数的参数一样,具体参见Function Declaration。 + +There are several special forms that allow closures to be written more concisely: + + +为了写起来更加简洁,闭包还有几种特殊形式: + +* A closure can omit the types of its parameters, its return type, or both. If you omit the parameter names and both types, omit the in keyword before the statements. If the omitted types can’t be inferred, a compile-time error is raised. + + +* 闭包可以省略参数和返回值的类型。如果省略了参数和参数类型,语句前面的in也要省略。如果省略的类型不能被自动甄别,那么就会抛出编译错误。 + +* A closure may omit names for its parameters. Its parameters are then implicitly named $ followed by their position: $0, $1, $2, and so on. + +* 闭包可以省略参数名。如果省略了它们则会隐式地命名为“$+它们的顺序号”:`$0`,`$1`,`$2`等。 + +* A closure that consists of only a single expression is understood to return the value of that expression. The contents of this expression is also considered when performing type inference on the surrounding expression. + +* 如果闭包中只包含一个表达式,那么该表达式就会自动成为该闭包的返回值。同时表达式的内容在进行类型推断的时候也会参考周围的表达式。 + +The following closure expressions are equivalent: + +以下几个表达式是等价的: + + myFunction { + (x: Int, y: Int) -> Int in + return x + y + } + + myFunction { + (x, y) in + return x + y + } + + myFunction { return $0 + $1 } + + myFunction { $0 + $1 } + +For information about passing a closure as an argument to a function, see Function Call Expression. + +关于将闭包作为函数参数的更多内容,请参见:Function Call Expression。 + +A closure expression can explicitly specify the values that it captures from the surrounding scope using a capture list. A capture list is written as a comma separated list surrounded by square brackets, before the list of parameters. If you use a capture list, you must also use the in keyword, even if you omit the parameter names, parameter types, and return type. + +可以通过使用捕获列表从周围作用域中捕获值来显式指定给闭包表达式。捕获列表是以在参数列表前使用中括号加逗号分隔的形式组成的。一旦使用了参数列表,即使省略了参数名,参数类型和返回值类型,也要使用in关键字。 + +Each entry in the capture list can be marked as weak or unowned to capture a weak or unowned reference to the value. + +捕获列表中的每一项都要标记为weak或unowned来捕获弱引用和无主引用。 + + myFunction{ print(self.title) } + // strong capture + myFunction { [weak self] in print(self!.title) } + // weak capture + myFunction { [unowned self] in print(self.title) } + // unowned capture + +在捕获列表中,你能绑定任意表达式给一个命名值。表达式在闭包形成时被根据指定强度计算并捕获。 + + // Weak capture of "self.parent" as "parent" + myFunction { [weak parent = self.parent] in print(parent!.title) } + +For more information and examples of closure expressions, see Closure Expressions. + +关于闭包表达式更多信息和例子,请参见 Closure Expressions。 + +> GRAMMAR OF A CLOSURE EXPRESSION + +> 闭包表达式的语法 + +> closure-expression → {closure-signatureoptstatements} +> +> closure-signature → parameter-clausefunction-resultoptin +> +> closure-signature → identifier-listfunction-resultoptin +> +> closure-signature → capture-listparameter-clausefunction-resultoptin +> +> closure-signature → capture-listidentifier-listfunction-resultoptin +> +> closure-signature → capture-listin +> +> capture-list → [capture-specifierexpression] +> +> capture-specifier → weak | unowned | unowned(safe)| unowned(unsafe) + + +# Implicit Member Expression +# 隐式成员表达式 + +An implicit member expression is an abbreviated way to access a member of a type, such as an enumeration case or a class method, in a context where type inference can determine the implied type. It has the following form: + + +在可以判断隐藏类型的上下文中,隐式成员表达式是访问某个类型的成员的简便写法,例如在枚举或类方法中。形式如下: + + .member name + +For example: + +例子: + + var x = MyEnumeration.SomeValue + x = .AnotherValue + +> GRAMMAR OF A IMPLICIT MEMBER EXPRESSION + +> 隐式成员表达式的语法: + +> implicit-member-expression → .identifier + + +## Parenthesized Expression +## 圆括号表达式 + +A parenthesized expression consists of a comma-separated list of expressions surrounded by parentheses. Each expression can have an optional identifier before it, separated by a colon (:). It has the following form: + + +圆括号表达式由中括号包裹的一组逗号分隔的子表达式列表组成。每个子表达式前面可以有一个可选标识符,由`:`隔开。形式如下: + + (identifier 1: expression 1, identifier 2: expression 2, ...) + +Use parenthesized expressions to create tuples and to pass arguments to a function call. If there is only one value inside the parenthesized expression, the type of the parenthesized expression is the type of that value. For example, the type of the parenthesized expression (1) is Int, not (Int). + + +圆括号表达式可以用来创建元祖或给函数传参。如果圆括号表达式中只有一个值,那么这个表达式的类型则与此值相同,例如表达式`(1)`的类型为`Int`而不是`(Int)`。 + +> GRAMMAR OF A PARENTHESIZED EXPRESSION + +> 圆括号表达式的语法 + +> parenthesized-expression → (expression-element-listopt) +> +> expression-element-list → expression-element expression-element,expression-element-list +> +> expression-element → expression identifier:expression + + +## Wildcard Expression +## 通配符表达式 + +A wildcard expression is used to explicitly ignore a value during an assignment. For example, in the following assignment 10 is assigned to x and 20 is ignored: + +通配符表达式用来在赋值的时候显式地忽略某个值。比如下面的赋值语句中,`10`被传递给`x`,`20`则被忽略。 + + (x, _) = (10, 20) + // x is 10, 20 is ignored + + +> GRAMMAR OF A WILDCARD EXPRESSIO + +> 通配符表达式的语法 + +> wildcard-expression → _ + + +## Postfix Expressions +## 后缀表达式 + +Postfix expressions are formed by applying a postfix operator or other postfix syntax to an expression. Syntactically, every primary expression is also a postfix expression. + + +后缀表达式由一个表达式后面加上一个后缀操作符或其他后缀语法组成。单纯从语法上讲,每个主表达式也是一个后缀表达式。 + +The Swift standard library provides the following postfix operators: + +* ++ Increment +* -- Decrement + +swift标准库提供了如下后缀操作符: + +* ++ 自增 +* -- 自减 + +For information about the behavior of these operators, see Basic Operators and Advanced Operators. + +关于这些表达式行为的更多信息,请参见“Basic Operators and Advanced Operators.” + +> GRAMMAR OF A POSTFIX EXPRESSION + +> 后缀表达式的语法 +> +> postfix-expression → primary-expression +> +> postfix-expression → postfix-expressionpostfix-operator +> +> postfix-expression → function-call-expression +> +> postfix-expression → initializer-expression +> +> postfix-expression → explicit-member-expression +> +> postfix-expression → postfix-self-expression +> +> postfix-expression → dynamic-type-expression +> +> postfix-expression → subscript-expression +> +> postfix-expression → forced-value-expression +> +> postfix-expression → optional-chaining-expression + + +## Function Call Expression +## 函数调用表达式 + +A function call expression consists of a function name followed by a comma-separated list of the function’s arguments in parentheses. Function call expressions have the following form: + + +函数调用表达式由函数名后加圆括号组成,圆括号里面为逗号分隔的函数参数列表。形式如下: + + function name(argument value 1, argument value 2) + +The function name can be any expression whose value is of a function type. + +上面的`function name`可以是任何返回值为函数类型的表达式。 + +If the function definition includes names for its parameters, the function call must include names before its argument values separated by a colon (:). This kind of function call expression has the following form: + +如果函数声明中包含了参数名,那么函数调用时必须在参数值前加上参数名,并用分号隔开。这种函数调用表达式形式如下: + + function name(argument name 1: argument value 1, argument name 2: argument value 2) + +A function call expression can include a trailing closure in the form of a closure expression immediately after the closing parenthesis. The trailing closure is understood as an argument to the function, added after the last parenthesized argument. The following function calls are equivalent: + +函数调用表达式可以包含一个由紧跟在圆括号后面由一个闭包表达式组成的尾随闭包(`trailing closure`)。追加在圆括号后面的尾随闭包会被当做函数的参数。下面两种写法均可: + + // someFunction takes an integer and a closure as its arguments + + someFunction(x, {$0 == 13}) + + someFunction(x) {$0 == 13} + +If the trailing closure is the function’s only argument, the parentheses can be omitted. + +如果这个闭包是函数的唯一参数,那么圆括号可以省略。 + + // someFunction takes a closure as its only argument + + myData.someMethod() {$0 == 13} + + myData.someMethod {$0 == 13} + +> GRAMMAR OF A FUNCTION CALL EXPRESSION + +> 函数调用表达式语法 + +> function-call-expression → postfix-expressionparenthesized-expression + +> function-call-expression → postfix-expressionparenthesized-expressionopttrailing-closure +> +> trailing-closure → closure-expression + + +## Initializer Expression + +## 初始化函数表达式 + +An initializer expression provides access to a type’s initializer. It has the following form: + +初始化函数表达式用来给类型初始化。形式如下: + + expression.init(initializer arguments) + + +You use the initializer expression in a function call expression to initialize a new instance of a type. Unlike functions, an initializer can’t be used as a value. For example: + +你可以在函数调用表达式中使用初始化函数表达式来初始化一个类型的实例。初始化函数不像函数,它不能有返回值,例如: + + var x = SomeClass.someClassFunction // ok + + var y = SomeClass.init // error + +You also use an initializer expression to delegate to the initializer of a superclass. + +初始化函数表达式还可以用来完成对父类初始化函数的代理。 + + class SomeSubClass: SomeSuperClass { + init() { + // subclass initialization goes here + super.init() + } + } + +> GRAMMAR OF AN INITIALIZER EXPRESSION + +> 初始化函数表达式的语法 + +> initializer-expression → postfix-expression.init + + +## Explicit Member Expression +## 显式成员表达式 + +A explicit member expression allows access to the members of a named type, a tuple, or a module. It consists of a period (.) between the item and the identifier of its member. + +显示成员表达式允许我们访问已命名类型、元祖或模块的成员。它由元素和成员的标识符以及二者之间的点(`.`)组成。 + + expression.member name + +The members of a named type are named as part of the type’s declaration or extension. For example: + +对于已命名类型,成员是类型定义或扩展的一部分。例如: + + class SomeClass { + var someProperty = 42 + } + let c = SomeClass() + let y = c.someProperty // Member access + +The members of a tuple are implicitly named using integers in the order they appear, starting from zero. For example: + +对于元祖,成员通过从零开始的它们出现的顺序整数来访问。例如: + + var t = (10, 20, 30) + t.0 = t.1 + // Now t is (20, 20, 30) + +The members of a module access the top-level declarations of that module. + +对于模块,成员访问的是模块的顶级(top-level)声明。 + +> GRAMMAR OF AN EXPLICIT MEMBER EXPRESSION + +> 显示成员表达式的语法 + +> explicit-member-expression → postfix-expression.decimal-digit +> +> explicit-member-expression → postfix-expression.identifiergeneric-argument-clauseopt + + +## Postfix Self Expression +## 后缀self表达式 + +A postfix self expression consists of an expression or the name of a type, immediately followed by .self. It has the following forms: + +后缀self表达式由表达式或类名接一个`.self`组成。形式如下: + + expression.self + type.self + +The first form evaluates to the value of the expression. For example, x.self evaluates to x. + +第一种形式计算出表达式(`expression`)的值。例如`x.self`就等于`x`。 + +The second form evaluates to the value of the type. Use this form to access a type as a value. For example, because SomeClass.self evaluates to the SomeClass type itself, you can pass it to a function or method that accepts a type-level argument. + +第二种形式计算出对应类型(`type`)的值。这种形式可以将某类型作为一个值来访问。例如,由于`SomeClass.self`等于`SomeClass`本身,所以你可以将其传给一个函数或方法。 + +> GRAMMAR OF A SELF EXPRESSION + +> 后缀self表达式的语法 + +> postfix-self-expression → postfix-expression.self + + + +## Dynamic Type Expression +## 动态类型表达式 + +A dynamicType expression consists of an expression, immediately followed by .dynamicType. It has the following form: + + +动态类型(`dynamicType`)表达式由表达式接`.dynamicType`组成。形式如下: + + expression.dynamicType + +The expression can’t be the name of a type. The entire dynamicType expression evaluates to the value of the runtime type of the expression, as the following example shows: + +表达式不能是类型的名字。整个动态类型表达式计算出表达式运行时的值,参见下例: + + class SomeBaseClass { + class func printClassName() { + println("SomeBaseClass") + } + } + class SomeSubClass: SomeBaseClass { + override class func printClassName() { + println("SomeSubClass") + } + } + let someInstance: SomeBaseClass = SomeSubClass() + // someInstance is of type SomeBaseClass at compile time, but + // someInstance is of type SomeSubClass at runtime + someInstance.dynamicType.printClassName() + // prints "SomeSubClass + +> GRAMMAR OF A DYNAMIC TYPE EXPRESSION + +> 动态类型表达式的语法 + +> dynamic-type-expression → postfix-expression.dynamicType + + +## Subscript Expression +## 下标表达式 + +A subscript expression provides subscript access using the getter and setter of the corresponding subscript declaration. It has the following form: + +下标表达式提供了通过响应的下标声明来访问getter/setter方法。形式如下: + + expression[index expressions] + +To evaluate the value of a subscript expression, the subscript getter for the expression’s type is called with the index expressions passed as the subscript parameters. To set its value, the subscript setter is called in the same way. + +下标表达式可以通过传递下标参数(`index expressions`)计算getter的值,setter亦同理。 + +For information about subscript declarations, see Protocol Subscript Declaration. + +更多关于下标声明的信息,参见Protocol Subscript Declaration。 + +> GRAMMAR OF A SUBSCRIPT EXPRESSION + +> 下标表达式语法: +> +> subscript-expression → postfix-expression[expression-list] + + +## Forced-Value Expression +## 强取值表达式 + +A forced-value expression unwraps an optional value that you are certain is not nil. It has the following form: + +强取值表达式用于对非空(not `nil`)的可选值进行拆包。形式如下: + + expression! + +If the value of the expression is not nil, the optional value is unwrapped and returned with the corresponding nonoptional type. Otherwise, a runtime error is raised. + +上式中,如果一个`expression`的值不是`nil`,那么该可选值会被拆包并返回响应的类型。否则抛出运行时错误。 + +> GRAMMAR OF A FORCED-VALUE EXPRESSION +> +> 强取值表达式的语法: +> +> forced-value-expression → postfix-expression! + + +## Optional-Chaining Expression +## 可选链式表达式 + +An optional-chaining expression provides a simplified syntax for using optional values in postfix expressions. It has the following form: + +可选链式表达式提供一种在后缀表达式中使用可选值的简化的语法。形式如下: + + expression? + +On its own, the postfix ? operator simply returns the value of its argument as an optional. + +后缀`?`表达式就是简单的将所传参数作为可选值返回。 + +Postfix expressions that contain an optional-chaining expression are evaluated in a special way. If the optional-chaining expression is nil, all of the other operations in the postfix expression are ignored and the entire postfix expression evaluates to nil. If the optional-chaining expression is not nil, the value of the optional-chaining expression is unwrapped and used to evaluate the rest of the postfix expression. In either case, the value of the postfix expression is still of an optional type. + +包含可选链式表达式的后缀表达式计算起来比较特殊。如果可选链式表达式为`nil`,所有在此后缀表达式中的操作符都将被忽略,然后整个后缀表达式返回`nil`。如果不为`nil`,则可选链式表达式被拆包然后应用于后续的计算。在这两种情况下,该后缀表达式仍然是一个可选值。 + +If a postfix expression that contains an optional-chaining expression is nested inside other postfix expressions, only the outermost expression returns an optional type. In the example below, when c is not nil, its value is unwrapped and used to evaluate both .property and .performAction(), and the entire expression c?.property.performAction() has a value of an optional type. + +如果一个包含可选链式表达式的后缀表达式嵌套在其他后缀表达式中,只有最外层的返回一个可选类型。下面例子中,当`c`不为`nil`,时,它将被拆包然后用于`.property`和`.performAction()`的计算,整个表达式`c?.property.performAction() `拥有一个可选类型的值。 + + var c: SomeClass? + var result: Bool? = c?.property.performAction() + +The following example shows the behavior of the example above without using optional chaining. + +如果不使用可选链表达式,那么上面例子的代码等价于: + + if let unwrappedC = c { + result = unwrappedC.property.performAction() + } + +> GRAMMAR OF AN OPTIONAL-CHAINING EXPRESSION +> +> 可选链式表达式的语法 + +> optional-chaining-expression → postfix-expression? + From 394132ff30895a2da04250985be560c66d5db11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=9C=E8=88=9F?= Date: Sun, 22 Jun 2014 23:19:07 +0800 Subject: [PATCH 161/261] finished Properties translation --- src/chapter2/10_Properties.md | 666 ++++++++++++++++++++++++++++++++++ src/words.md | 4 +- 2 files changed, 669 insertions(+), 1 deletion(-) diff --git a/src/chapter2/10_Properties.md b/src/chapter2/10_Properties.md index e69de29..76d3e6a 100644 --- a/src/chapter2/10_Properties.md +++ b/src/chapter2/10_Properties.md @@ -0,0 +1,666 @@ +# Properties +# 属性 + +Properties associate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value. Computed properties are provided by classes, structures, and enumerations. Stored properties are provided only by classes and structures. + +属性将值与特定的类,结构体或者枚举关联起来,存储属性将常量或变量值作为实力的一部分保存起来,而计算属性则用来计算(而非存储)一个值。计算属性可以用于类,结构体和枚举,存储属性只能用于类和结构体。 + + +Stored and computed properties are usually associated with instances of a particular type. However, properties can also be associated with the type itself. Such properties are known as type properties. + +存储和计算属性通常用于特定类型的实例。不过,属性也可以用于类型本身,这样的属性被称为类属性。 + + +In addition, you can define property observers to monitor changes in a property’s value, which you can respond to with custom actions. Property observers can be added to stored properties you define yourself, and also to properties that a subclass inherits from its superclass. + +另外,可以为属性定义监听器,以监听属性值的变化,这样就可以在属性值发生变化时触发自定义操作。可以在定义存储属性的时候为其添加属性监听器,也可以为子类继承父类的属性添加监听器。 + + +## Stored Properties +## 存储属性 + +In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure. Stored properties can be either variable stored properties (introduced by the var keyword) or constant stored properties (introduced by the let keyword). +简单而言,存储属性是一个特定类型实例或结构体中的常量或变量。存储属性可以是变量存储属性(用关键词 `var` 声明),也可以是常量属性(用关键词 `let` 声明)。 + + +You can provide a default value for a stored property as part of its definition, as described in Default Property Values. You can also set and modify the initial value for a stored property during initialization. This is true even for constant stored properties, as described in Modifying Constant Properties During Initialization. + +在定义存储属性时,可以为其指定默认值,详见 Default Property Values 。在存储属性初始化过程中,依然可以设置和修改它的初始值,甚至修改常量存储属性,详见 Modifying Constant Properties During Initialization。 + + +The example below defines a structure called FixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created: + +下面的示例定义了一个名为 `FixedLengthRange` 的结构体,它表示一个整型的范围,其范围长度一旦创建不能改变: + + struct FixedLengthRange { + var firstValue: Int + let length: Int + } + var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3) + // 表示整型值的范围为 0, 1, 2 + rangeOfThreeItems.firstValue = 6 + // 修改 firstValue 后, 表示的整型值的范围为: 6, 7, 8 + +Instances of FixedLengthRange have a variable stored property called firstValue and a constant stored property called length. In the example above, length is initialized when the new range is created and cannot be changed thereafter, because it is a constant property. + +`FixedLengthRange` 的实例包含一个名为 `firstValue` 的变量存储属性和一个名为 `length` 常量存储属性。在上面的示例中, `length` 在 `FixedLengthRange` 实例创建时初始化,并且在此后不能被修改,因为它是一个常量属性。 + + +###Stored Properties of Constant Structure Instances +###存储属性与常量实例 + + +If you create an instance of a structure and assign that instance to a constant, you cannot modify the instance’s properties, even if they were declared as variable properties: + +如果你为一个结构体创建一个实例, 并且把这个实例赋值给一个常量, 那么无论这个实例的属性是否为变量, 其属性都不能被修改。 + + let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) + // this range represents integer values 0, 1, 2, and 3 + // 表示取值范围为 整数的 0, 1, 2, 3 + rangeOfFourItems.firstValue = 6 + // this will report an error, even thought firstValue is a variable property + // 尽管firstValue是变量属性, 对其赋值也会报错 + +Because rangeOfFourItems is declared as a constant (with the let keyword), it is not possible to change its firstValue property, even though firstValue is a variable property. +This behavior is due to structures being value types. When an instance of a value type is marked as a constant, so are all of its properties. + +因为 `rangeOfFourItems`通过`let`关键词声明, 所以是个常量, 故, 无论它的属性是否为变量, 都无法改变它的属性值。 所以, 当一个实例是常量类型, 那么它的所有属性也会变成常量类型。 + + +The same is not true for classes, which are reference types. If you assign an instance of a reference type to a constant, you can still change that instance’s variable properties. + +这种情况对于引用类型(类)并不适用。 如果将某个引用类型的实例赋值给一个常量, 那么依然可以修改该实例的属性。 + +###Lazy Stored Properties +###惰性存储属性 + + +A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the @lazy attribute before its declaration. + +惰性存储属性只有在首次调用时才会进行初始化。 通过在存储属性声明前加上 `@lazy` 来声明一个惰性存储属性。 + +> NOTE +You must always declare a lazy property as a variable (with the var keyword), because its initial value may not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy. + +> 注意 +在声明一个惰性存储属性时, 必须将其定义为变量(通过`var`声明)。 这样做的原因是, 在实例初始化完成前, 可能无法获得惰性属性的初始值。 相反的, 常量属性的初始值必须在实例初始化完成之前赋值,所以常量属性不能被声明为惰性属性。 + +Lazy properties are useful when the initial value for a property is dependent on outside factors whose values are not known until after an instance’s initialization is complete. Lazy properties are also useful when the initial value for a property requires complex or computationally expensive setup that should not be performed unless or until it is needed. + +当某个属性的初始化依赖于其他实例的初始化时,惰性属性是非常有用的。惰性属性在需要复杂计算和耗费时间较长的属性初始化时,也是非常有用的,因为它可以在需要时再进行计算和初始化。 + +The example below uses a lazy stored property to avoid unnecessary initialization of a complex class. This example defines two classes called DataImporter and DataManager, neither of which is shown in full: + +下面这个例子中,演示了在一个复杂类的初始化过程中,如何通过惰性存储属性来避免不必要的初始化。示例中定义了两个类:`DataImporter`, `DataManager`(代码片段)。 + + class DataImporter { + /* + DataImporter is a class to import data from an external file. + The class is assumed to take a non-trivial amount of time to initialize. + + DataImporter 是一个可以从外部文件导入数据的类 + 该类的初始化会消耗很长一段时间 + + */ + var fileName = "data.txt" + // the DataImporter class would provide data importing functionality here + // 这里是DataImporter类导入数据的代码 + } + + class DataManager { + @lazy var importer = DataImporter() + var data = String[]() + // the DataManager class would provide data management functionality here + // DataManager类数据管理功能的代码 + } + + let manager = DataManager() + manager.data += "Some data" + manager.data += "Some more data" + // the DataImporter instance for the importer property has not yet been created + // importer 实例尚未初始化 + + +The DataManager class has a stored property called data, which is initialized with a new, empty array of String values. Although the rest of its functionality is not shown, the purpose of this DataManager class is to manage and provide access to this array of String data. + +`DataManager` 类拥有一个名为 `data` 的存储属性,该属性是一个空的字符串数组。虽然剩余的功能代码没有展示出来,不过 `DataManager` 类的目的是提供管理和访问该字符串数组的功能。 + + +Part of the functionality of the DataManager class is the ability to import data from a file. This functionality is provided by the DataImporter class, which is assumed to take a non-trivial amount of time to initialize. This might be because a DataImporter instance needs to open a file and read its contents into memory when the DataImporter instance is initialized. + +`DataManager`类的一个功能是从文件中导入数据。 该功能由 `DataImporter` 类提供,需要花费很长时间进行初始化。原因是 `DataImporter` 类的实例在初始化的时候需要读取文件并将文件内容写入内存。 + +It is possible for a DataManager instance to manage its data without ever importing data from a file, so there is no need to create a new DataImporter instance when the DataManager itself is created. Instead, it makes more sense to create the DataImporter instance if and when it is first used. + +对于 `DataManager` 类来说,无论是从文件中导入了数据,都不影响它管理自己的数据,所以没必要在它自己初始化的时候就去创建 `DataManager` 实例。更好的做法是,将 `DataImporter` 实例在第一次使用的时候初始化。 + + +Because it is marked with the @lazy attribute, the DataImporter instance for the importer property is only created when the importer property is first accessed, such as when its fileName property is queried: + +因为使用了 `@lazy`,故 `DataImporter` 的实例 `importer` 只会在 `importer`的实例第一次被访问的时候才会初始化,例如访问它的 `fileName` 属性: + +println(manager.importer.fileName) +// the DataImporter instance for the importer property has now been created +//此时, `DataImporter` 的实例 `importer` 才被创建 +// prints "data.txt" + +###Stored Properties and Instance Variables + +###存储属性和实例变量 + + +If you have experience with Objective-C, you may know that it provides two ways to store values and references as part of a class instance. In addition to properties, you can use instance variables as a backing store for the values stored in a property. + +`Object-C`中类的实例对象有两种存储值和引用的方法。除了属性,还可以使用实例变量保存值。 + +Swift unifies these concepts into a single property declaration. A Swift property does not have a corresponding instance variable, and the backing store for a property is not accessed directly. This approach avoids confusion about how the value is accessed in different contexts and simplifies the property’s declaration into a single, definitive statement. All information about the property including its name, type, and memory management characteristics—is defined in a single location as part of the type’s definition. + +在`Swift`中没有实例变量,`Swift` 将这些概念统一为了属性。这样避免了在不同上下文中值的不同访问方式的混淆,并且使属性声明简单明了。所有的属性信息:名称,类型,内存管理特征都包含在类型定义中。 + +##Computed Properties + +##计算属性 + + +In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly. + +除了存储属性外,类,结构体,枚举还可以定义计算属性。计算属性不能存储值,而是通过 `getter` 方法和 `setter` 方法(可选)间接的设置其他属性和值。 + + struct Point { + var x = 0.0, y = 0.0 + } + struct Size { + var width = 0.0, height = 0.0 + } + struct Rect { + var origin = Point() + var size = Size() + var center: Point { + get { + let centerX = origin.x + (size.width / 2) + let centerY = origin.y + (size.height / 2) + return Point(x: centerX, y: centerY) + } + set(newCenter) { + origin.x = newCenter.x - (size.width / 2) + origin.y = newCenter.y - (size.height / 2) + } + } + } + var square = Rect(origin: Point(x: 0.0, y: 0.0), + size: Size(width: 10.0, height: 10.0)) + 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))") + // prints "square.origin is now at (10.0, 10.0)" + // 输出 "square.origin is now at (10.0, 10.0)" + +This example defines three structures for working with geometric shapes: + +这个示例定义了三个结构体来表示一个几何形状: + +Point encapsulates an (x, y) coordinate. +`Point` 封装了坐标(x, y)。 + +Size encapsulates a width and a height. + +`Size` 封装了宽度和高度。 + +Rect defines a rectangle by an origin point and a size. + +`Rect` 用坐标原点和大小定义了一个矩形。 + +The Rect structure also provides a computed property called center. The current center position of a Rect can always be determined from its origin and size, and so you don’t need to store the center point as an explicit Point value. Instead, Rect defines a custom getter and setter for a computed variable called center, to enable you to work with the rectangle’s center as if it were a real stored property. + +`Rect` 结构体提供了一个名为 `center` 的计算属性。矩形的中心点总是可以通过它的原点坐标和大小计算出来,所以你没有必要保存一个确切的矩形中心点的值。这里的 `Rect` 为一个名为 `center` 的计算属性定义了自定义的 `getter` 和 `setter` 方法,以此来设置矩形的中心点。 + +The preceding example creates a new Rect variable called square. The square variable is initialized with an origin point of (0, 0), and a width and height of 10. This square is represented by the blue square in the diagram below. + +例子中接下来创建了一个名为 `square` 的 `Rect` 实例,`point` 初始值为(0,0), `width` 和 `height` 都是10,在下图中用蓝色正方形表示。 + +The square variable’s center property is then accessed through dot syntax (square.center), which causes the getter for center to be called, to retrieve the current property value. Rather than returning an existing value, the getter actually calculates and returns a new Point to represent the center of the square. As can be seen above, the getter correctly returns a center point of (5, 5). + +然后通过点运算符(`square.center`)访问了 `square` 实例的 `center` 属性,此时会触发 `center` 的 `getter` 方法,并返回当前的属性值。和直接返回值不同, `getter` 方法会计算并返回最新的属性值。从上面的代码可以看出, `getter` 方法正确的返回了中心点 `(5, 5)`。 + + +The center property is then set to a new value of (15, 15), which moves the square up and to the right, to the new position shown by the orange square in the diagram below. Setting the center property calls the setter for center, which modifies the x and y values of the stored origin property, and moves the square to its new position. + +接着为 `center` 属性设置了新值 `(15, 15)`,在下图中可以看出 `square` 向右上移动到了一个新的位置(橙色区域)。在设置 `center` 属性时调用了它的 `setter` 方法,修改了 `origin` 的 `x,y`值,并且改变了 `square` 的位置。 + +![Alt text](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/computedProperties_2x.png) + + +###Shorthand Setter Declaration + +###Setter声明简写 + +If a computed property’s setter does not define a name for the new value to be set, a default name of newValue is used. Here’s an alternative version of the Rect structure, which takes advantage of this shorthand notation: + +如果没有给属性的 `setter` 方法的新值指定名称,那么可以使用默认值 `newValue` 。下面是 `Rect` 结构体的简写形式: + + struct AlternativeRect { + var origin = Point() + var size = Size() + var center: Point { + get { + let centerX = origin.x + (size.width / 2) + let centerY = origin.y + (size.height / 2) + return Point(x: centerX, y: centerY) + } + set { + origin.x = newValue.x - (size.width / 2) + origin.y = newValue.y - (size.height / 2) + } + } + } + + +###Read-Only Computed Properties + +###只读计算属性 + +A computed property with a getter but no setter is known as a read-only computed property. A read-only computed property always returns a value, and can be accessed through dot syntax, but cannot be set to a different value. + +只有 `getter` 没有 `setter` 的计算属性是只读计算属性。只读计算属性可以通过点操作符访问,但不能为其设置其他值。 + + +> NOTE + +> You must declare computed properties—including read-only computed properties—as variable properties with the var keyword, because their value is not fixed. The let keyword is only used for constant properties, to indicate that their values cannot be changed once they are set as part of instance initialization. + + +> 注意 + +> 必须使用 `var` 关键词定义计算属性,包括只读计算属性,因为它们的值是可能改变的。 `let` 关键词只用于常量属性,其值在初始化后不可改变。 + +必须使用var关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。 + + +You can simplify the declaration of a read-only computed property by removing the get keyword and its braces: + +只读计算属性的声明可以去掉get关键词和花括号: + + struct Cuboid { + var width = 0.0, height = 0.0, depth = 0.0 + var volume: Double { + return width * height * depth + } + } + + let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0) + println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") + // prints "the volume of fourByFiveByTwo is 40.0" + // 输出 "the volume of fourByFiveByTwo is 40.0" + +This example defines a new structure called Cuboid, which represents a 3D rectangular box with width, height, and depth properties. This structure also has a read-only computed property called volume, which calculates and returns the current volume of the cuboid. It doesn’t make sense for volume to be settable, because it would be ambiguous as to which values of width, height, and depth should be used for a particular volume value. Nonetheless, it is useful for a Cuboid to provide a read-only computed property to enable external users to discover its current calculated volume. + +这个示例定义了一个名为 `Cuboid` 的结构体,表示一个3D的立方体,有 `width`,`height`,`depth`等属性。它还有一个名为 `volume` 的只读计算属性用来计算并返回 `cuboid` 当前的体积。我们没有必要去设置 `volume` 的值,因为 `volume` 的值可以通过 `width`,`height`,`depth`计算出来。所以比较合适的做法是,提供一个只读计算属性让用户可以获得当前的 `volume` 。 + + +###Property Observers + +###属性观察者 + +Property observers observe and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value. + +属性观察者用来观察并响应属性值的变化。在为属性赋值时,无论新值是否与原值相同,都会触发属性的观察者。 + +You can add property observers to any stored properties you define, apart from lazy stored properties. You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass. Property overriding is described in Overriding. + +可以为除了惰性属性外的其他任何存储属性定义观察者。通过属性重写,可以在子类中为它的父类属性(无论是存储或是计算属性)添加观察者。属性重写在重写一章有详细介绍。 + + +> NOTE +> +> You don’t need to define property observers for non-overridden +> computed properties, because you can observe and respond to changes to +> their value from directly within the computed property’s setter. + +> 注意 +> +> 不需要为非重写计算属性定义观察者,因为你可以直接使用计算属性的`setter`来完成。 + + +You have the option to define either or both of these observers on a property: +* willSet is called just before the value is stored. +* didSet is called immediately after the new value is stored. + +可以通过两种方式为属性定义观察者: +* `willSet` 在值发生改变之前调用 +* `didSet` 在值发生改变之后调用 + + +If you implement a willSet observer, it is passed the new property value as a constant parameter. You can specify a name for this parameter as part of your willSet implementation. If you choose not to write the parameter name and parentheses within your implementation, the parameter will still be made available with a default parameter name of newValue. + +`willSet` 会将新属性值作为常量参数,并且可以为该常量参数指定名称。如果没有为该参数指定名称,那么会使用默认的参数名称 `newValue`。 + + +Similarly, if you implement a didSet observer, it will be passed a constant parameter containing the old property value. You can name the parameter if you wish, or use the default parameter name of oldValue. + +与 `willSet` 类似,`didSet` 会将原属性值作为常量参数。同样可以为参数指定名称或者使用默认值 `oldValue`。 + +> NOTE +> +> willSet and didSet observers are not called when a property is first +> initialized. They are only called when the property’s value is set +> outside of an initialization context. + +> 注意 +> +> `willSet` 和 `didSet` 在属性初始化时不会被调用。 + +Here’s an example of willSet and didSet in action. The example below defines a new class called StepCounter, which tracks the total number of steps that a person takes while walking. This class might be used with input data from a pedometer or other step counter to keep track of a person’s exercise during their daily routine. + +这里有一个使用了 `willSet` 和 `didSet` 的示例。示例中定义了一个名为 `StepCounter` 的类,用来统计当人步行时的总步数,通过使用计步器等装置可以用这个类追踪人在日常工作中的运动量。 + + class StepCounter { + var totalSteps: Int = 0 { + willSet(newTotalSteps) { + println("About to set totalSteps to \(newTotalSteps)") + } + didSet { + if totalSteps > oldValue { + println("Added \(totalSteps - oldValue) steps") + } + } + } + } + let stepCounter = StepCounter() + stepCounter.totalSteps = 200 + // About to set totalSteps to 200 + // Added 200 steps + // 输出 About to set totalSteps to 200 + // 输出 Added 200 steps + stepCounter.totalSteps = 360 + // About to set totalSteps to 360 + // Added 160 steps + // 输出 About to set totalSteps to 360 + // 输出 Added 160 steps + stepCounter.totalSteps = 896 + // About to set totalSteps to 896 + // Added 536 steps + // 输出 About to set totalSteps to 896 + // 输出 Added 536 steps + +The StepCounter class declares a totalSteps property of type Int. This is a stored property with willSet and didSet observers. + +`StepCounter`定义了一个 `int` 类型的属性 `totalSteps`。 `totalSteps` 包含了两个观察者`willSet`和`didSet`。 + + +The willSet and didSet observers for totalSteps are called whenever the property is assigned a new value. This is true even if the new value is the same as the current value. + +当`totalSteps`的值改变时(不论新值是否与原值相同),`willSet` 和 `didSet` 都会被调用。 + + +This example’s willSet observer uses a custom parameter name of newTotalSteps for the upcoming new value. In this example, it simply prints out the value that is about to be set. + +示例中的`willSet`使用了一个名为`newTotalSteps`的参数接收新值。在这个例子中只是简单的将新值输出。 + + +The didSet observer is called after the value of totalSteps is updated. It compares the new value of totalSteps against the old value. If the total number of steps has increased, a message is printed to indicate how many new steps have been taken. The didSet observer does not provide a custom parameter name for the old value, and the default name of oldValue is used instead. + +`didSet`观察者会在`totalSteps`的值被修改后调用。它将`totalSteps`的新值与原值做比较,如果新值大于原值,则会输出新增了多少步。`didSet`观察者没有指定参数名,所以使用默认参数名`oldValue`。 + + +> NOTE +> +> If you assign a value to a property within its own didSet observer, +> the new value that you assign will replace the one that was just set. + + +> 注意 + +> 如果在`didSet`中给属性设置新值,那么新值会替换刚刚设置的值。 + +##Global and Local Variables + +##全局变量和局部变量 + + +The capabilities described above for computing and observing properties are also available to global variables and local variables. Global variables are variables that are defined outside of any function, method, closure, or type context. Local variables are variables that are defined within a function, method, or closure context. + +上面关于属性的计算和观察功能对于全局变量和局部变量同样适用。全局变量定义在所有函数,方法,闭包,类型之外。局部变量定义在函数,方法或闭包内部。 + + +The global and local variables you have encountered in previous chapters have all been stored variables. Stored variables, like stored properties, provide storage for a value of a certain type and allow that value to be set and retrieved. + +在前面的章节中全局和局部变量都是存储变量,类似于存储属性,它为特定类型的值提供存储空间,并允许对其进行读写。 + + +However, you can also define computed variables and define observers for stored variables, in either a global or local scope. Computed variables calculate rather than store a value, and are written in the same way as computed properties. + +另外,还可以在全局或局部作用域中定义计算变量,或者为存储变量定义观察者。计算变量用来计算而非存储一个值,声明方式和计算属性一样。 + + +> NOTE +> +> Global constants and variables are always computed lazily, in a +> similar manner to Lazy Stored Properties. Unlike lazy stored +> properties, global constants and variables do not need to be marked +> with the @lazy attribute. +> +> Local constants and variables are never computed lazily. + + +> 注意 +> +> 和惰性存储属性的方式类似,全局常量和变量总是延迟计算的。不同的是,全局常量和变量不需要使用`@lazy`属性进行声明。 +> +> 局部常量和变量则绝不会延迟计算。 + + +##Type Properties + +##类型属性 + + +Instance properties are properties that belong to an instance of a particular type. Every time you create a new instance of that type, it has its own set of property values, separate from any other instance. + +实例属性属于一个特定类型的实例。每次创建该类型的实例,它都拥有自己独立的一组属性,与其他实例对象无关。 + + +You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties. + +还可以定义属于类型自身的属性。不论该类型有多少实例,这些属性都只有一份。这种属性被称为类型属性。 + + +Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use (like a static constant in C), or a variable property that stores a value that is global to all instances of that type (like a static variable in C). + +类型属性用于定义所有特定的类型实例都可以使用的值,比如所有实例都可以使用同一个常量属性(类似于`C`中的静态常量),或者就像所有的实例都可以使用全局变量属性(类似于`C`中的静态常量)。 + + +For value types (that is, structures and enumerations), you can define stored and computed type properties. For classes, you can define computed type properties only. + +对于值类型(结构和枚举),可以定义存储和计算类型的属性。对于类,则只能定义计算类型的属性。 + + +Stored type properties for value types can be variables or constants. Computed type properties are always declared as variable properties, in the same way as computed instance properties. + +值类型的存储类型属性可以是变量和常量。计算类型属性和计算实例属性相同,通常声明为变量属性。 + +> NOTE +> +> Unlike stored instance properties, you must always give stored type +> properties a default value. This is because the type itself does not +> have an initializer that can assign a value to a stored type property +> at initialization time. + +> 注意 +> +> 与存储实例属性不同,必须为存储类型属性定义默认值。原因是类型本身没有一个可以在初始化时为类型属性赋值的构造器。 + + +###Type Property Syntax + +###类型属性语法 + + +In C and Objective-C, you define static constants and variables associated with a type as global static variables. In Swift, however, type properties are written as part of the type’s definition, within the type’s outer curly braces, and each type property is explicitly scoped to the type it supports. + +在`C`和`Objective-C`中,只能使用全局静态变量来定义依赖于某个属性的变量或常量。但在`Swift`中,类型属性可以作为类型定义的一部分,它的作用域也在类型的范围内。 + + +You define type properties for value types with the static keyword, and type properties for class types with the class keyword. The example below shows the syntax for stored and computed type properties: + +使用`static`关键词定义值类型的类型属性,`class`类型的类型属性用关键词`class`声明。下面的示例演示了存储类型属性和计算类型属性的语法: + + + struct SomeStructure { + static var storedTypeProperty = "Some value." + static var computedTypeProperty: Int { + // return an Int value here + // 这里将返回一个`Int`的值 + } + } + enum SomeEnumeration { + static var storedTypeProperty = "Some value." + static var computedTypeProperty: Int { + // return an Int value here + // 这里将返回一个`Int`的值 + } + } + class SomeClass { + class var computedTypeProperty: Int { + // return an Int value here + // 这里将返回一个`Int`的值 + } + } + + +> NOTE +> +> The computed type property examples above are for read-only computed +> type properties, but you can also define read-write computed type +> properties with the same syntax as for computed instance properties. + +注意 + +上面的计算类型属性的示例都是只读的,仍然可以定义可读写的计算类型属性。 + + +###Querying and Setting Type Properties + +###查询和设置类型属性 + + +Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type. For example: + +就像实例属性,类型属性通过点操作符查询和设置。不过,类型属性的是通过类型自身查询和设置,而非类型的实例: + + println(SomeClass.computedTypeProperty) + // prints "42" + // 输出 "42" + + println(SomeStructure.storedTypeProperty) + // prints "Some value." + // 输出 "Some value." + SomeStructure.storedTypeProperty = "Another value." + println(SomeStructure.storedTypeProperty) + // prints "Another value." + // 输出 "Another value." + +The examples that follow use two stored type properties as part of a structure that models an audio level meter for a number of audio channels. Each channel has an integer audio level between 0 and 10 inclusive. + +下面的示例定义了一个结构体和两个类型属性来为声道音量建模。每一个声道的音量范围是0到10。 + + +The figure below illustrates how two of these audio channels can be combined to model a stereo audio level meter. When a channel’s audio level is 0, none of the lights for that channel are lit. When the audio level is 10, all of the lights for that channel are lit. In this figure, the left channel has a current level of 9, and the right channel has a current level of 7: + +下图演示了如何将两个声道合并为一个立体声道。当某个声道的音量值是0时,所有灯都不会亮。当音量值是10时,所有灯都会亮起。下图中,左侧的音量值为9,右侧的音量值为7: + + +![Alt text](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/staticPropertiesVUMeter_2x.png) + +The audio channels described above are represented by instances of the AudioChannel structure: + +上面的声道通过`AudioChannel`的结构体实例表示如下: + + struct AudioChannel { + static let thresholdLevel = 10 + static var maxInputLevelForAllChannels = 0 + var currentLevel: Int = 0 { + didSet { + if currentLevel > AudioChannel.thresholdLevel { + // cap the new audio level to the threshold level + // 将音量值设置为最大值 + currentLevel = AudioChannel.thresholdLevel + } + if currentLevel > AudioChannel.maxInputLevelForAllChannels { + // store this as the new overall maximum input level + // 将音量值设置为当前值 + AudioChannel.maxInputLevelForAllChannels = currentLevel + } + } + } + } + +The AudioChannel structure defines two stored type properties to support its functionality. The first, thresholdLevel, defines the maximum threshold value an audio level can take. This is a constant value of 10 for all AudioChannel instances. If an audio signal comes in with a higher value than 10, it will be capped to this threshold value (as described below). + +`AudioChannel`定义了两个存储属性。首先,定义了音量最大值`thresholdLevel`,它是一个对所有实例可见的常量值。如果音量大于10,那么就取上限值10。 + + +The second type property is a variable stored property called maxInputLevelForAllChannels. This keeps track of the maximum input value that has been received by any AudioChannel instance. It starts with an initial value of 0. + +第二个类型属性是一个名为`maxInputLevelForAllChannels`的变量存储属性,用来表示所有实例的最大音量值。初始值为0。 + + +The AudioChannel structure also defines a stored instance property called currentLevel, which represents the channel’s current audio level on a scale of 0 to 10. + +`AudioChannel`结构体还定义了一个实例属性`currentLevel`,用来表示当前声道的音量值,取值0到10。 + + +The currentLevel property has a didSet property observer to check the value of currentLevel whenever it is set. This observer performs two checks: + + +`currentLevel`的值在每次设置时都会通过`didSet`进行两种检查: + +* If the new value of currentLevel is greater than the allowed thresholdLevel, the property observer caps currentLevel to thresholdLevel. +* If the new value of currentLevel (after any capping) is higher than any value previously received by any AudioChannel instance, the property observer stores the new currentLevel value in the maxInputLevelForAllChannels static property. + +* 如果`currentLevel`的新值大于允许的最大值`thresholdLevel`,则属性监听器将`currentLevel`设置为`thresholdLevel`。 +* 如果`currentLevel`的新值大于之前所有`AudioChannel`实例的值。那么属性监听器会将新值保存在静态属性`maxInputLevelForAllChannels`中。 + + +> NOTE +> +> In the first of these two checks, the didSet observer sets +> currentLevel to a different value. This does not, however, cause the +> observer to be called again. + +> 注意 +> +> 在第一次检查过程中,`didSet`监听器将`currentLevel`设置为了不同的值,但此时不会再次调用属性监听器。 + + +You can use the AudioChannel structure to create two new audio channels called leftChannel and rightChannel, to represent the audio levels of a stereo sound system: + +可以使用`AudioChannel`创建两个声道实例:`leftChannel`和`rightChannel`: + + var leftChannel = AudioChannel() + var rightChannel = AudioChannel() + +If you set the currentLevel of the left channel to 7, you can see that the maxInputLevelForAllChannels type property is updated to equal 7: + + +如果将`currentLevel`的左声道的值置为7,则可以看到类型属性`maxInputLevelForAllChannels`也更新为了7: + + leftChannel.currentLevel = 7 + println(leftChannel.currentLevel) + // prints "7" + // 输出 "7" + println(AudioChannel.maxInputLevelForAllChannels) + // print "7" + // 输出 "7" + +If you try to set the currentLevel of the right channel to 11, you can see that the right channel’s currentLevel property is capped to the maximum value of 10, and the maxInputLevelForAllChannels type property is updated to equal 10: + +如果想将`currentLevel`的右声道设置为11,你会发现右声道的`currentLevel`值被设置为了10,同时`maxInputLevelForAllChannels` 也更新为10。 + + + rightChannel.currentLevel = 11 + println(rightChannel.currentLevel) + // prints "10" + // 输出 "10" + println(AudioChannel.maxInputLevelForAllChannels) + // prints "10" + // 输出 "10" \ No newline at end of file diff --git a/src/words.md b/src/words.md index cb4ca6e..83597b1 100644 --- a/src/words.md +++ b/src/words.md @@ -1 +1,3 @@ -Class - 类 - Classes, structures, and enumerations can define subscripts \ No newline at end of file +Class - 类 - Classes, structures, and enumerations can define subscripts +as described in - 详见 - You can provide a default value for a stored property as part of its definition, as described in Default Property Values. +example - 示例 - The example below defines a structure called FixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created From cd9848c0a9c4e3802a9631874cf6d180a52dd51b Mon Sep 17 00:00:00 2001 From: Adams Date: Mon, 23 Jun 2014 00:36:25 +0800 Subject: [PATCH 162/261] Update 21_Protocols.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改格式 --- src/chapter2/21_Protocols.md | 854 ++++++++++++++++++++++++++++++++++- 1 file changed, 853 insertions(+), 1 deletion(-) diff --git a/src/chapter2/21_Protocols.md b/src/chapter2/21_Protocols.md index 33fc849..a9fcca5 100644 --- a/src/chapter2/21_Protocols.md +++ b/src/chapter2/21_Protocols.md @@ -1 +1,853 @@ -##协议 +#Protocols +A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol doesn’t actually provide an implementation for any of these requirements—it only describes what an implementation will look like. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol. + + +#协议 + +一个协议(protocol)定义了适合特定的任务或功能的方法、属性和其他需求。协议并不提供这些需求的实现,只描述了这个实现应该是怎样的。 + +协议能够被类(class),结构体(structure),枚举(enumeration)适配(adopted),同时,这些类型如果了满足一个协议需求,则被称为遵循(conform to)协议 + +Protocols can require that conforming types have specific instance properties, instance methods, type methods, operators, and subscripts. + +协议可以要求遵循(conforming)的类型有特定的实例属性(instance properties),实例方法(instance methods),类型方法(type methods),操作符(operators)和下标(subscripts)。 + + +##Protocol Syntax +##协议语法 +You define protocols in a very similar way to classes, structures, and enumerations: + +定义协议,与定义类,结构体,枚举的方式非常相似,如下所示: + + protocol SomeProtocol { + // protocol definition goes here + } + +Custom types state that they adopt a particular protocol by placing the protocol’s name after the type’s name, separated by a colon, as part of their definition. Multiple protocols can be listed, and are separated by commas: +在类型名称后添加协议名称,并以冒号`:`分割,表示自定义类型(Custom types)适配一个特定协议;实现多个协议时,各协议之间用逗号`,`分隔,如下所示: + + struct SomeStructure: FirstProtocol, AnotherProtocol { + // structure definition goes here + } +If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma: +若某个类有父类,要把父类放在所有其适配的协议之前,且用逗号`,`分割,如下所示: + + class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol { + // class definition goes here + } + +Property Requirements +##属性要求 + +A protocol can require any conforming type to provide an instance property or type property with a particular name and type. The protocol doesn’t specify whether the property should be a stored property or a computed property—it only specifies the required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable. + +协议可以要求任何遵循(conforming)类型,提供一个特定名称和类型的实例属性(instance property)或类型属性(type property)。协议不指定属性是存储型属性(stored property)还是计算型属性(calculate property)。 +协议同时指定了每个属性是否是可读(gettable)或可读写(gettable and settable) + + +If a protocol requires a property to be gettable and settable, that property requirement cannot be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for it also to be settable if this is useful for your own code. +如果协议要求属性可读写(gettable and settable),那常量存储属性(constant stored property)或者只读计算属性(read-only computed property)都无法满足此要求。如果协议只要求属性可读(gettable),那任何类型的属性都满足这个要求,即使这些属性是可写(settable)的。 + +Property requirements are always declared as variable properties, prefixed with the var keyword. Gettable and settable properties are indicated by writing { get set } after their type declaration, and gettable properties are indicated by writing { get }. + +协议里的属性要求,通常都是通过使用`var`关键字来声明的变量属性。 +在类型声明之后用{ get set }表示属性为可读写的。{ get }表示属性为可读的。 + + protocol SomeProtocol { + var mustBeSettable: Int { get set } + var doesNotNeedToBeSettable: Int { get } + } + +Always prefix type property requirements with the class keyword when you define them in a protocol. This is true even though type property requirements are prefixed with the static keyword when implemented by a structure or enumeration: + +当你在一个协议中定义一个某种类型的属性要求,总要前置`class` 关键字。同样某类型属性要求使用`static`关键字前缀,来定义结构体(structure)或枚举类型(enumeration) + +> 这样翻译正确么? + + protocol AnotherProtocol { + class var someTypeProperty: Int { get set } + } + +Here’s an example of a protocol with a single instance property requirement: + +下面是协议的一个例子,这个协议只有一个实例属性(instance property)要求: + + + protocol FullyNamed { + var fullName: String { get } + } + +The FullyNamed protocol defines any kind of thing that has a fully-qualified name. It doesn’t specify what kind of thing it must be—it only specifies that the thing must be able to provide a full name for itself. It specifies this requirement by stating that any FullyNamed type must have a gettable instance property called fullName, which is of type String. + +`FullyNamed`协议可以定义任何需要一个完整`name`的类型(方法,属性或者其他需求)。这个协议并不指定什么,只有一个需求:这个类型本身必须提供一个完整的名称。这个需求通过声明一个`String`类型的实例属性`fullName`,且这个属性必须是可读的(gettable)来指定。 + + + +Here’s an example of a simple structure that adopts and conforms to the FullyNamed protocol: + +下面的例子中,一个简单的结构体适配且遵循`FullyNamed`协议 + + struct Person: FullyNamed { + var fullName: String + } + let john = Person(fullName: "John Appleseed") + // john.fullName is "John Appleseed" + +This example defines a structure called Person, which represents a specific named person. It states that it adopts the FullyNamed protocol as part of the first line of its definition. +这个例子中定义了一个名为`Person`的结构体,代表一个有名字的人。它在第一行的结构体定义中,声明了其适配`FullyNamed`协议。 + +Each instance of Person has a single stored property called fullName, which is of type String. This matches the single requirement of the FullyNamed protocol, and means that Person has correctly conformed to the protocol. (Swift reports an error at compile-time if a protocol requirement is not fulfilled.) + +每个`Person`实例都有一个单独存储的,`String`类型的属性`fullName`。拥有这个属性代表满足了`FullyNamed`协议的要求,这意味着`Person`遵循协议。(在编译时如果不满足协议要求,swift会报告一个错误)。 + + +Here’s a more complex class, which also adopts and conforms to the FullyNamed protocol: +下面有一个更复杂的类,同样适配且遵循`FullyNamed`协议 + + class Starship: FullyNamed { + var prefix: String? + var name: String + init(name: String, prefix: String? = nil) { + self.name = name + self.prefix = prefix + } + var fullName: String { + return (prefix ? prefix! + " " : "") + name + } + } + var ncc1701 = Starship(name: "Enterprise", prefix: "USS") + // ncc1701.fullName is "USS Enterprise" + +This class implements the fullName property requirement as a computed read-only property for a starship. Each Starship class instance stores a mandatory name and an optional prefix. The fullName property uses the prefix value if it exists, and prepends it to the beginning of name to create a full name for the starship. +这个类提供了`fullName`属性,这个属性是`starship`这个类的一个只读的计算属性。 +每个`starship`类的实例存储一个强制性的名称和一个可选的前缀。当存在前缀时,`fullName`属性会把前缀添加到名称前面,从而创建了一个`starship`的全名。 + + +Method Requirements + +Protocols can require specific instance methods and type methods to be implemented by conforming types. These methods are written as part of the protocol’s definition in exactly the same way as for normal instance and type methods, but without curly braces or a method body. Variadic parameters are allowed, subject to the same rules as for normal methods. + + + +方法需求 + +若某种类型遵循协议,协议可以要求指定特定的实例方法和类型方法。这些方法作为协议定义的一部分,跟通常定义实例与类型方法的途径完全一样,但不需要书写大括号或方法的主体。方法允许含有可变参数,且与通常的方法遵循同样的规则。 + +NOTE + +Protocols use the same syntax as normal methods, but are not allowed to specify default values for method parameters. + +注意 + +协议与通常的方法语法相同,但不允许指定方法中参数的默认值 + +As with type property requirements, you always prefix type method requirements with the class keyword when they are defined in a protocol. This is true even though type method requirements are prefixed with the static keyword when implemented by a structure or enumeration: + + protocol SomeProtocol { + class func someTypeMethod() + } + +当你在一个协议中定义一个某种类型的方法要求,要前置`class` 关键字。同样某类型方法要求使用`static`关键字前缀,来定义结构体(structure)或枚举类型(enumeration) + +The following example defines a protocol with a single instance method requirement: +下面的例子中,定义了一个协议,协议要求一个实例方法。 + + protocol RandomNumberGenerator { + func random() -> Double + } +This protocol, RandomNumberGenerator, requires any conforming type to have an instance method called random, which returns a Double value whenever it is called. (Although it is not specified as part of the protocol, it is assumed that this value will be a number between 0.0 and 1.0 inclusive.) + +RandomNumberGenerator,该协议要求任何遵循协议的类型调用一个名为random的实例方法,这个方法无论何时调用,都会返回一个Double类型的值。(这个值在0.0与1.0之间,这一点没有在协议中指出)。 + + +The RandomNumberGenerator protocol does not make any assumptions about how each random number will be generated—it simply requires the generator to provide a standard way to generate a new random number. + +Here’s an implementation of a class that adopts and conforms to the RandomNumberGenerator protocol. This class implements a pseudorandom number generator algorithm known as a linear congruential generator: + + RandomNumberGenerator协议不会描述如何建立一个随机数,只需要指定一个随机数生成器,从而提供一种标准的方式来生成一个新随机数。 +   + 下面是一个类的实现,遵循RandomNumberGenerator协议。这个类实现了一种伪随机数发生器算法,称为线性同余(linear congruential)发生器: + + + class LinearCongruentialGenerator: RandomNumberGenerator { + var lastRandom = 42.0 + let m = 139968.0 + let a = 3877.0 + let c = 29573.0 + func random() -> Double { + lastRandom = ((lastRandom * a + c) % m) + return lastRandom / m + } + } + let generator = LinearCongruentialGenerator() + println("Here's a random number: \(generator.random())") + // prints "Here's a random number: 0.37464991998171" + println("And another one: \(generator.random())") + // prints "And another one: 0.729023776863283" + +Mutating Method Requirements + +突变方法要求 + +It is sometimes necessary for a method to modify (or mutate) the instance it belongs to. For instance methods on value types (that is, structures and enumerations) you place the mutating keyword before a method’s func keyword to indicate that the method is allowed to modify the instance it belongs to and/or any properties of that instance. This process is described in Modifying Value Types from Within Instance Methods. + +有时,实例的一个方法需要修改(或突变)实例的类型。对值类型(value types)(即结构体和枚举类型)的实例方法中,使用`mutating`关键字,写在方法的函数关键字`fun`前面,来表明实例中该方法允许修改其类型及任何属性。这个过程在 `在实例方法中修改值类型`章节中有详细的描述。 + +If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement. + +如果你定义的协议中,某个实例适配此协议,而实例方法需要改变其类型,协议定义时要在此方法前加上关键字`mutating`。这样可以让结构体及枚举类型适配协议,且满足实例方法的需求。 + +NOTE +注意 +If you mark a protocol instance method requirement as mutating, you do not need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations. + + +如果你在一个协议中实现的突变方法是为一个类服务的,不需要为其加上mutating关键字。 +mutating关键字只用在结构体与枚举类型中。 + + +The example below defines a protocol called Togglable, which defines a single instance method requirement called toggle. As its name suggests, the toggle method is intended to toggle or invert the state of any conforming type, typically by modifying a property of that type. +下面的例子中定义了一个togglable协议,包含一个名为togger的突变实例方法。正如名称所表达的,适配此协议的某实例中,toggle方法通常会通过改变实例的某个属性,来切换或恢复其类型。 + +The toggle method is marked with the mutating keyword as part of the Togglable protocol definition, to indicate that the method is expected to mutate the state of a conforming instance when it is called: +toggle方法前面加上了mutating关键字,作为Togglabel协议定义的一部分,则表示一个适配toggleabel协议的实例中,这个方法会在调用时改变实例的类型。 + + protocol Togglable { + mutating func toggle() + } + +If you implement the Togglable protocol for a structure or enumeration, that structure or enumeration can conform to the protocol by providing an implementation of the toggle method that is also marked as mutating. + +当你提供的枚举或结构体遵循Togglabl协议时,需要提供一个带有`mutating`前缀的toggle方法。 + + +The example below defines an enumeration called OnOffSwitch. This enumeration toggles between two states, indicated by the enumeration cases On and Off. The enumeration’s toggle implementation is marked as mutating, to match the Togglable protocol’s requirements: + + enum OnOffSwitch: Togglable { + case Off, On + mutating func toggle() { + switch self { + case Off: + self = On + case On: + self = Off + } + } + } + var lightSwitch = OnOffSwitch.Off + lightSwitch.toggle() + // lightSwitch is now equal to .On +Protocols as Types +协议类型 + +Protocols do not actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use in your code. +尽管协议本身并不实现任何功能,但协议可以作为完整的类型来使用。 +Because it is a type, you can use a protocol in many places where other types are allowed, including: +你可以把协议类型用在其他类型适用的场景里,比如: + +As a parameter type or return type in a function, method, or initializer + +在函数,方法或构造方法中作为形参类型(parameter type)或返回值类型(return type) +As the type of a constant, variable, or property +作为常量、变量或属性这三种类型之一 +As the type of items in an array, dictionary, or other container +作为数组,字典或其他容器中的元素类型 + +NOTE +注意 +Because protocols are types, begin their names with a capital letter (such as FullyNamed and RandomNumberGenerator) to match the names of other types in Swift (such as Int, String, and Double). +注意: 协议是一种类型,因此协议类型的名称应与Swift中其他类型(Int,Double,String)的写法相同,每一个单字的首字母都采用大写字母(大驼峰写法) + +Here’s an example of a protocol used as a type: +下面的例子中,协议被当作类型使用: + + class Dice { + let sides: Int + let generator: RandomNumberGenerator + init(sides: Int, generator: RandomNumberGenerator) { + self.sides = sides + self.generator = generator + } + func roll() -> Int { + return Int(generator.random() * Double(sides)) + 1 + } + } +This example defines a new class called Dice, which represents an n-sided dice for use in a board game. Dice instances have an integer property called sides, which represents how many sides they have, and a property called generator, which provides a random number generator from which to create dice roll values. +例子中定义了一个Dice类,用来表示桌游中的拥有N个面的骰子。Dice的实例包含sides和generator两个属性,前者是整型(integer),用来表示骰子有几个面,后者提供了一个随机数生成器,来表示骰子掷出的值。 + +The generator property is of type RandomNumberGenerator. Therefore, you can set it to an instance of any type that adopts the RandomNumberGenerator protocol. Nothing else is required of the instance you assign to this property, except that the instance must adopt the RandomNumberGenerator protocol. +generator属性的类型为RandomNumberGenerator,因此任何类型,若适配RandomNumberGenerator协议,其实例都可以赋值给generator,除此以外没有其他要求。 + +Dice also has an initializer, to set up its initial state. This initializer has a parameter called generator, which is also of type RandomNumberGenerator. You can pass a value of any conforming type in to this parameter when initializing a new Dice instance. +Dice类也包含一个构造方法,用于设置其初始状态。这个方法包含一个同样是RandomNumberGenerator类型的参数generator。在构造一个新的Dice的实例时,可以传入任何遵循RandomNumberGenerator协议的类型作为generator。 + +Dice provides one instance method, roll, which returns an integer value between 1 and the number of sides on the dice. This method calls the generator’s random method to create a new random number between 0.0 and 1.0, and uses this random number to create a dice roll value within the correct range. Because generator is known to adopt RandomNumberGenerator, it is guaranteed to have a random method to call. +Dice类提供了一个实例方法,roll,此方法会返回一个整型值,介于1和骰子面的数量之间。这个方法调用generator的随机�数方法来创建一在0.0和1.0之间的随机数,并使用这个随机数来确保骰子的滚动值在正确的范围内。因为generator适配RandomNumberGenerator协议,因此它可以保证有一个random方法供调用。 + +Here’s how the Dice class can be used to create a six-sided dice with a LinearCongruentialGenerator instance as its random number generator: + +下面的例子中,展示了如何使用线性同余发生器(LinearCongruentialGenerator)的实例作为随机数生成器,从而创建一个六面的骰子: + + + var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator()) + for _ in 1...5 { + println("Random dice roll is \(d6.roll())") + } + // Random dice roll is 3 + // Random dice roll is 5 + // Random dice roll is 4 + // Random dice roll is 5 + // Random dice roll is 4 + +Delegation +代理 +Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source. +代理(Delegation)是一种设计模式,它允许类或结构体将一些他们负责的功能转交(代理)给其他类型的实例。 +委托模式的实现需要定义一个协议,这个协议封装了那些需要被代理的功能,而一个遵循此协议的实例则拥有这些功能 + +The example below defines two protocols for use with dice-based board games: +下面的例子中定义了两个基于骰子游戏的协议: + + protocol DiceGame { + var dice: Dice { get } + func play() + } + protocol DiceGameDelegate { + func gameDidStart(game: DiceGame) + func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) + func gameDidEnd(game: DiceGame) + } + +The DiceGame protocol is a protocol that can be adopted by any game that involves dice. The DiceGameDelegate protocol can be adopted by any type to track the progress of a DiceGame. + +DiceGame协议可以被任意含有骰子的游戏所适配,DiceGameDelegate协议可以被任意用来追踪DiceGame过程的类型所适配 + +Here’s a version of the Snakes and Ladders game originally introduced in Control Flow. This version is adapted to use a Dice instance for its dice-rolls; to adopt the DiceGame protocol; and to notify a DiceGameDelegate about its progress: + +这里有一个,Snakes and Ladders游戏的新版本(之前的版本在流程控制这一节中介绍过)。新版本使用Dice类的实例作为掷骰子的需求,并且适配了DiceGame协议。同时通知(notify)DiceGameDelegate协议,用来记录游戏过程: + + class SnakesAndLadders: DiceGame { + let finalSquare = 25 + let dice = Dice(sides: 6, generator: LinearCongruentialGenerator()) + var square = 0 + var board: Int[] + init() { + board = Int[](count: finalSquare + 1, repeatedValue: 0) + board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 + board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 + } + var delegate: DiceGameDelegate? + func play() { + square = 0 + delegate?.gameDidStart(self) + gameLoop: while square != finalSquare { + let diceRoll = dice.roll() + delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll) + switch square + diceRoll { + case finalSquare: + break gameLoop + case let newSquare where newSquare > finalSquare: + continue gameLoop + default: + square += diceRoll + square += board[square] + } + } + delegate?.gameDidEnd(self) + } + } +For a description of the Snakes and Ladders gameplay, see the Break section of the Control Flow chapter. +你可以参考流程控制章节中对此游戏的介绍 +> 译者注 Snakes and Ladders 是蛇梯棋游戏,一种类似大富翁的游戏。 + +This version of the game is wrapped up as a class called SnakesAndLadders, which adopts the DiceGame protocol. It provides a gettable dice property and a play method in order to conform to the protocol. (The dice property is declared as a constant property because it does not need to change after initialization, and the protocol only requires that it is gettable.) + +这个版本的游戏封装为SnakesAndLadders类,该类适配DiceGame协议。这个类还提供了可读的dice属性和play方法,从而遵循了DiceGame协议。(dice属性声明为常量,因为构造之后dice属性就不在改变,且协议只要求dice为只读) + + + +The Snakes and Ladders game board setup takes place within the class’s init() initializer. All game logic is moved into the protocol’s play method, which uses the protocol’s required dice property to provide its dice roll values. + +Snakes And Ladders游戏通过构造方法(initializer)init初始化游戏。所有的游戏逻辑移到了play方法中,play方法使用协议要求的dice属性,来提供骰子掷出的值。 + +Note that the delegate property is defined as an optional DiceGameDelegate, because a delegate isn’t required in order to play the game. Because it is of an optional type, the delegate property is automatically set to an initial value of nil. Thereafter, the game instantiator has the option to set the property to a suitable delegate. +注意,delegate并不是玩游戏所必须的,因此delegate被定义为DiceGameDelegate协议类型的可选属性,delegate使用nil作为初始值。此后,游戏实例可以选择将其设置为一个合适的代理。 + + + +DiceGameDelegate provides three methods for tracking the progress of a game. These three methods have been incorporated into the game logic within the play method above, and are called when a new game starts, a new turn begins, or the game ends. + +DicegameDelegate协议提供了三个方法来跟踪游戏过程。这三个方法存在于游戏的逻辑中,即上面的play()方法内。分别在游戏开始时,新一轮开始时,游戏结束时被调用。 + + +Because the delegate property is an optional DiceGameDelegate, the play method uses optional chaining each time it calls a method on the delegate. If the delegate property is nil, these delegate calls fail gracefully and without error. If the delegate property is non-nil, the delegate methods are called, and are passed the SnakesAndLadders instance as a parameter. +因为delegate属性是一个遵循DiceGameDelegate的可选属性,因此在play()方法中使用了可选链(optional chaining )来在代理时调用方法。 若delegate属性为nil, 则delegate所调用的方法正常失败(fail gracefully)且不报错。若delegate不为nil,则方法能够被调用,且作为一个参数传入SnakesAndLadders实例中 +This next example shows a class called DiceGameTracker, which adopts the DiceGameDelegate protocol: +下一个例子展示了一个名为DiceGameTracker的类,适配DiceGameDelegate协议。 + + class DiceGameTracker: DiceGameDelegate { + var numberOfTurns = 0 + func gameDidStart(game: DiceGame) { + numberOfTurns = 0 + if game is SnakesAndLadders { + println("Started a new game of Snakes and Ladders") + } + println("The game is using a \(game.dice.sides)-sided dice") + } + func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) { + ++numberOfTurns + println("Rolled a \(diceRoll)") + } + func gameDidEnd(game: DiceGame) { + println("The game lasted for \(numberOfTurns) turns") + } + } +DiceGameTracker implements all three methods required by DiceGameDelegate. It uses these methods to keep track of the number of turns a game has taken. It resets a numberOfTurns property to zero when the game starts; increments it each time a new turn begins; and prints out the total number of turns once the game has ended. + +DiceGameTracker提供了DiceGameDelegate所要求的三个方法。它使用这三个方法来跟踪游戏进行的轮数。当游戏开始时,将numberOfTurns属性重置为0。每轮开始后递增这个值。当游戏结束时打印游戏进行的总轮数 + +The implementation of gameDidStart shown above uses the game parameter to print some introductory information about the game that is about to be played. The game parameter has a type of DiceGame, not SnakesAndLadders, and so gameDidStart can access and use only methods and properties that are implemented as part of the DiceGame protocol. However, the method is still able to use type casting to query the type of the underlying instance. In this example, it checks whether game is actually an instance of SnakesAndLadders behind the scenes, and prints an appropriate message if so. + +在如上所示的gameDidStart方法的实现中,游戏即将开始时使用了game参数来打印一些介绍性信息。game参数拥有一个DiceGame类型,而不是SnakesAndLadders,所以gameDidStart方法只能访问和使用DiceGame协议中的方法和属性。然而,该方法仍然能够使用类型检查(type casting)查询底层实例的类型。在这个例子中,它在幕后检查游戏是否是SnakesAndLadders的一个实例,当确认后打印一个适当的消息。 + +gameDidStart also accesses the dice property of the passed game parameter. Because game is known to conform to the DiceGame protocol, it is guaranteed to have a dice property, and so the gameDidStart method is able to access and print the dice’s sides property, regardless of what kind of game is being played. + +gameDidStart方法也能够访问dice属性,这个属性存在于被传递为参数的game中。game遵循DiceGame协议,因此被赋予了dice属性,不管运行何种游戏,gameDidStart方法都可以访问且打印骰子的边数。 +下面是DiceGameTracker的运行过程: +Here’s how DiceGameTracker looks in action: + + let tracker = DiceGameTracker() + let game = SnakesAndLadders() + game.delegate = tracker + game.play() + // Started a new game of Snakes and Ladders + // The game is using a 6-sided dice + // Rolled a 3 + // Rolled a 5 + // Rolled a 4 + // Rolled a 5 + // The game lasted for 4 turns + +Adding Protocol Conformance with an Extension +使用扩展添加协议一致性 +You can extend an existing type to adopt and conform to a new protocol, even if you do not have access to the source code for the existing type. Extensions can add new properties, methods, and subscripts to an existing type, and are therefore able to add any requirements that a protocol may demand. For more about extensions, see Extensions. + +即便不能修改现有类型的代码,你也可以扩展现有类型,从而适配和遵循新协议。扩展(extensions)可以在现有的类型上添加新属性、方法和下标,因此能够满足任何一个协议的需要。更多关于扩展相关的内容,请参考扩展。 + +NOTE +注意 +Existing instances of a type automatically adopt and conform to a protocol when that conformance is added to the instance’s type in an extension. +当你使用一个扩展,为一个实例的类型添加上某种对协议的适配后,这个类型已存在的所有实例,都会自动适配与遵循此协议。 + +For example, this protocol, called TextRepresentable, can be implemented by any type that has a way to be represented as text. This might be a description of itself, or a text version of its current state: + +举例来讲,下面的TextRepersentable协议,可以被任何能表现为文字的类型所适配。这有可能是其自身的描述,或是其状态的文字版本。 + + protocol TextRepresentable { + func asText() -> String + } + +The Dice class from earlier can be extended to adopt and conform to TextRepresentable: +之前的Dice类可以扩展为适配并遵循TextRepresentable协议: + + extension Dice: TextRepresentable { + func asText() -> String { + return "A \(sides)-sided dice" + } + } + +This extension adopts the new protocol in exactly the same way as if Dice had provided it in its original implementation. The protocol name is provided after the type name, separated by a colon, and an implementation of all requirements of the protocol is provided within the extension’s curly braces. +这个扩展以完全相同的方式适配了新协议,就像骰子提供了最初(适配协议)的实现。协议名称放在类型名称后,用`:`隔开,协议所要求的实现则提供在扩展的花括号内。 + + +Any Dice instance can now be treated as TextRepresentable: +现在Dice类型的实例可被当作是TextRepresentable类型: + + let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator()) + println(d12.asText()) + // prints "A 12-sided dice" + +Similarly, the SnakesAndLadders game class can be extended to adopt and conform to the TextRepresentable protocol: +同样,SnakesAndLadders类也可以扩展为适配且遵循TextRepresentable协议: + + extension SnakesAndLadders: TextRepresentable { + func asText() -> String { + return "A game of Snakes and Ladders with \(finalSquare) squares" + } + } + println(game.asText()) + // prints "A game of Snakes and Ladders with 25 squares" + +Declaring Protocol Adoption with an Extension +通过扩展声明协议适配 +If a type already conforms to all of the requirements of a protocol, but has not yet stated that it adopts that protocol, you can make it adopt the protocol with an empty extension: +若一个类型已经遵循了一个协议的所有要求,但未声明此类型适配这个协议,你可以使用一个空的扩展来让其适配协议。 + + struct Hamster { + var name: String + func asText() -> String { + return "A hamster named \(name)" + } + } + extension Hamster: TextRepresentable {} + +Instances of Hamster can now be used wherever TextRepresentable is the required type: +从现在起,Hamster的实例可以作为TextRepresentable所需要的类型来使用 + + let simonTheHamster = Hamster(name: "Simon") + let somethingTextRepresentable: TextRepresentable = simonTheHamster + println(somethingTextRepresentable.asText()) + // prints "A hamster named Simon" + +NOTE +注意 +Types do not automatically adopt a protocol just by satisfying its requirements. They must always explicitly declare their adoption of the protocol. +注意: 即使满足了协议的所有要求,类型也不会自动适配一个协议,因此你必须显式的声明协议适配。 + +Collections of Protocol Type +集合中的协议类型 + +A protocol can be used as the type to be stored in a collection such as an array or a dictionary, as mentioned in Protocols as Types. This example creates an array of TextRepresentable things: +协议可以作为集合(数组,字典)内所存储的类型使用,就像之前所讲的一样,协议作为类型使用: + + let things: TextRepresentable[] = [game, d12, simonTheHamster] + +It is now possible to iterate over the items in the array, and print each item’s textual representation: +如下所示,可以遍历things数组的元素,并打印每个元素的文本(通过asText方法) + + for thing in things { + println(thing.asText()) + } + // A game of Snakes and Ladders with 25 squares + // A 12-sided dice + // A hamster named Simon + +Note that the thing constant is of type TextRepresentable. It is not of type Dice, or DiceGame, or Hamster, even if the actual instance behind the scenes is of one of those types. Nonetheless, because it is of type TextRepresentable, and anything that is TextRepresentable is known to have an asText method, it is safe to call thing.asText each time through the loop. + +注意,thing常量是TextRepresentable类型的。它并非Dice、DiceGame或Hamster类型,即使thing所代表的实例,背后其实是其中一个类型。 +尽管如此,因为thing是TextRepresentable协议类型,此类型都包含asText方法,因此在每次循环中可以安全的调用一次asText方法 + +Protocol Inheritance +协议继承 + +A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to list multiple inherited protocols, separated by commas: + +协议能够继承一或多个其他协议,也可进一步在继承的协议上添加更多的需求。语法与类的继承相似,此外可以用逗号`,`分隔表示继承多个协议 + + protocol InheritingProtocol: SomeProtocol, AnotherProtocol { + // protocol definition goes here + } + +Here’s an example of a protocol that inherits the TextRepresentable protocol from above: +下面的例子中,一个协议继承了之前的TextRepresentable协议: + + protocol PrettyTextRepresentable: TextRepresentable { + func asPrettyText() -> String + } + +This example defines a new protocol, PrettyTextRepresentable, which inherits from TextRepresentable. Anything that adopts PrettyTextRepresentable must satisfy all of the requirements enforced by TextRepresentable, plus the additional requirements enforced by PrettyTextRepresentable. In this example, PrettyTextRepresentable adds a single requirement to provide an instance method called asPrettyText that returns a String. +这个例子定义了一个新的协议PrettyTextRepresentable,继承自TextRepresentable。若适配PrettyTextRepresentable协议,必须同时满足TextRepresentable协议的需求,且满足由PrettyTextRepresentable添加的额外需求。在这个例子中,PrettyTextRepresentable添加了另一需求,要求提供一个称为asPrettyText的实例方法,用于返回一个字符串。 +The SnakesAndLadders class can be extended to adopt and conform to PrettyTextRepresentable: +可以扩展SnakesAndLadders类,来使之适配且遵循PrettyTextRepresentable协议。 + + extension SnakesAndLadders: PrettyTextRepresentable { + func asPrettyText() -> String { + var output = asText() + ":\n" + for index in 1...finalSquare { + switch board[index] { + case let ladder where ladder > 0: + output += "▲ " + case let snake where snake < 0: + output += "▼ " + default: + output += "○ " + } + } + return output + } + } + +This extension states that it adopts the PrettyTextRepresentable protocol and provides an implementation of the asPrettyText method for the SnakesAndLadders type. Anything that is PrettyTextRepresentable must also be TextRepresentable, and so the asPrettyText implementation starts by calling the asText method from the TextRepresentable protocol to begin an output string. It appends a colon and a line break, and uses this as the start of its pretty text representation. It then iterates through the array of board squares, and appends an emoji representation for each square: + +这个扩展声明其适配PrettyTextRepresentable协议,并提供了SnakesAndLadders类型PrettyText方法的一个实现。任何PrettyTextRepresentable协议也是TextRepresentable的扩展,所以,asPrettyText方法的实现过程是这样的:首先调用来自TextRepresentable协议的asText方法开始输出字符串。方法的输出会附加一个冒号和一个换行符,使用这个作为美化文本输出的开始。然后遍历这个方格板数组中的每一个格子,用一个符号来表示: + +If the square’s value is greater than 0, it is the base of a ladder, and is represented by ▲. +If the square’s value is less than 0, it is the head of a snake, and is represented by ▼. +Otherwise, the square’s value is 0, and it is a “free” square, represented by ○. +The method implementation can now be used to print a pretty text description of any SnakesAndLadders instance: + +当遍历出的元素的值大于0时,表示一个梯子的底部,用`▲`符号表示 +当遍历出的元素的值小于0时,表示一个蛇头,用`▲`符号表示 +当遍历出的元素的值等于0时,表示一个空白方块,用`○`符号表示 +println(game.asPrettyText()) +// A game of Snakes and Ladders with 25 squares: +// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○ +Protocol Composition +协议合成 +It can be useful to require a type to conform to multiple protocols at once. You can combine multiple protocols into a single requirement with a protocol composition. Protocol compositions have the form protocol. You can list as many protocols within the pair of angle brackets (<>) as you need, separated by commas. +有一种很有用的方式,来表示一种适配多个协议的类型。你可以使用协议合成(Protocol Composition)来组合多个协议。 +协议合成的格式为protocal。你可以在尖括号(`<>`)内列出多个协议,用逗号`,`分隔。 + + + +Here’s an example that combines two protocols called Named and Aged into a single protocol composition requirement on a function parameter: +下面的例子中,把两个协议Named与Aged组合为一个协议合成,并作为函数的参数使用 + + protocol Named { + var name: String { get } + } + protocol Aged { + var age: Int { get } + } + struct Person: Named, Aged { + var name: String + var age: Int + } + func wishHappyBirthday(celebrator: protocol) { + println("Happy birthday \(celebrator.name) - you're \(celebrator.age)!") + } + let birthdayPerson = Person(name: "Malcolm", age: 21) + wishHappyBirthday(birthdayPerson) + // prints "Happy birthday Malcolm - you're 21!" + + +This example defines a protocol called Named, with a single requirement for a gettable String property called name. It also defines a protocol called Aged, with a single requirement for a gettable Int property called age. Both of these protocols are adopted by a structure called Person. +这个例子中,定义了一个Named协议,要求一个可读的String类型的属性`name`。同时定义了一个Aged协议,要求一个可读的Int类型的属性`Aged`。两个协议被`Person`结构体所适配。 + +The example also defines a function called wishHappyBirthday, which takes a single parameter called celebrator. The type of this parameter is protocol, which means “any type that conforms to both the Named and Aged protocols.” It doesn’t matter what specific type is passed to the function, as long as it conforms to both of the required protocols. +这个例子也定义了带有参数`celebrator`的函数`wishHappyBirthday`。参数的类型是`protocol`,表示任何同时遵循Named与Aged协议的类型。不管向函数传递何种参数,只要遵循两个协议即可。 + + +The example then creates a new Person instance called birthdayPerson and passes this new instance to the wishHappyBirthday function. Because Person conforms to both protocols, this is a valid call, and the wishHappyBirthday function is able to print its birthday greeting. +这个例子也创建了一个`Person`的实例`birthdayPerson`,且将这个实例作为参数传入`wishHappyBirthday`函数。因为Person同时适配 +两个协议,因此函数可以正常调用,并打印一个生日祝福。 + +NOTE +注意 +Protocol compositions do not define a new, permanent protocol type. Rather, they define a temporary local protocol that has the combined requirements of all protocols in the composition. +注意: 协议合成并不会生成一个新的协议类型,而是将多个协议合成为一个临时协议。 + +Checking for Protocol Conformance +协议遵循检查 + +You can use the is and as operators described in Type Casting to check for protocol conformance, and to cast to a specific protocol. Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a type: +你可以使用类型检查中介绍的`is`,`as`操作符,来检测某类型是否遵循某协议, + +The is operator returns true if an instance conforms to a protocol and returns false if it does not. +The as? version of the downcast operator returns an optional value of the protocol’s type, and this value is nil if the instance does not conform to that protocol. +The as version of the downcast operator forces the downcast to the protocol type and triggers a runtime error if the downcast does not succeed. +is操作符用于检查实例是否遵循某个协议,若不遵循则返回`false`。 +as?根据协议类型返回一个可选值,当实例遵循协议时,返回该协议类型;否则返回nil +as操作符可以对协议类型进行强制向下转型。若若换失败则会报一个运行时错误。 + +> 译者注: 向下转型就是把基类转换到继承类,向上转型就是把继承类转换为基类。 + +This example defines a protocol called HasArea, with a single property requirement of a gettable Double property called area: +下面的例子定义了协议HasArea,需要一个可读的Double类型的属性area。 + + @objc protocol HasArea { + var area: Double { get } + } +NOTE +注意 +You can check for protocol conformance only if your protocol is marked with the @objc attribute, as seen for the HasArea protocol above. This attribute indicates that the protocol should be exposed to Objective-C code and is described in Using Swift with Cocoa and Objective-C. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to be able to check for protocol conformance. +注意: 只有用`@objc`属性标注的协议,才可以做协议遵循检查。这个属性表示协议会暴露给Objective-C的代码,可以参考Using Siwft with Cocoa and Objectivei-c。即使你不打算与 Objective-C进行交互,当你需要进行协议遵循检查时,也要在协议前面添加`@objc`. + +Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to check for conformance, you will be able to apply that protocol only to class types. +还要注意一点,`@objc`协议只适用于类,不能用于结构体或枚举。因此只有协议被应用在类上,才能使用`@objc`检查协议的遵循。 + +Here are two classes, Circle and Country, both of which conform to the HasArea protocol: +下面两个类`Circle`与`Country`都遵循`HasArea`协议 + + class Circle: HasArea { + let pi = 3.1415927 + var radius: Double + var area: Double { return pi * radius * radius } + init(radius: Double) { self.radius = radius } + } + class Country: HasArea { + var area: Double + init(area: Double) { self.area = area } + } + +The Circle class implements the area property requirement as a computed property, based on a stored radius property. The Country class implements the area requirement directly as a stored property. Both classes correctly conform to the HasArea protocol. + +`Circle`类把`area`属性实现为基于存储属性 `radius`的计算属性, `Country`类则把`area`属性直接实现为存储型属性。这两个类都遵循`haxArea`协议。 + + +Here’s a class called Animal, which does not conform to the HasArea protocol: +这个例子中`Animal`类不遵循`HasArea`协议: + + class Animal { + var legs: Int + init(legs: Int) { self.legs = legs } + } +The Circle, Country and Animal classes do not have a shared base class. Nonetheless, they are all classes, and so instances of all three types can be used to initialize an array that stores values of type AnyObject: +`Circle`类,`Country`类,`Animal`类并没有一个相同的基类,可以采用`AnyObject`类型的数组来承载他们构造后的实例: + + let objects: AnyObject[] = [ + Circle(radius: 2.0), + Country(area: 243_610), + Animal(legs: 4) + ] +The objects array is initialized with an array literal containing a Circle instance with a radius of 2 units; a Country instance initialized with the surface area of the United Kingdom in square kilometers; and an Animal instance with four legs. + +The objects array can now be iterated, and each object in the array can be checked to see if it conforms to the HasArea protocol: + +objects数组使用数组字面量(array literal)初始化,数组包含一个`radius`为2的`Circle` 实例,aear属性等于英国面积的`Country`实例和一个`legs`属性为4的`Animal`实例。 + +现在objects数组可以被迭代,且可以对迭代出的每一个元素进行检查,看其是否遵循了`HasArea`协议: + + for object in objects { + if let objectWithArea = object as? HasArea { + println("Area is \(objectWithArea.area)") + } else { + println("Something that doesn't have an area") + } + } + // Area is 12.5663708 + // Area is 243610.0 + // Something that doesn't have an area + +Whenever an object in the array conforms to the HasArea protocol, the optional value returned by the as? operator is unwrapped with optional binding into a constant called objectWithArea. The objectWithArea constant is known to be of type HasArea, and so its area property can be accessed and printed in a type-safe way. + +Note that the underlying objects are not changed by the casting process. They continue to be a Circle, a Country and an Animal. However, at the point that they are stored in the objectWithArea constant, they are only known to be of type HasArea, and so only their area property can be accessed. +迭代出的元素使用可选绑定(optional binding)将其绑定到`objectWithArea`常量上,使用as?操作符判断其是否遵循`HasArea`协议。`objectWithArea`常量是遵循HasArea协议类型的实例,因此其`area`属性是可以被访问和打印的。 + +`objects`数组中元素的类型并不会因为向下转型而改变,它们仍然是`Circle`,`Country`,`Animal`类型。然而,当它们被存储到`objectWithArea`常量后,只会被认为是`HasArea`类型,因此只有`area`属性能够被访问。 +Optional Protocol Requirements +可选的协议要求 + +You can define optional requirements for protocols, These requirements do not have to be implemented by types that conform to the protocol. Optional requirements are prefixed by the @optional keyword as part of the protocol’s definition. + +您可以定义可选的协议要求,这些要求不需要类型实现符合协议。可选要求使用`@optional`关键字,作为协议的定义的一部分。 + +An optional protocol requirement can be called with optional chaining, to account for the possibility that the requirement was not implemented by a type that conforms to the protocol. For information on optional chaining, see Optional Chaining. + +You check for an implementation of an optional requirement by writing a question mark after the name of the requirement when it is called, such as someOptionalMethod?(someArgument). Optional property requirements, and optional method requirements that return a value, will always return an optional value of the appropriate type when they are accessed or called, to reflect the fact that the optional requirement may not have been implemented. + +可选协议要求通过可选链(optional chaining)进行调用,为一个类型实现不遵循协议预留可能,详细内容可以参考可选链章节。 + +你可以在实现名称后加上?来检查该实现,比如`someOptionalMethod?(someArgument)`。可选方法需求和可选属性要求,在调用或访问时都会返回一个可选值(optional value),当可选的要求可能没有被实施时,这个值也会反映出来。 + + + +NOTE + +Optional protocol requirements can only be specified if your protocol is marked with the @objc attribute. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to specify optional requirements. +注意: 可选协议要求只能在含有`@objc`前缀的协议中指定。即使你不准备与Objective-c进行交互,当你要指定可选协议需求时,也需要添加这个前缀。 + +Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to specify optional requirements, you will only be able to apply that protocol to class types. +还要注意,`@objc`协议只适用于类,不能用于结构体或枚举。因此只有协议被应用在类上,才能通过`@objc`指定可选协议要求。 + +The following example defines an integer-counting class called Counter, which uses an external data source to provide its increment amount. This data source is defined by the CounterDataSource protocol, which has two optional requirements: +下面的例子定义了一个计数器类`Counter`,它使用一个外部数据源提供其增量。这个数据源是`CounterDataSource`定义的协议,它有两个可选的要求: + + @objc protocol CounterDataSource { + @optional func incrementForCount(count: Int) -> Int + @optional var fixedIncrement: Int { get } + } +The CounterDataSource protocol defines an optional method requirement called incrementForCount and an optional property requirement called fixedIncrement. These requirements define two different ways for data sources to provide an appropriate increment amount for a Counter instance. + +`CounterDataSource`协议定义了一个可选的方法要求incrementForCount和一个可选的属性要求`fixedIncrement` 。这些要求定义了两种不同的方式的数据源,来给Counter实例提供一个适当的增量。 + + +NOTE +注意 +Strictly speaking, you can write a custom class that conforms to CounterDataSource without implementing either protocol requirement. They are both optional, after all. Although technically allowed, this wouldn’t make for a very good data source. +严格来讲,你可以实现一个类来适配协议`CounterDataSource`,而不去实现协议中的两个要求,因为`CounterDataSource`中的属性和方法要求都是可选的。尽管这样写是可以的,但这并不是一个好的数据源的实现。 + +The Counter class, defined below, has an optional dataSource property of type CounterDataSource?: +Counter类含有`CounterDataSource?`类型的可选属性`dataSource`,如下所示: + + @objc class Counter { + var count = 0 + var dataSource: CounterDataSource? + func increment() { + if let amount = dataSource?.incrementForCount?(count) { + count += amount + } else if let amount = dataSource?.fixedIncrement? { + count += amount + } + } + } +The Counter class stores its current value in a variable property called count. The Counter class also defines a method called increment, which increments the count property every time the method is called. + +`Counter`类通过`count`属性来存储当前值,`increment`方法在每次调用后增加`count`的值。 + + +The increment method first tries to retrieve an increment amount by looking for an implementation of the incrementForCount method on its data source. The increment method uses optional chaining to try to call incrementForCount, and passes the current count value as the method’s single argument. +`increment`方法首先通过可选链调用`incrementForCount`方法内数据源的实现,从而获取增量,并将当前的`count`值作为参数传入方法 + + + +Note two levels of optional chaining at play here. Firstly, it is possible that dataSource may be nil, and so dataSource has a question mark after its name to indicate that incrementForCount should only be called if dataSource is non-nil. Secondly, even if dataSource does exist, there is no guarantee that it implements incrementForCount, because it is an optional requirement. This is why incrementForCount is also written with a question mark after its name. +注意,这里有两级可选链。首先,`dataSource`可能为`nil`,所以`dataSource`后使用问好,表明只有在`dataSource`不为`nil`时才调用`incrementForCount`方法。其次,即使`dataSource`存在,也不能保证它实现了`incrementForCount`方法,因为这是一个可选的要求。这就是为什么`incrementForCount`的名字后面也跟着一个问号。 + +Because the call to incrementForCount can fail for either of these two reasons, the call returns an optional Int value. This is true even though incrementForCount is defined as returning a non-optional Int value in the definition of CounterDataSource. +以上原因表明,即使`CounterDataSource`协议中`incrementForCount`方法被定义为返回一个非可选的Int类型的值,在调用`incrementForCount`方法后,也会返回一个Int类型的可选值。 + +After calling incrementForCount, the optional Int that it returns is unwrapped into a constant called amount, using optional binding. If the optional Int does contain a value—that is, if the delegate and method both exist, and the method returned a value—the unwrapped amount is added onto the stored count property, and incrementation is complete. + +当调用完incrementForCount方法后,返回的可选值通过可选绑定,赋值给常量`amont`。 +如果可选值包含值-代表如果代理和方法都存在,方法返回了值-`amount`会赋给存储属性`count`,这个增量过程就完成了。 + +If it is not possible to retrieve a value from the incrementForCount method—either because dataSource is nil, or because the data source does not implement incrementForCount—then the increment method tries to retrieve a value from the data source’s fixedIncrement property instead. The fixedIncrement property is also an optional requirement, and so its name is also written using optional chaining with a question mark on the end, to indicate that the attempt to access the property’s value can fail. As before, the returned value is an optional Int value, even though fixedIncrement is defined as a non-optional Int property as part of the CounterDataSource protocol definition. +如果不能从incrementForCount方法获取到值 -可能`dataSource`为`nil`,或dataSource没有实现`incrementForCount方法`-increment方法会尝试从数据源中获取fixedIncrement属性的值来代替。`fixedIncrement`属性也是一个可选的要求,所以它也使用可选链,以一个问号结束,表明试图访问属性的值时可以失败。和之前一样,即使`CounterDataSource`协议中,`fixedIncrement`属性被定义为返回一个非可选的Int类型的值,返回值也是一个可选的Int类型的值。 +Here’s a simple CounterDataSource implementation where the data source returns a constant value of 3 every time it is queried. It does this by implementing the optional fixedIncrement property requirement: +这里有一个简单的CounterDataSource的实现,通过实现了可选属性fixedIncrement,每次查询都会返回一个常量3。 + + class ThreeSource: CounterDataSource { + let fixedIncrement = 3 + } + +You can use an instance of ThreeSource as the data source for a new Counter instance: +你可以使用ThreeSource的实例作为Counter实例的数据源: + + var counter = Counter() + counter.dataSource = ThreeSource() + for _ in 1...4 { + counter.increment() + println(counter.count) + } + // 3 + // 6 + // 9 + // 12 + +The code above creates a new Counter instance; sets its data source to be a new ThreeSource instance; and calls the counter’s increment method four times. As expected, the counter’s count property increases by three each time increment is called. +上面的代码创建了一个新的Counter实例,同时把数据源设置为ThreeSource的实例,之后调用了四次计数器的increment方法。正如我们所期望的,increment方法调用一次,计数器的count属性会增加3。 + +Here’s a more complex data source called TowardsZeroSource, which makes a Counter instance count up or down towards zero from its current count value: +这里有一个更加复杂的数据源例子`TowardsZeroSource`,使计数器实例会从当前计数值向上或向下计数,直到零: + + class TowardsZeroSource: CounterDataSource { + func incrementForCount(count: Int) -> Int { + if count == 0 { + return 0 + } else if count < 0 { + return 1 + } else { + return -1 + } + } + } +The TowardsZeroSource class implements the optional incrementForCount method from the CounterDataSource protocol and uses the count argument value to work out which direction to count in. If count is already zero, the method returns 0 to indicate that no further counting should take place. + +You can use an instance of TowardsZeroSource with the existing Counter instance to count from -4 to zero. Once the counter reaches zero, no more counting takes place: + +`TowardsZeroSource`类实现了`CounterDataSource`协议中可选的`incrementForCount`方法,使用`count`参数值来决定计数方向。如果`count`已经是零,方法返回0,表明不会有进一步计算了。 +   + 你可以在`Counter`实例中使用`TowardsZeroSource`实例,从-4计数至零。一旦计数器达到零就不会在计数了: + + counter.count = -4 + counter.dataSource = TowardsZeroSource() + for _ in 1...5 { + counter.increment() + println(counter.count) + } + // -3 + // -2 + // -1 + // 0 + // 0 From d4cf508b2993e53d4612862c4924eb2244388d6d Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Mon, 23 Jun 2014 01:08:16 +0800 Subject: [PATCH 163/261] Update 06_Functions.md --- src/chapter2/06_Functions.md | 164 +++++++++++++++++------------------ 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/src/chapter2/06_Functions.md b/src/chapter2/06_Functions.md index b8b72ad..cd97784 100644 --- a/src/chapter2/06_Functions.md +++ b/src/chapter2/06_Functions.md @@ -2,29 +2,30 @@ Functions are self-contained chunks of code that perform a specific task. You give a function a name that identifies what it does, and this name is used to “call” the function to perform its task when needed. -函数是执行特定任务的独立代码块。你可以给函数起一个名字来标识它的功能,并在需要时使用这个名字来“调用”该函数执行任务。 +函数是执行特定任务的独立代码块。可以给函数起一个名字,标识它是做什么的,并在需要时使用这个名字来“调用”函数执行任务。 Swift’s unified function syntax is flexible enough to express anything from a simple C-style function with no parameter names to a complex Objective-C-style method with local and external parameter names for each parameter. Parameters can provide default values to simplify function calls and can be passed as in-out parameters, which modify a passed variable once the function has completed its execution. -Swift的统一标准函数语法足够灵活来表达一切,从简单的无参数名的C风格函数到复杂的每个参数都有本地和外部参数名的Objective-C风格方法。可以为参数提供默认值来简化函数调用,也可以为参数传入in-out参数,一旦函数完成执行,传入的变量会被修改。 +Swift统一标准的函数语法十分灵活,可以表达任何函数。从简单的无参数名的C风格函数,到复杂的每个参数都带有局部和外部参数名的Objective-C风格函数。可以给参数提供默认值,以简化函数调用;也可以把参数当做in-out参数传值,函数执行结束时,可以改变传入变量的值。 Every function in Swift has a type, consisting of the function’s parameter types and return type. You can use this type like any other type in Swift, which makes it easy to pass functions as parameters to other functions, and to return functions from functions. Functions can also be written within other functions to encapsulate useful functionality within a nested function scope. -Swift的每个函数都有类型,包含函数参数类型和返回类型。你可以像swift中任何其他类型那样使用,这让函数作为参数传递给其他函数,和从函数返回函数变得十分容易。函数也可以定义在另一个函数中, 在嵌套函数范围内,封装特定功能。 +在Swift中,每个函数都有类型,由函数参数类型和返回类型组成。函数类型可以像任何其他类型那样使用,可以把函数作为参数传递给其他函数,也可以从函数中返回函数,函数类型让这些变得简单。函数也可以定义在另一个函数中, 在嵌套函数范围内,封装特定功能。 -# Defining and Calling Functions 定义和调用函数 + +# Defining and Calling Functions 函数定义和调用 When you define a function, you can optionally define one or more named, typed values that the function takes as input (known as parameters), and/or a type of value that the function will pass back as output when it is done (known as its return type). -定义函数时,你可以为其定义一个或多个具有名称、类型的值作为输入(称为参数),和/或该函数执行完毕后传回的一个有类型的值作为输出(称为返回值)。 +定义函数时,你可以定义一个或多个具有名称、类型的值作为函数输入(称为参数parameters),和(或者)定义在函数执行完毕后传回的一个有类型的值作为输出(称为返回值)。 Every function has a function name, which describes the task that the function performs. To use a function, you “call” that function with its name and pass it input values (known as arguments) that match the types of the function’s parameters. A function’s arguments must always be provided in the same order as the function’s parameter list. -每个函数都有一个函数名用来描述此函数运行的任务。使用函数时,通过函数名并传入符合函数参数类型的输入值(称为参数)来“调用”函数。必须按照函数参数列表相同的顺序提供函数参数。 +每个函数都有一个函数名,用来描述此函数执行的任务。使用函数时,通过函数名“调用”函数,并传入符合函数参数类型的输入值(称为参数,arguments)。提供给函数的参数必须与函数参数列表的顺序一致。 The function in the example below is called greetingForPerson, because that’s what it does—it takes a person’s name as input and returns a greeting for that person. To accomplish this, you define one input parameter—a String value called personName—and a return type of String, which will contain a greeting for that person: -下面例子中的函数叫做sayHello,因为这就是它的功能——它以人名作为输入,并返回对这个人的问候(greeting)。为了实现这一点,需要定义一个输入参数——一个名为personName的字符串值,和一个字符串类型的返回值带有对此人的问候。 +下面例子中的函数叫做sayHello,名字描述了它的用途,用人名作为输入,并返回对这个人的问候(greeting)。为了实现这些,需要定义一个输入参数——一个名为personName的String类型值,和一个带有对此人问候的String类型的返回值。 ```js func sayHello(personName: String) -> String { @@ -35,11 +36,11 @@ func sayHello(personName: String) -> String { All of this information is rolled up into the function’s definition, which is prefixed with the func keyword. You indicate the function’s return type with the return arrow -> (a hyphen followed by a right angle bracket), which is followed by the name of the type to return. -所有这些信息构成了一个函数的定义,并以 func 关键字作为前缀。使用返回箭头->(连字符后跟一个右尖括号)和紧接着的返回类型名来声明函数的返回类型。 +所有这些信息构成了一个函数的定义,并以关键字 func 作为前缀。使用返回箭头->(连字符后跟一个右尖括号)和紧接着的返回类型名来声明函数的返回类型。 The definition describes what the function does, what it expects to receive, and what it returns when it is done. The definition makes it easy for the function to be called elsewhere in your code in a clear and unambiguous way: -函数定义描述这个函数是做什么的,期望接收什么和运行结束后返回什么。这个定义使得在代码中任何地方用清晰明白的方式调用函数变得容易。 +函数定义描述了函数是做什么的,期望接收什么和执行结束后返回什么。这个定义使得在代码中的任何地方可以清晰明确地调用函数变得简单。 ```js println(sayHello("Anna")) @@ -50,15 +51,15 @@ println(sayHello("Brian")) You call the sayHello function by passing it a String argument value in parentheses, such as sayHello("Anna"). Because the function returns a String value, sayHello can be wrapped in a call to the println function to print that string and see its return value, as shown above. -通过在括号中传入一个字符串参数值来调用sayHello函数,如sayHello(“Anna”)。由于函数返回了一个字符串类型的值,sayHello可以包装在 println 函数中,用来打印这个字符串并查看它的返回值,如上所示。 +调用sayHello函数时,在圆括号中传入一个String类型参数值,例如sayHello(“Anna”)。由于这个函数返回了一个String类型的值,因此sayHello可以包装在 println 函数中,用来输出这个字符串并查看它的返回值,如上所示。 The body of the sayHello function starts by defining a new String constant called greeting and setting it to a simple greeting message for personName. This greeting is then passed back out of the function using the return keyword. As soon as return greeting is called, the function finishes its execution and returns the current value of greeting. -sayHello 函数的主体始于定义一个名为 greeting 的字符串常量,并为它设置对personName的简单问候信息。然后通过 return 关键字把 greeting 传出函数。一旦执行了 return greeting,函数结束执行并返回当前的greeting值。 +sayHello 的函数体先定义一个名为 greeting 的String 常量,并给它设置了对personName的简单问候信息。然后通过 return 关键字把 greeting 传出函数。一旦执行了 return greeting,函数就结束执行并返回greeting的当前值。 You can call the sayHello function multiple times with different input values. The example above shows what happens if it is called with an input value of "Anna", and an input value of "Brian". The function returns a tailored greeting in each case. -你可以传入不同的输入值多次调用 sayHello 函数。上述例子展示了输入值为“Anna”和“Brian”时发生了什么。每个例子中函数返回了定制的greeting。 +你可以传入不同的输入值多次调用sayHello 函数。上述例子展示了输入值为“Anna”和“Brian”时调用函数的结果。函数在每种情况下返回了各自定制的greeting。 To simplify the body of this function, combine the message creation and the return statement into one line: @@ -77,17 +78,17 @@ println(sayHelloAgain("Anna")) Function parameters and return values are extremely flexible in Swift. You can define anything from a simple utility function with a single unnamed parameter to a complex function with expressive parameter names and different parameter options. -Swift 中的函数参数和返回值都十分灵活。你可以定义任何函数,从单个未命名参数的简单工具函数到 具有表达性参数名和不同参数选项的复杂函数。 +Swift 中的函数参数和返回值十分灵活。你可以定义各种类型的函数,从只有一个未命名参数的简单功能函数到 具有表达性参数名和不同参数选项的复杂函数。 -## Multiple Input Parameters 多个输入参数 +## Multiple Input Parameters 多输入参数 Functions can have multiple input parameters, which are written within the function’s parentheses, separated by commas. -函数可以有多个输入参数,写在函数的括号内,以逗号分隔。 +函数可以有多个输入参数,写在函数的圆括号内,用逗号分隔。 This function takes a start and an end index for a half-open range, and works out how many elements the range contains: -下面这个函数接收半开区间的开始和结束索引,并计算出该区间范围包含多少个元素: +下面这个函数接收半开区间的开始和结束索引,并计算出这个区间范围包含多少个元素: ```js func halfOpenRangeLength(start: Int, end: Int) -> Int { @@ -101,7 +102,7 @@ println(halfOpenRangeLength(1, 10)) Functions are not required to define input parameters. Here’s a function with no input parameters, which always returns the same String message whenever it is called: -函数可以不定义输入参数。下面是一个无输入参数的函数,不管何时被调用总是返回相同的字符串信息: +函数可以不定义输入参数。下面是一个无输入参数的函数,不管何时调用总是返回相同的字符串信息: ```js func sayHelloWorld() -> String { @@ -113,13 +114,13 @@ println(sayHelloWorld()) The function definition still needs parentheses after the function’s name, even though it does not take any parameters. The function name is also followed by an empty pair of parentheses when the function is called. -虽然定义这种函数,并不需要任何参数,但在函数名后仍需要括号。所以调用函数时,函数名后总是紧跟一对空括号。 +虽然定义这种函数,并不需要任何参数,但在函数名后仍需要一对括号。所以调用函数时,函数名后总是紧跟一对空括号。 ## Functions Without Return Values 无返回值的函数 Functions are not required to define a return type. Here’s a version of the sayHello function, called waveGoodbye, which prints its own String value rather than returning it: -函数可以不定义返回类型。下面是sayHello 函数的一个版本,叫做sayGoodbye,这个函数只打印字符串而不返回。 +函数可以不定义返回类型。下面是sayHello 函数的另一个版本sayGoodbye,这个函数只输出String 值而不返回。 ```js func sayGoodbye(personName: String) { @@ -139,7 +140,7 @@ Because it does not need to return a value, the function’s definition does not > Strictly speaking, the sayGoodbye function does still return a value, even though no return value is defined. Functions without a defined return type return a special value of type Void. This is simply an empty tuple, in effect a tuple with zero elements, which can be written as (). -> 严格来说,即使函数sayGoodbye没有定义返回值,但它仍然返回了一个值。没有定义返回类型的函数会返回一个Void类型的特殊值。它仅仅是一个空元组(值组),实际为零个元素的元组,可以写成()。【 +> 严格来说,即使函数sayGoodbye没有定义返回值,它也会返回一个值。没有定义返回类型的函数会返回一个Void类型的特殊值。它仅仅是一个空元组(tuple),实际是零个元素的元组,可以写成()。 The return value of a function can be ignored when it is called: @@ -161,7 +162,7 @@ printWithoutCounting("hello, world") The first function, printAndCount, prints a string, and then returns its character count as an Int. The second function, printWithoutCounting, calls the first function, but ignores its return value. When the second function is called, the message is still printed by the first function, but the returned value is not used. -第一个函数printAndCount 打印一个字符串并返回整型的字符个数。第二个函数 printWithoutCounting 调用第一个函数,但忽略其返回值。调用第二个函数时,信息仍由第一个函数打印,但不使用其返回值。 +第一个函数printAndCount 输出一个字符串并返回Int类型的字符个数。第二个函数 printWithoutCounting 调用第一个函数,但忽略它的返回值。调用第二个函数时,信息仍由第一个函数输出,但不使用它的返回值。 > NOTE @@ -169,7 +170,7 @@ The first function, printAndCount, prints a string, and then returns its charact > Return values can be ignored, but a function that says it will return a value must always do so. A function with a defined return type cannot allow control to fall out of the bottom of the function without returning a value, and attempting to do so will result in a compile-time error. -> 返回值虽然可以被忽略,但函数必须总是返回一个值。定义返回类型的函数不允许控制函数的底部没有返回值,试图这样做会导致编译时错误。 +> 返回值虽然可以被忽略,但定义了返回类型的函数必须总是返回一个值。定义返回类型的函数不允许控制函数的最后没有返回值,试图这样做会导致编译时错误。 ## Functions with Multiple Return Values 多返回值函数 @@ -179,7 +180,7 @@ You can use a tuple type as the return type for a function to return multiple va The example below defines a function called count, which counts the number of vowels, consonants, and other characters in a string, based on the standard set of vowels and consonants used in American English: -下面的例子定义了count的函数,其基于美式英语中使用的元音和辅音的标准集合,来计算字符串中的元音、辅音和其他字符的个数: +下面的例子定义了count的函数,它基于美式英语中使用的元音和辅音的标准集合,来计算字符串中的元音、辅音和其他字符的个数: ```js func count(string: String) -> (vowels: Int, consonants: Int, others: Int) { @@ -211,13 +212,13 @@ println("\(total.vowels) vowels and \(total.consonants) consonants") Note that the tuple’s members do not need to be named at the point that the tuple is returned from the function, because their names are already specified as part of the function’s return type. -注意当函数返回时,元组的成员不需要命名,因为成员的名字已经指定作为函数返回类型的一部分。 +注意当函数返回时,元组的成员不需要命名,因为它们的名字已经在函数返回类型中定义了,作为函数返回类型的一部分。 # Function Parameter Names 函数参数名 All of the above functions define parameter names for their parameters: -以上所有的函数都定义了参数名: +以上所有的函数都给它们的参数定义了参数名: ```js func someFunction(parameterName: Int) { @@ -228,7 +229,7 @@ func someFunction(parameterName: Int) { However, these parameter names are only used within the body of the function itself, and cannot be used when calling the function. These kinds of parameter names are known as local parameter names, because they are only available for use within the function’s body. -然而,这些参数名只在该函数体内部使用,不能在调用函数时使用。这种参数名被称为本地(是不是应该翻译成 局部)参数名,因为它们只能在函数体内部获得和使用。 +然而,这些参数名只能在这个函数体内部使用,不能在调用函数时使用。这种参数名被称为局部参数名,因为它们只能在函数体内部获得和使用。 ## External Parameter Names 外部参数名 @@ -238,7 +239,7 @@ Sometimes it’s useful to name each parameter when you call a function, to indi If you want users of your function to provide parameter names when they call your function, define an external parameter name for each parameter, in addition to the local parameter name. You write an external parameter name before the local parameter name it supports, separated by a space: -如果希望用户在调用函数时提供参数名,除了定义本地参数名,还要给每个参数定义外部参数名。把外部参数名写在支持的本地(是不是应该翻译成 局部)参数名前,用空格分隔: +如果希望用户在调用函数时提供参数名,除了定义局部参数名,还要给每个参数定义外部参数名。把外部参数名写在支持的局部参数名前,用空格分隔: ```js func someFunction(externalParameterName localParameterName: Int) { @@ -251,11 +252,11 @@ func someFunction(externalParameterName localParameterName: Int) { > If you provide an external parameter name for a parameter, that external name must always be used when calling the function. -> 如果为参数提供了外部参数名,那么在调用函数时必须总是带上外部名。 +> 如果给参数提供了外部参数名,那么在调用函数时必须总是带上外部参数名。 As an example, consider the following function, which joins two strings by inserting a third “joiner” string between them: -例如下面的函数,把第三个名为“joiner”的字符串插入到另外两个字符串之间,进行连接: +例如下面的函数,把第三个名为“joiner”的字符串插入到另外两个字符串之间,进行字符串连接: ```js func join(s1: String, s2: String, joiner: String) -> String { @@ -304,17 +305,17 @@ The use of external parameter names enables this second version of the join func > Consider using external parameter names whenever the purpose of a function’s arguments would be unclear to someone reading your code for the first time. You do not need to specify external parameter names if the purpose of each parameter is clear and unambiguous when the function is called. -> 初次阅读这些代码的人,可能不清楚函数参数的用途,这时需要考虑使用外部参数名。如果调用函数时,每个参数的用意都很清楚、明确,那就不需要指定外部参数名。 +> 初次阅读这些代码的人,可能不清楚函数参数的用途,这时需要考虑使用外部参数名。如果调用函数时,每个参数的用意都很清楚、明确,那就不需要定义外部参数名。 ## Shorthand External Parameter Names 简写外部参数名 If you want to provide an external parameter name for a function parameter, and the local parameter name is already an appropriate name to use, you do not need to write the same name twice for that parameter. Instead, write the name once, and prefix the name with a hash symbol (#). This tells Swift to use that name as both the local parameter name and the external parameter name. -如果想给函数参数提供外部参数名,而本地(是不是应该翻译成 局部)参数名已经很适合了,那么你不需要给参数写两个相同的名字。而只用写一次,然后在名字前加上前缀符号(#)。这就告诉Swift使用这个名字同时作为本地参数名和外部参数名。 +如果想给函数参数提供外部参数名,而局部参数名已经很适合了,那么你不需要给参数写两个相同的名字。而只用写一次,然后在名字前加上符号(#)。这就告诉Swift使用这个名字同时作为本地参数名和外部参数名。 This example defines a function called containsCharacter, which defines external parameter names for both of its parameters by placing a hash symbol before their local parameter names: -下面的例子定义了名为containsCharacter的函数,该函数在本地(是不是应该翻译成 局部)参数名前加上#标识从而给它的两个参数定义外部参数名。 +下面的例子定义了containsCharacter的函数,这个函数在局部参数名前加上#标识从而给它的两个参数定义外部参数名。 ```js func containsCharacter(#string: String, #characterToFind: Character) -> Bool { @@ -340,17 +341,17 @@ let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v") You can define a default value for any parameter as part of a function’s definition. If a default value is defined, you can omit that parameter when calling the function. -你可以为函数定义中的任何参数定义默认值。如果定义了默认值,在调用函数时可以忽略该参数。 +在函数定义中,你可以给任何参数定义默认值。如果定义了默认值,在调用函数时可以忽略这个参数。 > NOTE 注意 > Place parameters with default values at the end of a function’s parameter list. This ensures that all calls to the function use the same order for their non-default arguments, and makes it clear that the same function is being called in each case. -> 在函数参数列表的最后设置参数默认值。这样可以确保对非默认参数,所有的函数调用使用相同的参数顺序,并明确每种情况都会调用相同的函数。 +> 把带有默认值的参数放在函数参数列表的最后。这样可以确保,所有的函数调用使用的非默认参数顺序相同,同时可以明确每种情况都会调用相同的函数。 Here’s a version of the join function from earlier, which provides a default value for its joiner parameter: -下面是之前版本的 join 函数,该函数为它的joiner 参数提供了默认值: +下面是之前版本的 join 函数,这个函数为它的joiner 参数提供了默认值: ```js func join(string s1: String, toString s2: String, @@ -361,7 +362,7 @@ func join(string s1: String, toString s2: String, If a string value for joiner is provided when the join function is called, that string value is used to join the two strings together, as before: -如果在调用 join 函数时,为 joiner 提供了字符串类型的值,该字符串值用来连接 另外两个字符串,和之前一样: +调用 join 函数时,如果给 joiner 提供了字符串类型的值,这个字符串值会像之前一样,连接 另外两个字符串: ```js join(string: "hello", toString: "world", withJoiner: "-") @@ -381,15 +382,15 @@ join(string: "hello", toString: "world") In most cases, it is useful to provide (and therefore require) an external name for any parameter with a default value. This ensures that the argument for that parameter is clear in purpose if a value is provided when the function is called. -在大多数情况下,给任何带有默认值的参数提供外部参数名十分有用(而且非常必要)。这确保了在给函数调用提供值时,参数的用途是明确的。 +在大多数情况下,给任何带有默认值的参数提供外部参数名十分有用(而且非常必要)。这可以确保在给函数调用提供值时,参数的用途是明确的。 To make this process easier, Swift provides an automatic external name for any defaulted parameter you define, if you do not provide an external name yourself. The automatic external name is the same as the local name, as if you had written a hash symbol before the local name in your code. -为了使这个过程更简单,如果你没有提供自定义的外部参数名,Swift 会为你定义的任何默认参数提供自动外部参数名。在代码中,如果你已经在本地参数名前加上 # 标识,那么自动外部参数名和本地参数名相同。 +为了使定义外部参数名更简单,如果你没有提供自定义的外部参数名,Swift 会为你定义的任何默认参数自动提供外部参数名。在代码中,如果你已经在本地参数名前加上 # 标识,那么自动外部参数名和本地参数名相同。 Here’s a version of the join function from earlier, which does not provide external names for any of its parameters, but still provides a default value for its joiner parameter: -下面是之前版本的 join函数,这个函数不为它的任何参数提供外部参数名,但仍然为它的 joiner 参数提供了默认值。 +下面是 join函数之前的版本,这个函数没有给它的任何参数提供外部参数名,但仍然为它的 joiner 参数提供了默认值。 ```js func join(s1: String, s2: String, joiner: String = " ") -> String { @@ -399,8 +400,8 @@ func join(s1: String, s2: String, joiner: String = " ") -> String { In this case, Swift automatically provides an external parameter name of joiner for the defaulted parameter. The external name must therefore be provided when calling the function, making the parameter’s purpose clear and unambiguous: -在这个例子中,Swift自动为默认参数joiner提供了外部参数名。因此,在调用该函数时,必须提供外部名,使该参数的用途明确、清晰。 - +在这个例子中,Swift自动为默认参数joiner提供了外部参数名。因此,在调用该函数时,必须使用外部参数名,使这个参数的用途明确清晰。 + ```js join("hello", "world", joiner: "-") // returns "hello-world” @@ -424,7 +425,7 @@ The values passed to a variadic parameter are made available within the function The example below calculates the arithmetic mean (also known as the average) for a list of numbers of any length: -下面的例子是对一个有任意个数的数字列表求算术平均数(也被称为平均数) +下面的例子可以对一个有任意个数的数字列表求算术平均数(也被称为平均数) ```js func arithmeticMean(numbers: Double...) -> Double { @@ -444,17 +445,18 @@ arithmeticMean(3, 8, 19) > A function may have at most one variadic parameter, and it must always appear last in the parameter list, to avoid ambiguity when calling the function with multiple parameters. -> 在调用带有多个参数的函数时,为了避免产生歧义,函数最多可以有一个可变参数,而且它必须总是放在参数列表的最后。 +> 在调用带有多个参数的函数时,为了避免产生歧义,函数最多只能有一个可变参数,而且它必须总是放在参数列表的最后。 + > If your function has one or more parameters with a default value, and also has a variadic parameter, place the variadic parameter after all the defaulted parameters at the very end of the list. -> 如果函数有一个或多个参数有默认值,且还有一个可变参数,请把可变参数放在所有默认参数列表的最后。 +> 如果函数有一个或多个参数带有默认值,且还有一个可变参数,请把可变参数放在所有默认参数列表的最后。 -## Constant and Variable Parameters 常量和变量参数 +## Constant and Variable Parameters 常量参数和变量参数 Function parameters are constants by default. Trying to change the value of a function parameter from within the body of that function results in a compile-time error. This means that you can’t change the value of a parameter by mistake. -函数参数默认都是常量。试图在函数体内改变参数的值会导致编译时错误。这会防止你意外地改变其参数值。 +函数参数默认都是常量。试图在函数体内改变参数值会导致编译时错误。这会防止你意外地改变参数值。 However, sometimes it is useful for a function to have a variable copy of a parameter’s value to work with. You can avoid defining a new variable yourself within the function by specifying one or more parameters as variable parameters instead. Variable parameters are available as variables rather than as constants, and give a new modifiable copy of the parameter’s value for your function to work with. @@ -462,7 +464,7 @@ However, sometimes it is useful for a function to have a variable copy of a para Define variable parameters by prefixing the parameter name with the keyword var: -可以在参数名前增加前缀关键字 var 来定义变量参数: +可以在参数名前增加关键字 var 来定义变量参数: ```js func alignRight(var string: String, count: Int, pad: Character) -> String { @@ -480,46 +482,45 @@ let paddedString = alignRight(originalString, 10, "-") This example defines a new function called alignRight, which aligns an input string to the right edge of a longer output string. Any space on the left is filled with a specified padding character. In this example, the string "hello" is converted to the string "-----hello”. -这个例子定义了名为alignRight的新函数,它把输入的 string 放在一个更长的输出字符串的最右端(译者注:以实现右对齐)。这个字符串的左边将被指定的字符所填充。在这个例子中,字符串“hello” 转换为 字符串“——hello”。 +这个例子定义了名为alignRight的新函数,它把输入的字符串放在一个更长的输出字符串的最右端(译者注:以实现右对齐)。这个字符串的左边用指定的字符填充。在这个例子中,字符串“hello” 转换为 字符串“——hello”。 The alignRight function defines the input parameter string to be a variable parameter. This means that string is now available as a local variable, initialized with the passed-in string value, and can be manipulated within the body of the function. -这个alignRight 函数把输入参数 string 定义为变量参数。这意味着在函数体内部可以把string当做本地变量使用,并初始化为传入的字符串值。 +函数alignRight 把输入参数 string 定义为变量参数。这意味着在函数体内部可以把string当做局部变量使用,并初始化为传入的字符串值。 The function starts by working out how many characters need to be added to the left of string in order to right-align it within the overall string. This value is stored in a local constant called amountToPad. The function then adds amountToPad copies of the pad character to the left of the existing string and returns the result. It uses the string variable parameter for all its string manipulation. -为了在整个字符串中右对齐 string,首先要算出 string 的左边需要添加多少字符。这个值储存在局部常量 amoutToPad 中。然后,函数在现有 string 的左边添加数量为 amoutToPad 的填充字符并返回结果。所有对 string 的操作均使用了 string 的可变参数。 +为了在整个字符串中右对齐 string,首先要算出 string 的左边需要添加多少字符。这个值储存在局部常量 amoutToPad 中。然后,函数在现有 string 的左边添加 amoutToPad 多个填充字符并返回结果。所有对 string 的操作均使用了 string 的可变参数。 > NOTE > The changes you make to a variable parameter do not persist beyond the end of each call to the function, and are not visible outside the function’s body. The variable parameter only exists for the lifetime of that function call. -> 变量参数的改变持续到每个函数调用的结束(不会超过),并在函数体外不可见。变量参数只存在于函数调用的生命周期中。 +> 变量参数的改变可以持续到每个函数调用的结束(不会超过),并在函数体外不可见。变量参数只存在于函数调用的生命周期中。 ## In-Out Parameters In-Out参数 Variable parameters, as described above, can only be changed within the function itself. If you want a function to modify a parameter’s value, and you want those changes to persist after the function call has ended, define that parameter as an in-out parameter instead. -变量参数,如前所述,只能在函数自身内部改变。如果希望函数可以修改参数值,且这些变化持续到函数调用结束之后,需要定义该参数为In-Out 参数。 +变量参数,如前所述,只能在函数自身内部改变。如果希望函数可以修改参数值,并且这些变化持续到函数调用结束之后,需要定义该参数为In-Out 参数。 You write an in-out parameter by placing the inout keyword at the start of its parameter definition. An in-out parameter has a value that is passed in to the function, is modified by the function, and is passed back out of the function to replace the original value. -在定义的参数前添加inout关键字,可以定义in-out参数。in-out参数的值会传入函数,被函数修改,然后传出函数来替换原始值。//TODO - +在定义的参数前添加inout关键字,可以定义in-out参数。传给函数的in-out参数的值会被函数修改,然后被传出函数,替换原来的值。 You can only pass a variable as the argument for an in-out parameter. You cannot pass a constant or a literal value as the argument, because constants and literals cannot be modified. You place an ampersand (&) directly before a variable’s name when you pass it as an argument to an inout parameter, to indicate that it can be modified by the function. -in-out参数作为函数参数,只能传入变量,不能传入常量或字面量。因为常量和字面量不能被修改。在变量名前直接加上&,把它作为参数传给inout参数,表明它可以被函数修改。 +in-out参数作为函数参数,只能传入变量,不能传入常量或字面量。因为常量和字面量不能被修改。在变量名前直接加上&,把它作为参数传给inout参数,表示它可以被函数修改。 > NOTE 注意 > In-out parameters cannot have default values, and variadic parameters cannot be marked as inout. If you mark a parameter as inout, it cannot also be marked as var or let. -> In-out参数不能有默认值,且可变参数不能标记为inout。如果定义一个参数为inout参数,就不能再定义它为var或let。 +> In-out参数不能有默认值,且可变参数不能用inout标记。如果定义一个参数为inout参数,就不能再用var或let标记。 Here’s an example of a function called swapTwoInts, which has two in-out integer parameters called a and b: -下面是swapTwoInts函数的例子,它有2个inout 整型参数a和b: +下面是swapTwoInts函数的例子,它有两个inout 整型参数a和b: ```js func swapTwoInts(inout a: Int, inout b: Int) { @@ -531,11 +532,11 @@ func swapTwoInts(inout a: Int, inout b: Int) { The swapTwoInts function simply swaps the value of b into a, and the value of a into b. The function performs this swap by storing the value of a in a temporary constant called temporaryA, assigning the value of b to a, and then assigning temporaryA to b. -swapTwoInts函数简单地交换a、b值。先把a值存储在临时常量temporaryA中,然后把b值赋给a,最后把temporaryA赋值给b来实现交换。 +函数swapTwoInts简单地交换a、b值。先把a值存储在临时常量temporaryA中,然后把b值赋给a,最后把temporaryA赋值给b来实现交换。 You can call the swapTwoInts function with two variables of type Int to swap their values. Note that the names of someInt and anotherInt are prefixed with an ampersand when they are passed to the swapTwoInts function: -可以调用 swapTwoInts 函数交换两个 Int 型变量的值。注意把someInt 和anotherInt 传给swapTwoInts函数时,它们的名字前都有&的前缀: +可以调用 swapTwoInts 函数交换两个 Int 型变量的值。注意把someInt 和anotherInt 传给swapTwoInts函数时,它们的名字前都有&作为前缀: ```js var someInt = 3 @@ -547,19 +548,19 @@ println("someInt is now \(someInt), and anotherInt is now \(anotherInt)") The example above shows that the original values of someInt and anotherInt are modified by the swapTwoInts function, even though they were originally defined outside of the function. -上面的例子说明函数 swapTwoInts 改变了 someInt 和anotherInt 的初始值,尽管它们的初始值是在函数外定义的。 +上面的例子显示出函数 swapTwoInts 改变了 someInt 和anotherInt 的初始值,尽管它们的初始值是在函数外定义的。 > NOTE 注意 > In-out parameters are not the same as returning a value from a function. The swapTwoInts example above does not define a return type or return a value, but it still modifies the values of someInt and anotherInt. In-out parameters are an alternative way for a function to have an effect outside of the scope of its function body. -> In-out参数和从函数中返回的值不一样。虽然上面swapTwoInts的例子没有定义返回类型和返回值,但它仍然修改了someInt 和anotherInt的值。In-out参数是函数对函数体范围外产生影响的另一种方式。 +> In-out参数和函数返回值不一样。虽然上面swapTwoInts的例子没有定义返回类型和返回值,但它仍然修改了someInt 和anotherInt的值。In-out参数是函数对函数体范围外产生影响的另一种方式。 # Function Types 函数类型 Every function has a specific function type, made up of the parameter types and the return type of the function. -每个函数都有一个特定的函数类型,由函数参数类型和返回类型组成。 +每个函数都有一个特定的函数类型,由函数参数类型和返回类型组成。 For example: @@ -576,7 +577,7 @@ func multiplyTwoInts(a: Int, b: Int) -> Int { This example defines two simple mathematical functions called addTwoInts and multiplyTwoInts. These functions each take two Int values, and return an Int value, which is the result of performing an appropriate mathematical operation. -这个例子定义了2个简单的数学函数addTwoInts 和multiplyTwoInts。每个函数都接受两个整型值并返回一个整型值——执行相应数学运算的结果。 +这个例子定义了两个简单的数学函数addTwoInts和multiplyTwoInts。每个函数都接受两个整型值并返回一个整型值——执行相应数学运算的结果。 The type of both of these functions is (Int, Int) -> Int. This can be read as: @@ -584,7 +585,7 @@ The type of both of these functions is (Int, Int) -> Int. This can be read as: “A function type that has two parameters, both of type Int, and that returns a value of type Int.” -函数类型是有2个整型参数和一个整型返回值 +这个函数类型有两个Int类型参数和一个Int类型返回值。 Here’s another example, for a function with no parameters or return value: @@ -598,13 +599,13 @@ func printHelloWorld() { The type of this function is () -> (), or “a function that has no parameters, and returns Void.” Functions that don’t specify a return value always return Void, which is equivalent to an empty tuple in Swift, shown as (). -这个函数的类型是() -> (),或”没有参数,且返回Void的函数。“不定义返回值的函数始终返回Void,相当于Swift中的空元组,写作()。 +这个函数的类型是() -> (),或理解为”没有参数,且返回Void的函数。“不定义返回值的函数始终返回Void,相当于Swift中的空元组,写作()。 -## Using Function Types 使用函数类型 +## Using Function Types 函数类型的使用 You use function types just like any other types in Swift. For example, you can define a constant or variable to be of a function type and assign an appropriate function to that variable: -你可以像使用Swift中任何其他类型那样使用函数类型。例如,可以定义一个函数类型的常量或变量,并且把对应的函数赋给这个变量。 +你可以像使用Swift中任何其他类型那样使用函数类型。例如,可以定义一个函数类型的常量或变量,并且把对应的函数赋值给它。 ```js var mathFunction: (Int, Int) -> Int = addTwoInts @@ -616,15 +617,15 @@ This can be read as: “Define a variable called mathFunction, which has a type of ‘a function that takes two Int values, and returns an Int value.’ Set this new variable to refer to the function called addTwoInts.” -”定义名为mathFunction的变量,该变量类型为’可以接收两个整型参数并返回整型值的函数’。设置这个新变量引用addTwoInts函数“ +”定义名为mathFunction的变量,该变量类型为’可以接收两个Int类型参数并返回Int类型值的函数’。设置这个新变量指向addTwoInts函数“ The addTwoInts function has the same type as the mathFunction variable, and so this assignment is allowed by Swift’s type-checker. -addTwoInts 函数和mathFunction 函数有相同的类型,因此Swift的类型检查允许这种赋值。 +函数addTwoInts 和mathFunction 有相同的类型,因此Swift的类型检查允许这种赋值。 You can now call the assigned function with the name mathFunction: -可以使用mathFunction名来调用函数: +可以使用mathFunction名来调用被赋值的函数: ```js println("Result: \(mathFunction(2, 3))") @@ -653,11 +654,11 @@ let anotherMathFunction = addTwoInts You can use a function type such as (Int, Int) -> Int as a parameter type for another function. This enables you to leave some aspects of a function’s implementation for the function’s caller to provide when the function is called. -可以使用类似 (Int, Int) -> Int的函数类型作为另一个函数的参数类型。在函数调用时,可以把一个函数的某些实现留给函数调用者来确定。 +可以使用类似 (Int, Int) -> Int的函数类型作为另一个函数的参数类型。这样在函数调用时,可以把一个函数的某些实现留给函数调用者。 Here’s an example to print the results of the math functions from above: -下面的例子可以打印上面数学函数的结果。 +下面的例子可以输出上面数学函数的计算结果。 ```js func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) { @@ -669,16 +670,15 @@ printMathResult(addTwoInts, 3, 5) This example defines a function called printMathResult, which has three parameters. The first parameter is called mathFunction, and is of type (Int, Int) -> Int. You can pass any function of that type as the argument for this first parameter. The second and third parameters are called a and b, and are both of type Int. These are used as the two input values for the provided math function. -这个例子定义了函数printMathResult,它有三个参数。第一参数是 mathFunction,(Int, Int) -> Int类型的。可以传入任何该类型的函数作为该函数的第一个参数。第二和第三个参数是a和b,都是整形。它们被用来作为所提供的数学函数的两个输入值。 +这个例子定义了printMathResult函数,它有三个参数。第一参数是 mathFunction,(Int, Int) -> Int类型的。可以传入任何这种类型的函数作为该函数的第一个参数。第二和第三个参数是a和b,都是Int类型。把它们作为所提供的数学函数的两个输入值。 When printMathResult is called, it is passed the addTwoInts function, and the integer values 3 and 5. It calls the provided function with the values 3 and 5, and prints the result of 8. -调用printMathResult 时,传入addTwoInts 函数、整型值3和5作为参数。让后把3和5作为参数调用 addTwoInts ,最后打印出结果8。 +调用printMathResult 时,传入addTwoInts 函数、Int类型的3和5作为参数。让后把3和5作为参数调用 addTwoInts ,最后输出结果8。 The role of printMathResult is to print the result of a call to a math function of an appropriate type. It doesn’t matter what that function’s implementation actually does—it matters only that the function is of the correct type. This enables printMathResult to hand off some of its functionality to the caller of the function in a type-safe way. -printMathResult 的作用是打印相应类型的数学函数的调用结果。与函数的具体实现无关,只与函数具有的正确类型有关。这让函数 printMathResult 以类型安全的方式,把它的部分功能交给其调用者。 - +函数printMathResult 的作用是输出相应类型的数学函数的调用结果。它与传入函数的具体实现无关,只与函数具有的正确类型有关。这让函数 printMathResult 以类型安全的方式,把它的部分功能交给其调用者去实现。 ## Function Types as Return Types @@ -686,7 +686,7 @@ printMathResult 的作用是打印相应类型的数学函数的调用结果。 You can use a function type as the return type of another function. You do this by writing a complete function type immediately after the return arrow (->) of the returning function. -可以使用函数 类型作为另一个函数的返回类型。通过在返回函数的返回箭头(->)后编写完整的函数类型。 +可以使用函数 类型作为另一个函数的返回类型。需要在返回函数的返回箭头(->)后编写完整的函数类型。 The next example defines two simple functions called stepForward and stepBackward. The stepForward function returns a value one more than its input value, and the stepBackward function returns a value one less than its input value. Both functions have a type of (Int) -> Int: @@ -703,7 +703,7 @@ func stepBackward(input: Int) -> Int { Here’s a function called chooseStepFunction, whose return type is “a function of type (Int) -> Int”. chooseStepFunction returns the stepForward function or the stepBackward function based on a Boolean parameter called backwards: -下面是函数chooseStepFunction,它的返回类型是”类型为(Int) -> Int的函数“。chooseStepFunction 根据布尔参数 backwards 判断是返回 stepForward 函数,还是返回 stepBackward 函数。 +下面是函数chooseStepFunction,它的返回类型是(Int) -> Int的函数。chooseStepFunction 根据Boolean 类型参数 backwards 判断是返回 stepForward 函数,还是返回 stepBackward 函数。 ```js func chooseStepFunction(backwards: Bool) -> (Int) -> Int { @@ -713,7 +713,7 @@ func chooseStepFunction(backwards: Bool) -> (Int) -> Int { You can now use chooseStepFunction to obtain a function that will step in one direction or the other: -使用函数chooseStepFunction,可以获得指示前进或后退的返回函数。 +使用函数chooseStepFunction,可以获得返回函数,指示前进或后退。 ```js var currentValue = 3 @@ -723,12 +723,12 @@ let moveNearerToZero = chooseStepFunction(currentValue > 0) The preceding example works out whether a positive or negative step is needed to move a variable called currentValue progressively closer to zero. currentValue has an initial value of 3, which means that currentValue > 0 returns true, causing chooseStepFunction to return the stepBackward function. A reference to the returned function is stored in a constant called moveNearerToZero. -前面的例子实现了确定 正向或是反向移动使 变量 currentValue 逐步趋向于零的功能。currentValue 初始值为3,这意味着currentValue > 0 返回true,导致chooseStepFunction 返回stepBackward 函数。返回的函数的引用被存储在常量moveNearerToZero中。 +前面的例子实现了是需要正向还是反向移动,使得变量 currentValue 逐步趋向于零的功能。currentValue 的初始值是3,这意味着currentValue > 0 返回true,使得chooseStepFunction 返回stepBackward 函数。返回的函数引用存储在常量moveNearerToZero中。 Now that moveNearerToZero refers to the correct function, it can be used to count to zero: -现在 moveNearerToZero 引用了正确的函数,可以用来计数到零: +现在 moveNearerToZero 指向了正确的函数,可以用来计数到零: ```js println("Counting to zero:") @@ -753,7 +753,7 @@ All of the functions you have encountered so far in this chapter have been examp Nested functions are hidden from the outside world by default, but can still be called and used by their enclosing function. An enclosing function can also return one of its nested functions to allow the nested function to be used in another scope. -嵌套函数默认在外部环境下不可访问,但仍可以被闭包函数调用。闭包函数也可以返回它其中一个嵌套函数,使得这个嵌套函数可以在其他作用域内使用。 +默认情况下,嵌套函数不能在外部访问,但仍可以被闭包函数调用。闭包函数也可以返回它其中一个嵌套函数,使得这个嵌套函数可以在其他作用域内使用。 You can rewrite the chooseStepFunction example above to use and return nested functions: From e92f73a0237416f18970f9470e72df2d7e17c055 Mon Sep 17 00:00:00 2001 From: Mengyuan Wu Date: Mon, 23 Jun 2014 01:43:33 +0800 Subject: [PATCH 164/261] finish 01_the_basics --- src/chapter2/01_The_Basics.md | 254 ++++++++++++++++++++++++++++++---- 1 file changed, 225 insertions(+), 29 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 9fea829..3ff2f01 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -676,135 +676,275 @@ The (404, "Not Found") tuple groups together an Int and a String to give the HTT You can create tuples from any permutation of types, and they can contain as many different types as you like. There’s nothing stopping you from having a tuple of type (Int, Int, Int), or (String, Bool), or indeed any other permutation you require. +你可以创建一个含任意类型组合的元组,它们可以包含任意多的类型。谁也不能阻止你创建一个(Int, Int, Int)类型或者(String, Bool)类型,又或者任意你想要的类型组合的元组。 + You can decompose a tuple’s contents into separate constants or variables, which you then access as usual: +你可以把一个元组的内容分解成独立的常量或变量,然后你就可以像平常一样调用它们: + +``` let (statusCode, statusMessage) = http404Error println("The status code is \(statusCode)") // prints "The status code is 404" +println("状态码是 \(statusCode)") +// 输出”状态码是404“ println("The status message is \(statusMessage)") // prints "The status message is Not Found" +``` + +``` +let (statusCode, statusMessage) = http404Error +println("状态码是 \(statusCode)") +// 输出”状态码是404“ +println("状态信息是 \(statusMessage)") +// prints "状态信息是 Not Found" +``` + If you only need some of the tuple’s values, ignore parts of the tuple with an underscore (_) when you decompose the tuple: +如果你只需要元组的一部分值,当你分解元组的时候使用下划线(_)来忽略元组的一部分值: + +``` let (justTheStatusCode, _) = http404Error println("The status code is \(justTheStatusCode)") // prints "The status code is 404" +``` + +``` +let (justTheStatusCode, _) = http404Error +println("状态码是 \(justTheStatusCode)") +// prints "状态码是 404" +``` + Alternatively, access the individual element values in a tuple using index numbers starting at zero: +同样的,使用从0开始的序列可以调用元组中的一个单独元素的值。 + +``` println("The status code is \(http404Error.0)") // prints "The status code is 404" println("The status message is \(http404Error.1)") // prints "The status message is Not Found" +``` + You can name the individual elements in a tuple when the tuple is defined: +定义元组的时候,你可以给元素单独命名: + +``` let http200Status = (statusCode: 200, description: "OK") +``` + If you name the elements in a tuple, you can use the element names to access the values of those elements: +如果你给元组中的元素命名了,你可以用这个名字来调用它们的值: + +``` println("The status code is \(http200Status.statusCode)") // prints "The status code is 200" println("The status message is \(http200Status.description)") // prints "The status message is OK" +``` + Tuples are particularly useful as the return values of functions. A function that tries to retrieve a web page might return the (Int, String) tuple type to describe the success or failure of the page retrieval. By returning a tuple with two distinct values, each of a different type, the function provides more useful information about its outcome than if it could only return a single value of a single type. For more information, see Functions with Multiple Return Values. -NOTE +作为函数的返回值元组是很有用的。 + +> NOTE + +> Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple. For more information, see Classes and Structures. + +> 注意 -Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple. For more information, see Classes and Structures. +> 当你处理一些相关数据的临时组合,元组是很有用的。如果你的数据结构超过了一个临时的范畴,用class或者structrue会比用元组tuple更合适。更多信息,参见[Classes and Structures](link)。 -Optionals +# Optionals +# 可选类型 You use optionals in situations where a value may be absent. An optional says: -There is a value, and it equals x +当值可能缺失的情况下,可以用可选类型(Options)。可选类型表示: + +- There is a value, and it equals x + or -There isn’t a value at all -NOTE +- There isn’t a value at all + + +- 那里有一个值,它等于x + +或者 + +- 值不存在 -The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structs, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there is a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants. +> NOTE + +> The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structs, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there is a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants. + +> 注意 + +> 可选类型在C或者Objective-C中都不存在。在Objective-C中最接近的是一个返回一个对象的方法也可以返回一个nil值的能力,nil的意思是“有效对象的缺失”。然而,它只对对象有效,对structs, basic C types, or enumeration values都是无效的。对这些类型,Objective-C通常会返回一个特殊值(比如NSNotFound)来表示值缺失。这样的方式假定我们调用方法时它必须知道有一个特殊值,并且要记得去检查它。Siwft的可选类型让你可以给任意类型的值声明这个值缺失,不需要任何其它的特殊常量。 Here’s an example. Swift’s String type has a method called toInt, which tries to convert a String value into an Int value. However, not every string can be converted into an integer. The string "123" can be converted into the numeric value 123, but the string "hello, world" does not have an obvious numeric value to convert to. +下面是一个例子。Siwft的字符串类型有一个toInt的方法,它会尝试将一个字符串类型转换成一个整数类型。然而,不是每一额字符串都可以转换成整数的。字符串“123”可以转换为数字量123,但是字符串"Hello, world"并没有一个明显的数字量可以转换。 + The example below uses the toInt method to try to convert a String into an Int: +下面这个例子用`toInt`方法尝试转换字符串到整数: + +``` let possibleNumber = "123" let convertedNumber = possibleNumber.toInt() // convertedNumber is inferred to be of type "Int?", or "optional Int" +``` + Because the toInt method might fail, it returns an optional Int, rather than an Int. An optional Int is written as Int?, not Int. The question mark indicates that the value it contains is optional, meaning that it might contain some Int value, or it might contain no value at all. (It can’t contain anything else, such as a Bool value or a String value. It’s either an Int, or it’s nothing at all.) -If Statements and Forced Unwrapping +因为`toInt`方法可能失败,它返回的是可以可选类型的整数,而不是一个整数。一个可选的整数表示为`Int?`,而不是`Int`。最后的问号表示这个值是可选的,意味着它可能包含整数类型的值,或者它没有值。(它不能包括其它任何值,比如布尔值或者字符串。它要不是一个整数,要不就没有值。) + +# If Statements and Forced Unwrapping +# If语句和强制解析 You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to true; if it has no value at all, it evaluates to false. +你可以使用if语句来判断一个可选类型是否有值。如果有值,它就等于true,如果没有值,就等于false。 + Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value: +一旦你确定可选类型是有值的,你可以在可选类型的名字后面加一个感叹号(!)来调用它的值。这个感叹号的意思是:”我知道这个可选类型的值一定存在一个值,请使用这个值。“这叫做可选值的强制解析: + +``` if convertedNumber { println("\(possibleNumber) has an integer value of \(convertedNumber!)") } else { println("\(possibleNumber) could not be converted to an integer") } // prints "123 has an integer value of 123" +``` + For more on the if statement, see Control Flow. -NOTE +更多信息,见[Control Flow](link)。 + +> NOTE + +> Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value. + +> 注意 -Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value. +> 如果你使用!来调用一个不存在的可选值,会报出实时错误。在使用!强制解析可选值之前总是确认这个可选值包含一个非nil的值。 -Optional Binding +# Optional Binding +# 可选值绑定 You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used with if and while statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action. if and while statements are described in more detail in Control Flow. +你可以使用可选值绑定(optional binding)来找出一个可选类型是否包含值,如果包含,则可以把这个值作为一个临时常量或变量来使用。可选值绑定可以和if或while语句一起来检查可选值里面的值,并且解析到一个常量或变量中,所有这些都在一步操作中完成。更多关于if和while语句的信息,见[Control Flow](link)。 + Write optional bindings for the if statement as follows: +像这样给if语句写可选值绑定: + +``` if let constantName = someOptional { statements } +``` + You can rewrite the possibleNumber example from above to use optional binding rather than forced unwrapping: +你可以用可选值绑定来代替强制解析来重写之前那个possibleNumber的例子: + +``` if let actualNumber = possibleNumber.toInt() { println("\(possibleNumber) has an integer value of \(actualNumber)") } else { println("\(possibleNumber) could not be converted to an integer") } // prints "123 has an integer value of 123" +``` + This can be read as: +这段代码可以解读为: + “If the optional Int returned by possibleNumber.toInt contains a value, set a new constant called actualNumber to the value contained in the optional.” +”如果可选整数值通过possibleNumber.toInt返回一个值,设定一个叫actualNumber的新的常量来储存这个可选整数中的值。“ + If the conversion is successful, the actualNumber constant becomes available for use within the first branch of the if statement. It has already been initialized with the value contained within the optional, and so there is no need to use the ! suffix to access its value. In this example, actualNumber is simply used to print the result of the conversion. +如果这个转换是成功的,那么常量actualNumber在if语句的第一个分支就可用了。它已经用可选量中的值初始化了,所以现在不需要用!后缀来调用这个值。在这个例子中,actualNumber只是简单的用于输出转换结果。 + You can use both constants and variables with optional binding. If you wanted to manipulate the value of actualNumber within the first branch of the if statement, you could write if var actualNumber instead, and the value contained within the optional would be made available as a variable rather than a constant. -nil +无论是常量还是变量你都可以使用可选值绑定。如果你希望对if语句第一个分支中actualNumber的值进行操作,你可以用if var actualNumber来声明,然后可选量中的值就会成为一个可用的变量而不是常量。 + +# nil +# nil You set an optional variable to a valueless state by assigning it the special value nil: +给可选变量一个没有值的状态是通过给它赋予一个特殊值nil来完成的: + +``` var serverResponseCode: Int? = 404 // serverResponseCode contains an actual Int value of 404 serverResponseCode = nil // serverResponseCode now contains no value -NOTE +``` -nil cannot be used with non-optional constants and variables. If a constant or variable in your code needs to be able to cope with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type. +> NOTE + +> nil cannot be used with non-optional constants and variables. If a constant or variable in your code needs to be able to cope with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type. + +> 注意 + +> nil不能被用于可选类型之外的常量和变量。如果你的代码中的常量或变量需要处理值缺失的情况,总是用一个可选的合适类型来声明它。 If you define an optional constant or variable without providing a default value, the constant or variable is automatically set to nil for you: +如果你定义一个可选的常量或变量,却没有赋初值,这个常量或变量会自动设为nil: + +``` var surveyAnswer: String? // surveyAnswer is automatically set to nil -NOTE +``` -Swift’s nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a non-existent object. In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types. +> NOTE + +> Swift’s nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a non-existent object. In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types. + +> 注意 + +> Swift的nil和Objective-C中的不完全一样。Objective-C中,nil是指向不存在的对象。而在Swift中,nil不知是一个指针——它是一个特定类型的值缺失。可选的任何类型都可以设为nil,不只是对象类型。 -Implicitly Unwrapped Optionals +# Implicitly Unwrapped Optionals +# 隐式解析可选值 As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist. +像之前说的,可选值意味着一个常量或变量允许“没有值”。可以通过if语句来判断可选值中是否有值存在,如果值存在则用可选值绑定来调用可选量的值。 + Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time. +有时候从程序的结构可以清楚的知道一个可选值在第一次值设定之后,它总是有值的。在这些情况下,把每次调用都检查并解析可选量的值去掉是很有用的,因为它们可以安全的被推断出它们总是有值的。 + These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional. +这些类型的可选值被定义为隐式解析可选值。当你创建可选值的时候,你可以通过写感叹号(String!)而不是问号(String?)的形式来写一个隐式解析的可选值。 + Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties. +如果可选值在第一次定义之后就肯定存在值并且之后每一刻都肯定存在,这种情况下隐式解析可选值是很有用红的。Swift中的隐式解析可选值的主要用法是在类的初始化过程中,参见[Unowned References and Implicitly Unwrapped Optional Properties](link)。 + An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it is accessed. The following example shows the difference in behavior between an optional String and an implicitly unwrapped optional String: +一个隐式解析可选值其实是一个普通的可选值,但它也可以像非可选的值那样使用,无须每次调用都解析可选量的值。下面的例子显示了一个普通的可选的字符串和一个隐式解析的可选字符串的区别: + +``` let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string." @@ -812,57 +952,113 @@ println(possibleString!) // requires an exclamation mark to access its value let assumedString: String! = "An implicitly unwrapped optional string." println(assumedString) // no exclamation mark is needed to access its value // prints "An implicitly unwrapped optional string." +``` + You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used. Rather than placing an exclamation mark after the optional’s name each time you use it, you place an exclamation mark after the optional’s type when you declare it. -NOTE +你可以把隐式解析可选值当作一个允许可选值每次都能自动解析的授权。你只需要当你声明的时候在可选量的类型后面放一个感叹号,而不用每次使用的时候都在可选值后面放感叹号。 -If you try to access an implicitly unwrapped optional when it does not contain a value, you will trigger a runtime error. The result is exactly the same as if you place an exclamation mark after a normal optional that does not contain a value. +> NOTE + +> If you try to access an implicitly unwrapped optional when it does not contain a value, you will trigger a runtime error. The result is exactly the same as if you place an exclamation mark after a normal optional that does not contain a value. + +> 注意 + +> 如果你试图调用一个没有值的隐式解析可选值,你会得到一个实时的错误。这和你在一个普通的不含值的可选值后面放感叹号的结果是完全一样的。 You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value: +你仍然可以把隐式解析可选值当作一个普通的可选值,来检查它是否含有值: + +``` if assumedString { println(assumedString) } // prints "An implicitly unwrapped optional string." +``` + You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement: +你同样可以对隐式解析可选值使用可选值绑定,在一行声明中来检查和解析它的值: + +``` if let definiteString = assumedString { println(definiteString) } // prints "An implicitly unwrapped optional string." -NOTE +``` -Implicitly unwrapped optionals should not be used when there is a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable. +> NOTE -Assertions +> Implicitly unwrapped optionals should not be used when there is a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable. + +> 注意 + +> 当一个变量有可能是nil的情况下,不应当使用隐式解析可选值。如果在整个过程中检查一个变量是否有nil值,你应该用一个普通的可选值。 + +# Assertions +# 断言 Optionals enable you to check for values that may or may not exist, and to write code that copes gracefully with the absence of a value. In some cases, however, it is simply not possible for your code to continue execution if a value does not exist, or if a provided value does not satisfy certain conditions. In these situations, you can trigger an assertion in your code to end code execution and to provide an opportunity to debug the cause of the absent or invalid value. -Debugging with Assertions +可选值让你可以检查一个值是否存在,并且优雅的处理值缺失的情况。然而,在一些情况下,如果值不存在或者值不满足指定的条件,你的程序就无法继续执行。在这些情况下,你可以在代码中触发一个断言,来中断代码的执行并且提供一个调试为什么值缺失或无效的机会。 + +## Debugging with Assertions +## 用断言来调试 An assertion is a runtime check that a logical condition definitely evaluates to true. Literally put, an assertion “asserts” that a condition is true. You use an assertion to make sure that an essential condition is satisfied before executing any further code. If the condition evaluates to true, code execution continues as usual; if the condition evaluates to false, code execution ends, and your app is terminated. +断言是判断一个逻辑条件是否为真的实时检查。基本上,一个断言就是“断定”(asserts)一个条件为真。你可以使用断言来确保在运行后续代码之前它的一个必要的条件是已经满足了的。如果这个条件为真,代码会正常执行,如果条件为否,代码会停止执行,并且你的app会终止。 + If your code triggers an assertion while running in a debug environment, such as when you build and run an app in Xcode, you can see exactly where the invalid state occurred and query the state of your app at the time that the assertion was triggered. An assertion also lets you provide a suitable debug message as to the nature of the assert. +如果你的代码值调试环境下触发了一个断言,比如当你在Xcode中创建并运行一个app的时候,你可以准确的看到非法语句出现的位置,也可以查询到当断言触发时app的状态。断言还允许你可以提供一个相应的调试信息。 + You write an assertion by calling the global assert function. You pass the assert function an expression that evaluates to true or false and a message that should be displayed if the result of the condition is false: +通过调用全局的断言函数来写一个断言。你给断言函数传入一个等于true或false的表达式,当结果是false的时候,会显示出一条信息: + +``` let age = -3 assert(age >= 0, "A person's age cannot be less than zero") // this causes the assertion to trigger, because age is not >= 0 +``` + In this example, code execution will continue only if age >= 0 evaluates to true, that is, if the value of age is non-negative. If the value of age is negative, as in the code above, then age >= 0 evaluates to false, and the assertion is triggered, terminating the application. +在这个例子里,只有age >= 0为真的时候代码才会继续执行,也就是,如果age的值是非负数。如果age的值是负数,在上面的代码中,这个age >= 0的条件判断为否,这个断言被触发,终止了这个程序。 + Assertion messages cannot use string interpolation. The assertion message can be omitted if desired, as in the following example: +断言信息不能使用字符串插值。如果你想,断言信息是可以省略的,像下面这个例子: + +``` assert(age >= 0) -When to Use Assertions +``` + +## When to Use Assertions +## 何时使用断言 Use an assertion whenever a condition has the potential to be false, but must definitely be true in order for your code to continue execution. Suitable scenarios for an assertion check include: -An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high. -A value is passed to a function, but an invalid value means that the function cannot fulfill its task. -An optional value is currently nil, but a non-nil value is essential for subsequent code to execute successfully. +如果一个条件有可能为否,但只有它为真的时候代码才能继续执行,这时应该使用断言。适当的使用断言检查的场景包括: + +- An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high. +- A value is passed to a function, but an invalid value means that the function cannot fulfill its task. +- An optional value is currently nil, but a non-nil value is essential for subsequent code to execute successfully. + +- 一个整数类型的下标索引被传入一个自定义的下标实现,但是这个下标索引值太小或太大。 +- 一个值传入一个函数,但是如果传入不合法的值,这个函数就无法满足需求。 +- 一个可选值当前的值是nil,但是后续代码成功执行需要一个非nil值。 + See also Subscripts and Functions. -NOTE +参见[Subscripts and Functions](link)。 + +> NOTE + +> Assertions cause your app to terminate and are not a substitute for designing your code in such a way that invalid conditions are unlikely to arise. Nonetheless, in situations where invalid conditions are possible, an assertion is an effective way to ensure that such conditions are highlighted and noticed during development, before your app is published. + +> 注意 -Assertions cause your app to terminate and are not a substitute for designing your code in such a way that invalid conditions are unlikely to arise. Nonetheless, in situations where invalid conditions are possible, an assertion is an effective way to ensure that such conditions are highlighted and noticed during development, before your app is published. \ No newline at end of file +> 断言会造成你的app终止,它并不能代替你设计代码来保证不合法情况不出现。尽管如此,当不合法的情况可能出现时,断言可以有效的保证在你的app正式发布之前,在开发过程中这种不合法的情况就会被高亮并被注意到。f \ No newline at end of file From 94e32a1a099c20b964a08737f803785d75c8a192 Mon Sep 17 00:00:00 2001 From: "nuo.xun" Date: Mon, 23 Jun 2014 10:39:35 +0800 Subject: [PATCH 165/261] v1.0.1 + --- src/chapter2/15_Deinitialization.md | 171 +++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 1 deletion(-) diff --git a/src/chapter2/15_Deinitialization.md b/src/chapter2/15_Deinitialization.md index b5c1818..5ad1996 100644 --- a/src/chapter2/15_Deinitialization.md +++ b/src/chapter2/15_Deinitialization.md @@ -1 +1,170 @@ -# 析构过程 \ No newline at end of file +# 析构过程 (Deinitialization) + +A deinitializer is called immediately before a class instance is deallocated. You write deinitializers with the deinit keyword, similar to how intializers are written with the init keyword. Deinitializers are only available on class types.” + +> 析构函数会在一个类的实例被释放之前被立即调用。用`deinit`关键词来声明析构函数,用`init`来标示类似于初始化的函数。析构函数仅在类中有效。 + +#### How Deinitialization Works + +> #### 析构过程是如何工作的 + +Swift automatically deallocates your instances when they are no longer needed, to free up resources. Swift handles the memory management of instances through automatic reference counting (ARC), as described in Automatic Reference Counting. Typically you don’t need to perform manual clean-up when your instances are deallocated. However, when you are working with your own resources, you might need to perform some additional clean-up yourself. For example, if you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated. + +> Swift 会自动释放不再需要的实例以释放资源。如自动引用计数那一章描述,Swift 通过自动引用计数(ARC)处理实例的内存管理。通常当你的实例被释放时不需要手动地去清理。但是,当使用自己的资源时,你可能需要进行一些额外的清理。例如,如果创建了一个自定义的类来打开一个文件,并写入一些数据,你可能需要在类实例被释放之前关闭该文件。 + + +Class definitions can have at most one deinitializer per class. The deinitializer does not take any parameters and is written without parentheses: + +> 在类的定义中,每个类最多只能有一个析构函数。析构函数不带任何参数,在写法上不带括号: + +```` +deinit { + // 执行析构过程 +} +```` + + +Deinitializers are called automatically, just before instance deallocation takes place. You are not allowed to call a deinitializer yourself. Superclass deinitializers are inherited by their subclasses, and the superclass deinitializer is called automatically at the end of a subclass deinitializer implementation. Superclass deinitializers are always called, even if a subclass does not provide its own deinitializer. + + +> 析构函数会自动在实例释放之前被调用,且不支持手动调用。子类会继承父类的析构函数,在子类析构函数实现的之后,将自动调用父类的析构函数。即便子类没有提供自身的析构函数,其父类的析构函数也总是被调用。 + + +Because an instance is not deallocated until after its deinitializer is called, a deinitializer can access all properties of the instance it is called on and can modify its behavior based on those properties (such as looking up the name of a file that needs to be closed). + +> 因为实例直到实例的析构函数被调用时才会被释放,所以析构函数有权访问所有被调用实例的属性,同时根据那些属性修改其行为(例如查找一个需被关闭文件的名称)。 + + + +#### Deinitializers in Action + +> #### 析构函数操作 + + +Here’s an example of a deinitializer in action. This example defines two new types, Bank and Player, for a simple game. The Bank structure manages a made-up currency, which can never have more than 10,000 coins in circulation. There can only ever be one Bank in the game, and so the Bank is implemented as a structure with static properties and methods to store and manage its current state:” + +> 下面是一个析构函数操作的例子。它是一个简单的游戏,定义了两种新类型,Bank和Player。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) { + coinsInBank += coins + } +} +```` + + +Bank keeps track of the current number of coins it holds with its coinsInBank property. It also offers two methods—vendCoins and receiveCoins—to handle the distribution and collection of coins. + +> Bank根据它的coinsInBank属性来侦听当前存有的货币数。除此之外Bank还提供两个其它方法,分别是receiveCoins和vendCoins,用于处理货币的存取。 + + + +vendCoins checks that there are enough coins in the bank before distributing them. If there are not enough coins, Bank returns a smaller number than the number that was requested (and returns zero if no coins are left in the bank). vendCoins declares numberOfCoinsToVend as a variable parameter, so that the number can be modified within the method’s body without the need to declare a new variable. It returns an integer value to indicate the actual number of coins that were provided. + +> vendCoins方法在 bank 取出货币之前检查是否有足够的量。如果货币不足,Bank则返会所有的剩余量(如果货币量为空则返回 0)。vendCoins方法中将numberOfCoinsToVend声明为一个变量,这样就可以在其它方法中对它进行修改,而无需定义一个新的变量。最终vendCoins方法将为取出的货币返回一个整型值。 + + + +The receiveCoins method simply adds the received number of coins back into the bank’s coin store. + +> 而 receiveCoins 方法更加简单, 将 bank 的货币存量和接收到的货币量相加后再保存回 bank 的货币存量。 + + + +The Player class describes a player in the game. Each player has a certain number of coins stored in their purse at any time. This is represented by the player’s coinsInPurse property: + +> 这里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) + } +} +```` + +Each Player instance is initialized with a starting allowance of a specified number of coins from the bank during initialization, although a Player instance may receive fewer than that number if not enough coins are available. + +> 每一个Player都由一个初始化函数加上指定货币量入参实例化得到,他们将在初始化的过程中从 bank 获得货币。如果 Bank 没有足够的货币存量用于支付,Player 取得的货币量可能会比指定的少。 + + + +The Player class defines a winCoins method, which retrieves a certain number of coins from the bank and adds them to the player’s purse. The Player class also implements a deinitializer, which is called just before a Player instance is deallocated. Here, the deinitializer simply returns all of the player’s coins to the bank: + +> Player类还定义了一个winCoins的方法,该方法可以让player从bank赢取一定数量的硬币存入自己钱包。同时Player类还实现了一个析构函数,它在Player实例释放前一步会被调用。这里的析构函数很简单:将所有player的货币都返还给银行: + + + + +```` +var playerOne: Player? = Player(coins: 100) +println("A new player has joined the game with \(playerOne!.coinsInPurse) coins") +// 打印 "新玩家加入游戏,为其分配100货币" +println("There are now \(Bank.coinsInBank) coins left in the bank") +// 打印 "目前银行货币存量为: 9900" +```` + + +A new Player instance is created, with a request for 100 coins if they are available. This Player instance is stored in an optional Player variable called playerOne. An optional variable is used here, because players can leave the game at any point. The optional lets you track whether there is currently a player in the game. + +> 这里创建了一个新的Player实例,如果银行存量充足他将获取100货币。由于玩家可能随时离开游戏,所以将Player实例存储在一个名为playerOne的可选Player变量中。这样您可以侦听当前是否还有玩家在游戏中。 + + + + + +Because playerOne is an optional, it is qualified with an exclamation mark (!) when its coinsInPurse property is accessed to print its default number of coins, and whenever its winCoins method is called: + +> 因为playerOne是可选的,所以由一个感叹号(!)来作前缀,每当其winCoins方法被调用时,会访问其coinsInPurse属性并打印出他的货币数目。 + + + + + +```` +playerOne!.winCoins(2_000) +println("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins") +// 打印 "PlayerOne 赢取 2000 货币,目前他拥有 2100 个货币" +println("The bank now only has \(Bank.coinsInBank) coins left") +// 打印 "目前银行货币存量为: 7900" +```` + + + + +Here, the player has won 2,000 coins. The player’s purse now contains 2,100 coins, and the bank has only 7,900 coins left. + +> 以上代码运行后,player 赢取了 2,000 货币。他的钱包目前有 2,100 个货币,bank 剩余 7,900 个货币。 + + + +```` +playerOne = nil +println("PlayerOne has left the game") +// 打印 "PlayerOne 离开了游戏" +println("The bank now has \(Bank.coinsInBank) coins") +// 打印 "目前银行货币存量为: 10000" +```` + + +The player has now left the game. This is indicated by setting the optional playerOne variable to nil, meaning “no Player instance.” At the point that this happens, the playerOne variable’s reference to the Player instance is broken. No other properties or variables are still referring to the Player instance, and so it is deallocated in order to free up its memory. Just before this happens, its deinitializer is called automatically, and its coins are returned to the bank. + +> 现在player要离开这个游戏。这将把可选的playerOne变量设置为nil,可以理解为“没有Player实例”的意思。这时playerOne变量对Player实例的引用断开。再没有其它属性或者变量还会引用player实例,为了清空内存,它将被释放掉。析构函数会在这一切发生前自动被触发调用,之后所有的货币将回归到银行,这还真是个游戏。 + From 2240e506e00df3b3755003cc62da48ad760ef6c2 Mon Sep 17 00:00:00 2001 From: rainoxu Date: Mon, 23 Jun 2014 10:40:49 +0800 Subject: [PATCH 166/261] =?UTF-8?q?=E9=98=B6=E6=AE=B5=E6=80=A7=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter3/09_Generic_Parameters_and_Arguments.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/chapter3/09_Generic_Parameters_and_Arguments.md b/src/chapter3/09_Generic_Parameters_and_Arguments.md index 35d65f8..cfba2c1 100644 --- a/src/chapter3/09_Generic_Parameters_and_Arguments.md +++ b/src/chapter3/09_Generic_Parameters_and_Arguments.md @@ -120,6 +120,8 @@ struct Dictionary: Collection, DictionaryLiteralCo The specialized version of the generic Dictionary type, Dictionary is formed by replacing the generic parameters KeyType: Hashable and ValueType with the concrete type arguments String and Int. Each type argument must satisfy all the constraints of the generic parameter it replaces, including any additional requirements specified in a where clause. In the example above, the KeyType type parameter is constrained to conform to the Hashable protocol and therefore String must also conform to the Hashable protocol. +Dictionary类型的特定配置```Dictionary```是由具体替换泛型参数```KeyType: Hashable```和```ValueType```的实参```String```与```Int```组成。每一个实参都必须满足它所替换的泛型型参所要求的约束条件,包括在```where```句式中指定的额外依赖条件。在以上的例子中,`KeyType`参数的约束条件是符合```Hashable```协议,```String```也必须符合```Hashable```协议。 + You can also replace a type parameter with a type argument that is itself a specialized version of a generic type (provided it satisfies the appropriate constraints and requirements). For example, you can replace the type parameter T in Array with a specialized version of an array, Array, to form an array whose elements are themselves arrays of integers. From ac813f20867c3d8a39bfa41f38051a92f6f6c7b6 Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Mon, 23 Jun 2014 10:45:25 +0800 Subject: [PATCH 167/261] Update 07_Closures.md --- src/chapter2/07_Closures.md | 442 ++++++++++++++++++++++++++++++++++++ 1 file changed, 442 insertions(+) diff --git a/src/chapter2/07_Closures.md b/src/chapter2/07_Closures.md index e69de29..d85fb6a 100644 --- a/src/chapter2/07_Closures.md +++ b/src/chapter2/07_Closures.md @@ -0,0 +1,442 @@ +# Closures 闭包 + +Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages. + +闭包是一个封闭的代码块,可以在你的程序中传递和使用。swift中的闭包跟objective-C和C语言中的block很类似,其他语言中的匿名函数也跟此相似。 + +Closures can capture and store references to any constants and variables from the context in which they are defined. This is known as closing over those constants and variables, hence the name “closures”. Swift handles all of the memory management of capturing for you. + +闭包可以将常量和变量从定义的地方通过捕获和指针引用保存起来,可以理解成将这些常量和变量封闭了起来,所以取名为“闭包”。swift会帮你处理所有闭包涉及的内存管理。 + +> note: +> Don’t worry if you are not familiar with the concept of “capturing”. It is explained in detail below in Capturing Values. +> 如果你还不是很熟悉“capturing”,这里有关于“capturing values”的细节。 + +Global and nested functions, as introduced in Functions, are actually special cases of closures. Closures take one of three forms: + +前面介绍过的全局函数和嵌套函数其实是闭包的特殊情况,闭包有以下三种: + +* Global functions are closures that have a name and do not capture any values. +* 全局函数是一种拥有函数名但是不会捕获任何值的闭包 + +* Nested functions are closures that have a name and can capture values from their enclosing function. +* 嵌套的函数是一种拥有函数名并且会捕获变量和常量得闭包 + +* Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context. +* 闭包表达式是一种没有名字的闭包,他通过轻量简便的语法定义,可以从他们的上下文中捕获变量和常量 + +Swift’s closure expressions have a clean, clear style, with optimizations that encourage brief, clutter-free syntax in common scenarios. These optimizations include: + +swift中的闭包表达式是一种非常简洁明了的语法,通过使用优化的闭包语法,使的一般场景中的代码显得非常的整洁,这些优化包含 + +* Inferring parameter and return value types from context +* 从上下文中自动推断出返回值类型 + +* Implicit returns from single-expression closures +* 单条语句的闭包自动获得隐式的返回 + +* Shorthand argument names +* 简化的参数名称(通过使用$0...$n来使用参数) + +* Trailing closure syntax +* 返回类型后置语法(函数返回值类型位于函数声明的末端) + +## Closure Expressions 闭包表达式 + +Nested functions, as introduced in Nested Functions, are a convenient means of naming and defining self-contained blocks of code as part of a larger function. However, it is sometimes useful to write shorter versions of function-like constructs without a full declaration and name. This is particularly true when you work with functions that take other functions as one or more of their arguments. + +嵌套的函数是一种自我包含的代码块,这是一种简单方便的方式,尤其在更大的函数中使用的时候。但是有时候通过一种更简洁的方式来定义函数会显得很实用,尤其在一些函数使用其他函数作为参数的时候。 + +Closure expressions are a way to write inline closures in a brief, focused syntax. Closure expressions provide several syntax optimizations for writing closures in their simplest form without loss of clarity or intent. The closure expression examples below illustrate these optimizations by refining a single example of the sort function over several iterations, each of which expresses the same functionality in a more succinct way. + +     闭包表达式是一种简洁并且聚焦的方式来定义内联的闭包,闭包表达式提供几种优化过的语法来定义闭包,并且不会看起来有混淆和歧义。下面的闭包表达式例子定义一些简单的排序函数,每一种都通过更简洁明了的方式达到了同样的目的。 +      + +### The Sort Function 排序函数 + +Swift’s standard library provides a function called sort, which sorts an array of values of a known type, based on the output of a sorting closure that you provide. Once it completes the sorting process, the sort function returns a new array of the same type and size as the old one, with its elements in the correct sorted order. + +     swift的标准库提供了一个函数叫做sort,通过你提供的排序闭包用来对数组中的元素进行排序。一旦完成排序,sort函数会返回一个跟以前类型和数量一样的数组,并且里面的元素都已经排列成正确的顺序。 + +The closure expression examples below use the sort function to sort an array of String values in reverse alphabetical order. Here’s the initial array to be sorted: + +     下面的闭包表达式例子通过使用sort函数来对一个都是string类型的数组排序,数组的定义如下 + +```js +     let names = ["Chris","Alex","Ewa","Barry","Daniella"] +``` + +The sort function takes two arguments: + +sort函数有2个参数 + +* An array of values of a known type. +* A closure that takes two arguments of the same type as the array’s contents, and returns a Bool value to say whether the first value should appear before or after the second value once the values are sorted. The sorting closure needs to return true if the first value should appear before the second value, and false otherwise. + +This example is sorting an array of String values, and so the sorting closure needs to be a function of type (String, String) -> Bool. + +这是一个对string类型的数组进行排序的例子,所以这个排序的闭包需要有以下类型(String,String) ->Bool. + +One way to provide the sorting closure is to write a normal function of the correct type, and to pass it in as the sort function’s second parameter: + +函数名字加正确的类型是排序闭包的写法之一,然后在sort函数中作为第二个参数传入。 + +```js +func backwards(s1:String,s2:String) -> Bool{ + return s1>s2 +} + +var reversed = sort(names,backwards) +// reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"] +``` + +If the first string (s1) is greater than the second string (s2), the backwards function will return true, indicating that s1 should appear before s2 in the sorted array. For characters in strings, “greater than” means “appears later in the alphabet than”. This means that the letter "B" is “greater than” the letter "A", and the string "Tom" is greater than the string "Tim". This gives a reverse alphabetical sort, with "Barry" being placed before "Alex", and so on. + +如果第一个字符串s1比第二个字符串s2比较值更大,函数backwards会返回true,这样在排序之后的数组中s1应该会排在s2之前,对于在字符串中的字符来说,“值大于”等于“在字符表中出现的更晚”,这意味着字符”B“比字符”A“的值更大,所以字符串”Tom“会比”Tim“更大。这个排序将会把字符表倒序排列,所以”Barry“会放在”Alex"之前。 + +However, this is a rather long-winded way to write what is essentially a single-expression function (a > b). In this example, it would be preferable to write the sorting closure inline, using closure expression syntax. + +然而这么繁重的写法在本质上只是一个表达式:a>b.在下面的例子里,使用闭包表达式写排序内联的闭包将会是更好的方式 + +### Closure Expression Syntax 闭包表达式语法 + +Closure expression syntax has the following general form: + +比表表达式语法定义如下: + +{ (parameters) -> return type in + statements +} + +{(参数)-> 返回值 in  +    语句 +} + +Closure expression syntax can use constant parameters, variable parameters, and inout parameters. Default values cannot be provided. Variadic parameters can be used if you name the variadic parameter and place it last in the parameter list. Tuples can also be used as parameter types and return types. + +闭包表达式语法可以使用常量,变量还有inout来作为参数,不能提供缺省参数,如果你要使用可选参数可以将它们定义在参数列表的结尾,tuples可以作为参数和返回值类型。 + +The example below shows a closure expression version of the backwards function from earlier: + +下面的例子是闭包表达式版本的backwords排序函数: + +```js +reversed = sort(names,{(s1:String,s2:String) -> Bool in  +return s1>s2}) +``` + +Note that the declaration of parameters and return type for this inline closure is identical to the declaration from the backwards function. In both cases, it is written as (s1: String, s2: String) -> Bool. However, for the inline closure expression, the parameters and return type are written inside the curly braces, not outside of them. + +在这个表达式的定义和返回值类型跟前面的backwords函数完全相同,在这两个例子中,都是这样写的(s1:String,s2:String)->Bool,然而对于内联的闭包表达式,参数和返回值类型都写在大括号里面。 + +The start of the closure’s body is introduced by the in keyword. This keyword indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin. + +闭包语句的书写在关键字in之后,这个关键字表明的意思是:闭包表达式的参数和返回值类型已经定义结束,闭包的语句可以开始书写了。 +Because the body of the closure is so short, it can even be written on a single line: + +因为这个闭包的语句太短了,所以可以写在一行之内 + +```js +reversed = sort(name,{(s1:String,s2:String) -> Bool in return s1 > s2 }) +``` + +This illustrates that the overall call to the sort function has remained the same. A pair of parentheses still wrap the entire set of arguments for the function. However, one of those arguments is now an inline closure. + +这个表达式在sort函数中跟前面的例子得到的效果是完全一样的,一对圆括号包含了函数中所有的参数集。 + +### Inferring Type From Context 上下文推断返回值类型 + +Because the sorting closure is passed as an argument to a function, Swift can infer the types of its parameters and the type of the value it returns from the type of the sort function’s second parameter. This parameter is expecting a function of type (String, String) -> Bool. This means that the String, String, and Bool types do not need to be written as part of the closure expression’s definition. Because all of the types can be inferred, the return arrow (->) and the parentheses around the names of the parameters can also be omitted: + +由于排序的闭包是作为函数的参数传入的,swift会根据sort函数的第二的参数类型来推断其参数参数和返回值的类型。这个参数期望的函数类型为(String,String)->Bool,这意味着String,String和BOOL类型并不强制需要在写闭包表达式里,因为所有类型都可以推断,返回的箭头->和他周围的参数名字都可以被省略 + +```js +     reversed = sort(names,{s1,s2 in return s1 > s2)}) +``` + +It is always possible to infer parameter types and return type when passing a closure to a function as an inline closure expression. As a result, you rarely need to write an inline closure in its fullest form. + +作为函数参数的内联闭包表达式都可以推断参数和返回值的类型,所以你很少需要写内联闭包的完整形式。 + +Nonetheless, you can make the types explicit if you wish, and doing so is encouraged if it avoids ambiguity for readers of your code. In the case of the sort function, the purpose of the closure is clear from the fact that sorting is taking place, and it is safe for a reader to assume that the closure is likely to be working with String values, because it is assisting with the sorting of an array of strings. + +虽然如此,如果你愿意你可以明确的写出参数的类型,这样可以让你的代码阅读起来能减少歧义。 + +### Implicit Returns from Single-Expression Closures 单表达式的隐式返回值 + +Single-expression closures can implicitly return the result of their single expression by omitting the return keyword from their declaration, as in this version of the previous example: + +     单表达式的返回值可以通过隐藏return关键字来隐式返回结果,上面的表达式可以写成: + +```js +     reversed = sort(names,{s1,s2 in s1 > s2}) +``` + +Here, the function type of the sort function’s second argument makes it clear that a Bool value must be returned by the closure. Because the closure’s body contains a single expression (s1 > s2) that returns a Bool value, there is no ambiguity, and the return keyword can be omitted. + +    这个例子里面,sort的第二个参数类型定义了闭包的返回值是BOOL类型,而且闭包表达式中只包含了一个表达式 (s1 >s2)而且这个表达式返回BOOL类型,所以这里省略掉return没有歧义。 + +### Shorthand Argument Names 参数名的缩写 + +Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on. + +swift里为内联的参数提供了参数的缩写功能,你可以通过$0,$1,$2来调用闭包的参数。 + +If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body: + +如果你在闭包表达式中使用参数名称的缩写,在闭包参数列表中就可以省略对其的定义,对应参数的类型将会通过函数参数的定义来推断,in关键字也可以被忽略掉: + +```js +     reversed = sort(name,{$0>$1} ) +``` + +Here, $0 and $1 refer to the closure’s first and second String arguments. + + 这个例子中,$0和$1表示闭包中的第一和第二个参数 + +### Operator Functions 运算符函数 + +There’s actually an even shorter way to write the closure expression above. Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a function that has two parameters of type String, and returns a value of type Bool. This exactly matches the function type needed for the sort function’s second parameter. Therefore, you can simply pass in the greater-than operator, and Swift will infer that you want to use its string-specific implementation: + +实际上还有更精简的方式来书写上面的闭包表达式,swift的String类型对于大于号(>)做了特别的实现,作为函数接受两个String类型的参数,返回值是BOOL类型,刚好满足sort函数中第二个参数的函数类型定义,所以,你可以简单的将大于运算法传递进去,swift会推断你需要使用这个String的运算符函数 + +```js +     reversed = sort(names,>) +``` + +For more about operator functions, see Operator Functions. + +更多关于运算符函数请看 Operator Functions + +## Trailing Closures 跟尾闭包 + +If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. A trailing closure is a closure expression that is written outside of (and after) the parentheses of the function call it supports: + +如果你需要将一个闭包表达式作为一个函数的最后一个参数传入,使用跟尾闭包的写法会更有可读性,尾闭包表达式全部写在函数最后的括号中。 + +```js +func someFunctionThatTakesAClosure(closure: () -> ()) { +    // function body goes here +} +  +// here's how you call this function without using a trailing closure: +  +someFunctionThatTakesAClosure({ +    // closure's body goes here +    }) +  +// here's how you call this function with a trailing closure instead: +  +someFunctionThatTakesAClosure() { +    // trailing closure's body goes here +} + +```js + +> 注意: +> If a closure expression is provided as the function’s only argument and you provide that expression as a trailing closure, you do not need to write a pair of parentheses () after the function’s name when you call the function. +> 如果函数只有闭包表达式这一个参数,你可以在使用跟尾闭包的时候把()省略掉。 + +The string-sorting closure from the Closure Expression Syntax section above can be written outside of the sort function’s parentheses as a trailing closure: + +上面的sort函数可以改写为 + +```js +     reversed = sort(name){$0>$1} +``` + +Trailing closures are most useful when the closure is sufficiently long that it is not possible to write it inline on a single line. As an example, Swift’s Array type has a map method which takes a closure expression as its single argument. The closure is called once for each item in the array, and returns an alternative mapped value (possibly of some other type) for that item. The nature of the mapping and the type of the returned value is left up to the closure to specify. + +跟尾闭包的写法在一些闭包包体逻辑非常长的时候很有用,例如,swift中的array类型有一个map的方法,这个方法只需要一个闭包表达式作为其参数,这个闭包会对数组中每一个元素调用一次,然后返回该函数映射的值(也可能是不同的类型),具体的映射方式和返回值由闭包中的逻辑决定。 + +After applying the provided closure to each array element, the map method returns a new array containing all of the new mapped values, in the same order as their corresponding values in the original array. + +     当提供数组闭包函数之后,map方法将返回一个新的数组,数组中包含了与原数组一一对应的值 + +Here’s how you can use the map method with a trailing closure to convert an array of Int values into an array of String values. The array [16, 58, 510] is used to create the new array ["OneSix", "FiveEight", "FiveOneZero"]: + +    在下面的例子中,你可以使用map函数和跟尾闭包来降数组中的Int值转换成String值。数组[16,58,510]用来创建新的数组[“OneSix”,”FiveEigh”,”FiveOneZero”]: + +```js +let digitNames = [ +    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four", +    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine" +] +let numbers = [16, 58, 510] +``` +The code above creates a dictionary of mappings between the integer digits and English-language versions of their names. It also defines an array of integers, ready to be converted into strings. + +上面的代码使用数字和它所对应的英文字符串创建了一个字典,然后定义了一个数字的数组,用来进行转换。 + +You can now use the numbers array to create an array of String values, by passing a closure expression to the array’s map method as a trailing closure. Note that the call to numbers.map does not need to include any parentheses after map, because the map method has only one parameter, and that parameter is provided as a trailing closure: + +现在你可以使用numers数组来创建一个对应的字符串数组,将一个闭包表达式作为跟尾闭包传递进数组的map函数,在写numbers.map方法的后面不需要添加括号,因为map方法只有一个参数,这个参数已经作为跟尾闭包的形式提供了 + +```js +let strings = numbers.map { +    (var number) -> String in +    var output = "" +    while number > 0 { +        output = digitNames[number % 10]! + output +        number /= 10 +    } +    return output +} +// strings is inferred to be of type String[] +// its value is ["OneSix", "FiveEight", "FiveOneZero"] +``` + +The map function calls the closure expression once for each item in the array. You do not need to specify the type of the closure’s input parameter, number, because the type can be inferred from the values in the array to be mapped. + +map函数将会对数组中的每一个元素调用一次闭包表达式,你不需要制定闭包表达式的输入参数类型,number,因为这个类型可以通过数组中元素的类型来进行推断。 + +In this example, the closure’s number parameter is defined as a variable parameter, as described in Constant and Variable Parameters, so that the parameter’s value can be modified within the closure body, rather than declaring a new local variable and assigning the passed number value to it. The closure expression also specifies a return type of String, to indicate the type that will be stored in the mapped output array. + +这个例子中,闭包中的number参数定义成变量参数(具体参见constans and variable parameters),所以这个参数的值可以在闭包内进行修改。闭包表达式指定了返回值类型为String,表明存储应映射值的新数组类型为String + +The closure expression builds a string called output each time it is called. It calculates the last digit of number by using the remainder operator (number % 10), and uses this digit to look up an appropriate string in the digitNames dictionary. + +上面的闭包表达式每次被调用的时候创建了一个字符串返回,使用取余运算(number%10)计算最后一位数字并且利用digitNames字段获取对应的字符串。 + +> 注意: +> The call to the digitNames dictionary’s subscript is followed by an exclamation mark (!), because dictionary subscripts return an optional value to indicate that the dictionary lookup can fail if the key does not exist. In the example above, it is guaranteed that number % 10 will always be a valid subscript key for the digitNames dictionary, and so an exclamation mark is used to force-unwrap the String value stored in the subscript’s optional return value. +> 字典digitNames的下表之后跟着一个惊叹号(!),因为字典下标返回了一个可选值,表明该Key对应的返回值可能不存在,在上面的例子中,number%10保证了在字典中总会有值对应,因此惊叹号强制取出存储在下表中的String类型 + +The string retrieved from the digitNames dictionary is added to the front of output, effectively building a string version of the number in reverse. (The expression number % 10 gives a value of 6 for 16, 8 for 58, and 0 for 510.) + +从digitNames字段中获取的字符串添加进输出的前部,逆序的建立了一个字符串的数组版本。(再表达式number%10中,如果number为16,则返回6,58则返回8,510返回0) + +The number variable is then divided by 10. Because it is an integer, it is rounded down during the division, so 16 becomes 1, 58 becomes 5, and 510 becomes 51. + +number变量之后除以10,因为是整数,再计算过程中未除尽的部分会被忽略,因此16变成1,58变成5,510变成了51 + +The process is repeated until number /= 10 is equal to 0, at which point the output string is returned by the closure, and is added to the output array by the map function. + +将整个过程重复,知道number/10变成0,这时闭包会将字符串输出,而map函数则将返回的字符串添加进一个新的映射数组中。 + +The use of trailing closure syntax in the example above neatly encapsulates the closure’s functionality immediately after the function that closure supports, without needing to wrap the entire closure within the map function’s outer parentheses. + +上面的例子中跟尾闭包语法在函数之后将具体的逻辑简介的包装了起来,而不需要将闭包包裹在括号之内 + +## Capturing Values 捕获值 + +A closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists. + +     闭包可以从变量和常量定义的上下文中捕获他们的值,即使定义他们的域已经不存在了,闭包仍然可以访问和改变他们的值 + +The simplest form of a closure in Swift is a nested function, written within the body of another function. A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function. + +     swift中嵌套函数是闭包最简形式,嵌套函数是定义在其他函数中的函数,它可以捕获外部函数中的所有参数和定义的常量和变量 + +Here’s an example of a function called makeIncrementor, which contains a nested function called incrementor. The nested incrementor function captures two values, runningTotal and amount, from its surrounding context. After capturing these values, incrementor is returned by makeIncrementor as a closure that increments runningTotal by amount each time it is called. + +     这面的makeIncrementor的函数,包含了一个叫做incrementor的嵌套函数,嵌套函数incrementor从上下文中捕获了两个值,runningTotal和amount。之后makeIncrementor将incrementor作为闭包返回,每次调用incrementor时,都会以amount作为增量来增加runningTotal的值 + +```js +func makeIncrementor(forIncrement amount: Int) -> () -> Int { +var runningTotal = 0 +func incrementor() -> Int { +runningTotal += amount +return runningTotal +} +return incrementor +} +``` +The return type of makeIncrementor is () -> Int. This means that it returns a function, rather than a simple value. The function it returns has no parameters, and returns an Int value each time it is called. To learn how functions can return other functions, see Function Types as Return Types. + +makeIncrementor的返回值类型是()->Int,这表示返回一个函数。这个返回的函数没有其他参数并且每次调用都返回一个Int类型的值。要学习如何在函数中返回其他函数,参见Function Types as Return Types + +The makeIncrementor function defines an integer variable called runningTotal, to store the current running total of the incrementor that will be returned. This variable is initialized with a value of 0. + +makeIncrementor函数定义了一个整形变量叫做runningTotal.这个变量存储了当前函数的返回值,并且初始化为0. + + +The makeIncrementor function has a single Int parameter with an external name of forIncrement, and a local name of amount. The argument value passed to this parameter specifies how much runningTotal should be incremented by each time the returned incrementor function is called. + +makeIncrementor defines a nested function called incrementor, which performs the actual incrementing. This function simply adds amount to runningTotal, and returns the result. + +makeIncrementor定义了一个内嵌函数叫做incrementor,这个函数执行真正的递增逻辑。在这个函数中将amount的值增加到runningTotal中,然后返回它的值。 + +When considered in isolation, the nested incrementor function might seem unusual: + +如果单独拿出来看,内嵌函数incrementor看上起会有点奇怪 + +```js +func incrementor() -> Int { + runningTotal += amount + return runningTotal +} +``` + +The incrementor function doesn’t have any parameters, and yet it refers to runningTotal and amount from within its function body. It does this by capturing the existing values of runningTotal and amount from its surrounding function and using them within its own function body. + +Intrementor函数没有任何参数,他引用的变量runningTotal和amouint来自包含它的函数体,通过捕获外部环境中的变量来实现上面例子中的效果。 + +Because it does not modify amount, incrementor actually captures and stores a copy of the value stored in amount. This value is stored along with the new incrementor function. + +因为没有修改amount参数,incrementor函数实际上是捕获和存储了一个amount的副本,这个值incrementor函数一起存储了起来。 + +However, because it modifies the runningTotal variable each time it is called, incrementor captures a reference to the current runningTotal variable, and not just a copy of its initial value. Capturing a reference ensures sure that runningTotal does not disappear when the call to makeIncrementor ends, and ensures that runningTotal will continue to be available the next time that the incrementor function is called. + +然后,因为它每次调用的时候都修改了runningTotal变量,incrementor捕获了一个指向当前runningTotal变量的引用,不单单只是拷贝了他的初始值。捕获一个引用确保了runningTotal变量不会在makeIncrementor调用结束的时候消失掉,而且确保变量runningTotal在下一次调用的时候也依然可以访问。 + +> 注意: +> Swift determines what should be captured by reference and what should be copied by value. You don’t need to annotate amount or runningTotal to say that they can be used within the nested incrementor function. Swift also handles all memory management involved in disposing of runningTotal when it is no longer needed by the incrementor function. +>      swift会决定对一个值是保存它的拷贝还是引用。你不需要声明amount和runningTotal他们会在incrementor内嵌函数中使用。swift也会处理所有的内存管理,当runningTotal不再需要的时候会将它释放掉。 + +Here’s an example of makeIncrementor in action: + +这里是makeIncrementor的一个例子 + +```js +let incrementByTen = makeIncrementor(forIncrement: 10) +``` + +This example sets a constant called incrementByTen to refer to an incrementor function that adds 10 to its runningTotal variable each time it is called. Calling the function multiple times shows this behavior in action: + +这个例子将一个叫做incrementByTen的常量保存10与runningTotal变量每次想加的引用。调用函数多次来查看结果: + +```js +incrementByTen() +// returns a value of 10 +incrementByTen() +// returns a value of 20 +incrementByTen() +// returns a value of 30 +``` + +If you create another incrementor, it will have its own stored reference to a new, separate runningTotal variable. In the example below, incrementBySeven captures a reference to a new runningTotal variable, and this variable is unconnected to the one captured by incrementByTen: + +如果你创建另外一个incrementor,它会有一个新的引用于之前的runningTotal完全分离,下面这个例子里面incrementBySeven捕获了一个新的runningTotal变量,这个变量跟incrementByTen捕获的没有任何联系 + +```js +let incrementBySeven = makeIncrementor(forIncrement: 7) +incrementBySeven() +// returns a value of 7 +incrementByTen() +// returns a value of 40 +``` + +> 注意 +> If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles. For more information, see Strong Reference Cycles for Closures. +>      如果你在闭包里访问了一个类实例的属性,闭包会捕获这个实例或者成员函数的引用,你会创建一个互相强引用的环,swift使用捕获列表来打破这个互相引用的环,详情请看Strong Reference Cycles for Closures. + +## Closures Are Reference Types 闭包都是引用类型 + +In the example above, incrementBySeven and incrementByTen are constants, but the closures these constants refer to are still able to increment the runningTotal variables that they have captured. This is because functions and closures are reference types. + +     上面的例子里面incrementBySeven和incrementByTen都是常量,但是这些常量引用的闭包仍然可以增加他们捕获的runningTotal变量的值,这是因为函数和闭包都是引用类型。 + +Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure. In the example above, it is the choice of closure that incrementByTen refers to that is constant, and not the contents of the closure itself. + +     任何时候当你将一个函数或者闭包赋值给一个常量或者变量,实际上你将这个闭包的引用设置给了这个常量或者变量。上面的例子中,变成常量的是这个闭包的引用,而不是只它的包体内包含的内容。 + +This also means that if you assign a closure to two different constants or variables, both of those constants or variables will refer to the same closure: + +     这意味着如果你将一个闭包赋值给两个不同的变量和常量,他们都会指向同一个闭包 + +```js +       let alsoIncrementByTen = incrementByTen +               alsoIncrementByTen() +               // returns a value of 50 +``` From 4b4485b9725af0e95ed7dc501b66da4ca557bf71 Mon Sep 17 00:00:00 2001 From: rainoxu Date: Mon, 23 Jun 2014 10:49:52 +0800 Subject: [PATCH 168/261] =?UTF-8?q?=E5=AE=8C=E6=88=90;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter3/09_Generic_Parameters_and_Arguments.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/chapter3/09_Generic_Parameters_and_Arguments.md b/src/chapter3/09_Generic_Parameters_and_Arguments.md index cfba2c1..75d23da 100644 --- a/src/chapter3/09_Generic_Parameters_and_Arguments.md +++ b/src/chapter3/09_Generic_Parameters_and_Arguments.md @@ -125,12 +125,17 @@ Dictionary类型的特定配置```Dictionary```是由具体替换 You can also replace a type parameter with a type argument that is itself a specialized version of a generic type (provided it satisfies the appropriate constraints and requirements). For example, you can replace the type parameter T in Array with a specialized version of an array, Array, to form an array whose elements are themselves arrays of integers. +你也可以用一个满足约束条件与依赖条件的类型实参的特定配置来替换类型形参。比如,你可以用特定的数组`Array`替换`Array`中的类型形参`T`,得到 +一个数组,且它的元素是跟它本身一样的由整形元素组成的数组。 + ``` let arrayOfArrays: Array> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] ``` As mentioned in Generic Parameter Clause, you don’t use a generic argument clause to specify the type arguments of a generic function or initializer. +正如在泛型参式句式里面提及的,不需要泛型实参句式指定泛形函数、初始化器的实参。 + > **GRAMMAR OF A GENERIC ARGUMENT CLAUSE** > generic-argument-clause → <­generic-argument-list­>­ From 15c89f3698b9411b731318cf0f8fae7e4c9b9bd8 Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Mon, 23 Jun 2014 10:50:53 +0800 Subject: [PATCH 169/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dfb6182..b4058c3 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ The Swift Programming Language 中文化项目 * 语句 [认领 by 玩家] * 声明 [认领 by 墨峰] * 属性 [认领 by 隐若] - * 模式 [认领 by 栖邀] + * 模式 [认领 by 栖邀][review by 紫溪 0%] * 泛型参数 [认领 by 龙刚] * 语法总结 [认领 by 无独] From f6190721c1be96d3d89de258d569f3dfe7365a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=8E=89=E6=9E=97=28=E9=A3=9E=E9=95=BF=29?= Date: Mon, 23 Jun 2014 10:51:37 +0800 Subject: [PATCH 170/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b4058c3..b615536 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The Swift Programming Language 中文化项目 * 字符串和字符 [认领 by 筱谷] * 集合类型 [认领 by 尘境] * 控制流 [认领 by 墨昕] - * 函数 [认领 by 紫溪] + * 函数 [认领 by 紫溪 review by 飞长] * 闭包 [认领 by 闻西] * 枚举 [已完成 by 灵吾] * 类和结构体 [已完成 by 晓毒] From 5c393c8a9cc22c1277909df9b1065386047aae31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=8E=89=E6=9E=97=28=E9=A3=9E=E9=95=BF=29?= Date: Mon, 23 Jun 2014 10:53:35 +0800 Subject: [PATCH 171/261] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b615536..d66136e 100644 --- a/README.md +++ b/README.md @@ -67,13 +67,13 @@ The Swift Programming Language 中文化项目 建库时间点:6月7日 (6月7日 - 已完成) -三大分会参与翻译工作具体人员确定时间点:6月8日 (进行中) +三大分会参与翻译工作具体人员确定时间点:6月8日 (已完成) -认领完成结束时间点:6月10日 (未开始) +认领完成结束时间点:6月10日 (已完成) -原文翻译完成时间点:6月20日 (未开始) +原文翻译完成时间点:6月20日 (已完成) -Review完成时间点:6月27日 (未开始) +Review完成时间点:6月27日 (进行中) # 关于术语 From 5cfd06ecb76b0f99f8dc4593834046bf791ddff5 Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Mon, 23 Jun 2014 13:26:11 +0800 Subject: [PATCH 172/261] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d66136e..9ad76ec 100644 --- a/README.md +++ b/README.md @@ -8,20 +8,20 @@ The Swift Programming Language 中文化项目 # 任务和进度 * 欢迎使用 Swift - * Swift 介绍 [已完成 by 飞长] - * Swift 初见 [认领 by 容隽] + * Swift 介绍 [已完成 by 飞长][review by 容隽] + * Swift 初见 [认领 by 容隽][review by 闻西] * Swift 教程 * 基础部分 [认领 by 琼雪] * 基本操作符 [认领 by 冰浠] * 字符串和字符 [认领 by 筱谷] * 集合类型 [认领 by 尘境] * 控制流 [认领 by 墨昕] - * 函数 [认领 by 紫溪 review by 飞长] + * 函数 [认领 by 紫溪][review by 飞长] * 闭包 [认领 by 闻西] * 枚举 [已完成 by 灵吾] * 类和结构体 [已完成 by 晓毒] * 属性 [认领 by 周源] - * 方法 [已完成 by 米尔] + * 方法 [已完成 by 米尔][review by 灵吾] * 下标 [已完成 by 递归] * 继承 [已完成 by 晗光] * 构造过程 [认领 by 刘康] From 8e1108bdc63521c8b70321a85e562e00f28d7f4c Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Mon, 23 Jun 2014 13:30:43 +0800 Subject: [PATCH 173/261] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 9ad76ec..f1c6a33 100644 --- a/README.md +++ b/README.md @@ -8,20 +8,20 @@ The Swift Programming Language 中文化项目 # 任务和进度 * 欢迎使用 Swift - * Swift 介绍 [已完成 by 飞长][review by 容隽] - * Swift 初见 [认领 by 容隽][review by 闻西] + * Swift 介绍 [已完成 by 飞长] [review by 容隽] + * Swift 初见 [认领 by 容隽] [review by 闻西] * Swift 教程 * 基础部分 [认领 by 琼雪] * 基本操作符 [认领 by 冰浠] * 字符串和字符 [认领 by 筱谷] * 集合类型 [认领 by 尘境] * 控制流 [认领 by 墨昕] - * 函数 [认领 by 紫溪][review by 飞长] + * 函数 [已完成 by 紫溪] [review by 飞长] * 闭包 [认领 by 闻西] * 枚举 [已完成 by 灵吾] * 类和结构体 [已完成 by 晓毒] * 属性 [认领 by 周源] - * 方法 [已完成 by 米尔][review by 灵吾] + * 方法 [已完成 by 米尔] [review by 灵吾] * 下标 [已完成 by 递归] * 继承 [已完成 by 晗光] * 构造过程 [认领 by 刘康] @@ -42,7 +42,7 @@ The Swift Programming Language 中文化项目 * 语句 [认领 by 玩家] * 声明 [认领 by 墨峰] * 属性 [认领 by 隐若] - * 模式 [认领 by 栖邀][review by 紫溪 0%] + * 模式 [已完成 by 栖邀] [review by 紫溪] * 泛型参数 [认领 by 龙刚] * 语法总结 [认领 by 无独] From 7c601f35452d4c07b99f63227691a14b066655fb Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Mon, 23 Jun 2014 13:40:38 +0800 Subject: [PATCH 174/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f1c6a33..1648f00 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ The Swift Programming Language 中文化项目 * Swift 教程 * 基础部分 [认领 by 琼雪] * 基本操作符 [认领 by 冰浠] - * 字符串和字符 [认领 by 筱谷] + * 字符串和字符 [认领 by 筱谷] [review by 尘境] * 集合类型 [认领 by 尘境] * 控制流 [认领 by 墨昕] * 函数 [已完成 by 紫溪] [review by 飞长] From 35a535be2a81cc7455a7f8c14b353ea62c03df53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Mon, 23 Jun 2014 13:54:33 +0800 Subject: [PATCH 175/261] =?UTF-8?q?=E4=BF=AE=E6=94=B9types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter3/03_Types.md | 80 ++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/src/chapter3/03_Types.md b/src/chapter3/03_Types.md index 18c168e..6b95612 100644 --- a/src/chapter3/03_Types.md +++ b/src/chapter3/03_Types.md @@ -3,13 +3,13 @@ In Swift, there are two kinds of types: named types and compound types. A named type is a type that can be given a particular name when it is defined. Named types include classes, structures, enumerations, and protocols. For example, instances of a user-defined class named MyClass have the type MyClass. In addition to user-defined named types, the Swift standard library defines many commonly used named types, including those that represent arrays, dictionaries, and optional values. -在swift里,有两种类型:命名类型和复合类型。命名类型是指当它被定义的时候能够给一个指定名字的类型。命名类型包含类、结构、枚举和协议。例如,用户定义的类的实例MyClass,其类型就是MyClass。除了用户定义的命名类型,swift标准库还定义了很多常用命名类型,包含的代表有数组,字典,可选值。 +在swift里,有两种类型:命名类型和复合类型。命名类型是指在定义的时候时候能够给一个指定名字的类型。命名类型包含类、结构、枚举和协议。例如,用户定义的类的实例MyClass,其类型就是MyClass。除了用户定义的命名类型,swift标准库还定义了很多常用命名类型,如一些数组,字典,可选值。 Data types that are normally considered basic or primitive in other languages—such as types that represent numbers, characters, and strings—are actually named types, defined and implemented in the Swift standard library using structures. Because they are named types, you can extend their behavior to suit the needs of your program, using an extension declaration, discussed in Extensions and Extension Declaration. -通常被其它语言视为是最基础或最原始的数据类型,例如数字、字符、字符串,实际上都是命名类型,swift标准库使用结构去定义和实现他们。因为他们是命名类型,你可以用扩展声明来扩展他们的行为,以满足你的程序需求,详细讨论请参考‘扩展和扩展声明’。 +一些被其它语言视为是最基础或最原始的数据类型,例如数字、字符、字符串,实际上都是命名类型,swift标准库使用结构去定义和实现他们。由于他们是命名类型的,你可以用扩展声明来扩展他们的功能,来满足你的程序需求,具体请参考‘扩展和扩展声明’。 A compound type is a type without a name, defined in the Swift language itself. There are two compound types: function types and tuple types. A compound type may contain named types and other compound types. For instance, the tuple type (Int, (Int, Int)) contains two elements: The first is the named type Int, and the second is another compound type (Int, Int). @@ -18,14 +18,14 @@ A compound type is a type without a name, defined in the Swift language itself. This chapter discusses the types defined in the Swift language itself and describes the type inference behavior of Swift. -本章讨论swif语言本身定义的类型,描述在swift中类型推断的方式。 +本章讨论swift语言本身定义的类型,并描述在swift中类型推断的方式。 > GRAMMAR OF A TYPE > > 类型的语法 > type → array-type function-type type-identifier tuple-type optional-type implicitly-unwrapped-optional-type protocol-composition-type metatype-type -> + > type -> 数组类型|函数类型|类型标识|元组类型|可选类型|隐式去包装可选类型|协议构成类型|元型类型 @@ -34,7 +34,7 @@ This chapter discusses the types defined in the Swift language itself and descri ## 类型注释 A type annotation explicitly specifies the type of a variable or expression. Type annotations begin with a colon (:) and end with a type, as the following examples show: -类型标注明确的指定一个变量或者表达式的类型。类型注释以冒号(:)开始,类型结束,如下面的列子: +类型标注明确的指定一个变量或者表达式的类型。类型注释以冒号(:)开始,类型结束,如下面的例子: 1. let someTuple:(Double, Double) = (3.14159, 2.71828) @@ -43,17 +43,18 @@ A type annotation explicitly specifies the type of a variable or expression. Typ In the first example, the expression someTuple is specified to “have the tuple type (Double, Double). In the second example, the parameter a to the function someFunction is specified to have the type Int. -在第一个例子中,表达式someTuple是被指定为元组类型(Double, Double)。在第二个例子中,函数someFuncion的参数a被指定为Int类型。 +在第一个例子中,表达式someTuple是被定义为元组类型(Double, Double)。在第二个例子中,函数someFuncion中的参数a被定义为Int类型。 Type annotations can contain an optional list of type attributes before the type. -类型注释可以在类型前面包含一个类型属性的可选列表。 +类型注释可以在类型前面添加一个类型属性的可选列表。 > GRAMMAR OF A TYPE ANNOTATION > 类型注释的语法 -> type-annotation → :attributesopttyp +> type-annotation → :attributes[opt]type +> > type-annotation -> :属性[可选]类型 @@ -62,15 +63,15 @@ Type annotations can contain an optional list of type attributes before the type A type identifier refers to either a named type or a type alias of a named or compound type. -类型标识符是指一个命名类型、命名类型的别名或复合类型。 +类型标识符是指一个命名类型或者说命名类型/复合类型的别名。 Most of the time, a type identifier directly refers to a named type with the same name as the identifier. For example, Int is a type identifier that directly refers to the named type Int, and the type identifier Dictionary directly refers to the named type Dictionary. -大多数情况下,类型标识符是指向相同名字的命名类型。例如,类型标识符Int指向命名类型Int,类型标识符Dictionary指向命名类型Dictionary。 +大多数情况下,类型标识符直接指向和标示符命名相同的命名类型。例如,类型标识符Int指向命名类型Int,类型标识符Dictionary指向命名类型Dictionary。 There are two cases in which a type identifier does not refer to a type with the same name. In the first case, a type identifier refers to a type alias of a named or compound type. For instance, in the example below, the use of Point in the “type annotation refers to the tuple type (Int, Int). -命名标识符和类型不同名的情况有两种。第一种情况,命名标识符指向命名类型的别名或者复合类型。例如下面的例子,类型标识符使用Point指向元组类型(Int, Int)。 +命名标识符和类型不同名有以下两种情况。第一种情况,命名标识符指向命名类型或者复合类型的别名。例如下面的例子,类型标识符使用Point指向元组类型(Int, Int)。 typealias Point = (Int, Int); let origin: Point = (0, 0); @@ -78,20 +79,20 @@ There are two cases in which a type identifier does not refer to a type with the In the second case, a type identifier uses dot (.) syntax to refer to named types declared in other modules or nested within other types. For example, the type identifier in the following code references the named type MyType that is declared in the ExampleModule module. -第二种情况,类型标识符用点(.)的语法指向声明在其它模块或在其它类型中嵌套的命名类型。例如,在下面的代码中,类型标识符引用在模块ExampleModule中声明的命名类型MyType。 +第二种情况,类型标识符用点(.)指向在其它模块中声明或嵌套在其它类型中的命名类型。例如,在下面的代码中,类型标识符引用在模块ExampleModule中声明的命名类型MyType。 var someValue: ExampleModule.MyType > GRAMMAR OF A TYPE IDENTIFIER -> + > 命名标识符的语法 -‌> type-identifier → type-namegeneric-argument-clauseopt type-namegeneric-argument-clauseopt.type-identifier +> type-identifier → type-namegeneric-argument-clauseopt type-namegeneric-argument-clauseopt.type-identifier > 命名标识符 -> 类型名称 泛型参数子句[可选]|类型名称 泛型参数子句[可选].类型标识符 -> -> type-name → identifier” + +> type-name → identifier > 类型标识符 -> 标识符 @@ -101,17 +102,17 @@ In the second case, a type identifier uses dot (.) syntax to refer to named type A tuple type is a comma-separated list of zero or more types, enclosed in parentheses. -元组类型是指在括号中,以逗号分隔的零到多个类型的列表。 +元组类型是指在括号中,用逗号分隔的零到多个类型的列表。 You can use a tuple type as the return type of a function to enable the function to return a single tuple containing “multiple values. You can also name the elements of a tuple type and use those names to refer to the values of the individual elements. An element name consists of an identifier followed immediately by a colon (:). For an example that demonstrates both of these features, see Functions with Multiple Return Values. -你可以用元组类型作为函数的返回值类型,这样函数就能返回包含多个值的单元组。你也可以给元组类型中的元素命名,用这些名字来引用单个元素的值。元素的名字由标识符和紧跟着的冒号(:)组成。这两种特性的例子演示,请看 ‘多个返回值的函数’。 +你可以用元组类型作为函数的返回值类型,这样函数就能返回包含多个值的单元组。你也可以给元组类型中的元素命名,用这些名字来指代单个元素的值。元素的名字由标识符和紧跟着的冒号(:)组成。关于这两种特性的具体用法,请看 ‘多个返回值的函数’。 Void is a typealias for the the empty tuple type, (). If there is only one element inside the parentheses, the type is simply the type of that element. For example, the type of (Int) is Int, not (Int). As a result, you can label a tuple element only when the tuple type has two or more elements. -Void是空元组类型的别名,()。如果在括号里面只有一个元素,那么这个类型就是元素的类型。例如,(Int)的类型是Int,不是(Int)。因此,你可以认为仅当元组类型包含两个或者更多元素的时候才是元组元素。 +Void是空元组类型的别名,表示为()。如果在括号里面只有一个元素,那么这个类型就是元素的类型。例如,(Int)的类型是Int,不是(Int)。因此,你可以认为仅当元组类型包含两个或者更多元素的时候才是元组元素。 > GRAMMAR OF A TUPLE TYPE @@ -144,18 +145,18 @@ Void是空元组类型的别名,()。如果在括号里面只有一个元素 A function type represents the type of a function, method, or closure and consists of a parameter and return type separated by an arrow (->): -函数类型表示一个函数,方法,闭包的类型,它由参数和返回类型组成,中间通过箭头(->)分隔: +函数类型表示一个函数,方法或者闭包的类型,它由参数和返回类型组成,中间通过箭头(->)分隔: parameter type -> return type Because the parameter type and the return type can be a tuple type, function types support functions and methods that take multiple paramaters and return multiple values. -因为参数类型和返回类型都可以为元组类型,所以函数类型支持函数和方法有多个参数和多个返回值。 +由于参数类型和返回类型都可以为元组类型,所以函数类型支持含有多个参数和多个返回值的函数和方法。 You can apply the auto_closure attribute to a function type that has a parameter type of () and that returns the type of an expression (see Type Attributes). An autoclosure function captures an implicit closure over the specified expression, instead of the expression itself. The following example uses the auto_closure attribute in defining a very simple assert function: -你可以为参数类型为(),返回值为表达式类型的函数类型申请auto_closure属性(请看 ’类型属性‘)。一个自动闭包函数捕获的是指定表达式上的隐式闭包而不是表达式本身。下面的例子用auto_closure属性定义一个简单的assert函数: +你可以把自动闭包(auto_closure)的属性归为有一个参数类型为(),返回值为表达的函数类型(请看 ‘类型属性’)。一个自动闭包函数捕获的是指定表达式上的隐式闭包而不是表达式本身。下面的例子用auto_closure属性来定义一个简单的assert函数: func simpleAssert(condition: @auto_closure () -> Bool, message: String){ if !condition(){ @@ -169,7 +170,7 @@ You can apply the auto_closure attribute to a function type that has a parameter A function type can have a variadic parameter as the last parameter in its parameter type. Syntactically, a variadic parameter consists of a base type name followed immediately by three dots (...), as in Int.... A variadic parameter is treated as an array that contains elements of the base type name. For instance, the variadic parameter Int... is treated as Int[]. For an example that uses a variadic parameter, see Variadic Parameters. -一个函数类型的参数类型里可以让一个可变参数作为其最后一个参数。 从语法上来说,可变参数可以由一个基础类型名称和紧跟着的三个点(...)组成,例如Int...。可变参数被认为是一个包含基础类型名称的数组。例如,可变参数Int... 被认为是Int[]。使用可变参数的例子,请参考 ‘可变参数’。 +一个函数类型在参数类型中可以让一个可变参数作为其最后一个参数。从语法上来说,可变参数可以由一个基础类型名称和紧跟着的三个点(...)组成,例如Int...。可变参数被认为是一个包含基础类型名称的数组。例如,可变参数Int... 被认为是Int[]。使用可变参数的例子,请参考 ‘可变参数’。 To specify an in-out parameter, prefix the parameter type with the inout keyword. You can’t mark a variadic parameter or a return type with the inout keyword. In-out parameters are discussed in In-Out Parameters. @@ -189,7 +190,7 @@ The type of a curried function is equivalent to a nested function type. For exam The function types of a curried function are grouped from right to left. For instance, the function type Int -> Int -> Int is understood as Int -> (Int -> Int)—that is, a function that takes an Int and returns another function that takes and return an Int. For example, you can rewrite the curried function addTwoNumbers()() as the following nested function: -柯里化函数的函数类型从右到左形成一组。例如,函数类型Int -> Int -> Int被理解为Int -> (Int -> Int) -- 指函数传入一个Int,然后返回另外一个输入输出都是Int的函数。 +柯里化函数的函数类型从右到左形成一组。例如,函数类型Int -> Int -> Int被理解为Int -> (Int -> Int) -- 指函数传入一个Int,然后返回另外一个输入输出都是Int的函数。例如,你可以把柯里化函数addTwoNumbers()()写成如下的嵌套函数形式: func addTwoNumbers(a: Int) -> (Int -> Int){ func addTheSecondNumber(b: Int) -> Int{ @@ -205,7 +206,7 @@ The function types of a curried function are grouped from right to left. For ins > 函数类型的语法 -> function-type → type->type” +> function-type → type->type > 函数类型 → 类型 -> 类型 @@ -226,30 +227,31 @@ In both cases, the constant someArray is declared as an array of strings. The el As the above example also shows, you can use square brackets to create an array using an array literal. Empty array literals are written using an empty pair of square brackets and can be used to create an empty array of a specified type. -如上面的例子显示,你可以利用数组自变量通过[]创建一个数组。空数组自变量用[]表示,也可以创建制定类型的空数组。 +如上所示,你可以用数组自变量和[]创建一个数组。空数组自变量用[]表示,也可以创建特定类型的空数组。 var emptyArray: Double[] = [] You can create multidimensional arrays by chaining multiple sets of square brackets to the name of the base type of the elements. For example, you can create a three-dimensional array of integers using three sets of square brackets: -你可以链接多组中括号创建多维数组。例如,你可以创建一个三维整数数组,通过三组中括号: +你可以用多组中括号相连来创建多维数组。例如,你可以用三组中括号来创建一个三维整数数组 var array3D: Int[][][] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] When accessing the elements in a multidimensional array, the left-most subscript index refers to the element at that index in the outermost array. The next subscript index to the right refers to the element at that index in the array that’s nested one level in. And so on. This means that in the example above, array3D[0] refers to [[1, 2], [3, 4]], array3D[0][1] refers to [3, 4], and array3D[0][1][1] refers to the value 4. -当访问多维数组里面的元素时,最左边的下标指向最外层数组的对应位置,接下来往右的下标指向第一层嵌套的数组的位置。依此类推。根据上面的例子,array3D[0]指向[[1, 2], [3, 4]],array3D[0][1]指向[3, 4],array3D[0][1][1]的值是4。 +当访问多维数组里面的元素时,最左边的下标指向数组最外层对应位置的元素,接下来往右的下标指向第一层嵌套的数组相应位置的元素。依此类推。根据上面的定义,则array3D[0]指向[[1, 2], [3, 4]],array3D[0][1]指向[3, 4],array3D[0][1][1]的值是4。 For a detailed discussion of the Swift standard library Array type, see Arrays. -数组类型在swift标准库中的详细讨论,请看“数组“。 +swift标准库中关于数组类型的详细讨论,请看“数组“ > GRAMMAR OF AN ARRAY TYPE > 数组类型的语法 -‌ + + > array-type → type[] array-type[] > 数组类型 → 类型[] 数组类型[] @@ -260,7 +262,7 @@ For a detailed discussion of the Swift standard library Array type, see Arrays. The Swift language defines the postfix ? as syntactic sugar for the named type Optional, which is defined in the Swift standard library. In other words, the following two declarations are equivalent: -在swift中定义后缀?为标准库定义的命名类型Optional的简写。换句话说,以下两种声明是相等的: +在swift中定义后缀?是标准库定义的命名类型Optional的简写。换句话说,以下两种声明是相等的: var optionalInteger: Int? var optionalInteger: Optional @@ -268,7 +270,7 @@ The Swift language defines the postfix ? as syntactic sugar for the named type O In both cases, the variable optionalInteger is declared to have the type of an optional integer. Note that no whitespace may appear between the type and the ?. -在这两种情况下,变量optionalInteger被声明是可选整数类型。注意,在类型和?之间没有空格。 +在这两种情况下,变量optionalInteger都是可选整数类型。注意,在类型和?之间没有空格。 The type Optional is an enumeration with two cases, None and Some(T), which are used to represent values that may or may not be present. Any type can be explicitly declared to be (or implicitly converted to) an optional type. When declaring an optional type, be sure to use parentheses to properly scope the ? operator. As an example, to declare an optional array of integers, write the type annotation as (Int[])?; writing Int[]? produces an error. @@ -276,7 +278,7 @@ Optional 是一个含有两种情况的枚举,None和Some(T),用来表示 If you don’t provide an initial value when you declare an optional variable or property, its value automatically defaults to nil. -当你声明一个可选变量或者可选属性的时候没有提供初始值,它的值会默认设置为nil。 +当你声明一个可选变量或者可选属性的时候没有提供初始值,它的值会默认为nil。 Optionals conform to the LogicValue protocol and therefore may occur in a Boolean context. In that context, if an instance of an optional type T? contains any value of type T (that is, it’s value is Optional.Some(T)), the optional type evaluates to true. Otherwise, it evaluates to false. @@ -291,7 +293,7 @@ If an instance of an optional type contains a value, you can access that value u Using the ! operator to unwrap an optional that has a value of nil results in a runtime error. -用操作符!去获取值为nil的可选变量回有运行错误。 +用操作符!去获取值为nil的可选变量会有运行错误。 You can also use optional chaining and optional binding to conditionally perform an operation on an optional expression. If the value is nil, no operation is performed and therefore no runtime error is produced. @@ -376,7 +378,7 @@ Protocol composition types have the following form: A protocol composition type allows you to specify a value whose type conforms to the requirements of multiple protocols without having to explicitly define a new, named protocol that inherits from each protocol you want the type to conform to. For example, specifying a protocol composition type protocol is effectively the same as defining a new protocol ProtocolD that inherits from ProtocolA, ProtocolB, and ProtocolC, but without having to introduce a new name. -它的类型符合多个协议的要求,不需定义新的命名协议,它继承了从每个协议符合的类型。。例如,指定一个协议组合类型protocol相当于定义一个新的协议ProtocolD,它继承了ProtocolA, ProtocolB和 ProtocolC,但是没有引入一个新的名字。 +一个协议组合类型的类型符合多个协议的要求,不需定义新的命名协议,它继承了从每个协议符合的类型。例如,指定一个协议组合类型protocol相当于定义一个新的协议ProtocolD,它继承了ProtocolA, ProtocolB和 ProtocolC,但是没有引入一个新的名字。 Each item in a protocol composition list must be either the name of protocol or a type alias of a protocol composition type. If the list is empty, it specifies the empty protocol composition type, which every type conforms to. @@ -410,7 +412,7 @@ A metatype type refers to the type of any type, including class types, structure The metatype of a class, structure, or enumeration type is the name of that type followed by .Type. The metatype of a protocol type—not the concrete type that conforms to the protocol at runtime—is the name of that protocol followed by .Protocol. For example, the metatype of the class type SomeClass is SomeClass.Type and the metatype of the protocol SomeProtocol is SomeProtocol.Protocol. -类、结构、枚举的元类型是相应的类型名称后面跟着.Type。协议类型的元类型 -- 不是具体的类型,根据协议运行时来适配 -- 是该协议名字后面跟着.Protocol。例如,类SomeClass的元类型是SomeClass.Type,协议SomeProtocol的元类型是SomeProtocol.Protocol。 +类、结构、枚举的元类型是相应的类型名称后面跟着的名字.Type。协议类型的元类型 -- 不是具体的类型,而是根据协议运行时来适配 -- 是该协议后面跟着的名字.Protocol。例如,类SomeClass的元类型是SomeClass.Type,协议SomeProtocol的元类型是SomeProtocol.Protocol。 You can use the postfix self expression to access a type as a value. For example, SomeClass.self returns SomeClass itself, not an instance of SomeClass. And SomeProtocol.self returns SomeProtocol itself, not an instance of a type that conforms to SomeProtocol at runtime. You can use a dynamicType expression with an instance of a type to access that instance’s runtime type as a value, as the following example shows: @@ -455,17 +457,17 @@ A type inheritance clause is used to specify which class a named type inherits f Class types may inherit from a single superclass and conform to any number of protocols. When defining a class, the name of the superclass must appear first in the list of type identifiers, followed by any number of protocols the class must conform to. If the class does not inherit from another class, the list may begin with a protocol instead. For an extended discussion and several examples of class inheritance, see Inheritance. -类类型可能继承单个超类,适配多个协议。当定义一个类的时候,超类的名称必须出现在类型标示符列表首位,接着类必须适配的一些协议。如果类不继承其他类,那么列表就是以协议开头。类机继承的扩展讨论和例子,请看 “继承”。 +类类型可能继承单个超类,适配多个协议。当定义一个类的时候,超类的名称必须出现在类型标示符列表首位,接着是类必须适配的一些协议。如果类不继承其他类,那么列表就是以协议开头。类机继承的扩展讨论和例子,请看 “继承”。 Other named types may only inherit from or conform to a list of protocols. Protocol types may inherit from any number of other protocols. When a protocol type inherits from other protocols, the set of requirements from those other protocols are aggregated together, and any type that inherits from the current protocol must conform to all of those requirements. -其他命名协议可能仅继承或适配一个协议列表。协议类型可能继承一些其它协议。当一个协议类型继承其它协议的时候,其它协议的条件会被集合在一起,任何继承当前协议的类型必须适配所有的这些条件。 +其他命名协议可能仅继承或适配一个协议列表。协议类型可能继承多个其它协议。当一个协议类型继承其它协议的时候,其它协议的条件会被集合在一起,任何继承当前协议的类型必须适配所有的这些条件。 A type inheritance clause in an enumeration definition may be either a list of protocols, or in the case of an enumeration that assigns raw values to its cases, a single, named type that specifies the type of those raw values. For an example of an enumeration definition that uses a type inheritance clause to specify the type of its raw values, see Raw Values. -在枚举类型里面定义的类型继承子句可以是一个协议列表,或者指定原始值的枚举实例,一个单独的指定原始值类型的命名型类型。在枚举定义中用类型继承子句来指定原始值类型的列子,请看 “原始类型”。 +在枚举类型里面定义的类型继承子句可以是一个协议列表,或者指定原始值的枚举实例,或一个单独的指定原始值类型的命名型类型。在枚举定义中用类型继承子句来指定原始值类型的例子,请看 “原始类型”。 > GRAMMAR OF A TYPE INHERITANCE CLAUSE From b9b6f7a27260abb198f81230f126b11739568750 Mon Sep 17 00:00:00 2001 From: Ben Zhe Date: Mon, 23 Jun 2014 13:56:18 +0800 Subject: [PATCH 176/261] =?UTF-8?q?Review=20=E8=AE=A4=E9=A2=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1648f00..dc12e1c 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,12 @@ The Swift Programming Language 中文化项目 * Swift 教程 * 基础部分 [认领 by 琼雪] * 基本操作符 [认领 by 冰浠] - * 字符串和字符 [认领 by 筱谷] [review by 尘境] + * 字符串和字符 [已完成 by 筱谷] [review by 尘境] * 集合类型 [认领 by 尘境] * 控制流 [认领 by 墨昕] * 函数 [已完成 by 紫溪] [review by 飞长] * 闭包 [认领 by 闻西] - * 枚举 [已完成 by 灵吾] + * 枚举 [已完成 by 灵吾] [review by 筱谷] * 类和结构体 [已完成 by 晓毒] * 属性 [认领 by 周源] * 方法 [已完成 by 米尔] [review by 灵吾] From 016d0476a90736375280a8c38fff4888657bbafa Mon Sep 17 00:00:00 2001 From: Neekey Date: Mon, 23 Jun 2014 13:59:50 +0800 Subject: [PATCH 177/261] =?UTF-8?q?review=20=E5=88=86=E9=85=8D=20[?= =?UTF-8?q?=E5=85=B3=E4=BA=8E=E8=AF=AD=E8=A8=80=E5=8F=82=E8=80=83]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc12e1c..7610cd8 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ The Swift Programming Language 中文化项目 * 泛型 [已完成 by 晴时] * 高级操作符 [认领 by 林晚] * 语言参考 - * 关于语言参考 [认领 by 筱强] + * 关于语言参考 [认领 by 筱强] [review by 隐若] * 词法结构 [认领 by 筱强] * 类型 [认领 by 兰梦] * 表达式 [认领 by 懂象] From 1b7ac3ce898be117a1893300fad19f3307c1eaa3 Mon Sep 17 00:00:00 2001 From: jayson Date: Mon, 23 Jun 2014 16:20:56 +0800 Subject: [PATCH 178/261] complete flow control --- src/chapter2/05_Control_Flow.md | 192 +++++++++++++++++++++++++------- 1 file changed, 149 insertions(+), 43 deletions(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index bbe74a3..ad9eccd 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -2,11 +2,11 @@ ## by moxin.xt -Swift提供类似C语言的控制流语法,比如```for```和```while```循环;```if```和```switch```的条件判断表达式以及``` break```,```continue```这种跳出循环的语句。 +Swift提供类似C语言的控制流语法,比如```for```和```while```循环;```if```和```switch```的条件判断语句语句以及``` break```,```continue```这种跳出循环的语句。 -Swift除了支持类似C语言这种```for-condition-increment```的表达式外,还支持```for-in```这种循环语句,可以轻松的遍历数组,字典,字符串等序列。 +Swift除了支持类似C语言这种```for-condition-increment```的语句外,还支持```for-in```这种循环语句,可以轻松的遍历数组,字典,字符串等序列。 -Swift的```switch```语句和C语言相比很强大,它不会像C语言那样,因为在case的分支中忘记写break而执行了下一条case的语句。同时case语句可以匹配任何类型模式,包括区间蒲培,元组和特定类型描述。 +Swift的```switch```语句和C语言相比很强大,它不会像C语言那样,因为在case的分支中忘记写break而执行了下一条case的语句。同时case语句可以进行不同类型的模式匹配,包括区间匹配,元组匹配和特定类型描述。```switch```语句中待匹配的值可以绑定到临时变量或常量上,便于```case```中得代码访问,同时,一些复杂的匹配条件可已通过```where```关键字来补充。 #For循环 @@ -32,7 +32,7 @@ for index in 1...5{ ``` -我们首先通过(```...```)表达式创建了一个数字集合,然后枚举集合中的每个元素,```index```值首先被赋值为range(```1```),然后执行循环体内的代码,上面这个例子中循环体内只有一行代码,作用是打印出```index```的值。当这行代码执行完后,```index```值会被更新,被赋值为range(```2```),```println```再次被调用,如此反复,直到循环结束。 +我们首先通过(```...```)语句创建了一个数字集合,然后枚举集合中的每个元素,```index```值首先被赋值为range(```1```),然后执行循环体内的代码,上面这个例子中循环体内只有一行代码,作用是打印出```index```的值。当这行代码执行完后,```index```值会被更新,被赋值为range(```2```),```println```再次被调用,如此反复,直到循环结束。 上面例子中```index```是个常量,在每次循环开始的时候会被自动赋值,因此它不需要在使用前通过```let```声明,因为它会被```for-in```隐式声明。 @@ -97,7 +97,7 @@ for (animalName, legCount) in numberOfLegs { ``` ## For-Condition-Increment -除了使用```for-in```这种循环表达式,Swift还提供了传统的C风格的``for```循环表达式,通常它需要一个循环执行条件和一个累加器: +除了使用```for-in```这种循环语句,Swift还提供了传统的C风格的``for```循环语句,通常它需要一个循环执行条件和一个累加器: ``` “for var index = 0; index < 3; ++index { @@ -107,21 +107,21 @@ for (animalName, legCount) in numberOfLegs { // index is 1 // index is 2 ``` -下面是这种语法通用的表达式: +下面是这种语法通用的语句: for ```initialization```;```condition```;```increment```{ ```statements``` } -和C语言一样,循环表达式被分号分割为3部分。但是和C语言不同的是,Swift不需要使用括号将"initialization;condition;increment"包围起来。 +和C语言一样,循环语句被分号分割为3部分。但是和C语言不同的是,Swift不需要使用括号将"initialization;condition;increment"包围起来。 循环执行顺序如下: -1,循环开始时执行一次initialization表达式,初始化循环使用的常量或变量。 +1,循环开始时执行一次initialization语句,初始化循环使用的常量或变量。 -2,condition表达式被执行,如果结果为```false```循环结束,执行循环体后面的代码。如果condition表达式结果为```true```,继续执行循环体内的代码 +2,condition语句被执行,如果结果为```false```循环结束,执行循环体后面的代码。如果condition语句结果为```true```,继续执行循环体内的代码 -3,当循环体内的代码被执行完时,increment表达式被执行。通常情况是增加或减少计数器的值,然后执行第2步,condition表达式会被再次执行。 +3,当循环体内的代码被执行完时,increment语句被执行。通常情况是增加或减少计数器的值,然后执行第2步,condition语句会被再次执行。 上面的for循环结构也可以如下表示: @@ -131,7 +131,7 @@ while ```condition``` { ```increment``` } -在for循环初始化时创建的变量或者常量只在循环体内有效,如果想获取循环结束时的```index```值,你必须将```index```显式的声明到循环表达式前: +在for循环初始化时创建的变量或者常量只在循环体内有效,如果想获取循环结束时的```index```值,你必须将```index```显式的声明到循环语句前: ``` var index: Int @@ -215,9 +215,9 @@ println("Game over!") 显然在上面这情况下,使用```while```循环是非常合适的,因为循环次数不确定,只能根据循环条件来判断是否要终止循环。 ###Do-While -另一个```while```循环的变种是```do-while```表达式,它首先执行一次循环,然后在判断循环执行条件。如此反复,直到循环条件返回```false```。 +另一个```while```循环的变种是```do-while```语句,它首先执行一次循环,然后在判断循环执行条件。如此反复,直到循环条件返回```false```。 -下面是```do-while```表达式的格式: +下面是```do-while```语句的格式: ``` do { @@ -255,16 +255,16 @@ println("Game over!") 这里的循环条件(```while square < finalSquare```)和前面相同,但它会在循环结束后被执行。```do-while```循环结构比前面的```while```更适合这个游戏。使用```do-while```时,```square+=board[square]```会立刻被执行,它省去了上个例子中对数组越界的判断。 -##条件表达式 +##条件语句 通常情况下我们需要在满足某种条件时执行一段代码或者在出错时执行另一段代码,也可能需要在某个值过大或过小时打印输出一些提示信息。这都需要你在代码中加入判断条件。 -Swift提供了两种条件判断的表达式,它们是```if```和```switch```。 +Swift提供了两种条件判断的语句,它们是```if```和```switch```。 -通常情况下,在条件分支比较少时,你使用```if```表达式,```switch```表达式用来处理复杂的判断条件和过多的条件分支,此外```switch```在模式匹配上非常有用。 +通常情况下,在条件分支比较少时,你使用```if```语句,```switch```语句用来处理复杂的判断条件和过多的条件分支,此外```switch```在模式匹配上非常有用。 ###If -```If```表达式很简单,当判断条件为```true```时,执行一段代码: +```If```语句很简单,当判断条件为```true```时,执行一段代码: ``` var temperatureInFahrenheit = 30 @@ -275,7 +275,7 @@ if temperatureInFahrenheit <= 32 { ``` 上面的例子会判断温度是否小于等于32华氏度。如果是,打印一条消息。 -```if```表达式通常和```else```搭配使用,当```if```表达式返回```false```时,```else```分支的代码会被执行: +```if```语句通常和```else```搭配使用,当```if```语句返回```false```时,```else```分支的代码会被执行: ``` temperatureInFahrenheit = 40 @@ -288,7 +288,7 @@ if temperatureInFahrenheit <= 32 { ``` -这种情况下```if```和```else```两个分支中的一个一定会被执行到,你也可以将多个```if```表达式连起来使用: +这种情况下```if```和```else```两个分支中的一个一定会被执行到,你也可以将多个```if```语句连起来使用: ``` temperatureInFahrenheit = 90 @@ -301,7 +301,7 @@ if temperatureInFahrenheit <= 32 { } // prints "It's really warm. Don't forget to wear sunscreen. ``` -这里,多了一个```if```表达式用来判断特定的温度范围。最后的```else```语句是可选的: +这里,多了一个```if```语句用来判断特定的温度范围。最后的```else```语句是可选的: ``` temperatureInFahrenheit = 72 @@ -316,7 +316,7 @@ if temperatureInFahrenheit <= 32 { ###Switch -```switch```表达式会将一个值和多种模式进行匹配。匹配成功则执行该条件所对应的代码。```switch```是一种可以替换```if```进行条件判断的表达式。```switch```的语法格式如下: +```switch```语句会将一个值和多种模式进行匹配。匹配成功则执行该条件所对应的代码。```switch```是一种可以替换```if```进行条件判断的语句。```switch```的语法格式如下: ``` switch some value to consider { @@ -329,13 +329,13 @@ default: otherwise, do something else } ``` -每个```switch```表达式都对应多个```case```表达式。除了可以用```case```表达式来比较具体的值以外,Swift提供了许多复杂的模式匹配,下一小节会详细介绍。 +每个```switch```语句都对应多个```case```语句。除了可以用```case```语句来比较具体的值以外,Swift提供了许多复杂的模式匹配,下一小节会详细介绍。 -```switch```语句内包含多个代码执行分支,这点和```if```表达式很像。```switch```表达式决定了那个分支会被执行,通常是根据变量值来决定的。 +```switch```语句内包含多个代码执行分支,这点和```if```语句很像。```switch```语句决定了那个分支会被执行,通常是根据变量值来决定的。 -每个```switch```表达式必须是完整的,意思是它提供的分支条件必须能涵盖所有情况,你可以定义一个默认的分支条件用来处理一些意外的条件。这种分支通常用关键字```default```表示,并且它必须是最后一个分支条件。 +每个```switch```语句必须是完整的,意思是它提供的分支条件必须能涵盖所有情况,你可以定义一个默认的分支条件用来处理一些意外的条件。这种分支通常用关键字```default```表示,并且它必须是最后一个分支条件。 -这个例子使用```switch```表达式类匹配一个小写字母变量```someCharacter```: +这个例子使用```switch```语句类匹配一个小写字母变量```someCharacter```: ``` let someCharacter: Character = "e" @@ -350,15 +350,15 @@ default: } // prints "e is a vowel” ``` -```switch```表达式的第一个```case```分支是匹配五个元音字母。同理,第二个```case```分支用来匹配所有的字符常量。 +```switch```语句的第一个```case```分支是匹配五个元音字母。同理,第二个```case```分支用来匹配所有的字符常量。 -通常来说列举出所有的字符不太现实,因此```switch```表达式提供了```default```分支用来匹配所有其它的字符,这确保了```switch```表达式的完整性。 +通常来说列举出所有的字符不太现实,因此```switch```语句提供了```default```分支用来匹配所有其它的字符,这确保了```switch```语句的完整性。 ###没有隐式贯穿 -和C语言或Objective-C相比,Swift中的```switch```表达式在执行完一条```case```分支的代码后,则认为```switch```语句执行完毕。在某个```case```分支没有```break```的情况下,不会继续执行下一条```case```分支的代码。这比C语言更简单和安全。 +和C语言或Objective-C相比,Swift中的```switch```语句在执行完一条```case```分支的代码后,则认为```switch```语句执行完毕。在某个```case```分支没有```break```的情况下,不会继续执行下一条```case```分支的代码。这比C语言更简单和安全。 注意: 你也可以在```case```分支代码执行前使用```break```语句来跳出这个分支,详见后面的章节。 @@ -376,7 +376,7 @@ default: // this will report a compile-time error ``` -和C语言不同,```switch```表达式不会既匹配`"a"`又匹配`"A"`。遇到这种情况,编译器会给出错误提示。这条规则会避免意外的执行了其它分支的代码。 +和C语言不同,```switch```语句不会既匹配`"a"`又匹配`"A"`。遇到这种情况,编译器会给出错误提示。这条规则会避免意外的执行了其它分支的代码。 一条```case```分支也可以匹配多个判断条件,用逗号隔开: @@ -388,12 +388,12 @@ value 2: } ``` 注意 - 对于```switch```表达式的某个case分支,你可以通过使用```fallthrough```关键字来强制贯穿改```case```分支。 + 对于```switch```语句的某个case分支,你可以通过使用```fallthrough```关键字来强制贯穿改```case```分支。 更对细节在Fallthrough一节有所介绍 ###区间匹配 -```switch```表达式的```case```分支可以是一个值区间同样支持范围匹配。下面这个例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式: +```switch```语句的```case```分支可以是一个值区间同样支持范围匹配。下面这个例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式: ``` let count = 3_000_000_000_000 @@ -421,7 +421,7 @@ println("There are \(naturalCount) \(countedThings).") ###元组 -你可以使用元组在同一个```switch```表达式中测试多个值。元组中的每个元素可以是一个区间,也可以是不同的值。我们使用(_)来匹配任何可能的值。 +你可以使用元组在同一个```switch```语句中测试多个值。元组中的每个元素可以是一个区间,也可以是不同的值。我们使用(_)来匹配任何可能的值。 下面的例子使用一个元组类型(```Int```,```Int```)的点(x,y)并用图标来描述它的分布: @@ -445,13 +445,13 @@ default: 【图】 -```switch```表达式用来判断这个点是否在原点;红色的X轴上;橘黄色的Y轴上;在蓝色的4x4的盒子内,还是在盒子外面。 +```switch```语句用来判断这个点是否在原点;红色的X轴上;橘黄色的Y轴上;在蓝色的4x4的盒子内,还是在盒子外面。 不像C语言,Swift支持不同的```case```分支匹配同一个结果,在这个例子中,点(0,0)满足所有4个分之条件。这种情况下只有第一条```case```语句被执行。点(0,0)会首先匹配第一条```case(0,0)```,后面的```case```语句会被忽略掉。 ###值绑定(Value Bindings) -```switch```表达式允许在一个```case```分支中,将待匹配的值绑定到一些常量或临时变量上。这就是值绑定。 +```switch```语句允许在一个```case```分支中,将待匹配的值绑定到一些常量或临时变量上。这就是值绑定。 下面的例子将使用值绑定的方法重写上面的代码: ``` @@ -469,7 +469,7 @@ case let (x, y): ``` 【图】 -上面我们通过```switch```表达式判断了```anotherPoint```这个点是否在红色的X,y轴上或者在非轴上的任意位置。 +上面我们通过```switch```语句判断了```anotherPoint```这个点是否在红色的X,y轴上或者在非轴上的任意位置。 上面三条```case```语句使用临时变量```x```,```y```来匹配```anotherPoint```中的值。第一条```case(let x, 0)```语句用来匹配所有```y```值为0的点,并把该点的```x```值赋值给常量```x```。同理,```case(0,let y)```匹配所有```x```值为0的点,并把该点得```y```值赋给常量```y```。 @@ -499,22 +499,22 @@ case let (x, y): ``` 【图】 -上面的```switch```表达式用来检测```yetAnotherPoint```这个点是否在绿色或紫色的对角线上。 +上面的```switch```语句用来检测```yetAnotherPoint```这个点是否在绿色或紫色的对角线上。 -上面的三条```switch```表达式声明了常量```x```和```y```用来临时保存```yetAnotherPoint```中的坐标值。这两个常量同时也被```where```用来创建一个过滤条件。只有当```where```的过滤条件返回```true```时,```case```分支的代码才会被执行。 +上面的三条```switch```语句声明了常量```x```和```y```用来临时保存```yetAnotherPoint```中的坐标值。这两个常量同时也被```where```用来创建一个过滤条件。只有当```where```的过滤条件返回```true```时,```case```分支的代码才会被执行。 和上面的例子一样```default```分支在这个例子中也可以被忽略。 -###控转移表达式 +###控转移语句 -控制转移表达式会改变代码执行的顺序。Swift提供了4个控制转移表达式: +控制转移语句会改变代码执行的顺序。Swift提供了4个控制转移语句: * continue * break * fallthrough * return -我们下面将会讨论```control```,```break````,```return```表达式,```return```将会在函数一章讨论。 +我们下面将会讨论```control```,```break````,```return```语句,```return```将会在函数一章讨论。 @@ -542,17 +542,17 @@ println(puzzleOutput) // prints "grtmndsthnklk ``` -在上面的代码中,一旦出现元音字母,当前循环就会被终止,并重新开始下一次循环。这会让```switch```表达式去匹配元音字符或空字符时不做处理,而不是让每一个匹配到的字符都被打印出来。 +在上面的代码中,一旦出现元音字母,当前循环就会被终止,并重新开始下一次循环。这会让```switch```语句去匹配元音字符或空字符时不做处理,而不是让每一个匹配到的字符都被打印出来。 ###break -```break```语句会立刻终止当前执行的整个控制流。```break```可被用在```switch```表达式里面或循环中用来提前结束控制流。 +```break```语句会立刻终止当前执行的整个控制流。```break```可被用在```switch```语句里面或循环中用来提前结束控制流。 ###循环体内的break 当在循环体内执行```break```时,会退出整个循环,代码从循环体后面的第一行开始执行。 -###Switch表达式中得break +###Switch语句中得break 当在```switch```中使用```break```时,会立即终止改```switch``代码块的执行,并且跳转到```switch```代码块结束的大括号(```}```)后的第一行代码。 @@ -593,4 +593,110 @@ if let integerValue = possibleIntegerValue { 在上面的例子中,想要把```Character```所有的的可能性都枚举出来是不现实的,所以使用```default```分支来包含所有上面没有匹配到字符的情况。由于这个```default```分支不需要执行任何动作,所以它只写了一条```break```语句。一旦落入到```default```分支中后,```break```语句就完成了该分支的所有代码操作,代码继续向下,开始执行```if let```语句。 +###Fallthrough + +Swift中的Switch语句不会从上到下进入每一个case分支。相反,一旦有一个case分支被匹配成功,整个state语句就结束执行了。相比之下,在C语言中,为了防止switch语句会贯穿执行每一个case分支,你需要在每个case分支的末尾插入```break```语句。和C语言相比,Swift支持这种避免贯穿行为会让```switch```语句更简洁和更安全也能规避错误执行多个case分支的情况。 + +如果你一定要使用C风格的贯穿(fallthrough)机制,你可以在每个需要支持该特性的case分支中使用```fallthrough```关键字。下面这个例子展示了如何使用```fallthrough```来实现对数字的文本描述: + +``` +let integerToDescribe = 5 +var description = "The number \(integerToDescribe) is" +switch integerToDescribe { +case 2, 3, 5, 7, 11, 13, 17, 19: + description += " a prime number, and also" + fallthrough +default: + description += " an integer." +} +println(description) +// prints "The number 5 is a prime number, and also an integer. +``` +这个例子中声明了一个叫```description```的```string```类型的变量,并且为其赋了初值。然后这个函数通过```switch```语句来判断```integerToDescribe```的值。如果```integerToDescribe```的值为数组中的一个素数,则该函数会为```decription```后面追加一段文本用来提示改数字式质数。然后会使用```fallthrough```关键字来执行```default```中的代码。在```default```分支中会为```description```后面继续追加一段文本。至此,```switch```语句才算执行完成。 + +如果```integerToDescribe```的值不在这组质数当中,则它不会和第一条```case```语句匹配。由于没有其它的分支存在,所以```integerToDescribe```会落入```default```分支。 + +当```switch```语句执行完成后,关于这个数字的描述会通过```println```函数打印出来。在这个例子中,数字```5```被正确的识别为一个质数。 + + 注意: + 和C语言的```switch```语句一样,```fallthrough```不会检查它落入执行的```case```分支的条件是否匹配, + 它只是简单的执行下一条```case```(或```default```)中的代码。 + +###Labeled语句 + +在```swift```中,可以在循环或```switch```函数中嵌套循环或```switch```函数来实现比较复杂的控制流结构。但是,在循环或```switch```函数中可以使用```break```语句提前终止其执行过程。因此,有些时候显示的调用```break```来标识终止循环或```switch```是非常有好处的。类似的,如果一个循环中嵌套了多个循环,使用```continue```来标识其影响的循环体也是很有用的。 + +为了实现上面的目标,你可以通过标签来标识某个循环或```switch```语句。使用```break```或```continue```时,带上这个标签,这个标签可以用来结束或执行被标记的代码段。 + +标签语句通常被放到一些关键字的前面,通过分号隔开。下面是一个通过标签来标记```while```语句的例子,循环或```switch```语句和它类似: + +``` +label name: while condition { + statements +} + +``` + +下面这个例子将使用```break```和```continue```,配合带标签的```while```循环,该循环和前面的梯子和蛇的例子一直。这次,该游戏新增加了一条规则 + +* 为了胜利,你必须恰好到达第25个格子中 + +如果某一次掷骰子会把你带到超过25的地方,必须重新掷骰子,直到你恰好到达第25号格子的位子 + +游戏的棋盘和前面的一样: + +【图】 + +```finalSquare```,```board```,```square```和```diceRoll```的值和之前初始化的值相同: + +``` +let finalSquare = 25 +var board = Int[](count: finalSquare + 1, repeatedValue: 0) +board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 +board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 +var square = 0 +var diceRoll = 0 + +``` +这个版本会使用```while```循环和```switch```语句来实现游戏的逻辑。```while```循环有个标签叫做```gameLoop```,用来表示这个循环是这个游戏的主循环。 + +```while```循环的条件是```while square != finalSquare```用来表示你必须正好落在第25个格子中: + +``` +gameLoop: while square != finalSquare { + if ++diceRoll == 7 { diceRoll = 1 } + switch square + diceRoll { + case finalSquare: + // diceRoll will move us to the final square, so the game is over + break gameLoop + case let newSquare where newSquare > finalSquare: + // diceRoll will move us beyond the final square, so roll again + continue gameLoop + default: + // this is a valid move, so find out its effect + square += diceRoll + square += board[square] + } +} +println("Game over!") + +``` + +在每个循环开始前都需要掷骰子,与之前立刻移动玩家不同,这次利用```switch```语句计算每次掷骰子产生的结果,从而决定玩家是否可以移动: + +* 如果掷骰子的结果恰好将玩家移动到最后的方格中,那么游戏结束。```break gameLoop```会将代码跳到循环后的第一条语句,继续执行后面的代码。 + +* 如果掷骰子的结果将玩家移动到超过最后一个方格的位置,那么这次结果是无效的,玩家需要重新掷骰子。```continue gameLoop```会将当前循环终止并重新开始下一次循环。 + +* 在所有其余的情况中,掷骰子的结果是有效的,玩家会前进```diceRoll```个格子,游戏的逻辑会检测是否遇到梯子或者蛇。循环结束时,代码将回到```while```条件判定检查是否要进行下一次循环。 + + 注意: + + 如果```break```语句没有使用```gameLoop```标签,那么它将会中断```switch```代码块而不是```while```。 使用```gameLoop```标签可以更直观的体现循环在哪里被终止的。 + + 我们还注意到,跳到下一次循环的语句:```continue gameLoop```并不一定要使用```gameLoop```标签。由于代码中只 有一个循环,因此```continue```语句是没有歧义的,但是在这里使用```gameLoop```标签也是没有任何坏处的。在```break```旁边加上标签可以保证代码的一致性,是代码逻辑更清楚,更容易被人读懂和理解。 + + + + From 3ed1323555946e6b223a3cd5dfd3fbeaff338afd Mon Sep 17 00:00:00 2001 From: zearlin Date: Mon, 23 Jun 2014 18:40:09 +0800 Subject: [PATCH 179/261] Update 17_Optional_Chaining.md --- src/chapter2/17_Optional_Chaining.md | 300 +++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) diff --git a/src/chapter2/17_Optional_Chaining.md b/src/chapter2/17_Optional_Chaining.md index e69de29..8793fc8 100644 --- a/src/chapter2/17_Optional_Chaining.md +++ b/src/chapter2/17_Optional_Chaining.md @@ -0,0 +1,300 @@ +> 翻译:[zearlin](https://github.com/zearlin) + +# 可选链 +----------------- + +可选链(Optional Chaining)是针对当前可能为空值(`nil`)的可选元素的属性,方法及下标调用和查寻的一种处理。 若可选元素为赋值对应的属性,方法或下标都会被成功调用;反之当可选成员为空值(`nil`)时,侧其属性,方法或下标调为会返回空值(`nil`)。多个的查寻可一起链式调用,并当链路的任意一环为nil时链路调用失败。 + +> 注意: +Swift中的可选链与Object-C中空值的方法调用相似,是一种更为全面的实现,适用于所有的类型及支持调用成功与否的判断。 + +## 可选链,强制解析的一种替代方案 + +当你想调用一个属性,方法或下标时通过在可选元素(`optional value`)后添置一个问号(?)来声明一个为可选链,当可选元素为非空时,侧与通过添置感叹号(!)来强解析其值的做法非常相似。主要的区别在于当可选元素为空时可选链会得体地以调用失败结束,而强制解析则会引发一个运行时错误。 + +考虑到可选链空值调用这一情况,可选链的返回值一定为可选值,即使你所查寻的属性,方法或下标返回的并不是是一个可选值。你可以通过返回的可选值来判断可选链的调用是成功的(返回的可选元素有值),还是因为链式中的空值元素而调用失败(返回的可选元素为空)。 + +具体来说,可选链的返回值类型与预期的返回值类型一致,但封装为了一个可选元素。原本返回为整型的属性,在可选链调用中会返回为可选整型(Int?) + +我们将在后续的几个代码片段中解释可选链与强制解析的区别及让你了解如果判断调用成功与否。 + +首先,我们先定义Person与Residence两个类: + +```swift +class Person { + var residence: Residence? +} + +class Residence { + var numberOfRooms = 1 +} +``` + +`Residence`实例拥有一个命名为`numberOfRooms`的整型属性。而`Person`实例有一个可选属性`residence`其类型为`Residence?`。 + +如果你创建一个新的`Person`实例,它的`residence`属性由于是被定义为可选型的,此属性将默认初始化为空。下面的代码中,john的residence属性值为空: + + +```swift +let john = Person() +``` + +如果你在`residence`后添置感叹号(`!`)以强制解析的方式来访问`person`的`residence`的属性`numberOfRooms`时,会引发一个运行时错误,因为`residence`为空无法被解析。 + +```swift +let roomCount = john.residence!.numberOfRooms +//将导致运行时错误 +``` +当`john.residence`为非空及为`roomCount`设一个可理的房间数时以述的代码会被成功调用。然后如上面所演示的,当`residence`为空这段代码就会触发一个运行时错误。 + +可选链提供了访问`numberOfRooms`值的另一种方式。 在这里通过以问号来取代先前的感叹号以可选链的方式调用。 + +```swift +if let roomCount = john.residence?.numberOfRooms { + println("John's residence has \(roomCount) room(s).") +} else { + println("Unable to retrieve the number of rooms.") +} +// 打印 "Unable to retrieve the number of rooms. +``` + +这将告诉Swift将可选的`residence`属于链式中的一环并得到`numberOfRooms`的值当`residence`存在时。 + +因为尝试访问`numberOfRooms`时存在失败的可能,所以可选链返回一个类型为`Int?` 或称之为“可选整型”的值。 当`residence`为空时,这个可选整型也将为空,以表示`numberOfRooms`无法被访问。 + +需要注意一点即使`numberOfRooms`为非可选整型。通来可选链的方式来调用`numberOfRooms`的值查询时返回的类型是`Int?`而不是一个常规的`Int`。 + +我们给`john.residence`分配一个`Residence`实例让它不在为一个空值: + +```swift +john.residence = Residence() +``` + +此时`john.residence`包含了一个真实的`Residence`实例而不再为空了。如果你以先前相同的可选链方式去访问`numberOfRooms`,它将返回一个包含默认值 1 的`Int?`: + +```swift +if let roomCount = john.residence?.numberOfRooms { + println("John's residence has \(roomCount) room(s).") +} else { + println("Unable to retrieve the number of rooms.") +} +// 打印 "John's residence has 1 room(s)"。 +``` + +##定义可选链的模型(实体)类 + +可选链支持多层的属性,方法及下标调用。这一特性让你可以进一步的调用关联类型的复杂模型中的子属性及判断这些子属性对应的属性,方法及下标下否可以访问。 + +在下面的代码片段中为后续的几个例子使用定义了四个实体类,这些类都是基于`Person`和`Residence`模型通过增加`Room`及`Address`类及一些相关的属性,方法及下标进行扩展的。 + +`Person`类还是于先前定义的相同: + +```swift +class Person { + var residence: Residence? +} +``` + +`Residence `类比之前复杂些。这次我们为 `Residence `声明了一个名为 `rooms `的变量,其初始值为 `Room[] `类型的空数值。 + +```swift +class Residence { + var rooms = Room[]() + var numberOfRooms: Int { + return rooms.count + } + subscript(i: Int) -> Room { + return rooms[i] + } + func printNumberOfRooms() { + println("The number of rooms is \(numberOfRooms)") + } + var address: Address? +} +``` +因为在这一版的`Residence`中存储了一个Room实例数组,所以其`numberOfRooms`属性以计算属性的方式实现。计算的`numberOfRooms`属性只是简单的返回了`rooms`数组的`count`属性。 + +为了更便捷的访问它的`rooms`数组,在这一版中`Residence`提供了一个只读下标,一开始我们假设传参的引索是有效的。如果索引是有效的,下标将返回`rooms`数组与请求索引相对应的`room`对象。 + +`Residence`还提供了一个名为`printNumberOfRooms`的方法,用于简单地打印房间数。 + +最后,`Residence`还定义了一个类型为`Address?`的可选属性`address`,对应的`Address`类会在下文中定义。 + +`rooms`数组中用到的`Room`类非常简单只拥有一个`name`属性及对应设置房间名的构造器。 + +```swift +class Room { + let name: String + init(name: String) { self.name = name } +} +``` + +模型中最后的一个类叫`Address`。类中有三个类型为`String?`的可选属性。作为地址信息中的一部分头两个属性`buildingName`及`buildingNumber`是两个可供选择的方式来定位特定的建筑物。 第三个属性,`stree`,则用来保存地址中的街道名称的: + +```swift +class Address { + var buildingName: String? + var buildingNumber: String? + var street: String? + func buildingIdentifier() -> String? { + if buildingName { + return buildingName + } else if buildingNumber { + return buildingNumber + } else { + return nil + } + } +} +``` +`Address`类中还提供了一个名为`buildingIdentifier`的方法,其返回类型为`String?`。 这个方法检查`buildingName`及`buildingName`是否有值,若`buildingName`有值则返回`buildingName`,若非则返回`buildingNumber`的值,如果两者均无则返回空。 + +##以可选链方式的属性调用 + +如先前演示的可选链做为强制解析的一个替代方式,你可以利用可选链来访问可选元素的属性,及检测属性的访问是否能成功,但你不能通过可选链的方式为属性赋值。 + +利用前先写好的类一个新的`Person`实例,并与之前先一样尝试访问它的`numberOfRooms`属性: + +```swift +let john = Person() +if let roomCount = john.residence?.numberOfRooms { + println("John's residence has \(roomCount) room(s).") +} else { + println("Unable to retrieve the number of rooms.") +} +// 打印 "Unable to retrieve the number of rooms。 +``` + +因为`john.residence`为空,所以这个可选链与先前的一样调用失败并没引错误。 + +##以可选链方式的方法调用法 + +你能以可选链的方式去调用一个可选元素的方法,及检测是否方法调用不否成功。即使在方法没有定义返回值的情况下一样可行。 + +`Residence`的`printNumberOfRooms`方法会打印`numberOfRooms`的当前值。方法如下: + +```swift +func printNumberOfRooms(){ + println(“The number of rooms is \(numberOfRooms)”) +} +``` +这个方法没有声明返回值,无返回值函数及方法都会带有一个隐式的返回类型为`Void`(参见Function Without Return Values)。 + +如果你通过可选链的方式去调用一个可选元素的方法,该方法返回的将是`Void?`,而非`Void`,因为通过可选链方式调用的方法返回的均为可选类型。这样让你可以通过一个`If`语句去测试`printNumberOfRooms`方法是否可调用,即使该方法本身没有定义返回值。当`printNumberOfRooms`方法通过可选链调用成功时隐式的返回值为`Void`,否非为空: + +```swift +if john.residence?.printNumberOfRooms() { + println("It was possible to print the number of rooms.") +} else { + println("It was not possible to print the number of rooms.") +} +// 打印 "It was not possible to print the number of rooms."。 +``` + +##以可选链方式的下标调用 + +你可以通过可选链的方式去获取可选元素对应下标的值,及判断下标调用是否成功,然而,你不能在可选链中去设置一个下标的值。 + +> 注意: +当你要通过可选链的试访问对应可选元素的下标时,你应该将问号置于下标所带的括号前,而非后。可选链的问号通常都是紧随表达式中的可选元素后的。 + +下面的例子中我们将通过在`Residence`类中定义的下标去获取`rooms`数组中第一间房间的名称。由于`john.residence`当前为空,所以下标的调用失败。 + +```swift +if let firstRoomName = john.residence?[0].name { + println("The first room name is \(firstRoomName).") +} else { + println("Unable to retrieve the first room name.") +} +// 打印 "Unable to retrieve the first room name."。 +``` + +下标调用时我们将可选链的问号置于`john.residence`后于下标的括号前。因为`john.residence`为可选链需要尝试调用的可选元素。 + +如果我们为`john.residence`创建并分配一个`Residence`实体且其`rooms`属性带一个或多个Room实体,你就可以通过`Residence`的下标在可选链中访问对应的成员了: + +```swift +let johnsHouse = Residence() +johnsHouse.rooms += Room(name: "Living Room") +johnsHouse.rooms += Room(name: "Kitchen") +john.residence = johnsHouse + +if let firstRoomName = john.residence?[0].name { + println("The first room name is \(firstRoomName).") +} else { + println("Unable to retrieve the first room name.") +} +// 打印 "The first room name is Living Room."。 +``` + +##多层链式 + +你可以通过多层链式来访问实体中的属性,方法及下标。多层可选链式调用并不会增加返回值的可选性/形成可选嵌套。 + +也就是说: + +通过可选链得到的值一定为可选类型,无论你想获取的目标值是否为可选。同理一个目标值原为可选元素,不过因为链式的调用而加深变可选性。 + +因此: + +当你想从可选链中得到一个`Int`时,你得到的总会是一个`Int?`类型的值,无论通过多少层的可选链。相同的,原为`Int?`类型的返回值也一样,无论经过多少层得到的还是`Int?`类型。 + +下面的例子中我们将尝试访问从`john`的`residence`属性中的`address`属于获取期其`street`属性的值。这里我们将有两层的可选链调用,链式中的两环`residence`和`address`均为可选类型的属性: + +```swift +if let johnsStreet = john.residence?.address?.street { + println("John's street name is \(johnsStreet).") +} else { + println("Unable to retrieve the address.") +} +// 打印 "Unable to retrieve the address.”。 +``` + +虽然当前的`john.residence`含有一个有效的`Residence`实例。然而`john.residence.address`的还是为空值,所以调用`john.residence?.address?.street`失败了。 + +值得注意在下面的例子中,你将尝试去获得`street`属性的值。 这个属性的类型为`String?`。所以`john.residence?.address?`的返回值也是`String?`,即使经过了两层的可选链路来访问。 + +如果你为`john.street.address`分配一个真实的`Address`实例并为其`street`赋值,你就可以通过多层可用选连的试去访问相关的值。 + +```swift +let johnsAddress = Address() +johnsAddress.buildingName = "The Larches" +johnsAddress.street = "Laurel Street" +john.residence!.address = johnsAddress +``` + +```swift +if let johnsStreet = john.residence?.address?.street { + println("John's street name is \(johnsStreet).") +} else { + println("Unable to retrieve the address.") +} +// 打印 "John's street name is Laurel Street."。 +``` + +注意我们需要通过感叹号来为`jonh.residence.address`赋值。 因为`john.residence`属性是一个可选类型,所以在为`residence`的`address`属性赋值前,我们需要用感叹得到它的实际值先。 + +##返回可选值方法的链式调用 + +先前的例子中我们展示了如果通过可选链路来获取一个可选属性的值。如有需要我们也可以用可选链的方式去调用返回值为可选类型的方法,并也可将其返回值做为链式中的一环。 + +下下面的例子中通过可选链调用了`Address`类的`buildingIdentifier`方法。 这个方法的返回类型为`String?`。 如先前所述,通过可选链调用该方法的最终返回类型也是为`String?`: + +```swift +if let buildingIdentifier = john.residence?.address?.buildingIdentifier() { + println("John's building identifier is \(buildingIdentifier).") +} +// 打印 "John's building identifier is The Larches."。 +``` + +如果你想将该方法的返回值也置于链式中,只需将可选链路的问号置于方法调用的括号后: + +```swift +if let upper = john.residence?.address?.buildingIdentifier()?.uppercaseString { + println("John's uppercase building identifier is \(upper).") +} +// 打印 "John's uppercase building identifier is THE LARCHES."。 +``` + +> 注意: +在上面的例子中,你将可选链的问号置于括后面是因为你想加入链式中的可选元素是`buildingIdentifier`的返回值,而不是该方法本身。 From 31e2f2626a56264ff7d6003d91fd7bbd71e02cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=8D=E9=B1=BC?= Date: Mon, 23 Jun 2014 18:48:23 +0800 Subject: [PATCH 180/261] update md --- src/chapter2/17_Optional_Chaining.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/17_Optional_Chaining.md b/src/chapter2/17_Optional_Chaining.md index 8793fc8..85642a5 100644 --- a/src/chapter2/17_Optional_Chaining.md +++ b/src/chapter2/17_Optional_Chaining.md @@ -1,6 +1,6 @@ > 翻译:[zearlin](https://github.com/zearlin) -# 可选链 +# 可选链 ----------------- 可选链(Optional Chaining)是针对当前可能为空值(`nil`)的可选元素的属性,方法及下标调用和查寻的一种处理。 若可选元素为赋值对应的属性,方法或下标都会被成功调用;反之当可选成员为空值(`nil`)时,侧其属性,方法或下标调为会返回空值(`nil`)。多个的查寻可一起链式调用,并当链路的任意一环为nil时链路调用失败。 From fcdd4b62c13adf1ac1a7eb8a6e155c8e4149324b Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Mon, 23 Jun 2014 21:42:07 +0800 Subject: [PATCH 181/261] Update 08_Patterns.md review --- src/chapter3/08_Patterns.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/chapter3/08_Patterns.md b/src/chapter3/08_Patterns.md index 19d2752..d69a775 100644 --- a/src/chapter3/08_Patterns.md +++ b/src/chapter3/08_Patterns.md @@ -3,15 +3,15 @@ A pattern represents the structure of a single value or a composite value. For example, the structure of a tuple ```(1, 2)``` is a comma-separated list of two elements. Because patterns represent the structure of a value rather than any one particular value, you can match them with a variety of values. For instance, the pattern (x, y) matches the tuple (1, 2) and any other two-element tuple. In addition matching a pattern with a value, you can extract part or all of a composite value and bind each part to a constant or variable name. -模式代表了单个值或者复合值的结构。例如,元组```(1, 2)```的结构是逗号分隔的两个元素的列表。因为模式代表一种值的结构,而不是特定的某个值,你可以把模式和各种同类型的值进行匹配。比如,模式```(x, y)```可以匹配元组```(1, 2)```,以及任何含两个元素的元组。除了将模式与一个值匹配外,你可以从合成值中提取部分或全部,然后分别把各部分和一个常量或变量进行绑定。 +模式代表了单个值或者复合值的结构。例如,元组```(1, 2)```的结构是用逗号分隔的两个元素的列表。因为[to:由于]模式代表一种值的结构,而不是特定的某个值,你可以把模式和各种同类型的值进行匹配。比如,模式```(x, y)```可以匹配元组```(1, 2)```,以及任何含有两个元素的元组。除了将模式与一个[去掉“一个”]值匹配外,你可以从合成值中提取部分或全部,然后分别把各部分和一个常量或变量进行绑定。[to:并把各部分分别同常量或变量进行绑定]。 In Swift, patterns occur in variable and constant declarations (on their left-hand side), in ```for-in``` statements, and in ```switch``` statements (in their case labels). Although any pattern can occur in the case labels of a ```switch``` statement, in the other contexts, only wildcard patterns, identifier patterns, and patterns containing those two patterns can occur. -在Swift中,模式出现在变量和常量的声明(放在它们的左侧),```for-in```语句及```switch```语句(放在其case标签内)中。尽管任何模式都可以出现在```switch```语句的case标签中,但在其他情况下,只有通配符模式,标识符模式和包含这两种模式的模式才能出现。 +在Swift中,模式出现在变量和常量的声明(放在它们的左侧)、```for-in```语句及```switch```语句(放在其case标签内)中。尽管任何模式都可以出现在```switch```语句的case标签中,但在其他情况下,只有通配符模式、标识符模式和包含这两种模式的模式才能出现。 You can specify a type annotation for a wildcard pattern, an identifier pattern, and a tuple pattern to constraint the pattern to match only values of a certain type. -你可以为通配符模式,标识符模式和元组模式指定类型注释,用来限制这种模式只匹配某种类型的值。 +你可以为通配符模式、标识符模式和元组模式指定类型注释,用来限制这种模式只匹配某种类型的值。 > GRAMMAR OF A PATTERN > @@ -82,7 +82,7 @@ for _ in 1...3 { An identifier pattern matches any value and binds the matched value to a variable or constant name. For example, in the following constant declaration, ```someValue``` is an identifier pattern that matches the value ```42``` of type ```Int```: -标识符模式匹配任何值,并将匹配的值绑定到一个变量或常量。例如,在下面的常量声明中,```someValue```是一个标识符模式,其匹配了类型是```Int```的值```42```。 +标识符模式匹配任何值,并把匹配的值绑定到一个变量或常量。例如,在下面的常量声明中,```someValue```是一个标识符模式,其匹配了类型是```Int```的值```42```。[to:它匹配了Int类型的值42] ``` let someValue = 42 @@ -98,7 +98,7 @@ When the match succeeds, the value ```42``` is bound (assigned) to the constant When the pattern on the left-hand side of a variable or constant declaration is an identifier pattern, the identifier pattern is implicitly a subpattern of a value-binding pattern. -当一个变量或常量声明的左边是标识符模式时,标识符模式是隐式的值绑定模式。 +当一个变量或常量声明的左边是标识符模式时,标识符模式是隐式的值绑定模式。[to:标识符模式是值绑定模式的隐式子模式] > GRAMMAR OF AN IDENTIFIER PATTERN > @@ -115,11 +115,11 @@ When the pattern on the left-hand side of a variable or constant declaration is A value-binding pattern binds matched values to variable or constant names. Value-binding patterns that bind a matched value to the name of a constant begin with the keyword ```let```; those that bind to the name of variable begin with the keyword ```var```. -值绑定模式绑定匹配的值到一个变量或常量。绑定匹配值给常量时,以关键字```let```开头;绑定给变量时,则使用关键字```var```。 +值绑定模式绑定匹配的值到一个变量或常量[to:值绑定模式把匹配的值绑定到一个变量或常量上]。绑定匹配值给常量时[to:把匹配值绑定给常量时],以关键字```let```开头;绑定给变量时,则使用关键字```var```。 Identifiers patterns within a value-binding pattern bind new named variables or constants to their matching values. For example, you can decompose the elements of a tuple and bind the value of each element to a corresponding identifier pattern. -包含在值绑定模式中的标识符模式,会绑定新的变量或常量到其匹配的值。例如,你可以分解一个元组的元素,并把每个元素绑定到相应的标识符模式中。 +包含在值绑定模式中的标识符模式,会绑定新的变量或常量到其匹配的值[to:会把新命名的变量或常量绑定到它们匹配的值]。例如,你可以分解一个元组的元素,并把每个元素绑定到相应的标识符模式中。 ``` let point = (3, 2) @@ -143,7 +143,7 @@ case let (x, y): In the example above, ```let``` distributes to each identifier pattern in the tuple pattern ```(x, y)```. Because of this behavior, the ```switch``` cases ```case let (x, y):``` and ```case (let x, let y):``` match the same values. -在上面的例子中,```let```将元组模式```(x, y)```分配到各个标识符模式。因为这种行为,```switch```语句中的```case let (x, y):```和```case (let x, let y):```匹配的值是一样的。 +在上面的例子中,```let```将元组模式```(x, y)```分配到各个标识符模式[to:]。因为这种行为,```switch```语句中的```case let (x, y):```和```case (let x, let y):```匹配的值是一样的。 > GRAMMAR OF A VALUE-BINDING PATTERN > From 0bb1f965e49e308e2707be013d374ad80bca67b7 Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Mon, 23 Jun 2014 22:33:08 +0800 Subject: [PATCH 182/261] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7610cd8..b039e6c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The Swift Programming Language 中文化项目 * Swift 介绍 [已完成 by 飞长] [review by 容隽] * Swift 初见 [认领 by 容隽] [review by 闻西] * Swift 教程 - * 基础部分 [认领 by 琼雪] + * 基础部分 [已完成 by 琼雪] * 基本操作符 [认领 by 冰浠] * 字符串和字符 [已完成 by 筱谷] [review by 尘境] * 集合类型 [认领 by 尘境] From 214fadae646430faf246fd66f2ff3f976a7a4d91 Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Tue, 24 Jun 2014 01:08:04 +0800 Subject: [PATCH 183/261] Update 08_Patterns.md over --- src/chapter3/08_Patterns.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/chapter3/08_Patterns.md b/src/chapter3/08_Patterns.md index d69a775..73cce02 100644 --- a/src/chapter3/08_Patterns.md +++ b/src/chapter3/08_Patterns.md @@ -143,7 +143,7 @@ case let (x, y): In the example above, ```let``` distributes to each identifier pattern in the tuple pattern ```(x, y)```. Because of this behavior, the ```switch``` cases ```case let (x, y):``` and ```case (let x, let y):``` match the same values. -在上面的例子中,```let```将元组模式```(x, y)```分配到各个标识符模式[to:]。因为这种行为,```switch```语句中的```case let (x, y):```和```case (let x, let y):```匹配的值是一样的。 +在上面的例子中,```let```将元组模式```(x, y)```分配到各个标识符模式[to:let把元素分配给元组模式(x,y)的相应标识符模式]。因为这种行为[to:正是由于这种行为],```switch```语句中的```case let (x, y):```和```case (let x, let y):```匹配的值是一样的。 > GRAMMAR OF A VALUE-BINDING PATTERN > @@ -160,15 +160,15 @@ In the example above, ```let``` distributes to each identifier pattern in the tu A tuple pattern is a comma-separated list of zero or more patterns, enclosed in parentheses. Tuple patterns match values of corresponding tuple types. -元组模式是被一对圆括号包围、并以逗号分隔的列表,列表中可以包含零或多个模式。元组模式会匹配相应元组类型的值。 +元组模式是被一对圆括号包围、并以逗号分隔的列表,列表中可以包含零或多个模式[to:元组模式是被一对圆括号包围,含有零或多个模式,并用逗号分隔的列表]。元组模式会匹配相应元组类型的值。 You can constrain a tuple pattern to match certain kinds of tuple types by using type annotations. For example, the tuple pattern ```(x, y): (Int, Int)``` in the constant declaration ``` let (x, y): (Int, Int) = (1, 2)``` matches only tuple types in which both elements are of type ``` Int``` . To constrain only some elements of a tuple pattern, provide type annotations directly to those individual elements. For example, the tuple pattern in ``` let (x: String, y)``` matches any two-element tuple type, as long as the first element is of type ``` String``` . -你可以使用类型注释来限制一个元组模式仅匹配某种类型的元组。例如,在常量申明```let (x, y): (Int, Int) = (1, 2)```中的元组模式```(x, y): (Int, Int)```只匹配两个元素都是```Int```这种类型的元组。如果仅需要限制元组模式中的某几个元素,直接对这几个元素提供类型注释即可。例如,在```let (x: String, y)```中的元组模式,将匹配包含两个元素且第一个元素类型是```String```的任意元组。 +你可以使用类型注释来限制一个元组模式仅匹配某种类型的元组。例如,在常量声明```let (x, y): (Int, Int) = (1, 2)```中的元组模式```(x, y): (Int, Int)```只匹配两个元素都是```Int```类型的元组。如果仅需要限制元组模式中的某几个元素,直接对这几个元素提供类型注释即可。例如,在```let (x: String, y)```中的元组模式,将匹配[增加“任意”]包含两个元素且第一个元素类型是```String```的任意[去掉“任意”]元组。 When a tuple pattern is used as the pattern in a ```for-in``` statement or in a variable or constant declaration, it can contain only wildcard patterns, identifier patterns, or other tuple patterns that contain those. For example, the following code isn’t valid because the element ```0``` in the tuple pattern ```(x, 0)``` is an expression pattern: -当元组模式被用在```for-in```语句、变量或常量声明中时,它可以包含通配符模式、标识符模式或者其他包含这两种模式的模式。例如,下面这段代码是不正确的,因为```(x, 0)```中的元素```0```是一个表达式模式: +当元组模式["被用在"to“用于”]```for-in```语句、变量或常量声明中时,它只可以包含通配符模式、标识符模式或者其他包含这两种模式的模式。例如,下面这段代码是不正确的,因为元组模式```(x, 0)```中的元素```0```是一个[去掉“一个”]表达式模式: ``` let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] @@ -188,7 +188,7 @@ for (x, 0) in points { The parentheses around a tuple pattern that contains a single element have no effect. The pattern matches values of that single element’s type. For example, the following are equivalent: -对于只包含一个元素的元组,包围元组的圆括号是不起作用的。模式会匹配该单个元素的类型。例如,下面的不同写法是等效的: +对于只包含一个元素的元组,包围元组的圆括号是不起作用的。模式会匹配该单个元素的类型。例如,下面的不同写法是等效的["等效的"to“等价的”]: ``` let a = 2 // a: Int = 2 @@ -246,7 +246,7 @@ If the enumeration case you’re trying to match has any associated values, the There are two type-casting patterns, the ```is``` pattern and the ```as``` pattern. Both type-casting patterns appear only in ```switch``` statement case labels. The ```is``` and ```as``` patterns have the following form: -有两种类型转换模式,分别是```is```模式和```as```模式。这两种模式均只出现在```switch```语句的case标签中。```is```模式和```as```模式有以下形式: +有两种类型转换模式,分别是```is```模式和```as```模式。这两种模式均["均"to"都"]只出现在```switch```语句的case标签中。```is```模式和```as```模式有以下形式: > is type > @@ -323,7 +323,7 @@ default: You can overload the ```~=``` operator to provide custom expression matching behavior. For example, you can rewrite the above example to compare the point expression with a string representations of points. -你可以重载```~=```操作符来提供自定义的表达式匹配行为。例如,你可以重写上面的例子来比较使用字符串所表达的点。 +你可以重载```~=```操作符来提供自定义的表达式匹配行为。例如,你可以重写上面的例子来比较使用字符串所表达的点[你可以使用point的字符串形式来比较point表达式]。 ``` // Overload the ~= operator to match a string with an integer From 6264a2f55b8ac0cea5ff6d862cb7753f432df5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B1=B3=E5=B0=94?= Date: Tue, 24 Jun 2014 06:31:59 +0800 Subject: [PATCH 184/261] after review --- src/chapter2/11_Methods.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/chapter2/11_Methods.md b/src/chapter2/11_Methods.md index 639298e..ccc3213 100644 --- a/src/chapter2/11_Methods.md +++ b/src/chapter2/11_Methods.md @@ -2,11 +2,11 @@ Methods are functions that are associated with a particular type. Classes, structures, and enumerations can all define instance methods, which encapsulate specific tasks and functionality for working with an instance of a given type. Classes, structures, and enumerations can also define type methods, which are associated with the type itself. Type methods are similar to class methods in Objective-C. -方法是指和某些特定类型相关联的函数。类、结构体、枚举都可以定义实例方法, 这些实例方法可以将特定任务和功能封装到一个指定的类型实例中。类、结构体、美剧也可以定义类型方法, 这些类型方法仅和类型本身有关联。 类型方法和 Objective-C 中的类方法(class methods)很相似。 +方法是指和某些特定类型相关联的函数。类、结构体、枚举都可以定义实例方法, 这些实例方法可以将特定任务和功能封装到一个指定类型的实例中。类、结构体、枚举也可以定义类型方法, 这些类型方法仅和类型本身有关联。 类型方法和 Objective-C 中的类方法(class methods)很相似。 The fact that structures and enumerations can define methods in Swift is a major difference from C and Objective-C. In Objective-C, classes are the only types that can define methods. In Swift, you can choose whether to define a class, structure, or enumeration, and still have the flexibility to define methods on the type you create. -事实上,结构体和枚举可以在 Swift 中定义方法, 成为了和 C、Objective-C 之间一个主要区别。在 Objective-C 中,只有类(Class)才能定义方法。在 Swift 中,你可以选择在类、结构体、枚举、甚至是你自己定义的类型中,去定义方法。 +事实上,Swift 中的结构体和枚举也可以定义方法, 这也是和 C、Objective-C 一个主要区别。在 Objective-C 中,只有类(Class)才能定义方法。在 Swift 中,你可以选择在类、结构体、枚举、甚至是你自己定义的类型中,去定义方法。 ## 实例方法(Instance Methods) @@ -16,7 +16,7 @@ Instance methods are functions that belong to instances of a particular class, s You write an instance method within the opening and closing braces of the type it belongs to. An instance method has implicit access to all other instance methods and properties of that type. An instance method can be called only on a specific instance of the type it belongs to. It cannot be called in isolation without an existing instance. -实例类型要写在类型的括号中。实例方法可以隐式地访问这个类型的所有实例方法和属性。实例方法只能被它所属类型的实例调用,不能在实例之外被独立调用。 +实例类型要写在类型的大括号中。实例方法可以隐式地访问这个类型的所有实例方法和属性。实例方法只能被它所属类型的实例调用,不能在实例之外被独立调用。 Here’s an example that defines a simple `Counter` class, which can be used to count the number of times an action occurs: @@ -80,7 +80,7 @@ counter.reset() ``` -## 方法的内部参数和外部参数(Local and External Parameter Names for Methods) +## 方法的内部参数名和外部参数名(Local and External Parameter Names for Methods) Function parameters can have both a local name (for use within the function’s body) and an external name (for use when calling the function), as described in External Parameter Names. The same is true for method parameters, because methods are just functions that are associated with a type. However, the default behavior of local names and external names is different for functions and methods. @@ -147,7 +147,7 @@ The default behavior described above mean that method definitions in Swift are w Sometimes it’s useful to provide an external parameter name for a method’s first parameter, even though this is not the default behavior. You can either add an explicit external name yourself, or you can prefix the first parameter’s name with a hash symbol to use the local name as an external name too. -有时候,提供为方法的第一个参数提供一个外部参数名称是有用的,即使这不是个默认行为。你可以自己增加一个明确的外部名称,也可以给第一个参数增加一个 # 的前缀,使得内部名称可以作为外部名称使用。 +有时候,为方法的第一个参数提供一个外部参数名称是有用的,即使这不是个默认行为。你可以自己增加一个明确的外部名称,也可以给第一个参数增加一个 # 的前缀,使得内部名称可以作为外部名称使用。 Conversely, if you do not want to provide an external name for the second or subsequent parameter of a method, override the default behavior by using an underscore character (`_`) as an explicit external parameter name for that parameter. @@ -335,7 +335,7 @@ Within the body of a type method, the implicit self property refers to the type More generally, any unqualified method and property names that you use within the body of a type method will refer to other type-level methods and properties. A type method can call another type method with the other method’s name, without needing to prefix it with the type name. Similarly, type methods on structures and enumerations can access static properties by using the static property’s name without a type name prefix. -更广泛的说,在类型方法体内,没有显式调用的方法和属性都会被指代为其他类型级别的方法和属性。类型方法可以通过其他方法名来调用其他类型方法,而不需要在方法名前增加类型名称。同样的,结构体和枚举的类型方法也可以通过静态属性名直接获取静态属性,而不需要在属性名前增加类型名称。 +更普遍地说,在类型方法体内,没有显式调用的方法和属性都会被指代为其他类型级别的方法和属性。类型方法可以通过其他方法名来调用其他类型方法,而不需要在方法名前增加类型名称。同样的,结构体和枚举的类型方法也可以通过静态属性名直接获取静态属性,而不需要在属性名前增加类型名称。 The example below defines a structure called `LevelTracker`, which tracks a player’s progress through the different levels or stages of a game. It is a single-player game, but can store information for multiple players on a single device. @@ -370,7 +370,7 @@ struct LevelTracker { The `LevelTracker` structure keeps track of the highest level that any player has unlocked. This value is stored in a static property called `highestUnlockedLevel`. -`LevelTracker` 结构体持续记录被任何一个玩家解锁的最高关卡。这个值被保存在静态属性 `highestUnlockedLevel` 中。 +`LevelTracker` 结构体跟踪记录被任何一个玩家解锁的最高关卡。这个值被保存在静态属性 `highestUnlockedLevel` 中。 `LevelTracker` also defines two type functions to work with the `highestUnlockedLevel` property. The first is a type function called `unlockLevel`, which updates the value of `highestUnlockedLevel` whenever a new level is unlocked. The second is a convenience type function called `levelIsUnlocked`, which returns `true` if a particular level number is already unlocked. (Note that these type methods can access the `highestUnlockedLevel` static property without your needing to write it as `LevelTracker.highestUnlockedLevel`.) From 88caa4834eda744c3b1f5885e2a59ad61a16f825 Mon Sep 17 00:00:00 2001 From: KohPoll Date: Tue, 24 Jun 2014 10:01:50 +0800 Subject: [PATCH 185/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b039e6c..54f1393 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ The Swift Programming Language 中文化项目 * Swift 介绍 [已完成 by 飞长] [review by 容隽] * Swift 初见 [认领 by 容隽] [review by 闻西] * Swift 教程 - * 基础部分 [已完成 by 琼雪] + * 基础部分 [已完成 by 琼雪] [review by 栖邀] * 基本操作符 [认领 by 冰浠] * 字符串和字符 [已完成 by 筱谷] [review by 尘境] * 集合类型 [认领 by 尘境] From 1b59f897ff6126cd0e03ef8e45de4b26292fdf32 Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Tue, 24 Jun 2014 10:05:33 +0800 Subject: [PATCH 186/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 54f1393..b79d5ac 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The Swift Programming Language 中文化项目 * 声明 [认领 by 墨峰] * 属性 [认领 by 隐若] * 模式 [已完成 by 栖邀] [review by 紫溪] - * 泛型参数 [认领 by 龙刚] + * 泛型参数 [认领 by 龙刚] [review by 墨峰] * 语法总结 [认领 by 无独] # 分工 From 3bb058c03f19a7bf767599fb30321a8139b46e83 Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Tue, 24 Jun 2014 10:12:49 +0800 Subject: [PATCH 187/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b79d5ac..653f15c 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The Swift Programming Language 中文化项目 * 类和结构体 [已完成 by 晓毒] * 属性 [认领 by 周源] * 方法 [已完成 by 米尔] [review by 灵吾] - * 下标 [已完成 by 递归] + * 下标 [已完成 by 递归] [review by 琼雪] * 继承 [已完成 by 晗光] * 构造过程 [认领 by 刘康] * 析构过程 [认领 by 许诺] From eb27270796552c3ecbdd96b65f93e89577b6d4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Tue, 24 Jun 2014 10:16:24 +0800 Subject: [PATCH 188/261] add review name --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b039e6c..7b56ca9 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,9 @@ The Swift Programming Language 中文化项目 * 高级操作符 [认领 by 林晚] * 语言参考 * 关于语言参考 [认领 by 筱强] [review by 隐若] - * 词法结构 [认领 by 筱强] - * 类型 [认领 by 兰梦] - * 表达式 [认领 by 懂象] + * 词法结构 [认领 by 筱强][review by 懂象] + * 类型 [认领 by 兰梦][review by 筱强] + * 表达式 [认领 by 懂象][review by 懂象] * 语句 [认领 by 玩家] * 声明 [认领 by 墨峰] * 属性 [认领 by 隐若] From ba0091fc6ad7284a35e5c9885030130597da88d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Tue, 24 Jun 2014 10:18:38 +0800 Subject: [PATCH 189/261] change review name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 567c71c..7529b77 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ The Swift Programming Language 中文化项目 * 关于语言参考 [认领 by 筱强] [review by 隐若] * 词法结构 [认领 by 筱强][review by 懂象] * 类型 [认领 by 兰梦][review by 筱强] - * 表达式 [认领 by 懂象][review by 懂象] + * 表达式 [认领 by 懂象][review by 兰梦] * 语句 [认领 by 玩家] * 声明 [认领 by 墨峰] * 属性 [认领 by 隐若] From f67f112777c59077bbf5f108a50241bea4a6147c Mon Sep 17 00:00:00 2001 From: Neekey Date: Tue, 24 Jun 2014 10:29:30 +0800 Subject: [PATCH 190/261] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20review=20=E7=9B=AE?= =?UTF-8?q?=E6=A0=87=E4=B8=BA=20=E8=AF=AD=E5=8F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7529b77..fa71620 100644 --- a/README.md +++ b/README.md @@ -35,11 +35,11 @@ The Swift Programming Language 中文化项目 * 泛型 [已完成 by 晴时] * 高级操作符 [认领 by 林晚] * 语言参考 - * 关于语言参考 [认领 by 筱强] [review by 隐若] + * 关于语言参考 [认领 by 筱强] * 词法结构 [认领 by 筱强][review by 懂象] * 类型 [认领 by 兰梦][review by 筱强] * 表达式 [认领 by 懂象][review by 兰梦] - * 语句 [认领 by 玩家] + * 语句 [认领 by 玩家] [review by 隐若] * 声明 [认领 by 墨峰] * 属性 [认领 by 隐若] * 模式 [已完成 by 栖邀] [review by 紫溪] From cd2bb6e6772eb91296e4e3a6f7a909d56e722f73 Mon Sep 17 00:00:00 2001 From: Zeng Yun Date: Tue, 24 Jun 2014 10:56:20 +0800 Subject: [PATCH 191/261] =?UTF-8?q?=E8=AE=A4=E9=A2=86=E6=9E=84=E9=80=A0?= =?UTF-8?q?=E8=BF=87=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa71620..55028ef 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ The Swift Programming Language 中文化项目 * 方法 [已完成 by 米尔] [review by 灵吾] * 下标 [已完成 by 递归] [review by 琼雪] * 继承 [已完成 by 晗光] - * 构造过程 [认领 by 刘康] + * 构造过程 [认领 by 刘康] [review by 晓毒] * 析构过程 [认领 by 许诺] * 自动引用计数 [认领 by 韩国兴/MK] * 可选链 [认领 by 重鱼] From f1f010740501972c4dde99c8a281a863ee625ea6 Mon Sep 17 00:00:00 2001 From: zearlin Date: Tue, 24 Jun 2014 11:03:26 +0800 Subject: [PATCH 192/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 55028ef..df63436 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ The Swift Programming Language 中文化项目 * 类型转换 [认领 by 孟志昂] * 嵌套类型 [认领 by 祁涛] * 扩展 [已完成 by 袁鹏] - * 协议 [认领 by 姜天意] + * 协议 [认领 by 姜天意][review by 重鱼] * 泛型 [已完成 by 晴时] * 高级操作符 [认领 by 林晚] * 语言参考 From 1c6e3ac250996d976583c252a99a72720b881929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=93=E6=98=8E=28=E9=80=92=E5=BD=92=29?= Date: Tue, 24 Jun 2014 11:05:23 +0800 Subject: [PATCH 193/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df63436..ad581f0 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ The Swift Programming Language 中文化项目 * 属性 [认领 by 周源] * 方法 [已完成 by 米尔] [review by 灵吾] * 下标 [已完成 by 递归] [review by 琼雪] - * 继承 [已完成 by 晗光] + * 继承 [已完成 by 晗光] [review by 递归] * 构造过程 [认领 by 刘康] [review by 晓毒] * 析构过程 [认领 by 许诺] * 自动引用计数 [认领 by 韩国兴/MK] From 80851e098ec2aa16e053e1b8234ddcad70fea3e9 Mon Sep 17 00:00:00 2001 From: rainoxu Date: Tue, 24 Jun 2014 11:46:13 +0800 Subject: [PATCH 194/261] =?UTF-8?q?=E8=AE=A4=E9=A2=86review=E7=AB=A0?= =?UTF-8?q?=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad581f0..db2a2eb 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The Swift Programming Language 中文化项目 * 类型 [认领 by 兰梦][review by 筱强] * 表达式 [认领 by 懂象][review by 兰梦] * 语句 [认领 by 玩家] [review by 隐若] - * 声明 [认领 by 墨峰] + * 声明 [认领 by 墨峰] [review by 龙刚] * 属性 [认领 by 隐若] * 模式 [已完成 by 栖邀] [review by 紫溪] * 泛型参数 [认领 by 龙刚] [review by 墨峰] From 7ce50febeb1430582c386004ef6c8491a79180f2 Mon Sep 17 00:00:00 2001 From: Adams Date: Tue, 24 Jun 2014 13:16:06 +0800 Subject: [PATCH 195/261] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ad581f0..3362316 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,13 @@ The Swift Programming Language 中文化项目 * 闭包 [认领 by 闻西] * 枚举 [已完成 by 灵吾] [review by 筱谷] * 类和结构体 [已完成 by 晓毒] - * 属性 [认领 by 周源] + * 属性 [认领 by 周源] [review by 林晚] * 方法 [已完成 by 米尔] [review by 灵吾] * 下标 [已完成 by 递归] [review by 琼雪] * 继承 [已完成 by 晗光] [review by 递归] * 构造过程 [认领 by 刘康] [review by 晓毒] - * 析构过程 [认领 by 许诺] - * 自动引用计数 [认领 by 韩国兴/MK] + * 析构过程 [认领 by 许诺] [review by 祁涛] + * 自动引用计数 [认领 by 韩国兴/MK] [review by 孟志昂] * 可选链 [认领 by 重鱼] * 类型转换 [认领 by 孟志昂] * 嵌套类型 [认领 by 祁涛] From a32bba52bb255b98261bb2a4ebf283723c6d2396 Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Tue, 24 Jun 2014 13:28:46 +0800 Subject: [PATCH 196/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3362316..116102f 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ The Swift Programming Language 中文化项目 * 自动引用计数 [认领 by 韩国兴/MK] [review by 孟志昂] * 可选链 [认领 by 重鱼] * 类型转换 [认领 by 孟志昂] - * 嵌套类型 [认领 by 祁涛] + * 嵌套类型 [认领 by 祁涛][review by 袁鹏] * 扩展 [已完成 by 袁鹏] * 协议 [认领 by 姜天意][review by 重鱼] * 泛型 [已完成 by 晴时] From caaf109d723a82acb30f8bf88fdff8729602b46f Mon Sep 17 00:00:00 2001 From: Adams Date: Tue, 24 Jun 2014 13:35:31 +0800 Subject: [PATCH 197/261] Update 21_Protocols.md --- src/chapter2/21_Protocols.md | 75 ++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/chapter2/21_Protocols.md b/src/chapter2/21_Protocols.md index a9fcca5..871be19 100644 --- a/src/chapter2/21_Protocols.md +++ b/src/chapter2/21_Protocols.md @@ -24,12 +24,14 @@ You define protocols in a very similar way to classes, structures, and enumerati } Custom types state that they adopt a particular protocol by placing the protocol’s name after the type’s name, separated by a colon, as part of their definition. Multiple protocols can be listed, and are separated by commas: + 在类型名称后添加协议名称,并以冒号`:`分割,表示自定义类型(Custom types)适配一个特定协议;实现多个协议时,各协议之间用逗号`,`分隔,如下所示: struct SomeStructure: FirstProtocol, AnotherProtocol { // structure definition goes here } If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma: + 若某个类有父类,要把父类放在所有其适配的协议之前,且用逗号`,`分割,如下所示: class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol { @@ -37,6 +39,7 @@ If a class has a superclass, list the superclass name before any protocols it ad } Property Requirements + ##属性要求 A protocol can require any conforming type to provide an instance property or type property with a particular name and type. The protocol doesn’t specify whether the property should be a stored property or a computed property—it only specifies the required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable. @@ -46,6 +49,7 @@ A protocol can require any conforming type to provide an instance property or ty If a protocol requires a property to be gettable and settable, that property requirement cannot be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for it also to be settable if this is useful for your own code. + 如果协议要求属性可读写(gettable and settable),那常量存储属性(constant stored property)或者只读计算属性(read-only computed property)都无法满足此要求。如果协议只要求属性可读(gettable),那任何类型的属性都满足这个要求,即使这些属性是可写(settable)的。 Property requirements are always declared as variable properties, prefixed with the var keyword. Gettable and settable properties are indicated by writing { get set } after their type declaration, and gettable properties are indicated by writing { get }. @@ -94,6 +98,7 @@ Here’s an example of a simple structure that adopts and conforms to the FullyN // john.fullName is "John Appleseed" This example defines a structure called Person, which represents a specific named person. It states that it adopts the FullyNamed protocol as part of the first line of its definition. + 这个例子中定义了一个名为`Person`的结构体,代表一个有名字的人。它在第一行的结构体定义中,声明了其适配`FullyNamed`协议。 Each instance of Person has a single stored property called fullName, which is of type String. This matches the single requirement of the FullyNamed protocol, and means that Person has correctly conformed to the protocol. (Swift reports an error at compile-time if a protocol requirement is not fulfilled.) @@ -199,6 +204,7 @@ If you define a protocol instance method requirement that is intended to mutate NOTE 注意 + If you mark a protocol instance method requirement as mutating, you do not need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations. @@ -238,9 +244,11 @@ The example below defines an enumeration called OnOffSwitch. This enumeration to lightSwitch.toggle() // lightSwitch is now equal to .On Protocols as Types + 协议类型 Protocols do not actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use in your code. + 尽管协议本身并不实现任何功能,但协议可以作为完整的类型来使用。 Because it is a type, you can use a protocol in many places where other types are allowed, including: 你可以把协议类型用在其他类型适用的场景里,比如: @@ -255,10 +263,13 @@ As the type of items in an array, dictionary, or other container NOTE 注意 + Because protocols are types, begin their names with a capital letter (such as FullyNamed and RandomNumberGenerator) to match the names of other types in Swift (such as Int, String, and Double). + 注意: 协议是一种类型,因此协议类型的名称应与Swift中其他类型(Int,Double,String)的写法相同,每一个单字的首字母都采用大写字母(大驼峰写法) Here’s an example of a protocol used as a type: + 下面的例子中,协议被当作类型使用: class Dice { @@ -273,15 +284,19 @@ Here’s an example of a protocol used as a type: } } This example defines a new class called Dice, which represents an n-sided dice for use in a board game. Dice instances have an integer property called sides, which represents how many sides they have, and a property called generator, which provides a random number generator from which to create dice roll values. + 例子中定义了一个Dice类,用来表示桌游中的拥有N个面的骰子。Dice的实例包含sides和generator两个属性,前者是整型(integer),用来表示骰子有几个面,后者提供了一个随机数生成器,来表示骰子掷出的值。 The generator property is of type RandomNumberGenerator. Therefore, you can set it to an instance of any type that adopts the RandomNumberGenerator protocol. Nothing else is required of the instance you assign to this property, except that the instance must adopt the RandomNumberGenerator protocol. + generator属性的类型为RandomNumberGenerator,因此任何类型,若适配RandomNumberGenerator协议,其实例都可以赋值给generator,除此以外没有其他要求。 Dice also has an initializer, to set up its initial state. This initializer has a parameter called generator, which is also of type RandomNumberGenerator. You can pass a value of any conforming type in to this parameter when initializing a new Dice instance. + Dice类也包含一个构造方法,用于设置其初始状态。这个方法包含一个同样是RandomNumberGenerator类型的参数generator。在构造一个新的Dice的实例时,可以传入任何遵循RandomNumberGenerator协议的类型作为generator。 Dice provides one instance method, roll, which returns an integer value between 1 and the number of sides on the dice. This method calls the generator’s random method to create a new random number between 0.0 and 1.0, and uses this random number to create a dice roll value within the correct range. Because generator is known to adopt RandomNumberGenerator, it is guaranteed to have a random method to call. + Dice类提供了一个实例方法,roll,此方法会返回一个整型值,介于1和骰子面的数量之间。这个方法调用generator的随机�数方法来创建一在0.0和1.0之间的随机数,并使用这个随机数来确保骰子的滚动值在正确的范围内。因为generator适配RandomNumberGenerator协议,因此它可以保证有一个random方法供调用。 Here’s how the Dice class can be used to create a six-sided dice with a LinearCongruentialGenerator instance as its random number generator: @@ -301,11 +316,14 @@ Here’s how the Dice class can be used to create a six-sided dice with a Linear Delegation 代理 + Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source. + 代理(Delegation)是一种设计模式,它允许类或结构体将一些他们负责的功能转交(代理)给其他类型的实例。 委托模式的实现需要定义一个协议,这个协议封装了那些需要被代理的功能,而一个遵循此协议的实例则拥有这些功能 The example below defines two protocols for use with dice-based board games: + 下面的例子中定义了两个基于骰子游戏的协议: protocol DiceGame { @@ -357,7 +375,9 @@ Here’s a version of the Snakes and Ladders game originally introduced in Contr } } For a description of the Snakes and Ladders gameplay, see the Break section of the Control Flow chapter. + 你可以参考流程控制章节中对此游戏的介绍 + > 译者注 Snakes and Ladders 是蛇梯棋游戏,一种类似大富翁的游戏。 This version of the game is wrapped up as a class called SnakesAndLadders, which adopts the DiceGame protocol. It provides a gettable dice property and a play method in order to conform to the protocol. (The dice property is declared as a constant property because it does not need to change after initialization, and the protocol only requires that it is gettable.) @@ -371,6 +391,7 @@ The Snakes and Ladders game board setup takes place within the class’s init() Snakes And Ladders游戏通过构造方法(initializer)init初始化游戏。所有的游戏逻辑移到了play方法中,play方法使用协议要求的dice属性,来提供骰子掷出的值。 Note that the delegate property is defined as an optional DiceGameDelegate, because a delegate isn’t required in order to play the game. Because it is of an optional type, the delegate property is automatically set to an initial value of nil. Thereafter, the game instantiator has the option to set the property to a suitable delegate. + 注意,delegate并不是玩游戏所必须的,因此delegate被定义为DiceGameDelegate协议类型的可选属性,delegate使用nil作为初始值。此后,游戏实例可以选择将其设置为一个合适的代理。 @@ -381,6 +402,7 @@ DicegameDelegate协议提供了三个方法来跟踪游戏过程。这三个方 Because the delegate property is an optional DiceGameDelegate, the play method uses optional chaining each time it calls a method on the delegate. If the delegate property is nil, these delegate calls fail gracefully and without error. If the delegate property is non-nil, the delegate methods are called, and are passed the SnakesAndLadders instance as a parameter. + 因为delegate属性是一个遵循DiceGameDelegate的可选属性,因此在play()方法中使用了可选链(optional chaining )来在代理时调用方法。 若delegate属性为nil, 则delegate所调用的方法正常失败(fail gracefully)且不报错。若delegate不为nil,则方法能够被调用,且作为一个参数传入SnakesAndLadders实例中 This next example shows a class called DiceGameTracker, which adopts the DiceGameDelegate protocol: 下一个例子展示了一个名为DiceGameTracker的类,适配DiceGameDelegate协议。 @@ -413,6 +435,8 @@ The implementation of gameDidStart shown above uses the game parameter to print gameDidStart also accesses the dice property of the passed game parameter. Because game is known to conform to the DiceGame protocol, it is guaranteed to have a dice property, and so the gameDidStart method is able to access and print the dice’s sides property, regardless of what kind of game is being played. gameDidStart方法也能够访问dice属性,这个属性存在于被传递为参数的game中。game遵循DiceGame协议,因此被赋予了dice属性,不管运行何种游戏,gameDidStart方法都可以访问且打印骰子的边数。 + + 下面是DiceGameTracker的运行过程: Here’s how DiceGameTracker looks in action: @@ -429,14 +453,18 @@ Here’s how DiceGameTracker looks in action: // The game lasted for 4 turns Adding Protocol Conformance with an Extension + 使用扩展添加协议一致性 + You can extend an existing type to adopt and conform to a new protocol, even if you do not have access to the source code for the existing type. Extensions can add new properties, methods, and subscripts to an existing type, and are therefore able to add any requirements that a protocol may demand. For more about extensions, see Extensions. 即便不能修改现有类型的代码,你也可以扩展现有类型,从而适配和遵循新协议。扩展(extensions)可以在现有的类型上添加新属性、方法和下标,因此能够满足任何一个协议的需要。更多关于扩展相关的内容,请参考扩展。 NOTE 注意 + Existing instances of a type automatically adopt and conform to a protocol when that conformance is added to the instance’s type in an extension. + 当你使用一个扩展,为一个实例的类型添加上某种对协议的适配后,这个类型已存在的所有实例,都会自动适配与遵循此协议。 For example, this protocol, called TextRepresentable, can be implemented by any type that has a way to be represented as text. This might be a description of itself, or a text version of its current state: @@ -448,6 +476,7 @@ For example, this protocol, called TextRepresentable, can be implemented by any } The Dice class from earlier can be extended to adopt and conform to TextRepresentable: + 之前的Dice类可以扩展为适配并遵循TextRepresentable协议: extension Dice: TextRepresentable { @@ -457,10 +486,12 @@ The Dice class from earlier can be extended to adopt and conform to TextRepresen } This extension adopts the new protocol in exactly the same way as if Dice had provided it in its original implementation. The protocol name is provided after the type name, separated by a colon, and an implementation of all requirements of the protocol is provided within the extension’s curly braces. + 这个扩展以完全相同的方式适配了新协议,就像骰子提供了最初(适配协议)的实现。协议名称放在类型名称后,用`:`隔开,协议所要求的实现则提供在扩展的花括号内。 Any Dice instance can now be treated as TextRepresentable: + 现在Dice类型的实例可被当作是TextRepresentable类型: let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator()) @@ -468,6 +499,7 @@ Any Dice instance can now be treated as TextRepresentable: // prints "A 12-sided dice" Similarly, the SnakesAndLadders game class can be extended to adopt and conform to the TextRepresentable protocol: + 同样,SnakesAndLadders类也可以扩展为适配且遵循TextRepresentable协议: extension SnakesAndLadders: TextRepresentable { @@ -479,8 +511,11 @@ Similarly, the SnakesAndLadders game class can be extended to adopt and conform // prints "A game of Snakes and Ladders with 25 squares" Declaring Protocol Adoption with an Extension + 通过扩展声明协议适配 + If a type already conforms to all of the requirements of a protocol, but has not yet stated that it adopts that protocol, you can make it adopt the protocol with an empty extension: + 若一个类型已经遵循了一个协议的所有要求,但未声明此类型适配这个协议,你可以使用一个空的扩展来让其适配协议。 struct Hamster { @@ -492,6 +527,7 @@ If a type already conforms to all of the requirements of a protocol, but has not extension Hamster: TextRepresentable {} Instances of Hamster can now be used wherever TextRepresentable is the required type: + 从现在起,Hamster的实例可以作为TextRepresentable所需要的类型来使用 let simonTheHamster = Hamster(name: "Simon") @@ -501,18 +537,23 @@ Instances of Hamster can now be used wherever TextRepresentable is the required NOTE 注意 + Types do not automatically adopt a protocol just by satisfying its requirements. They must always explicitly declare their adoption of the protocol. + 注意: 即使满足了协议的所有要求,类型也不会自动适配一个协议,因此你必须显式的声明协议适配。 Collections of Protocol Type + 集合中的协议类型 A protocol can be used as the type to be stored in a collection such as an array or a dictionary, as mentioned in Protocols as Types. This example creates an array of TextRepresentable things: + 协议可以作为集合(数组,字典)内所存储的类型使用,就像之前所讲的一样,协议作为类型使用: let things: TextRepresentable[] = [game, d12, simonTheHamster] It is now possible to iterate over the items in the array, and print each item’s textual representation: + 如下所示,可以遍历things数组的元素,并打印每个元素的文本(通过asText方法) for thing in things { @@ -546,6 +587,7 @@ Here’s an example of a protocol that inherits the TextRepresentable protocol f } This example defines a new protocol, PrettyTextRepresentable, which inherits from TextRepresentable. Anything that adopts PrettyTextRepresentable must satisfy all of the requirements enforced by TextRepresentable, plus the additional requirements enforced by PrettyTextRepresentable. In this example, PrettyTextRepresentable adds a single requirement to provide an instance method called asPrettyText that returns a String. + 这个例子定义了一个新的协议PrettyTextRepresentable,继承自TextRepresentable。若适配PrettyTextRepresentable协议,必须同时满足TextRepresentable协议的需求,且满足由PrettyTextRepresentable添加的额外需求。在这个例子中,PrettyTextRepresentable添加了另一需求,要求提供一个称为asPrettyText的实例方法,用于返回一个字符串。 The SnakesAndLadders class can be extended to adopt and conform to PrettyTextRepresentable: 可以扩展SnakesAndLadders类,来使之适配且遵循PrettyTextRepresentable协议。 @@ -579,18 +621,21 @@ The method implementation can now be used to print a pretty text description of 当遍历出的元素的值大于0时,表示一个梯子的底部,用`▲`符号表示 当遍历出的元素的值小于0时,表示一个蛇头,用`▲`符号表示 当遍历出的元素的值等于0时,表示一个空白方块,用`○`符号表示 + println(game.asPrettyText()) // A game of Snakes and Ladders with 25 squares: // ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○ Protocol Composition 协议合成 It can be useful to require a type to conform to multiple protocols at once. You can combine multiple protocols into a single requirement with a protocol composition. Protocol compositions have the form protocol. You can list as many protocols within the pair of angle brackets (<>) as you need, separated by commas. + 有一种很有用的方式,来表示一种适配多个协议的类型。你可以使用协议合成(Protocol Composition)来组合多个协议。 协议合成的格式为protocal。你可以在尖括号(`<>`)内列出多个协议,用逗号`,`分隔。 Here’s an example that combines two protocols called Named and Aged into a single protocol composition requirement on a function parameter: + 下面的例子中,把两个协议Named与Aged组合为一个协议合成,并作为函数的参数使用 protocol Named { @@ -612,30 +657,38 @@ Here’s an example that combines two protocols called Named and Aged into a sin This example defines a protocol called Named, with a single requirement for a gettable String property called name. It also defines a protocol called Aged, with a single requirement for a gettable Int property called age. Both of these protocols are adopted by a structure called Person. + 这个例子中,定义了一个Named协议,要求一个可读的String类型的属性`name`。同时定义了一个Aged协议,要求一个可读的Int类型的属性`Aged`。两个协议被`Person`结构体所适配。 The example also defines a function called wishHappyBirthday, which takes a single parameter called celebrator. The type of this parameter is protocol, which means “any type that conforms to both the Named and Aged protocols.” It doesn’t matter what specific type is passed to the function, as long as it conforms to both of the required protocols. + 这个例子也定义了带有参数`celebrator`的函数`wishHappyBirthday`。参数的类型是`protocol`,表示任何同时遵循Named与Aged协议的类型。不管向函数传递何种参数,只要遵循两个协议即可。 The example then creates a new Person instance called birthdayPerson and passes this new instance to the wishHappyBirthday function. Because Person conforms to both protocols, this is a valid call, and the wishHappyBirthday function is able to print its birthday greeting. + 这个例子也创建了一个`Person`的实例`birthdayPerson`,且将这个实例作为参数传入`wishHappyBirthday`函数。因为Person同时适配 两个协议,因此函数可以正常调用,并打印一个生日祝福。 NOTE 注意 + Protocol compositions do not define a new, permanent protocol type. Rather, they define a temporary local protocol that has the combined requirements of all protocols in the composition. + 注意: 协议合成并不会生成一个新的协议类型,而是将多个协议合成为一个临时协议。 Checking for Protocol Conformance + 协议遵循检查 You can use the is and as operators described in Type Casting to check for protocol conformance, and to cast to a specific protocol. Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a type: + 你可以使用类型检查中介绍的`is`,`as`操作符,来检测某类型是否遵循某协议, The is operator returns true if an instance conforms to a protocol and returns false if it does not. The as? version of the downcast operator returns an optional value of the protocol’s type, and this value is nil if the instance does not conform to that protocol. The as version of the downcast operator forces the downcast to the protocol type and triggers a runtime error if the downcast does not succeed. + is操作符用于检查实例是否遵循某个协议,若不遵循则返回`false`。 as?根据协议类型返回一个可选值,当实例遵循协议时,返回该协议类型;否则返回nil as操作符可以对协议类型进行强制向下转型。若若换失败则会报一个运行时错误。 @@ -643,20 +696,25 @@ as操作符可以对协议类型进行强制向下转型。若若换失败则会 > 译者注: 向下转型就是把基类转换到继承类,向上转型就是把继承类转换为基类。 This example defines a protocol called HasArea, with a single property requirement of a gettable Double property called area: + 下面的例子定义了协议HasArea,需要一个可读的Double类型的属性area。 @objc protocol HasArea { var area: Double { get } } + NOTE 注意 You can check for protocol conformance only if your protocol is marked with the @objc attribute, as seen for the HasArea protocol above. This attribute indicates that the protocol should be exposed to Objective-C code and is described in Using Swift with Cocoa and Objective-C. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to be able to check for protocol conformance. + 注意: 只有用`@objc`属性标注的协议,才可以做协议遵循检查。这个属性表示协议会暴露给Objective-C的代码,可以参考Using Siwft with Cocoa and Objectivei-c。即使你不打算与 Objective-C进行交互,当你需要进行协议遵循检查时,也要在协议前面添加`@objc`. Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to check for conformance, you will be able to apply that protocol only to class types. + 还要注意一点,`@objc`协议只适用于类,不能用于结构体或枚举。因此只有协议被应用在类上,才能使用`@objc`检查协议的遵循。 Here are two classes, Circle and Country, both of which conform to the HasArea protocol: + 下面两个类`Circle`与`Country`都遵循`HasArea`协议 class Circle: HasArea { @@ -676,12 +734,14 @@ The Circle class implements the area property requirement as a computed property Here’s a class called Animal, which does not conform to the HasArea protocol: + 这个例子中`Animal`类不遵循`HasArea`协议: class Animal { var legs: Int init(legs: Int) { self.legs = legs } } + The Circle, Country and Animal classes do not have a shared base class. Nonetheless, they are all classes, and so instances of all three types can be used to initialize an array that stores values of type AnyObject: `Circle`类,`Country`类,`Animal`类并没有一个相同的基类,可以采用`AnyObject`类型的数组来承载他们构造后的实例: @@ -712,10 +772,12 @@ objects数组使用数组字面量(array literal)初始化,数组包含一个` Whenever an object in the array conforms to the HasArea protocol, the optional value returned by the as? operator is unwrapped with optional binding into a constant called objectWithArea. The objectWithArea constant is known to be of type HasArea, and so its area property can be accessed and printed in a type-safe way. Note that the underlying objects are not changed by the casting process. They continue to be a Circle, a Country and an Animal. However, at the point that they are stored in the objectWithArea constant, they are only known to be of type HasArea, and so only their area property can be accessed. + 迭代出的元素使用可选绑定(optional binding)将其绑定到`objectWithArea`常量上,使用as?操作符判断其是否遵循`HasArea`协议。`objectWithArea`常量是遵循HasArea协议类型的实例,因此其`area`属性是可以被访问和打印的。 `objects`数组中元素的类型并不会因为向下转型而改变,它们仍然是`Circle`,`Country`,`Animal`类型。然而,当它们被存储到`objectWithArea`常量后,只会被认为是`HasArea`类型,因此只有`area`属性能够被访问。 Optional Protocol Requirements + 可选的协议要求 You can define optional requirements for protocols, These requirements do not have to be implemented by types that conform to the protocol. Optional requirements are prefixed by the @optional keyword as part of the protocol’s definition. @@ -735,18 +797,22 @@ You check for an implementation of an optional requirement by writing a question NOTE Optional protocol requirements can only be specified if your protocol is marked with the @objc attribute. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to specify optional requirements. + 注意: 可选协议要求只能在含有`@objc`前缀的协议中指定。即使你不准备与Objective-c进行交互,当你要指定可选协议需求时,也需要添加这个前缀。 Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to specify optional requirements, you will only be able to apply that protocol to class types. + 还要注意,`@objc`协议只适用于类,不能用于结构体或枚举。因此只有协议被应用在类上,才能通过`@objc`指定可选协议要求。 The following example defines an integer-counting class called Counter, which uses an external data source to provide its increment amount. This data source is defined by the CounterDataSource protocol, which has two optional requirements: + 下面的例子定义了一个计数器类`Counter`,它使用一个外部数据源提供其增量。这个数据源是`CounterDataSource`定义的协议,它有两个可选的要求: @objc protocol CounterDataSource { @optional func incrementForCount(count: Int) -> Int @optional var fixedIncrement: Int { get } } + The CounterDataSource protocol defines an optional method requirement called incrementForCount and an optional property requirement called fixedIncrement. These requirements define two different ways for data sources to provide an appropriate increment amount for a Counter instance. `CounterDataSource`协议定义了一个可选的方法要求incrementForCount和一个可选的属性要求`fixedIncrement` 。这些要求定义了两种不同的方式的数据源,来给Counter实例提供一个适当的增量。 @@ -755,6 +821,7 @@ The CounterDataSource protocol defines an optional method requirement called inc NOTE 注意 Strictly speaking, you can write a custom class that conforms to CounterDataSource without implementing either protocol requirement. They are both optional, after all. Although technically allowed, this wouldn’t make for a very good data source. + 严格来讲,你可以实现一个类来适配协议`CounterDataSource`,而不去实现协议中的两个要求,因为`CounterDataSource`中的属性和方法要求都是可选的。尽管这样写是可以的,但这并不是一个好的数据源的实现。 The Counter class, defined below, has an optional dataSource property of type CounterDataSource?: @@ -777,14 +844,17 @@ The Counter class stores its current value in a variable property called count. The increment method first tries to retrieve an increment amount by looking for an implementation of the incrementForCount method on its data source. The increment method uses optional chaining to try to call incrementForCount, and passes the current count value as the method’s single argument. + `increment`方法首先通过可选链调用`incrementForCount`方法内数据源的实现,从而获取增量,并将当前的`count`值作为参数传入方法 Note two levels of optional chaining at play here. Firstly, it is possible that dataSource may be nil, and so dataSource has a question mark after its name to indicate that incrementForCount should only be called if dataSource is non-nil. Secondly, even if dataSource does exist, there is no guarantee that it implements incrementForCount, because it is an optional requirement. This is why incrementForCount is also written with a question mark after its name. + 注意,这里有两级可选链。首先,`dataSource`可能为`nil`,所以`dataSource`后使用问好,表明只有在`dataSource`不为`nil`时才调用`incrementForCount`方法。其次,即使`dataSource`存在,也不能保证它实现了`incrementForCount`方法,因为这是一个可选的要求。这就是为什么`incrementForCount`的名字后面也跟着一个问号。 Because the call to incrementForCount can fail for either of these two reasons, the call returns an optional Int value. This is true even though incrementForCount is defined as returning a non-optional Int value in the definition of CounterDataSource. + 以上原因表明,即使`CounterDataSource`协议中`incrementForCount`方法被定义为返回一个非可选的Int类型的值,在调用`incrementForCount`方法后,也会返回一个Int类型的可选值。 After calling incrementForCount, the optional Int that it returns is unwrapped into a constant called amount, using optional binding. If the optional Int does contain a value—that is, if the delegate and method both exist, and the method returned a value—the unwrapped amount is added onto the stored count property, and incrementation is complete. @@ -793,8 +863,11 @@ After calling incrementForCount, the optional Int that it returns is unwrapped i 如果可选值包含值-代表如果代理和方法都存在,方法返回了值-`amount`会赋给存储属性`count`,这个增量过程就完成了。 If it is not possible to retrieve a value from the incrementForCount method—either because dataSource is nil, or because the data source does not implement incrementForCount—then the increment method tries to retrieve a value from the data source’s fixedIncrement property instead. The fixedIncrement property is also an optional requirement, and so its name is also written using optional chaining with a question mark on the end, to indicate that the attempt to access the property’s value can fail. As before, the returned value is an optional Int value, even though fixedIncrement is defined as a non-optional Int property as part of the CounterDataSource protocol definition. + 如果不能从incrementForCount方法获取到值 -可能`dataSource`为`nil`,或dataSource没有实现`incrementForCount方法`-increment方法会尝试从数据源中获取fixedIncrement属性的值来代替。`fixedIncrement`属性也是一个可选的要求,所以它也使用可选链,以一个问号结束,表明试图访问属性的值时可以失败。和之前一样,即使`CounterDataSource`协议中,`fixedIncrement`属性被定义为返回一个非可选的Int类型的值,返回值也是一个可选的Int类型的值。 + Here’s a simple CounterDataSource implementation where the data source returns a constant value of 3 every time it is queried. It does this by implementing the optional fixedIncrement property requirement: + 这里有一个简单的CounterDataSource的实现,通过实现了可选属性fixedIncrement,每次查询都会返回一个常量3。 class ThreeSource: CounterDataSource { @@ -802,6 +875,7 @@ Here’s a simple CounterDataSource implementation where the data source returns } You can use an instance of ThreeSource as the data source for a new Counter instance: + 你可以使用ThreeSource的实例作为Counter实例的数据源: var counter = Counter() @@ -816,6 +890,7 @@ You can use an instance of ThreeSource as the data source for a new Counter inst // 12 The code above creates a new Counter instance; sets its data source to be a new ThreeSource instance; and calls the counter’s increment method four times. As expected, the counter’s count property increases by three each time increment is called. + 上面的代码创建了一个新的Counter实例,同时把数据源设置为ThreeSource的实例,之后调用了四次计数器的increment方法。正如我们所期望的,increment方法调用一次,计数器的count属性会增加3。 Here’s a more complex data source called TowardsZeroSource, which makes a Counter instance count up or down towards zero from its current count value: From 40f157476cf94470b4982e4979960e8eb0f732b1 Mon Sep 17 00:00:00 2001 From: Adams Date: Tue, 24 Jun 2014 13:42:19 +0800 Subject: [PATCH 198/261] Update 21_Protocols.md --- src/chapter2/21_Protocols.md | 65 ++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/src/chapter2/21_Protocols.md b/src/chapter2/21_Protocols.md index 871be19..ce4150f 100644 --- a/src/chapter2/21_Protocols.md +++ b/src/chapter2/21_Protocols.md @@ -162,16 +162,16 @@ The following example defines a protocol with a single instance method requireme } This protocol, RandomNumberGenerator, requires any conforming type to have an instance method called random, which returns a Double value whenever it is called. (Although it is not specified as part of the protocol, it is assumed that this value will be a number between 0.0 and 1.0 inclusive.) -RandomNumberGenerator,该协议要求任何遵循协议的类型调用一个名为random的实例方法,这个方法无论何时调用,都会返回一个Double类型的值。(这个值在0.0与1.0之间,这一点没有在协议中指出)。 +`RandomNumberGenerator`,该协议要求任何遵循协议的类型调用一个名为random的实例方法,这个方法无论何时调用,都会返回一个Double类型的值。(这个值在0.0与1.0之间,这一点没有在协议中指出)。 The RandomNumberGenerator protocol does not make any assumptions about how each random number will be generated—it simply requires the generator to provide a standard way to generate a new random number. Here’s an implementation of a class that adopts and conforms to the RandomNumberGenerator protocol. This class implements a pseudorandom number generator algorithm known as a linear congruential generator: - RandomNumberGenerator协议不会描述如何建立一个随机数,只需要指定一个随机数生成器,从而提供一种标准的方式来生成一个新随机数。 + `RandomNumberGenerator`协议不会描述如何建立一个随机数,只需要指定一个随机数生成器,从而提供一种标准的方式来生成一个新随机数。    - 下面是一个类的实现,遵循RandomNumberGenerator协议。这个类实现了一种伪随机数发生器算法,称为线性同余(linear congruential)发生器: + 下面是一个类的实现,遵循`RandomNumberGenerator`协议。这个类实现了一种伪随机数发生器算法,称为线性同余(linear congruential)发生器: class LinearCongruentialGenerator: RandomNumberGenerator { @@ -208,15 +208,17 @@ NOTE If you mark a protocol instance method requirement as mutating, you do not need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations. -如果你在一个协议中实现的突变方法是为一个类服务的,不需要为其加上mutating关键字。 -mutating关键字只用在结构体与枚举类型中。 - +如果你在一个协议中实现的突变方法是为一个类服务的,不需要为其加`上mutating`关键字。 +mutating`关键字只用在结构体与枚举类型中。 +` The example below defines a protocol called Togglable, which defines a single instance method requirement called toggle. As its name suggests, the toggle method is intended to toggle or invert the state of any conforming type, typically by modifying a property of that type. -下面的例子中定义了一个togglable协议,包含一个名为togger的突变实例方法。正如名称所表达的,适配此协议的某实例中,toggle方法通常会通过改变实例的某个属性,来切换或恢复其类型。 + +下面的例子中定义了一个`togglable`协议,包含一个名为`togger`的突变实例方法。正如名称所表达的,适配此协议的某实例中,toggle方法通常会通过改变实例的某个属性,来切换或恢复其类型。 The toggle method is marked with the mutating keyword as part of the Togglable protocol definition, to indicate that the method is expected to mutate the state of a conforming instance when it is called: -toggle方法前面加上了mutating关键字,作为Togglabel协议定义的一部分,则表示一个适配toggleabel协议的实例中,这个方法会在调用时改变实例的类型。 + +`toggle`方法前面加上了`mutating`关键字,作为`Togglabel`协议定义的一部分,则表示一个适配`toggleabel`协议的实例中,这个方法会在调用时改变实例的类型。 protocol Togglable { mutating func toggle() @@ -224,7 +226,7 @@ toggle方法前面加上了mutating关键字,作为Togglabel协议定义的一 If you implement the Togglable protocol for a structure or enumeration, that structure or enumeration can conform to the protocol by providing an implementation of the toggle method that is also marked as mutating. -当你提供的枚举或结构体遵循Togglabl协议时,需要提供一个带有`mutating`前缀的toggle方法。 +当你提供的枚举或结构体遵循`Togglable`协议时,需要提供一个带有`mutating`前缀的`toggle`方法。 The example below defines an enumeration called OnOffSwitch. This enumeration toggles between two states, indicated by the enumeration cases On and Off. The enumeration’s toggle implementation is marked as mutating, to match the Togglable protocol’s requirements: @@ -243,6 +245,7 @@ The example below defines an enumeration called OnOffSwitch. This enumeration to var lightSwitch = OnOffSwitch.Off lightSwitch.toggle() // lightSwitch is now equal to .On + Protocols as Types 协议类型 @@ -250,15 +253,21 @@ Protocols as Types Protocols do not actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use in your code. 尽管协议本身并不实现任何功能,但协议可以作为完整的类型来使用。 + Because it is a type, you can use a protocol in many places where other types are allowed, including: + 你可以把协议类型用在其他类型适用的场景里,比如: As a parameter type or return type in a function, method, or initializer 在函数,方法或构造方法中作为形参类型(parameter type)或返回值类型(return type) + As the type of a constant, variable, or property + 作为常量、变量或属性这三种类型之一 + As the type of items in an array, dictionary, or other container + 作为数组,字典或其他容器中的元素类型 NOTE @@ -283,21 +292,22 @@ Here’s an example of a protocol used as a type: return Int(generator.random() * Double(sides)) + 1 } } + This example defines a new class called Dice, which represents an n-sided dice for use in a board game. Dice instances have an integer property called sides, which represents how many sides they have, and a property called generator, which provides a random number generator from which to create dice roll values. -例子中定义了一个Dice类,用来表示桌游中的拥有N个面的骰子。Dice的实例包含sides和generator两个属性,前者是整型(integer),用来表示骰子有几个面,后者提供了一个随机数生成器,来表示骰子掷出的值。 +例子中定义了一个`Dice`类,用来表示桌游中的拥有N个面的骰子。`Dice`的实例包含`sides`和`generator`两个属性,前者是整型(integer),用来表示骰子有几个面,后者提供了一个随机数生成器,来表示骰子掷出的值。 The generator property is of type RandomNumberGenerator. Therefore, you can set it to an instance of any type that adopts the RandomNumberGenerator protocol. Nothing else is required of the instance you assign to this property, except that the instance must adopt the RandomNumberGenerator protocol. -generator属性的类型为RandomNumberGenerator,因此任何类型,若适配RandomNumberGenerator协议,其实例都可以赋值给generator,除此以外没有其他要求。 +`generator`属性的类型为`RandomNumberGenerator`,因此任何类型,若适配`RandomNumberGenerator`协议,其实例都可以赋值给`generator`,除此以外没有其他要求。 Dice also has an initializer, to set up its initial state. This initializer has a parameter called generator, which is also of type RandomNumberGenerator. You can pass a value of any conforming type in to this parameter when initializing a new Dice instance. -Dice类也包含一个构造方法,用于设置其初始状态。这个方法包含一个同样是RandomNumberGenerator类型的参数generator。在构造一个新的Dice的实例时,可以传入任何遵循RandomNumberGenerator协议的类型作为generator。 +`Dice`类也包含一个构造方法,用于设置其初始状态。这个方法包含一个同样是`RandomNumberGenerator`类型的参数`generator`。在构造一个新的`Dice`的实例时,可以传入任何遵循`RandomNumberGenerator`协议的类型作为`generator` Dice provides one instance method, roll, which returns an integer value between 1 and the number of sides on the dice. This method calls the generator’s random method to create a new random number between 0.0 and 1.0, and uses this random number to create a dice roll value within the correct range. Because generator is known to adopt RandomNumberGenerator, it is guaranteed to have a random method to call. -Dice类提供了一个实例方法,roll,此方法会返回一个整型值,介于1和骰子面的数量之间。这个方法调用generator的随机�数方法来创建一在0.0和1.0之间的随机数,并使用这个随机数来确保骰子的滚动值在正确的范围内。因为generator适配RandomNumberGenerator协议,因此它可以保证有一个random方法供调用。 +Dice类提供了一个实例方法`roll`,此方法会返回一个整型值,介于1和骰子面的数量之间。这个方法调用`generator`的随机数方法,来创建一在0.0和1.0之间的随机数,并使用这个随机数来确保骰子的滚动值在正确的范围内。因为`generator`适配`RandomNumberGenerator`协议,因此它可以保证有一个`random`方法供调用。 Here’s how the Dice class can be used to create a six-sided dice with a LinearCongruentialGenerator instance as its random number generator: @@ -338,11 +348,11 @@ The example below defines two protocols for use with dice-based board games: The DiceGame protocol is a protocol that can be adopted by any game that involves dice. The DiceGameDelegate protocol can be adopted by any type to track the progress of a DiceGame. -DiceGame协议可以被任意含有骰子的游戏所适配,DiceGameDelegate协议可以被任意用来追踪DiceGame过程的类型所适配 +`DiceGame`协议可以被任意含有骰子的游戏所适配,`DiceGameDelegate`协议可以被任意用来追踪`DiceGame`过程的类型所适配 Here’s a version of the Snakes and Ladders game originally introduced in Control Flow. This version is adapted to use a Dice instance for its dice-rolls; to adopt the DiceGame protocol; and to notify a DiceGameDelegate about its progress: -这里有一个,Snakes and Ladders游戏的新版本(之前的版本在流程控制这一节中介绍过)。新版本使用Dice类的实例作为掷骰子的需求,并且适配了DiceGame协议。同时通知(notify)DiceGameDelegate协议,用来记录游戏过程: +这里有一个,`Snakes and Ladders`游戏的新版本(之前的版本在流程控制这一节中介绍过)。新版本使用`Dice`类的实例作为掷骰子的需求,并且适配了`DiceGame`协议。同时通知(notify)`DiceGameDelegate`协议,用来记录游戏过程: class SnakesAndLadders: DiceGame { let finalSquare = 25 @@ -382,30 +392,32 @@ For a description of the Snakes and Ladders gameplay, see the Break section of t This version of the game is wrapped up as a class called SnakesAndLadders, which adopts the DiceGame protocol. It provides a gettable dice property and a play method in order to conform to the protocol. (The dice property is declared as a constant property because it does not need to change after initialization, and the protocol only requires that it is gettable.) -这个版本的游戏封装为SnakesAndLadders类,该类适配DiceGame协议。这个类还提供了可读的dice属性和play方法,从而遵循了DiceGame协议。(dice属性声明为常量,因为构造之后dice属性就不在改变,且协议只要求dice为只读) +这个版本的游戏封装为`SnakesAndLadders`类,该类适配`DiceGame`协议。这个类还提供了可读的`dice`属性和`play`方法,从而遵循了`DiceGame`协议。(`dice`属性声明为常量,因为构造之后dice属性就不在改变,且协议只要求`dice`为只读) The Snakes and Ladders game board setup takes place within the class’s init() initializer. All game logic is moved into the protocol’s play method, which uses the protocol’s required dice property to provide its dice roll values. -Snakes And Ladders游戏通过构造方法(initializer)init初始化游戏。所有的游戏逻辑移到了play方法中,play方法使用协议要求的dice属性,来提供骰子掷出的值。 +`Snakes And Ladders`游戏通过构造方法(initializer)`init`初始化游戏。所有的游戏逻辑移到了`play`方法中,`play`方法使用协议要求的`dice`属性,来提供骰子掷出的值。 Note that the delegate property is defined as an optional DiceGameDelegate, because a delegate isn’t required in order to play the game. Because it is of an optional type, the delegate property is automatically set to an initial value of nil. Thereafter, the game instantiator has the option to set the property to a suitable delegate. -注意,delegate并不是玩游戏所必须的,因此delegate被定义为DiceGameDelegate协议类型的可选属性,delegate使用nil作为初始值。此后,游戏实例可以选择将其设置为一个合适的代理。 +注意,`delegate`属性并不是游戏运行所必须的,因此`delegate`被定义为`DiceGameDelegate`协议类型的可选属性,`delegate`使用nil作为初始值。此后,游戏实例可以选择将其设置为一个合适的代理。 DiceGameDelegate provides three methods for tracking the progress of a game. These three methods have been incorporated into the game logic within the play method above, and are called when a new game starts, a new turn begins, or the game ends. -DicegameDelegate协议提供了三个方法来跟踪游戏过程。这三个方法存在于游戏的逻辑中,即上面的play()方法内。分别在游戏开始时,新一轮开始时,游戏结束时被调用。 +`DicegameDelegate`协议提供了三个方法来跟踪游戏过程。这三个方法存在于游戏的逻辑中,即上面的play()方法内。分别在游戏开始时,新一轮开始时,游戏结束时被调用。 Because the delegate property is an optional DiceGameDelegate, the play method uses optional chaining each time it calls a method on the delegate. If the delegate property is nil, these delegate calls fail gracefully and without error. If the delegate property is non-nil, the delegate methods are called, and are passed the SnakesAndLadders instance as a parameter. -因为delegate属性是一个遵循DiceGameDelegate的可选属性,因此在play()方法中使用了可选链(optional chaining )来在代理时调用方法。 若delegate属性为nil, 则delegate所调用的方法正常失败(fail gracefully)且不报错。若delegate不为nil,则方法能够被调用,且作为一个参数传入SnakesAndLadders实例中 +因为`delegate`属性是一个遵循`DiceGameDelegate`的可选属性,因此在`play`方法中使用了可选链(optional chaining )来在代理时调用方法。 若`delegate`属性为`nil`, 则`delegate`所调用的方法正常失败(fail gracefully)且不报错。若`delegate`不为`nil`,则方法能够被调用,且作为一个参数传入`SnakesAndLadders`实例中 + This next example shows a class called DiceGameTracker, which adopts the DiceGameDelegate protocol: -下一个例子展示了一个名为DiceGameTracker的类,适配DiceGameDelegate协议。 + +下一个例子展示了一个名为`DiceGameTracker`的类,适配`DiceGameDelegate`协议。 class DiceGameTracker: DiceGameDelegate { var numberOfTurns = 0 @@ -424,6 +436,7 @@ This next example shows a class called DiceGameTracker, which adopts the DiceGam println("The game lasted for \(numberOfTurns) turns") } } + DiceGameTracker implements all three methods required by DiceGameDelegate. It uses these methods to keep track of the number of turns a game has taken. It resets a numberOfTurns property to zero when the game starts; increments it each time a new turn begins; and prints out the total number of turns once the game has ended. DiceGameTracker提供了DiceGameDelegate所要求的三个方法。它使用这三个方法来跟踪游戏进行的轮数。当游戏开始时,将numberOfTurns属性重置为0。每轮开始后递增这个值。当游戏结束时打印游戏进行的总轮数 @@ -622,15 +635,17 @@ The method implementation can now be used to print a pretty text description of 当遍历出的元素的值小于0时,表示一个蛇头,用`▲`符号表示 当遍历出的元素的值等于0时,表示一个空白方块,用`○`符号表示 -println(game.asPrettyText()) -// A game of Snakes and Ladders with 25 squares: -// ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○ + println(game.asPrettyText()) + // A game of Snakes and Ladders with 25 squares: + // ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○ + Protocol Composition 协议合成 + It can be useful to require a type to conform to multiple protocols at once. You can combine multiple protocols into a single requirement with a protocol composition. Protocol compositions have the form protocol. You can list as many protocols within the pair of angle brackets (<>) as you need, separated by commas. 有一种很有用的方式,来表示一种适配多个协议的类型。你可以使用协议合成(Protocol Composition)来组合多个协议。 -协议合成的格式为protocal。你可以在尖括号(`<>`)内列出多个协议,用逗号`,`分隔。 +协议合成的格式为protocal``。你可以在尖括号(`<>`)内列出多个协议,用逗号`,`分隔。 From 2e5e9511a790a8921085c88655ce0eb41ad474cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Tue, 24 Jun 2014 14:08:29 +0800 Subject: [PATCH 199/261] add review member --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3362316..38f9a7f 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ The Swift Programming Language 中文化项目 * 泛型 [已完成 by 晴时] * 高级操作符 [认领 by 林晚] * 语言参考 - * 关于语言参考 [认领 by 筱强] + * 关于语言参考 [认领 by 筱强] [review by 懂象] * 词法结构 [认领 by 筱强][review by 懂象] * 类型 [认领 by 兰梦][review by 筱强] * 表达式 [认领 by 懂象][review by 兰梦] From be71afe327fefabb197fbcfc9c9273d4f87d8b8e Mon Sep 17 00:00:00 2001 From: MrSunny Date: Tue, 24 Jun 2014 14:17:35 +0800 Subject: [PATCH 200/261] =?UTF-8?q?review=20=E9=AB=98=E7=BA=A7=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit review 高级操作符 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38f9a7f..43a5648 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ The Swift Programming Language 中文化项目 * 扩展 [已完成 by 袁鹏] * 协议 [认领 by 姜天意][review by 重鱼] * 泛型 [已完成 by 晴时] - * 高级操作符 [认领 by 林晚] + * 高级操作符 [认领 by 林晚][review by 周源] * 语言参考 * 关于语言参考 [认领 by 筱强] [review by 懂象] * 词法结构 [认领 by 筱强][review by 懂象] From 547efe1a6387612b0676fa56ddaf3104ccdf7545 Mon Sep 17 00:00:00 2001 From: "huijun.wenghj" Date: Tue, 24 Jun 2014 16:36:46 +0800 Subject: [PATCH 201/261] =?UTF-8?q?=E7=8E=A9=E5=AE=B6=E6=B7=BB=E5=8A=A0rev?= =?UTF-8?q?iew?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 43a5648..891eed1 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The Swift Programming Language 中文化项目 * 构造过程 [认领 by 刘康] [review by 晓毒] * 析构过程 [认领 by 许诺] [review by 祁涛] * 自动引用计数 [认领 by 韩国兴/MK] [review by 孟志昂] - * 可选链 [认领 by 重鱼] + * 可选链 [认领 by 重鱼] [review by 玩家] * 类型转换 [认领 by 孟志昂] * 嵌套类型 [认领 by 祁涛] * 扩展 [已完成 by 袁鹏] From ba3e708af421e9e3a8d80303dfa3b684604317a9 Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Tue, 24 Jun 2014 19:12:43 +0800 Subject: [PATCH 202/261] =?UTF-8?q?=E7=AE=80=E5=8D=95=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E5=87=A0=E5=A4=84=E7=BF=BB=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/01_The_Basics.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 3ff2f01..0996853 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -7,7 +7,7 @@ Swift是一个用于iOS和OS X平台开发的新的编程语言。尽管如此 Swift provides its own versions of all fundamental C and Objective-C types, including Int for integers; Double and Float for floating-point values; Bool for Boolean values; and String for textual data. Swift also provides powerful versions of the two primary collection types, Array and Dictionary, as described in Collection Types. -Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值Int,浮点值Double和Float,布尔值Bool,以及文本值String。Swift还提供了两个强大的常见集合类型,数组和字典,见[集合类型](link to 集合类型)。 +Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值Int,浮点值Double和Float,布尔值Bool,以及文本值String。Swift还提供了两个强大的常见集合类型,数组和字典,见[集合类型](link)。 Like C, Swift uses variables to store and refer to values by an identifying name. Swift also makes extensive use of variables whose values cannot be changed. These are known as constants, and are much more powerful than constants in C. Constants are used throughout Swift to make code safer and clearer in intent when you work with values that do not need to change. @@ -93,7 +93,7 @@ The colon in the declaration means “…of type…,” so the code above can be The phrase “of type String” means “can store any String value.” Think of it as meaning “the type of thing” (or “the kind of thing”) that can be stored. -“类型是”表示“可以储存任意的字符串类型的值”。可以把它想作是“一个事物的类型”它可以储存的。(Think of it as meaning “the type of thing” (or “the kind of thing”) that can be stored. 妈蛋这句真心不会翻啊……) +“类型是字符串”表示“可以储存任意的字符串类型的值”。可以把它想作是它可以储存的“一个事物的类型”。 The welcomeMessage variable can now be set to any string value without error: @@ -149,7 +149,7 @@ You can change the value of an existing variable to another value of a compatibl Unlike a variable, the value of a constant cannot be changed once it is set. Attempting to do so is reported as an error when your code is compiled: -和变量不同,常量的值一旦设定就不能更改。尝试这样做会导致代码编译时报错。 +和变量不同,常量的值一旦设定就不能更改。尝试更改会导致代码编译时报错。 let languageName = "Swift" languageName = "Swift++" @@ -187,7 +187,7 @@ The println function can print more complex logging messages, in a similar manne Swift uses string interpolation to include the name of a constant or variable as a placeholder in a longer string, and to prompt Swift to replace it with the current value of that constant or variable. Wrap the name in parentheses and escape it with a backslash before the opening parenthesis: -Swift使用字符串内插(string interpolation)的方式将常量或变量名以占位符的形式加入一个长的字符串中,并且提示Swift用常量或变量的当前值取代替它。将名字包裹在括号中并在前面加上反斜扛来转义。 +Swift使用字符串内插(string interpolation)的方式将常量或变量名以占位符的形式加入一个长的字符串中,并且提示Swift用常量或变量的当前值取代替它。书写格式是将名字包裹在括号中并在前面加上反斜扛来转义: ``` println("The current value of friendlyWelcome is \(friendlyWelcome)") From 36adae50912b8b0e6e26b1eef24606d40ee6a535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=96=E9=82=80?= Date: Wed, 25 Jun 2014 09:16:13 +0800 Subject: [PATCH 203/261] first review --- src/chapter2/01_The_Basics.md | 40 +++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 3ff2f01..99a269c 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -9,29 +9,65 @@ Swift provides its own versions of all fundamental C and Objective-C types, incl Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值Int,浮点值Double和Float,布尔值Bool,以及文本值String。Swift还提供了两个强大的常见集合类型,数组和字典,见[集合类型](link to 集合类型)。 +***建议对语法关键字加上代码标记 {*** + +Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值```Int```,浮点值```Double```和```Float```,布尔值```Bool```,以及文本值```String```。Swift还提供了两个强大的常见集合类型,```Array```(数组)和```Dictionary```(字典),见[集合类型](link to 集合类型)。 + +***}*** + Like C, Swift uses variables to store and refer to values by an identifying name. Swift also makes extensive use of variables whose values cannot be changed. These are known as constants, and are much more powerful than constants in C. Constants are used throughout Swift to make code safer and clearer in intent when you work with values that do not need to change. 和C一样,Swift使用具有唯一名称的变量(variables)来储存和指向特定值。Swift还对那些值不能改变的变量进行了扩展,他们也被称为常量(Constants),Swift中的常量比C中的常量更加强大。在Swift中当你需要处理一些恒定不变的值的时候,使用常量(Constants)可以让代码更加安全和整洁。 +***感觉括号就统一用中文,会不会好点= ={*** + +和C一样,Swift使用具有唯一名称的变量(variables)来储存和指向特定值。Swift还对那些值不能改变的变量进行了扩展,他们也被称为常量(Constants),Swift中的常量比C中的常量更加强大。在Swift中当你需要处理一些恒定不变的值的时候,使用常量(Constants)可以让代码更加安全和整洁。 + +***}*** + In addition to familiar types, Swift introduces advanced types not found in Objective-C. These include tuples, which enable you to create and pass around groupings of values. Tuples can return multiple values from a function as a single compound value. 除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,包括:元组(tuples),你可以创建和传递一组数值。元组(tuples)可以在函数中以一个复合值的形式返回多个数值。 +***加粗那句这样翻译感觉更通顺{*** + +除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,***比如可以创建和传递一组数值的元组(tuples)。元组能在函数中以一个复合值的形式返回多个值。*** + +***}*** + Swift also introduces optional types, which handle the absence of a value. Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”. Optionals are similar to using nil with pointers in Objective-C, but they work for any type, not just classes. Optionals are safer and more expressive than nil pointers in Objective-C and are at the heart of many of Swift’s most powerful features. Swift还有可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用nil,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的nil,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大的特性的核心。 -Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This enables you to catch and fix errors as early as possible in the development prObjective Cess. +***对语法关键字加代码标记,一些细节调整 {*** + +Swift还引入了可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用```nil```,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的```nil```,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大特性的核心。 + +***}*** + +Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This enables you to catch and fix errors as early as possible in the development process. 可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(String),类型安全性会阻止你错误的给它赋一个整型(Int)的值。这让你在开发的过程中尽早的发现问题。 +***对语法关键字加标记 {*** + +可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(```String```),类型安全性会阻止你错误的给它赋一个整型(```Int```)的值。这让你在开发过程中能尽早发现和解决问题。 + +***}*** + # Constants and Variables # 常量和变量 -**Constants and variables associate a name (such as maximumNumberOfLoginAttempts or welcomeMessage) with a value of a particular type (such as the number 10 or the string "Hello"). The value of a constant cannot be changed once it is set, whereas a variable can be set to a different value in the future. +Constants and variables associate a name (such as maximumNumberOfLoginAttempts or welcomeMessage) with a value of a particular type (such as the number 10 or the string "Hello"). The value of a constant cannot be changed once it is set, whereas a variable can be set to a different value in the future. 常量和变量对应一个变量名(如maximumNumberOfLoginAttempts或welcomeMessage)以及对应类型的值(如数字10或字符串"Hello")。常量的值一旦设定旧不能改变,变量的值可以改变。 +***对语法关键字加标记 {*** + +常量和变量对应一个变量名(如```maximumNumberOfLoginAttempts```或```welcomeMessage```)以及对应类型的值(如数字```10```或字符串```"Hello"```)。常量的值一旦设定就不能改变,变量的值可以改变。 + +***}*** + # Declaring Constants and Variables # 声明常量和变量 From 1c7aca8610a56692348fe6e50ac5899adee24ff1 Mon Sep 17 00:00:00 2001 From: crazygx Date: Wed, 25 Jun 2014 18:42:25 +0800 Subject: [PATCH 204/261] =?UTF-8?q?=E8=AE=A4=E9=A2=86review=20=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a3d244a..44b5005 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The Swift Programming Language 中文化项目 * 析构过程 [认领 by 许诺] [review by 祁涛] * 自动引用计数 [认领 by 韩国兴/MK] [review by 孟志昂] * 可选链 [认领 by 重鱼] [review by 玩家] - * 类型转换 [认领 by 孟志昂] + * 类型转换 [认领 by 孟志昂] [review by 耿霄] * 嵌套类型 [认领 by 祁涛][review by 袁鹏] * 扩展 [已完成 by 袁鹏] * 协议 [认领 by 姜天意][review by 重鱼] From 6f9e2e1565908e879757187e5843b6568c3a8b68 Mon Sep 17 00:00:00 2001 From: Neekey Date: Thu, 26 Jun 2014 19:28:08 +0800 Subject: [PATCH 205/261] =?UTF-8?q?=E9=9A=90=E8=8B=A5=20review=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1=E4=BF=AE=E6=94=B9=E4=B8=BA=20=E6=B3=9B=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 44b5005..a8f82ee 100644 --- a/README.md +++ b/README.md @@ -29,17 +29,17 @@ The Swift Programming Language 中文化项目 * 自动引用计数 [认领 by 韩国兴/MK] [review by 孟志昂] * 可选链 [认领 by 重鱼] [review by 玩家] * 类型转换 [认领 by 孟志昂] [review by 耿霄] - * 嵌套类型 [认领 by 祁涛][review by 袁鹏] + * 嵌套类型 [认领 by 祁涛] [review by 袁鹏] * 扩展 [已完成 by 袁鹏] - * 协议 [认领 by 姜天意][review by 重鱼] - * 泛型 [已完成 by 晴时] - * 高级操作符 [认领 by 林晚][review by 周源] + * 协议 [认领 by 姜天意] [review by 重鱼] + * 泛型 [已完成 by 晴时] [review by 隐若] + * 高级操作符 [认领 by 林晚] [review by 周源] * 语言参考 * 关于语言参考 [认领 by 筱强] [review by 懂象] - * 词法结构 [认领 by 筱强][review by 懂象] - * 类型 [认领 by 兰梦][review by 筱强] - * 表达式 [认领 by 懂象][review by 兰梦] - * 语句 [认领 by 玩家] [review by 隐若] + * 词法结构 [认领 by 筱强] [review by 懂象] + * 类型 [认领 by 兰梦] [review by 筱强] + * 表达式 [认领 by 懂象] [review by 兰梦] + * 语句 [认领 by 玩家] * 声明 [认领 by 墨峰] [review by 龙刚] * 属性 [认领 by 隐若] * 模式 [已完成 by 栖邀] [review by 紫溪] From 3192ea3690603cd02d02aa674752aa3aa74e3ad6 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Thu, 26 Jun 2014 22:35:32 +0800 Subject: [PATCH 206/261] =?UTF-8?q?=E7=BB=A7=E6=89=BF=20=E6=A0=A1=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/13_Inheritance.md | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/chapter2/13_Inheritance.md b/src/chapter2/13_Inheritance.md index 3cfffac..2ab8e9e 100644 --- a/src/chapter2/13_Inheritance.md +++ b/src/chapter2/13_Inheritance.md @@ -8,7 +8,7 @@ A class can *inherit* methods, properties, and other characteristics from anothe Inheritance is a fundamental behavior that differentiates classes from other types in Swift. Classes in Swift can call and access methods, properties, and subscripts belonging to their superclass and can provide their own overriding versions of those methods, properties, and subscripts to refine or modify their behavior. Swift helps to ensure your overrides are correct by checking that the override definition has a matching superclass definition. -在Swift语言中,继承是区分类与其他类型的一个基本行为。一个类可以访问并调用其父类中的方法,属性和下标,也可以通过重写它们来修改或优化它们的行为。Swift通过检查重写的定义是否能与一个父类中的定义匹配来确保重写的正确性。 +在Swift语言中,继承是区分类与其他类型的一个基本行为。一个类可以访问并调用其父类中的方法、属性和下标,也可以通过重写它们来修改或优化它们的行为。Swift通过检查重写的定义是否能与一个父类中的定义匹配来确保重写的正确性。 Classes can also add property observers to inherited properties in order to be notified when the value of a property changes. Property observers can be added to any property, regardless of whether it was originally defined as a stored or computed property. @@ -30,7 +30,7 @@ Swift中的类没有继承一个全局的基类。没有指定父类的类会自 The example below defines a base class called `Vehicle`. This base class declares two properties(`numberOfWheels` and `maxPassengers`) that are universal to all vehicles. These properties are used by a method called `description`, which returns a `String` description of the vehicle’s characteristics: -下面的例子定义了一个基类`Vehicle`。类中声明了两个所有车辆都通用的属性(`numberOfWheels`和`maxPassengers`)。这两个属性在方法`description`中被使用,这个方法返回一个`String`类型的值来描述车辆的特性。 +下面的例子定义了一个基类`Vehicle`。类中声明了两个所有车辆都通用的属性(`numberOfWheels`和`maxPassengers`)。这两个属性在方法`description`中被使用,这个方法返回一个`String`类型的值来描述车辆的特性: ``` class Vehicle { @@ -56,7 +56,7 @@ You use initializers to create a new instance of a type. Although initializers a In its simplest form, an initializer is like an instance method with no parameters, written using the `init` keyword: -在最简单的形式中,构造器就像是一个没有参数的实例方法,用关键词`init`来声明。 +在最简单的形式中,构造器就像是一个没有参数的实例方法,用关键词`init`来声明: ``` init() { @@ -66,7 +66,7 @@ init() { To create a new instance of `Vehicle`, call this initializer with *initializer syntax*, written as `TypeName` followed by empty parentheses: -创建一个`Vehicle`类实例需要通过使用*构造器语法*来调用构造器,写法是在类名后加上一对空的括号。 +创建一个`Vehicle`类实例需要通过使用*构造器语法*来调用构造器,写法是在类名后加上一对空的括号: ``` let someVehicle = Vehicle() @@ -89,7 +89,7 @@ The `Vehicle` class defines common characteristics for an arbitrary vehicle, but To indicate that a class has a superclass, write the superclass name after the original class name, separated by a colon: -当声明一个类的父类时,需要将父类的名字写在原有类之后,并用冒号分隔: +当声明一个类的父类时,需要将父类的名字写在原有类之后,并用冒号分隔: ``` class SomeClass: SomeSuperclass { @@ -141,7 +141,7 @@ The default value of `maxPassengers` provided by `Vehicle` is already correct fo As well as inheriting the properties of `Vehicle`, `Bicycle` also inherits its methods. If you create an instance of `Bicycle`, you can call its inherited `description` method to see how its properties have been updated: -除了继承了`Vehicle`类中的属性,`Bicycle`类还继承了它的方法。创建了一个`Bicycle`的实例后,可以通过调用它继承过来的`description`方法来观察类中属性的更新。 +除了继承了`Vehicle`类中的属性,`Bicycle`类还继承了它的方法。创建了一个`Bicycle`的实例后,可以通过调用它继承过来的`description`方法来观察类中属性的更新: ``` let bicycle = Bicycle() @@ -195,7 +195,7 @@ Note that the `description` method is also inherited by `Tandem`. Instance metho ##重写 A subclass can provide its own custom implementation of an instance method, class method, instance property, or subscript that it would otherwise inherit from a superclass. This is known as *overriding*. -子类可以为继承过来的实例方法,类方法,实例属性或脚本提供它自己的实现,这个行为被称作*重写*。 +子类可以为继承过来的实例方法、类方法、实例属性或下标提供它自己的实现,这个行为被称作*重写*。 To override a characteristic that would otherwise be inherited, you prefix your overriding definition with the `override` keyword. Doing so clarifies that you intend to provide an override and have not provided a matching definition by mistake. Overriding by accident can cause unexpected behavior, and any overrides without the `override` keyword are diagnosed as an error when your code is compiled. @@ -203,18 +203,18 @@ To override a characteristic that would otherwise be inherited, you prefix your The `override` keyword also prompts the Swift compiler to check that your overriding class’s superclass (or one of its parents) has a declaration that matches the one you provided for the override. This check ensures that your overriding definition is correct. -`Override`关键字也会提醒Swift编译器去校验被继承的父类(或其中中一个父类)中是否有匹配的声明用于被重写。这个检查可以确保你的重写定义是正确的。 +`override`关键字也会提醒Swift编译器去校验被继承的父类(或其中中一个父类)中是否有匹配的声明用于被重写。这个检查可以确保你的重写定义是正确的。 ##Accessing Superclass Methods, Properties, and Subscripts -##访问父类的方法,属性和脚本 +##访问父类的方法、属性和下标 When you provide a method, property, or subscript override for a subclass, it is sometimes useful to use the existing superclass implementation as part of your override. For example, you can refine the behavior of that existing implementation or store a modified value in an existing inherited variable. -当你访问父类的方法,属性或脚本时,有时在你的重写版本中使用已存在的父类实现会很有作用。比如你可以优化一个已有的实现或者在一个继承来的变量重储存一个修改过的值。 +当你访问父类的方法、属性或下标时,有时在你的重写版本中使用已存在的父类实现会很有用。比如你可以优化一个已有的实现或者在一个继承来的变量重储存一个修改过的值。 Where this is appropriate, you access the superclass version of a method, property, or subscript by using the `super` prefix: -在适当的地方,你可以通过`super`前缀来访问父类版本的方法,属性或脚本: +在适当的地方,你可以通过`super`前缀来访问父类版本的方法、属性或下标: * An overridden method named `someMethod` can call the superclass version of `someMethod` by calling `super.someMethod()` within the overriding method implementation. * An overridden property called `someProperty` can access the superclass version of `someProperty` as `super.someProperty` within the overriding getter or setter implementation. @@ -222,7 +222,7 @@ Where this is appropriate, you access the superclass version of a method, proper * 一个重写的方法`someMethod`可以在方法实现中通过`super.someMethod()`来调用父类版本的`someMethod`。 * 一个重写的属性`someProperty`可以在getter和setter方法的重写实现中通过`super.someProperty`来访问父类版本的`someProperty`。 -* 一个重写的脚本`someIndex`可以在脚本实现中通过`super[someIndex]`来调用父类版本的`someIndex`。 +* 一个重写的下标`someIndex`可以在实现中通过`super[someIndex]`来调用相同下标的父类版本的。 ##Overriding Methods ##重写方法 @@ -232,7 +232,7 @@ You can override an inherited instance or class method to provide a tailored or The following example defines a new subclass of `Vehicle` called `Car`, which overrides the `description` method it inherits from `Vehicle`: -下面的例子定义了`Vehicle`类的一个新子类`Car`, 子类中重写了从父类中继承过来的方法`description`: +下面的例子定义了`Vehicle`类的一个新子类`Car`, 子类中重写了从父类中继承过来的方法`description`: ``` class Car: Vehicle { @@ -263,7 +263,7 @@ Rather than providing a completely custom implementation of `description`, the o If you create a new instance of `Car`, and print the output of its `description` method, you can see that the description has indeed changed: -如果你创建一个`Car`类的实例,并打印`description`方法的输出,你会发现描述的信息已经发生了改变。 +如果你创建一个`Car`类的实例,并打印`description`方法的输出,你会发现描述的信息已经发生了改变: ``` let car = Car() @@ -347,7 +347,7 @@ Note also that you cannot provide both an overriding setter and an overriding pr ``` 注意 你不可以为继承来的常量存储型属性或只读计算型属性添加属性观察器。这些属性的值是不可以被修改的,所以在重写时为它们提供`willSet`和`didSet`的实现是不恰当的。 -注意你也不能同事提供重写的setter方法和属性观察期。如果你想要观察属性值的变化,并且你已经给那个属性提供了定制的setter方法,在setter方法中你就已经可以观察到任何属性值的变化了。 +注意你不能同时提供重写的setter方法和属性观察期。如果你想要观察属性值的变化,并且你已经给那个属性提供了定制的setter方法,在setter方法中你就已经可以观察到任何属性值的变化了。 ``` The following example defines a new class called `AutomaticCar`, which is a subclass of `Car`. The `AutomaticCar` class represents a car with an automatic gearbox, which automatically selects an appropriate gear to use based on the current speed. `AutomaticCar` also provides a custom `description` method to print the current gear. @@ -370,7 +370,7 @@ class AutomaticCar: Car { Whenever you set the `speed` property of an `AutomaticCar` instance, the property’s `didSet` observer automatically sets the `gear` property to an appropriate choice of gear for the new speed. Specifically, the property observer chooses a gear which is the new `speed` value divided by `10`, rounded down to the nearest integer, plus `1`. A speed of `10.0` produces a gear of `1`, and a speed of `35.0` produces a gear of `4`: -当你为一个`AutomaticCar`实例设置`speed`属性时,属性的`didSet`观察器会自动设置`gear`属性到一个合适的档位。具体的计算方法是,属性观察者将新设置的速度值除以`10`,向下取整之后再加`1`。例如速度是`10`的时候档位是`1`,速度是`35.0`的时候档位是`4`。 +当你为一个`AutomaticCar`实例设置`speed`属性时,属性的`didSet`观察器会自动设置`gear`属性到一个合适的档位。具体的计算方法是,属性观察者将新设置的速度值除以`10`,向下取整之后再加`1`。例如速度是`10`的时候档位是`1`,速度是`35.0`的时候档位是`4`: ``` let automatic = AutomaticCar() @@ -382,12 +382,12 @@ println("AutomaticCar: \(automatic.description())") ##Preventing Overrides ##防止重写 You can prevent a method, property, or subscript from being overridden by marking it as *final*. Do this by writing the `@final` attribute before its introducer keyword (such as `@final var`, `@final func`, `@final class func`, and `@final subscript`). -你可以通过标记一个属性,方法或附属脚本为*final*来防止它们被重写。具体方法是在声明它们的关键字前加上`@final` (例如`@final var`, `@final func`, `@final class func`及`@final subscript`)。 +你可以通过标记一个属性、方法或下标为*final*来防止它们被重写。具体方法是在声明它们的关键字前加上`@final` (例如`@final var`, `@final func`, `@final class func`及`@final subscript`)。 Any attempts to override a final method, property, or subscript in a subclass are reported as a compile-time error. Methods, properties or subscripts that you add to a class in an extension can also be marked as final within the extension’s definition. -如果被标记为final的方法,属性或附属脚本在子类中被尝试重写,在编译时便会报错。在扩展时被添加到类中的方法,属性或附属脚本也可以在扩展的定义中标记为final。 +如果被标记为final的方法、属性或下标在子类中被尝试重写,在编译时便会报错。在扩展时被添加到类中的方法,属性或附属脚本也可以在扩展的定义中标记为final。 You can mark an entire class as final by writing the `@final` attribute before the `class` keyword in its class definition (`@final class`). Any attempts to subclass a final class will be reported as a compile-time error. -你也可以通过在关键字class前添加`@final`属性(`@final class`)来把整个类标记为final。如此以来这个类就不可以被继承,否则在编译时会报错。 +你也可以通过在关键字class前添加`@final`属性(`@final class`)来把整个类标记为final。如此一来这个类就不可以被继承,否则在编译时会报错。 From c33f42b87baf1d0e909d313c2812f35c195be473 Mon Sep 17 00:00:00 2001 From: bingxi Date: Fri, 27 Jun 2014 10:06:16 +0800 Subject: [PATCH 207/261] =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/02_Basic_Operators.md | 272 +++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) diff --git a/src/chapter2/02_Basic_Operators.md b/src/chapter2/02_Basic_Operators.md index fb08b76..fa66a09 100644 --- a/src/chapter2/02_Basic_Operators.md +++ b/src/chapter2/02_Basic_Operators.md @@ -71,4 +71,276 @@ Swift 支持基本的四则运算: ###求余运算 +求余运算(a % b)是计算b的多少倍刚刚好可以容入a,返回多出来的那部分(余数)。 +>注意: +求余运算(%)在其他语言也叫取模运算。然而严格说来,我们看该运算符对负数的操作结果,"求余"比"取模"更合适些。 +我们来谈谈取余是怎么回事,计算9 % 4,你先计算出4的多少倍会刚好可以容入9中: +<图> +2倍,非常好,那余数是1(用橙色标出) + +在 Swift 中这么来表达: + + 9 % 4 // 等于 1 + +为了得到a % b的结果,%计算了以下等式,并输出余数作为结果: + +a = (b × 倍数) + 余数 + +当倍数取最大值的时候,就会刚好可以容入a中。 + +把9和4代入等式中,我们得1: + + 9 = (4 × 2) + 1 +同样的方法,我来们计算 -9 % 4: + + -9 % 4 // 等于 -1 +把-9和4代入等式,-2是取到的最大整数: + + -9 = (4 × -2) + -1 + +余数是-1。 + +在对负数b求余时,b的符号会被忽略。这意味着 a % b 和 a % -b的结果是相同的。 +###浮点数求余计算 +与 C 语言和 Objective-C不同,Swift中可以对浮点数进行求余。 + + 8 % 2.5 // 等于 0.5 + +这个例子中,8除于2.5等于3余0.5,所以结果是一个Double值0.5。 +[图片]{} + +###自增和自增运算 +和 C 语言一样,Swift 也提供了方便对变量本身加1或减1的自增(++)和自减(--)的运算符。其操作对象可以是整形和浮点型。 + + var i = 0 + ++i // 现在 i = 1 + +每调用一次++i,i的值就会加1。实际上,++i是i = i + 1的简写,而--i是i = i - 1的简写。 + +++和--既是前置又是后置运算。++i,i++,--i和i--都是有效的写法。 + +我们需要注意的是这些运算符修改了i后有一个返回值。如果你只想修改i的值,那你就可以忽略这个返回值。但如果你想使用返回值,你就需要留意前置和后置操作的返回值是不同的。 + +当++前置的时候,先自増再返回。 +当++后置的时候,先返回再自增。 + + var a = 0 + let b = ++a // a 和 b 现在都是 1 + let c = a++ // a 现在 2, 但 c 是 a 自增前的值 1 + +上述例子,let b = ++a先把a加1了再返回a的值。所以a和b都是新值1。 + +而let c = a++,是先返回了a的值,然后a才加1。所以c得到了a的旧值1,而a加1后变成2。 + +除非你需要使用i++的特性,不然推荐你使用++i和--i,因为先修改后返回这样的行为更符合我们的逻辑。 + + +###一元负号 +数值的正负号可以使用前缀-(即一元负号)来切换: + + let three = 3 + let minusThree = -three // minusThree 等于 -3 + let plusThree = -minusThree // plusThree 等于 3, 或 "负负3" + +一元负号(-)写在操作数之前,中间没有空格。 +###一元正号 +一元正号(+)不做任何改变地返回操作数的值。 + + let minusSix = -6 + let alsoMinusSix = +minusSix // alsoMinusSix 等于 -6 +虽然一元+做无用功,但当你在使用一元负号来表达负数时,你可以使用一元正号来表达正数,如此你的代码会具有对称美。 + +##复合赋值 +和C 语言一样,Swift 也提供把其他运算符和赋值运算(=)组合的复合赋值运算符,加赋运算(+=)是其中一个例子: + + var a = 1 + a += 2 // a 现在是 3 + +表达式a += 2是a = a + 2的简写,一个加赋运算就把加法和赋值两件事完成了。 +>注意: +复合赋值运算没有返回值,let b = a += 2这类代码是错误。这不同于上面提到的自增和自减运算符。 + +在表达式章节里有复合运算符的完整列表。 ‌ + +##比较运算 +swift支持所有c语言中的比较运算 + +* 等于(a == b) +* 不等于(a != b) +* 大于(a > b) +* 小于(a < b) +* 大于等于(a >= b) +* 小于等于(a <= b) + +>注意: +Swift 也提供恒等===和不恒等!==这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在类与结构。 + +每个比较运算都返回了一个标识表达式是否成立的布尔值: + + 1 == 1 // true, 因为 1 等于 1 + 2 != 1 // true, 因为 2 不等于 1 + 2 > 1 // true, 因为 2 大于 1 + 1 < 2 // true, 因为 1 小于2 + 1 >= 1 // true, 因为 1 大于等于 1 + 2 <= 1 // false, 因为 2 并不小于等于 1 + +比较运算多用于条件语句,如if条件: + + let name = "world" + if name == "world" { + println("hello, world") + } else { + println("I'm sorry \(name), but I don't recognize you") + } + // 输出 "hello, world", 因为 `name` 就是等于 "world" +关于if语句,请看控制流。 + +##三元条件运算 +三元条件运算的特殊在于它是有三个操作数的运算符,它的原型是 问题 ? 答案1 : 答案2。它简洁地表达根据问题成立与否作出二选一的操作。如果问题成立,返回答案1的结果; 如果不成立,返回答案2的结果。 + + +使用三元条件运算简化了以下代码 + + if question: { + answer1 + } else { + answer2 + } + +这里有个计算表格行高的例子。如果有表头,那行高应比内容高度要高出50像素; 如果没有表头,只需高出20像素。 + + let contentHeight = 40 + let hasHeader = true + let rowHeight = contentHeight + (hasHeader ? 50 : 20) + // rowHeight 现在是 90 + + let contentHeight = 40 + let hasHeader = true + var rowHeight = contentHeight + +这样写会比下面的代码简洁: + + if hasHeader { + rowHeight = rowHeight + 50 + } else { + rowHeight = rowHeight + 20 + } + // rowHeight 现在是 90 + +第一段代码例子使用了三元条件运算,所以一行代码就能让我们得到正确答案。这比第二段代码简洁得多,无需将rowHeight定义成变量,因为它的值无需在if语句中改变。 + +三元条件运算提供有效率且便捷的方式来表达二选一的选择。需要注意的事,过度使用三元条件运算就会由简洁的代码变成难懂的代码。我们应避免在一个组合语句使用多个三元条件运算符。 + +##区间运算符 +Swift 提供了两个方便表达一个区间的值的运算符。 +###闭区间运算符 +闭区间运算符(a...b)定义一个包含从a到b(包括a和b)的所有值的区间。 ‌ 闭区间运算符在迭代一个区间的所有值时是非常有用的,如在for-in循环中: + + for index in 1...5 { + println("\(index) * 5 = \(index * 5)") + } + // 1 * 5 = 5 + // 2 * 5 = 10 + // 3 * 5 = 15 + // 4 * 5 = 20 + // 5 * 5 = 25 + +关于for-in,请看控制流。 + +###半闭区间 +半闭区间(a..b)定义一个从a到b但不包括b的区间。 之所以称为半闭区间,是因为该区间包含第一个值而不包括最后的值。 + +半闭区间的实用性在于当你使用一个0始的列表(如数组)时,非常方便地从0数到列表的长度。 + + let names = ["Anna", "Alex", "Brian", "Jack"] + let count = names.count + for i in 0..count { + println("第 \(i + 1) 个人叫 \(names[i])") + } + // 第 1 个人叫 Anna + // 第 2 个人叫 Alex + // 第 3 个人叫 Brian + // 第 4 个人叫 Jack + +数组有4个元素,但0..count只数到3(最后一个元素的下标),因为它是半闭区间。关于数组,请查阅数组。 + +##逻辑运算 +逻辑运算的操作对象是逻辑布尔值。Swift 支持基于 C 语言的三个标准逻辑运算。 + +* 逻辑非(!a) +* 逻辑与(a && b) +* 逻辑或(a || b) + + +###逻辑非 +逻辑非运算(!a)对一个布尔值取反,使得true变false,false变true。 + +它是一个前置运算符,需出现在操作数之前,且不加空格。读作非 a,然后我们看以下例子: + + let allowedEntry = false + if !allowedEntry { + println("ACCESS DENIED") + } + // 输出 "ACCESS DENIED" + +if !allowedEntry语句可以读作 "如果 非 alowed entry。",接下一行代码只有在如果 "非 allow entry" 为true,即allowEntry为false时被执行。 +在示例代码中,小心地选择布尔常量或变量有助于代码的可读性,并且避免使用双重逻辑非运算,或混乱的逻辑语句。 + +###逻辑与 +逻辑与(a && b)表达了只有a和b的值都为true时,整个表达式的值才会是true。 +只要任意一个值为false,整个表达式的值就为false。事实上,如果第一个值为false,那么是不去计算第二个值的,因为它已经不可能影响整个表达式的结果了。这被称做 "短路计算(short-circuit evaluation)"。 +以下例子,只有两个Bool值都为true值的时候才允许进入: + + let enteredDoorCode = true + let passedRetinaScan = false + if enteredDoorCode && passedRetinaScan { + println("Welcome!") + } else { + println("ACCESS DENIED") + } + // 输出 "ACCESS DENIED" + +###逻辑或 +逻辑或(a || b)是一个由两个连续的|组成的中置运算符。它表示了两个逻辑表达式的其中一个为true,整个表达式就为true。 + +同逻辑与运算类似,逻辑或也是"短路计算"的,当左端的表达式为true时,将不计算右边的表达式了,因为它不可能改变整个表达式的值了。 +以下示例代码中,第一个布尔值(hasDoorKey)为false,但第二个值(knowsOverridePassword)为true,所以整个表达是true,于是允许进入: + + let hasDoorKey = false + let knowsOverridePassword = true + if hasDoorKey || knowsOverridePassword { + println("Welcome!") + } else { + println("ACCESS DENIED") + } + // 输出 "Welcome!" + +###组合逻辑 +我们可以组合多个逻辑运算来表达一个复合逻辑: + + if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword { + println("Welcome!") + } else { + println("ACCESS DENIED") + } + // 输出 "Welcome!" + +这个例子使用了含多个&&和||的复合逻辑。但无论怎样,&&和||始终只能操作两个值。所以这实际是三个简单逻辑连续操作的结果。我们来解读一下: + +如果我们输入了正确的密码并通过了视网膜扫描; 或者我们有一把有效的钥匙; 又或者我们知道紧急情况下重置的密码,我们就能把门打开进入。 + +前两种情况,我们都不满足,所以前两个简单逻辑的结果是false,但是我们是知道紧急情况下重置的密码的,所以整个复杂表达式的值还是true。 + +###使用括号来明确优先级 +为了一个复杂表达式更容易读懂,在合适的地方使用括号来明确优先级是很有效的,虽然它并非必要的。在上个关于门的权限的例子中,我们给第一个部分加个括号,使用它看起来逻辑更明确: + + if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword { + println("Welcome!") + } else { + println("ACCESS DENIED") + } + // 输出 "Welcome!" + +这括号使得前两个值被看成整个逻辑表达中独立的一个部分。虽然有括号和没括号的输出结果是一样的,但对于读代码的人来说有括号的代码更清晰。可读性比简洁性更重要,请在可以让你代码变清晰地地方加个括号吧! + From 3493fef8f72e9972a6488601da87476d1f5959ea Mon Sep 17 00:00:00 2001 From: Neekey Date: Fri, 27 Jun 2014 16:40:02 +0800 Subject: [PATCH 208/261] =?UTF-8?q?review=20=E5=88=B0=20#=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=8F=82=E6=95=B0=20=E7=AB=A0=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/22_Generics.md | 1052 +++++++++++++++++------------------ 1 file changed, 526 insertions(+), 526 deletions(-) diff --git a/src/chapter2/22_Generics.md b/src/chapter2/22_Generics.md index 14ed065..1cb5771 100644 --- a/src/chapter2/22_Generics.md +++ b/src/chapter2/22_Generics.md @@ -7,14 +7,14 @@ Generic code enables you to write flexible, reusable functions and types that ca Generics are one of the most powerful features of Swift, and much of the Swift standard library is built with generic code. In fact, you’ve been using generics throughout this Language Guide, even if you didn’t realize it. For example, Swift’s Array and Dictionary types are both generic collections. You can create an array that holds Int values, or an array that holds String values, or indeed an array for any other type that can be created in Swift. Similarly, you can create a dictionary to store values of any specified type, and there are no limitations on what that type can be. -泛型是Swift中非常强大的特性之一,而且很多Swift中的基础库是用泛型构建的。事实上,不管你有没有意识到,其实在整本swift介绍中你都会用到泛型。例如,Swift中的Array和Dictionary类型都是泛型集合。你可以创建一个int类型的数组,也可以创建String类型的数组,事实上在Swift中你可以创建任意类型的数组。同样地,你也可以创建一个存储任意类型数据的字典类型; +泛型是Swift中非常强大的特性之一,而且很多Swift的标准库都是用泛型构建的。事实上,不管你有没有意识到,在学习这本swift语言指南的过程中,你已经在使用泛型了。例如,Swift中的Array和Dictionary类型都是泛型集合。你可以创建一个数组用来储存int类型的数值,也可以储存string类型的数值,事实上在Swift中你可以创建数组来储存任意类型的值。同样地,你也可以创建一个存储任意数值类型的字典类型; #The Problem That Generics Solve #泛型解决的问题 Here’s a standard, non-generic function called `swapTwoInts`, which swaps two Int values: -下边代码是一个标准的、非泛型函数`swapTwoInts`, 用于交换两个int值: +下面的代码是一个标准的、非泛型函数`swapTwoInts`, 用于交换两个int值: ``` func swapTwoInts(inout a: Int, inout b: Int) { @@ -42,9 +42,9 @@ println("someInt is now \(someInt), and anotherInt is now \(anotherInt)") The `swapTwoInts` function is useful, but it can only be used with Int values. If you want to swap two String values, or two Double values, you have to write more functions, such as the `swapTwoStrings` and `swapTwoDoubles `functions shown below: -`swapTwoInts`函数是有用的,但是这个函数只能交换int值。如果想交换两个NSString、或者是两个Double类型的值,你不得不写更多的代码,比如`swapTwoStrings`,`swapTwoDoublesfunctions`,如下所示: +`swapTwoInts`函数非常有用,但是它只能交换int值。如果想交换两个String、或者是两个Double类型的值,你不得不再写几个函数,比如`swapTwoStrings`,`swapTwoDoublesfunctions`,如下所示: -``` +``` func swapTwoStrings(inout a: String, inout b: String) { let temporaryA = a a = b @@ -59,19 +59,19 @@ func swapTwoDoubles(inout a: Double, inout b: Double) { You may have noticed that the bodies of the `swapTwoInts`, `swapTwoStrings`, and `swapTwoDoubles` functions are identical. The only difference is the type of the values that they accept (Int, String, and Double). -也许,你已经注意到了,这三个函数的内容基本上是相同的,唯一的区别就是传参类型不一样,分别是Int,String,Double. +也许你已经注意到了,这三个函数的内容基本上是相同的,唯一的区别就是传参类型不一样(Int,String,Double)。 It would be much more useful, and considerably more flexible, to write a single function that could swap two values of any type. This is the kind of problem that generic code can solve. (A generic version of these functions is defined below.) -你会想,如果可以只写一个函数就可以交换两个任意类型的值,那一定会很强大、相当的灵活。这正是泛型所解决的问题。(泛型版的这种函数如下)。 +如果可以只编写一个函数就能提供交换两个任意类型的值的功能的话,这种方式将更加有用和灵活。而这正是泛型所要解决的问题。(下面是使用泛型重新编写的函数)。 ``` NOTE In all three functions, it is important that the types of a and b are defined to be the same as each other. If a and b were not of the same type, it would not be possible to swap their values. Swift is a type-safe language, and does not allow (for example) a variable of type String and a variable of type Double to swap values with each other. Attempting to do so would be reported as a compile-time error. ``` -``` -注意 -在上边的三个函数中,a和b的类型必须是一样的。如果不一样,就不能交互两者的值。Swift是类型安全的语言,不允许一个`String`和`Double`类型变量互相交互值。如果试图操作,会有编译错误。 +``` +注意 +上面的三个函数中,a和b的类型必须是一样的。如果不一样,就不能交换两者的值。Swift是类型安全的语言,不允许一个`String`和`Double`类型变量互相交换值。如果试图进行这样的操作,会出现编译错误。 ``` #Generic Functions @@ -79,7 +79,7 @@ In all three functions, it is important that the types of a and b are defined to Generic functions can work with any type. Here’s a generic version of the `swapTwoInts` function from above, called `swapTwoValues`: -泛型函数可以工作于任何类型。下面就是上边提到的`swapTwoInts`的泛型版本,`swapTwoValues`: +泛型函数可以和任何类型一起使用。下面就是上面的`swapTwoInts`的泛型版本,`swapTwoValues`: ``` func swapTwoValues(inout a: T, inout b: T) { @@ -90,7 +90,7 @@ func swapTwoValues(inout a: T, inout b: T) { ``` The body of the `swapTwoValues` function is identical to the body of the `swapTwoInts` function. However, the first line of `swapTwoValues` is slightly different from `swapTwoInts`. Here’s how the first lines compare: -除了第一行有一点区别之外,`swapTwoValues`和`swapTwoInts`的主题内容是一样的,如下所示: +`swapTwoValues`和`swapTwoInts`的函数主体内容是一样的,仅仅在第一行有一些细微的区别,下面是两者的比较: ``` func swapTwoInts(inout a: Int, inout b: Int) @@ -99,25 +99,25 @@ func swapTwoValues(inout a: T, inout b: T) The generic version of the function uses a placeholder type name (called T, in this case) instead of an actual type name (such as Int, String, or Double). The placeholder type name doesn’t say anything about what T must be, but it does say that both a and b must be of the same type T, whatever T represents. The actual type to use in place of T will be determined each time the `swapTwoValues` function is called. -泛型版本使用了节点类型命名(一般都使用字母T)来代替实际的类型名称(比如Int,String,或者Double)。节点类型定义限制a和b必须是相同类型,而不限制到底是什么类型,T可以代表任意类型。只有当`swapTwoValues`真正调用的时候,才会决定T代表什么类型。 +泛型版本使用了占位符作为类型的名称(在这里使用T作为占位符)来代替实际的类型名称(比如Int,String,或者Double)。占位符类型定义限制a和b必须是相同类型,而不限制到底是什么类型,T可以代表任意类型。只有当`swapTwoValues`真正调用的时候,才会决定T代表什么类型。 The other difference is that the generic function’s name (swapTwoValues) is followed by the placeholder type name (T) inside angle brackets (). The brackets tell Swift that T is a placeholder type name within the`swapTwoValues` function definition. Because T is a placeholder, Swift does not look for an actual type called T. -另一个区别是泛型函数后边跟着的类型(T)是放到尖括号里边的()。尖括号告诉Swift,T是`swapTwoValues`所定义的一个节点类型。由于T表示节点,swift不会查找命名为T的类型。 +另一个区别是泛型函数后边跟着的类型(T)是放到尖括号里边的()。尖括号告诉Swift,T是`swapTwoValues`的函数定义中的一个占位符类型。由于T是一个占位符,因此swift不会去查找是否存在命名为T的类型。 The `swapTwoValues` function can now be called in the same way as `swapTwoInts`, except that it can be passed two values of any type, as long as both of those values are of the same type as each other. Each time `swapTwoValues` is called, the type to use for T is inferred from the types of values passed to the function. - -除了要求传入的两个任何类型值是同一类型外,`swapTwoValues`函数,也可以作为`swapTwoInts`函数被调用。每次`swapTwoValues`被调用,T所代表的类型值都会传给函数。 + +`swapTwoValues`函数现在可以和`swapTwoInts`一样被调用。除此之外,`swapTwoValues`可以接收两个任意类型的参数,只要这两个参数的类型相同。每次`swapTwoValues`被调用,T所代表类型会根据实际传入的参数来确定。 In the two examples below, T is inferred to be Int and String respectively: - -在下边的例子中,T分别指定为Int和String类型。 + +在下边的例子中,T分别代表Int和String类型。 ``` var someInt = 3 var anotherInt = 107 swapTwoValues(&someInt, &anotherInt) -// someInt is now 107, and anotherInt is now +// someInt is now 107, and anotherInt is now var someString = "hello" var anotherString = "world" @@ -128,537 +128,537 @@ swapTwoValues(&someString, &anotherString) ``` NOTE The swapTwoValues function defined above is inspired by a generic function called swap, which is part of the Swift standard library, and is automatically made available for you to use in your apps. If you need the behavior of the swapTwoValues function in your own code, you can use Swift’s existing swap function rather than providing your own implementation. -``` -``` -注意 -上边定义的`swapTwoValues`函数是受`swap`函数的启发而实现的,存在Swift的基础库中,可以在其它类中任意使用。如果你需要`swapTwoValues`类似的功能,可以直接使用Swift中已存在的`swap`方法。 +``` +``` +注意 +上边定义的`swapTwoValues`函数是受到一个泛型函数`swap`的启发而实现的,这个函数被包含在Swift的标准库中,你可以直接在你的应用中使用它。如果在你的代码中需要一个和`swapTwoValues`类似的功能,可以直接使用Swift中已存在的`swap`方法,而不需要自己再实现一遍。 ``` #Type Parameters -#参数类型 -In the swapTwoValues example above, the placeholder type T is an example of a type parameter. Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of matching angle brackets (such as ). - -在上边的`swapTwoValues`例子中,T占位符是一种参数类型实例。参数类型实例指定相同的占位符类型,紧跟在函数名称之后尖括号内(例如)。 +#类型参数 +In the swapTwoValues example above, the placeholder type T is an example of a type parameter. Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of matching angle brackets (such as ). -Once specified, a type parameter can be used to define the type of a function’s parameters (such as the a and b parameters of the swapTwoValues function); or as the function’s return type; or as a type annotation within the body of the function. In each case, the placeholder type represented by the type parameter is replaced with an actual type whenever the function is called. (In the swapTwoValues example above, T was replaced with Int the first time the function was called, and was replaced with String the second time it was called.) - -一旦被指定,参数类型可以用作函数的参数值类型(例如`swapTwoValues`参数中的a和b参数);或者也可以作为函数的返回值类型。这每个例子中,占位符类型可以代表类型参数,当在函数被调用时,会以真实类型代替,在`swapTwoValues`的例子中,当第一次调用时,T会被Int代替,第二次调用中T会被String代替。 +在上边的`swapTwoValues`例子中,占位符T是一个关于使用类型参数的例子。类型参数通过给定一个占位符类型的方式,放置于紧跟在函数名称之后的尖括号内(例如)。 + +Once specified, a type parameter can be used to define the type of a function’s parameters (such as the a and b parameters of the swapTwoValues function); or as the function’s return type; or as a type annotation within the body of the function. In each case, the placeholder type represented by the type parameter is replaced with an actual type whenever the function is called. (In the swapTwoValues example above, T was replaced with Int the first time the function was called, and was replaced with String the second time it was called.) + +一旦被指定,参数类型可以用来定义函数接收的参数(例如`swapTwoValues`函数中的a和b参数);或者也可以作为函数的返回值类型。这每个例子中,被类型参数代表的占位符类型,在函数被调用时,会被真实的参数类型所代替。(在`swapTwoValues`的例子中,当函数被第一次调用时,T会被Int代替,第二次调用中T会被String代替。) You can provide more than one type parameter by writing multiple type parameter names within the angle brackets, separated by commas. - -你可支持多个类型参数,命名在尖括号中,用逗号分开。 + +你可以在尖括号中通过逗号分隔的方式指定多个类型参数名称,来为函数提供多个类型参数的功能。 ‌ #Naming Type Parameters #参数类型命名 -In simple cases where a generic function or generic type needs to refer to a single placeholder type (such as the swapTwoValues generic function above, or a generic collection that stores a single type, such as Array), it is traditional to use the single-character name T for the type parameter. However, you are can use any valid identifier as the type parameter name. - +In simple cases where a generic function or generic type needs to refer to a single placeholder type (such as the swapTwoValues generic function above, or a generic collection that stores a single type, such as Array), it is traditional to use the single-character name T for the type parameter. However, you are can use any valid identifier as the type parameter name. + 在一般的情况下,如果泛型函数或者泛型类型需要指定一个占位符(像上边的`swapTwoValues`泛型函数或者只包含单个类型的泛型集合,比如数组),通常会用一个字符T来代表参数类型。不过,你也可以用任意有效的标示符来表示参数类型。 If you are defining more complex generic functions, or generic types with multiple parameters, it can be useful to provide more descriptive type parameter names. For example, Swift’s Dictionary type has two type parameters—one for its keys and one for its values. If you were writing Dictionary yourself, you might name these two type parameters KeyType and ValueType to remind you of their purpose as you use them within your generic code. - -如果你定义了复杂的泛型函数或者泛型类型,需要多个参数,使用更多的描述类型是有必要的。比如Swift中的字典类型就有两个参数,其中一个键,一个值。如果你自己写字典类型,你也许会定义两个类型`KeyType`和`ValueType`,用来记住在泛型代码中的作用。 + +如果你定义了复杂的泛型函数或者泛型类型,需要多个参数,使用更多的描述类型是有必要的。比如Swift中的字典类型就有两个参数,其中一个键,一个值。如果你自己写字典类型,你也许会定义两个类型`KeyType`和`ValueType`,用来记住在泛型代码中的作用。 ``` NOTE Always give type parameters UpperCamelCase names (such as T and KeyType) to indicate that they are a placeholder for a type, not a value. -``` -``` -注意 -请始终使用大写字母开头的驼峰式命名法(例如T和KeyType)来给类型参数命名,以表明它们是类型的占位符,而非类型值。 +``` +``` +注意 +请始终使用大写字母开头的驼峰式命名法(例如T和KeyType)来给类型参数命名,以表明它们是类型的占位符,而非类型值。 ``` #Generic Types #泛型类型 -In addition to generic functions, Swift enables you to define your own generic types. These are custom classes, structures, and enumerations that can work with any type, in a similar way to Array and Dictionary. - +In addition to generic functions, Swift enables you to define your own generic types. These are custom classes, structures, and enumerations that can work with any type, in a similar way to Array and Dictionary. + 除了泛型函数,Swift可以定义自己的泛型类型。可以是自定义的类、结构、枚举类作用于任何类型。和数组及字段的方式相同。 -This section shows you how to write a generic collection type called Stack. A stack is an ordered set of values, similar to an array, but with a more restricted set of operations than Swift’s Array type. An array allows new items to be inserted and removed at any location in the array. A stack, however, allows new items to be appended only to the end of the collection (known as pushing a new value on to the stack). Similarly, a stack allows items to be removed only from the end of the collection (known as popping a value off the stack). - +This section shows you how to write a generic collection type called Stack. A stack is an ordered set of values, similar to an array, but with a more restricted set of operations than Swift’s Array type. An array allows new items to be inserted and removed at any location in the array. A stack, however, allows new items to be appended only to the end of the collection (known as pushing a new value on to the stack). Similarly, a stack allows items to be removed only from the end of the collection (known as popping a value off the stack). + 这部分展示如何写泛型版本的堆栈。堆栈是一系类值域的集合,和数组类似,但是比数据的有更多的限制的集合。数组允许元素可以从任何位置插入或者删除。堆栈,只允许从集合的顶部插入元素(如同push一个值到堆栈)。同样的,堆栈只允许从集合的顶部删除一个元素(记为从堆栈pop出一个值)。 ``` NOTE The concept of a stack is used by the UINavigationController class to model the view controllers in its navigation hierarchy. You call the UINavigationController class pushViewController:animated: method to add (or push) a view controller on to the navigation stack, and its popViewControllerAnimated: method to remove (or pop) a view controller from the navigation stack. A stack is a useful collection model whenever you need a strict “last in, first out” approach to managing a collection. -``` - -``` -注意 -堆栈的概念被用在`UINavigationController`类中,模拟试图控制器的导航结构。你调用`UINavigationController`的`pushViewController:animated: `方法添加一个视图到堆栈中,调用` popViewControllerAnimated:`方法从堆栈中删除一个试图。堆栈是非常有用的,当你需要一个严格的“先进先出”的方式来管理集合时。 -``` - -The illustration below shows the push / pop behavior for a stack: - -下边图表展示的是堆栈的进入、进出特性: - -![stack](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPushPop_2x.png) - - -1. There are currently three values on the stack. -2. A fourth value is “pushed” on to the top of the stack. -3. The stack now holds four values, with the most recent one at the top. -4. The top item in the stack is removed, or “popped”. -5. After popping a value, the stack once again holds three values. - -1.当前堆栈里有3个值 -2.第四个值从堆栈的顶部push进去 -3.现在堆栈中有4个值,其中最先进的在最顶部 -4.堆栈最顶部的值被移除,或者叫“popped” -5.当推出一个值后,堆栈重新变成了三个值 - -Here’s how to write a non-generic version of a “stack, in this case for a stack of Int values - -下边是如何写一个不是泛型版本的堆栈,这个例子中得堆栈是Int类型: - -``` -struct IntStack { - var items = Int[]() - mutating func push(item: Int) { - items.append(item) - } - mutating func pop() -> Int { - return items.removeLast() - } -} -``` -This structure uses an Array property called items to store the values in the stack. Stack provides two methods, push and pop, to push and pop values on and off the stack. These methods are marked as mutating, because they need to modify (or mutate) the structure’s items array. - -这个结构中使用数组属性`items`去存储堆栈中的数据。堆栈提供两个方法`push` 和`pop`,用于推入数据到堆栈,或者从堆栈推出数据。这些方法定义为`mutating`类型,原因是需要修改结构中得items数组的值。 - -The IntStack type shown above can only be -“used with Int values, however. It would be much more useful to define a generic Stack class, that can manage a stack of any type of value. - -上边的这个`IntStack`类型只能用于Int值。然而,定义泛型类型的堆栈类型,可以管理堆栈中得任意类型,是非常有用的。 - -Here’s a generic version of the same code: - -上边是相同代码的泛型版本: - -``` -struct Stack { - var items = T[]() - mutating func push(item: T) { - items.append(item) - } - mutating func pop() -> T { - return items.removeLast() - } -} -``` -Note how the generic version of Stack is essentially the same as the non-generic version, but with a placeholder type parameter called T instead of an actual type of Int. This “type parameter is written within a pair of angle brackets () immediately after the structure’s name. - -可以注意到,除了使用T代替真实int类型之外,下边的泛型版本的堆栈结构和上边非泛型版本的基本上一样的。这种类型参数是在紧接着结构的名称后跟着一对尖括号(). - -T defines a placeholder name for “some type T” to be provided later on. This future type can be referred to as “T” anywhere within the structure’s definition. In this case, T is used as a placeholder in three places: - -`T`定义了一个名称为”某种类型T“的节点提供给后边用。这种将来类型可以在结构体定义中的任何地方表示为`T`。在这个例子中,`T`在如下的几个地方会被使用: - -1. To create a property called items, which is initialized with an empty array of values of type T -2. To specify that the push method has a single parameter called item, which must be of type T -3. To specify that the value returned by the pop method will be a value of type T - -1.创建成员变量`items`,被初始化为包含类型T的空数组 -2.指定`push`方法有一个参数item,类型为T类型 -3.指定`pop`方法返回结果类型为T - -You create instances of Stack in a similar way to Array and Dictionary, by writing the actual type to be used for this specific stack within angle brackets after the type name when creating a new instance with initializer syntax: - -像创建Array和Dictionary一样,创建一个Stack实例,在初始化时,紧随类型名后边尖括号中写出实际用到的类型: - -``` -var stackOfStrings = Stack() -stackOfStrings.push("uno") -stackOfStrings.push("dos") -stackOfStrings.push("tres") -stackOfStrings.push("cuatro") -// the stack now contains 4 strings -``` - -Here’s how stackOfStrings looks after pushing these four values on to the stack: - -下边展示`stackOfStrings`是如何把四个值push进栈: - -![进栈](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPushedFourStrings_2x.png) - - Popping a value from the stack returns and removes the top value, "cuatro": - - 下图是如何从栈中pop一个值的过程,移除栈最顶上结果,“cuatro”,并返回其值: - -``` - let fromTheTop = stackOfStrings.pop() - // fromTheTop is equal to "cuatro", and the stack now contains 3 strings -``` +``` + +``` +注意 +堆栈的概念被用在`UINavigationController`类中,模拟试图控制器的导航结构。你调用`UINavigationController`的`pushViewController:animated: `方法添加一个视图到堆栈中,调用` popViewControllerAnimated:`方法从堆栈中删除一个试图。堆栈是非常有用的,当你需要一个严格的“先进先出”的方式来管理集合时。 +``` + +The illustration below shows the push / pop behavior for a stack: + +下边图表展示的是堆栈的进入、进出特性: + +![stack](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPushPop_2x.png) + + +1. There are currently three values on the stack. +2. A fourth value is “pushed” on to the top of the stack. +3. The stack now holds four values, with the most recent one at the top. +4. The top item in the stack is removed, or “popped”. +5. After popping a value, the stack once again holds three values. + +1.当前堆栈里有3个值 +2.第四个值从堆栈的顶部push进去 +3.现在堆栈中有4个值,其中最先进的在最顶部 +4.堆栈最顶部的值被移除,或者叫“popped” +5.当推出一个值后,堆栈重新变成了三个值 + +Here’s how to write a non-generic version of a “stack, in this case for a stack of Int values + +下边是如何写一个不是泛型版本的堆栈,这个例子中得堆栈是Int类型: + +``` +struct IntStack { + var items = Int[]() + mutating func push(item: Int) { + items.append(item) + } + mutating func pop() -> Int { + return items.removeLast() + } +} +``` +This structure uses an Array property called items to store the values in the stack. Stack provides two methods, push and pop, to push and pop values on and off the stack. These methods are marked as mutating, because they need to modify (or mutate) the structure’s items array. + +这个结构中使用数组属性`items`去存储堆栈中的数据。堆栈提供两个方法`push` 和`pop`,用于推入数据到堆栈,或者从堆栈推出数据。这些方法定义为`mutating`类型,原因是需要修改结构中得items数组的值。 + +The IntStack type shown above can only be +“used with Int values, however. It would be much more useful to define a generic Stack class, that can manage a stack of any type of value. + +上边的这个`IntStack`类型只能用于Int值。然而,定义泛型类型的堆栈类型,可以管理堆栈中得任意类型,是非常有用的。 + +Here’s a generic version of the same code: + +上边是相同代码的泛型版本: + +``` +struct Stack { + var items = T[]() + mutating func push(item: T) { + items.append(item) + } + mutating func pop() -> T { + return items.removeLast() + } +} +``` +Note how the generic version of Stack is essentially the same as the non-generic version, but with a placeholder type parameter called T instead of an actual type of Int. This “type parameter is written within a pair of angle brackets () immediately after the structure’s name. + +可以注意到,除了使用T代替真实int类型之外,下边的泛型版本的堆栈结构和上边非泛型版本的基本上一样的。这种类型参数是在紧接着结构的名称后跟着一对尖括号(). + +T defines a placeholder name for “some type T” to be provided later on. This future type can be referred to as “T” anywhere within the structure’s definition. In this case, T is used as a placeholder in three places: + +`T`定义了一个名称为”某种类型T“的节点提供给后边用。这种将来类型可以在结构体定义中的任何地方表示为`T`。在这个例子中,`T`在如下的几个地方会被使用: + +1. To create a property called items, which is initialized with an empty array of values of type T +2. To specify that the push method has a single parameter called item, which must be of type T +3. To specify that the value returned by the pop method will be a value of type T + +1.创建成员变量`items`,被初始化为包含类型T的空数组 +2.指定`push`方法有一个参数item,类型为T类型 +3.指定`pop`方法返回结果类型为T + +You create instances of Stack in a similar way to Array and Dictionary, by writing the actual type to be used for this specific stack within angle brackets after the type name when creating a new instance with initializer syntax: + +像创建Array和Dictionary一样,创建一个Stack实例,在初始化时,紧随类型名后边尖括号中写出实际用到的类型: + +``` +var stackOfStrings = Stack() +stackOfStrings.push("uno") +stackOfStrings.push("dos") +stackOfStrings.push("tres") +stackOfStrings.push("cuatro") +// the stack now contains 4 strings +``` + +Here’s how stackOfStrings looks after pushing these four values on to the stack: + +下边展示`stackOfStrings`是如何把四个值push进栈: + +![进栈](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPushedFourStrings_2x.png) + + Popping a value from the stack returns and removes the top value, "cuatro": + + 下图是如何从栈中pop一个值的过程,移除栈最顶上结果,“cuatro”,并返回其值: + +``` + let fromTheTop = stackOfStrings.pop() + // fromTheTop is equal to "cuatro", and the stack now contains 3 strings +``` Here’s how the stack looks after popping its top value: - -下边是推出最顶层数据之后的堆栈效果: - -![移除堆栈效果](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPoppedOneString_2x.png) - - Because it is a generic type, Stack can be used to create a stack of any valid type in Swift, in a similar manner to Array and Dictionary. - - 由于`Stack`是泛型类型,所以在Swift中可以用于创建任何有效类型的栈,方式同`Array`和`Dictionary`。 - -#Type Constraints -#类型约束 - -The swapTwoValues function and the Stack type can work with any type. However, it is sometimes useful to enforce certain type constraints on the types that can be used with generic functions and generic types. Type constraints specify that a type parameter must inherit from a specific class, or conform to a particular protocol or protocol composition. - -`swapTwoValues`函数和`Stack`类型可以作用于任何类型,不过,有的时候对泛型函数和泛型类型上做类型强制约束是非常有用的。类型约束指定参数类型必须继承一个指定类型参数或者遵循一个特定的协议或协议构成。 - -For example, Swift’s Dictionary type places a limitation on the types that can be used as keys for a dictionary. As described in Dictionaries, the type of a dictionary’s keys must be hashable. That is, it must provide a way to make itself uniquely representable. Dictionary needs its keys to be hashable so that it can check whether it already contains a value for a particular key. Without this requirement, Dictionary could not tell whether it should insert or replace a value for a particular key, nor would it be able to find a value for a given key that is already in the dictionary. - -例如,Swift中的`Dictionary`对键值做了约束。在字典的描述中,字典的键值类型必须是可哈希的,就是说他必须有一种方法保证其是唯一的。`Dictionary`约定键值是可哈希的,是为了便于检查其是否已经包含某个特定键的值。如果没有这个约束,就不能告诉是否可以插入或者替换某个特定键的值,也不能查找到某个已经存储在字典中的特定值。 - -This requirement is enforced by a type constraint on the key type for Dictionary, which specifies that the key type must conform to the Hashable protocol, a special protocol defined in the Swift standard library. All of Swift’s basic types (such as String, Int, Double, and Bool) are hashable by default. - -这个需求强制加上一个类型约束作用于Dictionary的键上,而且其键类型必须遵循Hashable协议(Swift 标准库中定义的一个特定协议)。所有的 Swift 基本类型(如String,Int,Double和 Bool)默认都是可哈希。 - -You can define your own type constraints when creating custom generic types, and these constraints provide much of the power of generic programming. Abstract concepts like Hashable characterize types in terms of their conceptual characteristics, rather than their explicit type. - -当你创建自定义泛型类型时,你可以定义你自己的类型约束,当然,这些约束要支持泛型编程的强力特征中的多数。抽象概念如可哈希具有的类型特征是根据它们概念特征来界定的,而不是它们的直接类型特征。 - -##Type Constraint Syntax - -##类型约束语法 - You write type constraints by placing a single class or protocol constraint after a type parameter’s name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types): - - 你可以通过在参数名称的后边以冒号分割,加上类型参数约束。基础的泛型函数的类型约束语法如下(同样的,泛型类型的语法相同) - -``` - func someFunction(someT: T, someU: U) { - // function body goes here - } - ``` -The hypothetical function above has two type parameters. The first type parameter, T, has a type constraint that requires T to be a subclass of SomeClass. The second type parameter, U, has a type constraint that requires U to conform to the protocol SomeProtocol. - -上边函数有两个参数。参数一类型参数为T,需要T必须是`SomeClass`子类;第二个参数类型为U,需要U必须遵循`SomeClass`协议。 - -##Type Constraints in Action -##类型约束行为 - -Here’s a non-generic function called findStringIndex, which is given a String value to find and an array of String values within which to find it. The findStringIndex function returns an optional Int value, which will be the index of the first matching string in the array if it is found, or nil if the string cannot be found: - -这里有个名为findStringIndex的非泛型函数,该函数是去查找包含一指定String值的数组。若查找到匹配的字符串,findStringIndex函数返回该字符串在数组中的索引位置(Int),反之返回nil: - - func findStringIndex(array: String[], valueToFind: String) -> Int? { - for (index, value) in enumerate(array) { - if value == valueToFind { - return index - } - } - return nil - } - -The findStringIndex function can be used to find a string value in an array of strings: - -`findStringIndex`用于查找数组中的指定String值: - - let strings = ["cat", "dog", "llama", "parakeet", "terrapin"] - if let foundIndex = findStringIndex(strings, "llama") { - println("The index of llama is \(foundIndex)") - } - // prints "The index of llama is 2" - -The principle of finding the index of a value in an array isn’t useful only for strings, however. You can write the same functionality as a generic function called findIndex, by replacing any mention of strings with values of some type T instead. - -如果只是查找数组中的指定字符串用处不大,但是你可以写出相同功能的泛型版本`findIndex`,用T代替字符串类型。 - -Here’s how you might expect a generic version of findStringIndex, called findIndex, to be written. Note that the return type of this function is still Int?, because the function returns an optional index number, not an optional value from the array. Be warned, though—this function does not compile, for reasons explained after the example: - -下边是你理想中的`findStringIndex`的泛型版本`findIndex`。注意到函数的返回结果仍然是Int?,这是因为这个函数使用用于返回具体的索引值,而不是搜索值。需要提醒的是,这个函数不会编译,原因后边会说明: - - func findIndex(array: T[], valueToFind: T) -> Int? { - for (index, value) in enumerate(array) { - if value == valueToFind { - return index - } - } - return nil - } - -This function does not compile as written above. The problem lies with the equality check, “if value == valueToFind”. Not every type in Swift can be compared with the equal to operator (==). If you create your own class or structure to represent a complex data model, for example, then the meaning of “equal to” for that class or structure is not something that Swift can guess for you. Because of this, it is not possible to guarantee that this code will work for every possible type T, and an appropriate error is reported when you try to compile the code. - -这个函数按照上边的写法不会编译。原因是因为比较这部分`“if value == valueToFind”. 不是所有的泛型类型都可以用比较操作`==`。如果你创建了自己的函数或者结构代表一个负责的数据模型,那么Swift语言没法猜出这个类或者结果等于的意思。正因为如此,不能保证这个代码可以作用于所有类型T,而且会编译出错。 - -All is not lost, however. The Swift standard library defines a protocol called Equatable, which requires any conforming type to implement the equal to operator (==) and the not equal to operator (!=) to compare any two values of that type. All of Swift’s standard types automatically support the Equatable protocol. - -不过,有解决方法。Swift 标准库中定义了一个Equatable协议,该协议要求任何遵循的类型实现等式符(==)和不等符(!=)对任何两个该类型进行比较。所有的 Swift 标准类型自动支持Equatable协议。 - -Any type that is Equatable can be used safely with the findIndex function, because it is guaranteed to support the equal to operator. To express this fact, you write a type constraint of Equatable as part of the type parameter’s definition when you define the function: - -任何Equatable类型都可以安全的使用在findIndex函数中,它保证可以支持等号操作。为了说明这个事实,你定义函数时,可以写一个Equatable类型约束作为类型参数定义的一部分: - - func findIndex(array: T[], valueToFind: T) -> Int? { - for (index, value) in enumerate(array) { - if value == valueToFind { - return index - } - } - return nil - } - -The single type parameter for findIndex is written as T: Equatable, which means “any type T that conforms to the Equatable protocol. - -`findIndex`的类型参数可以写成`T: Equatable`,表示任意实现` Equatable`协议的类型。 - -The findIndex function now compiles successfully and can be used with any type that is Equatable, such as Double or String: - -`findIndex`类型现在可以成功编译,并且可以用于任意实现了` Equatable`协议的类型,比如`Doubl`e 或者`String`: - - let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3) - // doubleIndex is an optional Int with no value, because 9.3 is not in the array - let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea") - // stringIndex is an optional Int containing a value of 2 - -#Associated Types -#关联类型 -When defining a protocol, it is sometimes useful to declare one or more associated types as part of the protocol’s definition. An associated type gives a placeholder name (or alias) to a type that is used as part of the protocol. The actual type to use for that associated type is not specified until the protocol is adopted. Associated types are specified with the typealias keyword. - -当定义一个协议时,有时声明一个或多个关联类型作为协议的一部分非常有用。一个关联类型给定作用于协议部分的类型一个节点名(或别名)。作用于关联类型实际类型不需要指定,直到协议接受。关联类型被指定为typealias关键字。 - -##Associated Types in Action -##关联类型行为 - -Here’s an example of a protocol called Container, which declares an associated type called ItemType: - -下边是一个协议`Container`,定义了关联类型`ItemType`: - - protocol Container { - typealias ItemType - mutating func append(item: ItemType) - var count: Int { get } - subscript(i: Int) -> ItemType { get } - } - -The Container protocol defines three required capabilities that any container must provide: - -上述协议定义了三个必须支持的兼容协议: - -1. It must be possible to add a new item to the container with an append method. -2. It must be possible to access a count of the items in the container through a count property that returns an Int value. -3. It must be possible to retrieve each item in the container with a subscript that takes an Int index value. - -1. 必须可以通过append方法添加新的元素到容器中。 -2. 必须提供一个属性方法可以获取容器中的元素数目,并返回一个Int值。 -3. 必须可以通过Int索引下标检索每个值。 - -This protocol doesn’t specify how the items in the container should be stored or what type they are allowed to be. The protocol only specifies the three bits of functionality that any type must provide in order to be considered a Container. A conforming type can provide additional functionality, as long as it satisfies these three requirements. - -这个协议没有指定容器中items该如何存储,也没有指定数据是什么类型。协议只是指定了三个任意遵循Container类型所必须的功能点。只要满足这三个条件,遵循协议的类型也可以添加额外的功能。 - -Any type that conforms to the Container protocol must be able to specify the type of values it stores. Specifically, it must ensure that only items of the right type are added to the container, and it must be clear about the type of the items returned by its subscript. - -任意遵循Container协议的类型必须指定所存储的数据值类型。必须保证指定的数据类型可以存储到Container中,而且必须明确可以通过其下标返回结果值。 - -To define these requirements, the Container protocol needs a way to refer to the type of the elements that a container will hold, without knowing what that type is for a specific container. The Container protocol needs to specify that any value passed to the append method must have the same type as the container’s element type, and that the value returned by the container’s subscript will be of the same type as the container’s element type. - -为了定义这些条件,Container协议需要一个方法指定容器里的元素将会保留,不需要知道特定容器的类型。Container协议需要定义任何append方法添加至容器中的值和容器中的元素是相同类型,并且通过容器下标返回的容器元素值的类型是相同的。 - -To achieve this, the Container protocol declares an associated type called ItemType, written as typealias ItemType. The protocol does not define what ItemType is an alias for—that information is left for any conforming type to provide. Nonetheless, the ItemType alias provides a way to refer to the type of the items in a Container, and to define a type for use with the append method and subscript, to ensure that the expected behavior of any Container is enforced. - -为了达到这个目的,container协议声明了一个相关类型ItemType,记为`typealias ItemType`。该协议不会定义ItemType是谁的别名,这个信息留给任何遵循协议的类型来提供。尽管如此,ItemType别名支持一种方法识别在一个容器里的items类型,并定义一种使用在append方法和下标中的类型,保证任何期望的Container行为是强制性的。 - -Here’s a version of the non-generic IntStack type from earlier, adapted to conform to the Container protocol: - -下边是之前的IntStack结构的非泛型版本,适用于遵循Container协议: - - struct IntStack: Container { - // original IntStack implementation - var items = Int[]() - mutating func push(item: Int) { - items.append(item) - } - mutating func pop() -> Int { - return items.removeLast() - } - // conformance to the Container protocol - typealias ItemType = Int - mutating func append(item: Int) { - self.push(item) - } - var count: Int { - return items.count - } - subscript(i: Int) -> Int { - return items[i] - } - } - -The IntStack type implements all three of the Container protocol’s requirements, and in each case wraps part of the IntStack type’s existing functionality to satisfy these requirements. - -`IntStack`类型实现了`Container`协议的所有需求,每个包含部分的功能都满足这些要求。 - -Moreover, IntStack specifies that for this implementation of Container, the appropriate ItemType to use is a type of Int. The definition of typealias ItemType = Int turns the abstract type of ItemType into a concrete type of Int for this implementation of the Container protocol. - -此外, `IntStack`指定了`Container`的实现,合适的`ItemType`被用作Int类型。对于Container协议实现来说,定义 `typealias ItemType = Int`,将抽象的`ItemType`类型转换为具体的Int类型。 - -Thanks to Swift’s type inference, you don’t actually need to declare a concrete ItemType of Int as part of the definition of IntStack. Because IntStack conforms to all of the requirements of the Container protocol, Swift can infer the appropriate ItemType to use, simply by looking at the type of the append method’s item parameter and the return type of the subscript. Indeed, if you delete the typealias ItemType = Int line from the code above, everything still works, because it is clear what type should be used for ItemType. - -感谢Swift类型参考,你实际上不用在IntStack定义部分声明具体的Int的ItemType。由于IntStack满足Container协议的所有要求,只需通过简单的查找append方法中的item参数类型和下标返回的类型,Swift就可以推断出合适的ItemType来使用。实际上,如果你删除了上述代码中的 typealias ItemType = Int,仍可以正常运行,因为它清楚的知道ItemType使用的是何种类型。 - -You can also make the generic Stack type conform to the Container protocol: - -你同样可以生成遵循Containner协议的泛型Stack类型: - - struct Stack: Container { - // original Stack implementation - var items = T[]() - mutating func push(item: T) { - items.append(item) - } - mutating func pop() -> T { - return items.removeLast() - } - // conformance to the Container protocol - mutating func append(item: T) { - self.push(item) - } - var count: Int { - return items.count - } - subscript(i: Int) -> T { - return items[i] - } - } - -This time, the placeholder type parameter T is used as the type of the append method’s item parameter and the return type of the subscript. Swift can therefore infer that T is the appropriate type to use as the ItemType for this particular container. - -这个时候,占位符T被用作append方法的item参数类型和下标的返回类型。Swift因此也就可以推断出用作ItemType的T的合适类型。 - -#Extending an Existing Type to Specify an Associated Type -#扩展一个存在的类型为一指定关联类型 - -You can extend an existing type to add conformance to a protocol, as described in Adding Protocol Conformance with an Extension. This includes a protocol with an associated type. - -你可以用[使用扩展来添加协议兼容性](../chapter2/21_Protocols.html)的方法,扩展一个已存在的类型遵循指定协议。这包含一个关联类型的协议。 - -Swift’s Array type already provides an append method, a count property, and a subscript with an Int index to retrieve its elements. These three capabilities match the requirements of the Container protocol. This means that you can extend Array to conform to the Container protocol simply by declaring that Array adopts the protocol. You do this with an empty extension, as described in Declaring Protocol Adoption with an Extension: - -Swift中的数据类型已经提供了`append`方法、`count`属性方法和下标索引方法。这三个功能满足`Container`协议。也就是说你可以扩展数组方法遵循Container协议,只需简单声明Array适用于该协议。你用一个空的扩展来这么做,就像[通过扩展补充协议声明](../chapter2/21_Protocols.html)中描述的一样。 - - extension Array: Container {} - -Array’s existing append method and subscript enable Swift to infer the appropriate type to use for ItemType, just as for the generic Stack type above. After defining this extension, you can use any Array as a Container. - -数组存在的append方法和下标索引方法使Swift可以推断出ItemType的实际类型,像上边的泛型版`Stack`一样。当定义了这个扩展之后,你可以用这个数组作为容器。 - -#Where Clauses -#Where语句 - -Type constraints, as described in Type Constraints, enable you to define requirements on the type parameters associated with a generic function or type. - -类型约束确保相关的泛型函数和类型的指定参数满足需求。 - -It can also be useful to define requirements for associated types. You do this by defining where clauses as part of a type parameter list. A where clause enables you to require that an associated type conforms to a certain protocol, and/or that certain type parameters and associated types be the same. You write a where clause by placing the where keyword immediately after the list of type parameters, followed by one or more constraints for associated types, and/or one or more equality relationships between types and associated types. - -定义关联类型的满足条件也是非常有用的。你可以通过定义where语句作为类型参数的一部分。通过where语句指定一个关联类型遵循一个特定的协议,以及(或)那个特定的类型参数和关联类型可以是相同的。可以在类型参数后,紧跟着where语句,where语句中跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型的等于关系。 - -The example below defines a generic function called allItemsMatch, which checks to see if two Container instances contain the same items in the same order. The function returns a Boolean value of true if all items match and a value of false if they do not. - -下边的例子定义了泛型函数`allItemsMatch`,用于判断两个`Container`实例是否包含相同的元素并具有相同的顺序。如果所有元素满足条件,函数返回true,否则返回false。 - -The two containers to be checked do not have to be the same type of container (although they can be), but they do have to hold the same type of items. This requirement is expressed through a combination of type constraints and where clauses: - -需要检查的两个`containers`,不需要是相同类型的`container`(当然也可以是相同的),但是他们的元素必须相同。这个需求通过一个类型约束和where语句相结合来表示: - - func allItemsMatch< - C1: Container, C2: Container - where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> - (someContainer: C1, anotherContainer: C2) -> Bool { - // check that both containers contain the same number of items - if someContainer.count != anotherContainer.count { - return false - } - // check each pair of items to see if they are equivalent - for i in 0..someContainer.count { - if someContainer[i] != anotherContainer[i] { - return false - } - } - // all items match, so return true - return true - } - -This function takes two arguments called `someContainer` and `anotherContainer`. The `someContainer` argument is of type `C1`, and the `anotherContainer` argument is of type `C2`. Both `C1` and `C2` are placeholder type parameters for two container types to be determined when the function is called. - -这个函数有两个参数`someContainer`和`anotherContainer`。`someContainer`参数是`C1`类型,`anotherContainer`参数是`C2`类型。`C1`和`C2`都是占位符,真正的参数类型等函数运行时决定。 - -The function’s type parameter list places the following requirements on the two type parameters: - -这个函数的类型参数列紧随在两个类型参数需求的后面: - - C1 must conform to the Container protocol (written as C1: Container). - - C2 must also conform to the Container protocol (written as C2: Container). - - The ItemType for C1 must be the same as the ItemType for C2 (written as C1.ItemType == C2.ItemType). - - The ItemType for C1 must conform to the Equatable protocol (written as C1.ItemType: Equatable). - -``` - C1必须遵循`Container`协议(写法`C1: Container`) - C2必须遵循`Container`协议(写法`C2: Container`) - C1的ItemType必须和C2的ItemType相等(写法C1.ItemType == C2.ItemType) - C1的ItemType必须遵循`Equatable`协议 -``` - -The third and fourth requirements are defined as part of a where clause, and are written after the where keyword as part of the function’s type parameter list. - -第三四个要求在where语句中定义,并作为参数类型值部分内容放到where语句后。 - -These requirements mean: - -这几个要求意义是: - - someContainer is a container of type C1. - - anotherContainer is a container of type C2. - - someContainer and anotherContainer contain the same type of items. - - The items in someContainer can be checked with the not equal operator (!=) to see if they are different from each other. - -``` -someContainer是C1类型的anotherContainer -anotherContainer是C2类型的anotherContainer -someContainer和anotherContainer包含相同类型的元素 -someContainer中的元素可以通过调用不等于操作(!=)判断他们是否不同 -``` - -The third and fourth requirements combine to mean that the items in anotherContainer can also be checked with the != operator, because they are exactly the same type as the items in someContainer. - -第三四个需求结合起来标示`anotherContainer`的元素同样可以调用`!=`操作,因为他们和`someContainer`中的类型是一样的。 - -These requirements enable the allItemsMatch function to compare the two containers, even if they are of a different container type. - -这些要求使得`allItemsMatch`函数可以比较两个`containers`,即便他们具有不同的`containers`类型。 - -The allItemsMatch function starts by checking that both containers contain the same number of items. If they contain a different number of items, there is no way that they can match, and the function returns false. - -`allItemsMatch`函数会先检查`containers`是否包含相同数目的元素。如果包含内容不相同,他们互相也就不相等,结果返回`false`。 - -After making this check, the function iterates over all of the items in someContainer with a for-in loop and the half-closed range operator (..). For each item, the function checks whether the item from someContainer is not equal to the corresponding item in anotherContainer. If the two items are not equal, then the two containers do not match, and the function returns false. - -如果具有相同的元素个数,函数通过`for-in`循环和半闭区间操作(..)来迭代`someContainer`中的所有元素。循环中,`someContainer`中的元素是否和`anotherContainer`中的对应元素相同。如果有不相同的,函数返回`false`。 - -If the loop finishes without finding a mismatch, the two match, and the function returns true. - -如果循环过程中没有一个不相同的,则`containers`相等,结果返回`true`。 - -Here’s how the `allItemsMatch` function looks in action: - -这里演示了`allItemsMatch`函数运算的过程: - - var stackOfStrings = Stack() - stackOfStrings.push("uno") - stackOfStrings.push("dos") - stackOfStrings.push("tres") - var arrayOfStrings = ["uno", "dos", "tres"] - if allItemsMatch(stackOfStrings, arrayOfStrings) { - println("All items match.") - } else { - println("Not all items match.") - } - // prints "All items match." - -The example above creates a Stack instance to store String values, and pushes three strings onto the stack. The example also creates an Array instance initialized with an array literal containing the same three strings as the stack. Even though the stack and the array are of a different type, they both conform to the Container protocol, and both contain the same type of values. You can therefore call the allItemsMatch function with these two containers as its arguments. In the example above, the allItemsMatch function correctly reports that all of the items in the two containers match. - -上边的例子中创建一个`Stack`实例存储字符串值,然后`push`三个字符串到堆栈中。同样创建一个数组实例初始化为包含三个字符串,和堆栈元素相同。尽管堆栈和数组是不同的数据类型,但是他们遵循相同的协议,并且包含相同的数据类型,相同的数据值。所以你可以调用`allItemsMatch`去比较两者。在上边的例子中,`allItemsMatch`函数会返回两者包含的所有元素相匹配。 + +下边是推出最顶层数据之后的堆栈效果: + +![移除堆栈效果](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPoppedOneString_2x.png) + + Because it is a generic type, Stack can be used to create a stack of any valid type in Swift, in a similar manner to Array and Dictionary. + + 由于`Stack`是泛型类型,所以在Swift中可以用于创建任何有效类型的栈,方式同`Array`和`Dictionary`。 + +#Type Constraints +#类型约束 + +The swapTwoValues function and the Stack type can work with any type. However, it is sometimes useful to enforce certain type constraints on the types that can be used with generic functions and generic types. Type constraints specify that a type parameter must inherit from a specific class, or conform to a particular protocol or protocol composition. + +`swapTwoValues`函数和`Stack`类型可以作用于任何类型,不过,有的时候对泛型函数和泛型类型上做类型强制约束是非常有用的。类型约束指定参数类型必须继承一个指定类型参数或者遵循一个特定的协议或协议构成。 + +For example, Swift’s Dictionary type places a limitation on the types that can be used as keys for a dictionary. As described in Dictionaries, the type of a dictionary’s keys must be hashable. That is, it must provide a way to make itself uniquely representable. Dictionary needs its keys to be hashable so that it can check whether it already contains a value for a particular key. Without this requirement, Dictionary could not tell whether it should insert or replace a value for a particular key, nor would it be able to find a value for a given key that is already in the dictionary. + +例如,Swift中的`Dictionary`对键值做了约束。在字典的描述中,字典的键值类型必须是可哈希的,就是说他必须有一种方法保证其是唯一的。`Dictionary`约定键值是可哈希的,是为了便于检查其是否已经包含某个特定键的值。如果没有这个约束,就不能告诉是否可以插入或者替换某个特定键的值,也不能查找到某个已经存储在字典中的特定值。 + +This requirement is enforced by a type constraint on the key type for Dictionary, which specifies that the key type must conform to the Hashable protocol, a special protocol defined in the Swift standard library. All of Swift’s basic types (such as String, Int, Double, and Bool) are hashable by default. + +这个需求强制加上一个类型约束作用于Dictionary的键上,而且其键类型必须遵循Hashable协议(Swift 标准库中定义的一个特定协议)。所有的 Swift 基本类型(如String,Int,Double和 Bool)默认都是可哈希。 + +You can define your own type constraints when creating custom generic types, and these constraints provide much of the power of generic programming. Abstract concepts like Hashable characterize types in terms of their conceptual characteristics, rather than their explicit type. + +当你创建自定义泛型类型时,你可以定义你自己的类型约束,当然,这些约束要支持泛型编程的强力特征中的多数。抽象概念如可哈希具有的类型特征是根据它们概念特征来界定的,而不是它们的直接类型特征。 + +##Type Constraint Syntax + +##类型约束语法 + You write type constraints by placing a single class or protocol constraint after a type parameter’s name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types): + + 你可以通过在参数名称的后边以冒号分割,加上类型参数约束。基础的泛型函数的类型约束语法如下(同样的,泛型类型的语法相同) + +``` + func someFunction(someT: T, someU: U) { + // function body goes here + } + ``` +The hypothetical function above has two type parameters. The first type parameter, T, has a type constraint that requires T to be a subclass of SomeClass. The second type parameter, U, has a type constraint that requires U to conform to the protocol SomeProtocol. + +上边函数有两个参数。参数一类型参数为T,需要T必须是`SomeClass`子类;第二个参数类型为U,需要U必须遵循`SomeClass`协议。 + +##Type Constraints in Action +##类型约束行为 + +Here’s a non-generic function called findStringIndex, which is given a String value to find and an array of String values within which to find it. The findStringIndex function returns an optional Int value, which will be the index of the first matching string in the array if it is found, or nil if the string cannot be found: + +这里有个名为findStringIndex的非泛型函数,该函数是去查找包含一指定String值的数组。若查找到匹配的字符串,findStringIndex函数返回该字符串在数组中的索引位置(Int),反之返回nil: + + func findStringIndex(array: String[], valueToFind: String) -> Int? { + for (index, value) in enumerate(array) { + if value == valueToFind { + return index + } + } + return nil + } + +The findStringIndex function can be used to find a string value in an array of strings: + +`findStringIndex`用于查找数组中的指定String值: + + let strings = ["cat", "dog", "llama", "parakeet", "terrapin"] + if let foundIndex = findStringIndex(strings, "llama") { + println("The index of llama is \(foundIndex)") + } + // prints "The index of llama is 2" + +The principle of finding the index of a value in an array isn’t useful only for strings, however. You can write the same functionality as a generic function called findIndex, by replacing any mention of strings with values of some type T instead. + +如果只是查找数组中的指定字符串用处不大,但是你可以写出相同功能的泛型版本`findIndex`,用T代替字符串类型。 + +Here’s how you might expect a generic version of findStringIndex, called findIndex, to be written. Note that the return type of this function is still Int?, because the function returns an optional index number, not an optional value from the array. Be warned, though—this function does not compile, for reasons explained after the example: + +下边是你理想中的`findStringIndex`的泛型版本`findIndex`。注意到函数的返回结果仍然是Int?,这是因为这个函数使用用于返回具体的索引值,而不是搜索值。需要提醒的是,这个函数不会编译,原因后边会说明: + + func findIndex(array: T[], valueToFind: T) -> Int? { + for (index, value) in enumerate(array) { + if value == valueToFind { + return index + } + } + return nil + } + +This function does not compile as written above. The problem lies with the equality check, “if value == valueToFind”. Not every type in Swift can be compared with the equal to operator (==). If you create your own class or structure to represent a complex data model, for example, then the meaning of “equal to” for that class or structure is not something that Swift can guess for you. Because of this, it is not possible to guarantee that this code will work for every possible type T, and an appropriate error is reported when you try to compile the code. + +这个函数按照上边的写法不会编译。原因是因为比较这部分`“if value == valueToFind”. 不是所有的泛型类型都可以用比较操作`==`。如果你创建了自己的函数或者结构代表一个负责的数据模型,那么Swift语言没法猜出这个类或者结果等于的意思。正因为如此,不能保证这个代码可以作用于所有类型T,而且会编译出错。 + +All is not lost, however. The Swift standard library defines a protocol called Equatable, which requires any conforming type to implement the equal to operator (==) and the not equal to operator (!=) to compare any two values of that type. All of Swift’s standard types automatically support the Equatable protocol. + +不过,有解决方法。Swift 标准库中定义了一个Equatable协议,该协议要求任何遵循的类型实现等式符(==)和不等符(!=)对任何两个该类型进行比较。所有的 Swift 标准类型自动支持Equatable协议。 + +Any type that is Equatable can be used safely with the findIndex function, because it is guaranteed to support the equal to operator. To express this fact, you write a type constraint of Equatable as part of the type parameter’s definition when you define the function: + +任何Equatable类型都可以安全的使用在findIndex函数中,它保证可以支持等号操作。为了说明这个事实,你定义函数时,可以写一个Equatable类型约束作为类型参数定义的一部分: + + func findIndex(array: T[], valueToFind: T) -> Int? { + for (index, value) in enumerate(array) { + if value == valueToFind { + return index + } + } + return nil + } + +The single type parameter for findIndex is written as T: Equatable, which means “any type T that conforms to the Equatable protocol. + +`findIndex`的类型参数可以写成`T: Equatable`,表示任意实现` Equatable`协议的类型。 + +The findIndex function now compiles successfully and can be used with any type that is Equatable, such as Double or String: + +`findIndex`类型现在可以成功编译,并且可以用于任意实现了` Equatable`协议的类型,比如`Doubl`e 或者`String`: + + let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3) + // doubleIndex is an optional Int with no value, because 9.3 is not in the array + let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea") + // stringIndex is an optional Int containing a value of 2 + +#Associated Types +#关联类型 +When defining a protocol, it is sometimes useful to declare one or more associated types as part of the protocol’s definition. An associated type gives a placeholder name (or alias) to a type that is used as part of the protocol. The actual type to use for that associated type is not specified until the protocol is adopted. Associated types are specified with the typealias keyword. + +当定义一个协议时,有时声明一个或多个关联类型作为协议的一部分非常有用。一个关联类型给定作用于协议部分的类型一个节点名(或别名)。作用于关联类型实际类型不需要指定,直到协议接受。关联类型被指定为typealias关键字。 + +##Associated Types in Action +##关联类型行为 + +Here’s an example of a protocol called Container, which declares an associated type called ItemType: + +下边是一个协议`Container`,定义了关联类型`ItemType`: + + protocol Container { + typealias ItemType + mutating func append(item: ItemType) + var count: Int { get } + subscript(i: Int) -> ItemType { get } + } + +The Container protocol defines three required capabilities that any container must provide: + +上述协议定义了三个必须支持的兼容协议: + +1. It must be possible to add a new item to the container with an append method. +2. It must be possible to access a count of the items in the container through a count property that returns an Int value. +3. It must be possible to retrieve each item in the container with a subscript that takes an Int index value. + +1. 必须可以通过append方法添加新的元素到容器中。 +2. 必须提供一个属性方法可以获取容器中的元素数目,并返回一个Int值。 +3. 必须可以通过Int索引下标检索每个值。 + +This protocol doesn’t specify how the items in the container should be stored or what type they are allowed to be. The protocol only specifies the three bits of functionality that any type must provide in order to be considered a Container. A conforming type can provide additional functionality, as long as it satisfies these three requirements. + +这个协议没有指定容器中items该如何存储,也没有指定数据是什么类型。协议只是指定了三个任意遵循Container类型所必须的功能点。只要满足这三个条件,遵循协议的类型也可以添加额外的功能。 + +Any type that conforms to the Container protocol must be able to specify the type of values it stores. Specifically, it must ensure that only items of the right type are added to the container, and it must be clear about the type of the items returned by its subscript. + +任意遵循Container协议的类型必须指定所存储的数据值类型。必须保证指定的数据类型可以存储到Container中,而且必须明确可以通过其下标返回结果值。 + +To define these requirements, the Container protocol needs a way to refer to the type of the elements that a container will hold, without knowing what that type is for a specific container. The Container protocol needs to specify that any value passed to the append method must have the same type as the container’s element type, and that the value returned by the container’s subscript will be of the same type as the container’s element type. + +为了定义这些条件,Container协议需要一个方法指定容器里的元素将会保留,不需要知道特定容器的类型。Container协议需要定义任何append方法添加至容器中的值和容器中的元素是相同类型,并且通过容器下标返回的容器元素值的类型是相同的。 + +To achieve this, the Container protocol declares an associated type called ItemType, written as typealias ItemType. The protocol does not define what ItemType is an alias for—that information is left for any conforming type to provide. Nonetheless, the ItemType alias provides a way to refer to the type of the items in a Container, and to define a type for use with the append method and subscript, to ensure that the expected behavior of any Container is enforced. + +为了达到这个目的,container协议声明了一个相关类型ItemType,记为`typealias ItemType`。该协议不会定义ItemType是谁的别名,这个信息留给任何遵循协议的类型来提供。尽管如此,ItemType别名支持一种方法识别在一个容器里的items类型,并定义一种使用在append方法和下标中的类型,保证任何期望的Container行为是强制性的。 + +Here’s a version of the non-generic IntStack type from earlier, adapted to conform to the Container protocol: + +下边是之前的IntStack结构的非泛型版本,适用于遵循Container协议: + + struct IntStack: Container { + // original IntStack implementation + var items = Int[]() + mutating func push(item: Int) { + items.append(item) + } + mutating func pop() -> Int { + return items.removeLast() + } + // conformance to the Container protocol + typealias ItemType = Int + mutating func append(item: Int) { + self.push(item) + } + var count: Int { + return items.count + } + subscript(i: Int) -> Int { + return items[i] + } + } + +The IntStack type implements all three of the Container protocol’s requirements, and in each case wraps part of the IntStack type’s existing functionality to satisfy these requirements. + +`IntStack`类型实现了`Container`协议的所有需求,每个包含部分的功能都满足这些要求。 + +Moreover, IntStack specifies that for this implementation of Container, the appropriate ItemType to use is a type of Int. The definition of typealias ItemType = Int turns the abstract type of ItemType into a concrete type of Int for this implementation of the Container protocol. + +此外, `IntStack`指定了`Container`的实现,合适的`ItemType`被用作Int类型。对于Container协议实现来说,定义 `typealias ItemType = Int`,将抽象的`ItemType`类型转换为具体的Int类型。 + +Thanks to Swift’s type inference, you don’t actually need to declare a concrete ItemType of Int as part of the definition of IntStack. Because IntStack conforms to all of the requirements of the Container protocol, Swift can infer the appropriate ItemType to use, simply by looking at the type of the append method’s item parameter and the return type of the subscript. Indeed, if you delete the typealias ItemType = Int line from the code above, everything still works, because it is clear what type should be used for ItemType. + +感谢Swift类型参考,你实际上不用在IntStack定义部分声明具体的Int的ItemType。由于IntStack满足Container协议的所有要求,只需通过简单的查找append方法中的item参数类型和下标返回的类型,Swift就可以推断出合适的ItemType来使用。实际上,如果你删除了上述代码中的 typealias ItemType = Int,仍可以正常运行,因为它清楚的知道ItemType使用的是何种类型。 + +You can also make the generic Stack type conform to the Container protocol: + +你同样可以生成遵循Containner协议的泛型Stack类型: + + struct Stack: Container { + // original Stack implementation + var items = T[]() + mutating func push(item: T) { + items.append(item) + } + mutating func pop() -> T { + return items.removeLast() + } + // conformance to the Container protocol + mutating func append(item: T) { + self.push(item) + } + var count: Int { + return items.count + } + subscript(i: Int) -> T { + return items[i] + } + } + +This time, the placeholder type parameter T is used as the type of the append method’s item parameter and the return type of the subscript. Swift can therefore infer that T is the appropriate type to use as the ItemType for this particular container. + +这个时候,占位符T被用作append方法的item参数类型和下标的返回类型。Swift因此也就可以推断出用作ItemType的T的合适类型。 + +#Extending an Existing Type to Specify an Associated Type +#扩展一个存在的类型为一指定关联类型 + +You can extend an existing type to add conformance to a protocol, as described in Adding Protocol Conformance with an Extension. This includes a protocol with an associated type. + +你可以用[使用扩展来添加协议兼容性](../chapter2/21_Protocols.html)的方法,扩展一个已存在的类型遵循指定协议。这包含一个关联类型的协议。 + +Swift’s Array type already provides an append method, a count property, and a subscript with an Int index to retrieve its elements. These three capabilities match the requirements of the Container protocol. This means that you can extend Array to conform to the Container protocol simply by declaring that Array adopts the protocol. You do this with an empty extension, as described in Declaring Protocol Adoption with an Extension: + +Swift中的数据类型已经提供了`append`方法、`count`属性方法和下标索引方法。这三个功能满足`Container`协议。也就是说你可以扩展数组方法遵循Container协议,只需简单声明Array适用于该协议。你用一个空的扩展来这么做,就像[通过扩展补充协议声明](../chapter2/21_Protocols.html)中描述的一样。 + + extension Array: Container {} + +Array’s existing append method and subscript enable Swift to infer the appropriate type to use for ItemType, just as for the generic Stack type above. After defining this extension, you can use any Array as a Container. + +数组存在的append方法和下标索引方法使Swift可以推断出ItemType的实际类型,像上边的泛型版`Stack`一样。当定义了这个扩展之后,你可以用这个数组作为容器。 + +#Where Clauses +#Where语句 + +Type constraints, as described in Type Constraints, enable you to define requirements on the type parameters associated with a generic function or type. + +类型约束确保相关的泛型函数和类型的指定参数满足需求。 + +It can also be useful to define requirements for associated types. You do this by defining where clauses as part of a type parameter list. A where clause enables you to require that an associated type conforms to a certain protocol, and/or that certain type parameters and associated types be the same. You write a where clause by placing the where keyword immediately after the list of type parameters, followed by one or more constraints for associated types, and/or one or more equality relationships between types and associated types. + +定义关联类型的满足条件也是非常有用的。你可以通过定义where语句作为类型参数的一部分。通过where语句指定一个关联类型遵循一个特定的协议,以及(或)那个特定的类型参数和关联类型可以是相同的。可以在类型参数后,紧跟着where语句,where语句中跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型的等于关系。 + +The example below defines a generic function called allItemsMatch, which checks to see if two Container instances contain the same items in the same order. The function returns a Boolean value of true if all items match and a value of false if they do not. + +下边的例子定义了泛型函数`allItemsMatch`,用于判断两个`Container`实例是否包含相同的元素并具有相同的顺序。如果所有元素满足条件,函数返回true,否则返回false。 + +The two containers to be checked do not have to be the same type of container (although they can be), but they do have to hold the same type of items. This requirement is expressed through a combination of type constraints and where clauses: + +需要检查的两个`containers`,不需要是相同类型的`container`(当然也可以是相同的),但是他们的元素必须相同。这个需求通过一个类型约束和where语句相结合来表示: + + func allItemsMatch< + C1: Container, C2: Container + where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> + (someContainer: C1, anotherContainer: C2) -> Bool { + // check that both containers contain the same number of items + if someContainer.count != anotherContainer.count { + return false + } + // check each pair of items to see if they are equivalent + for i in 0..someContainer.count { + if someContainer[i] != anotherContainer[i] { + return false + } + } + // all items match, so return true + return true + } + +This function takes two arguments called `someContainer` and `anotherContainer`. The `someContainer` argument is of type `C1`, and the `anotherContainer` argument is of type `C2`. Both `C1` and `C2` are placeholder type parameters for two container types to be determined when the function is called. + +这个函数有两个参数`someContainer`和`anotherContainer`。`someContainer`参数是`C1`类型,`anotherContainer`参数是`C2`类型。`C1`和`C2`都是占位符,真正的参数类型等函数运行时决定。 + +The function’s type parameter list places the following requirements on the two type parameters: + +这个函数的类型参数列紧随在两个类型参数需求的后面: + + C1 must conform to the Container protocol (written as C1: Container). + + C2 must also conform to the Container protocol (written as C2: Container). + + The ItemType for C1 must be the same as the ItemType for C2 (written as C1.ItemType == C2.ItemType). + + The ItemType for C1 must conform to the Equatable protocol (written as C1.ItemType: Equatable). + +``` + C1必须遵循`Container`协议(写法`C1: Container`) + C2必须遵循`Container`协议(写法`C2: Container`) + C1的ItemType必须和C2的ItemType相等(写法C1.ItemType == C2.ItemType) + C1的ItemType必须遵循`Equatable`协议 +``` + +The third and fourth requirements are defined as part of a where clause, and are written after the where keyword as part of the function’s type parameter list. + +第三四个要求在where语句中定义,并作为参数类型值部分内容放到where语句后。 + +These requirements mean: + +这几个要求意义是: + + someContainer is a container of type C1. + + anotherContainer is a container of type C2. + + someContainer and anotherContainer contain the same type of items. + + The items in someContainer can be checked with the not equal operator (!=) to see if they are different from each other. + +``` +someContainer是C1类型的anotherContainer +anotherContainer是C2类型的anotherContainer +someContainer和anotherContainer包含相同类型的元素 +someContainer中的元素可以通过调用不等于操作(!=)判断他们是否不同 +``` + +The third and fourth requirements combine to mean that the items in anotherContainer can also be checked with the != operator, because they are exactly the same type as the items in someContainer. + +第三四个需求结合起来标示`anotherContainer`的元素同样可以调用`!=`操作,因为他们和`someContainer`中的类型是一样的。 + +These requirements enable the allItemsMatch function to compare the two containers, even if they are of a different container type. + +这些要求使得`allItemsMatch`函数可以比较两个`containers`,即便他们具有不同的`containers`类型。 + +The allItemsMatch function starts by checking that both containers contain the same number of items. If they contain a different number of items, there is no way that they can match, and the function returns false. + +`allItemsMatch`函数会先检查`containers`是否包含相同数目的元素。如果包含内容不相同,他们互相也就不相等,结果返回`false`。 + +After making this check, the function iterates over all of the items in someContainer with a for-in loop and the half-closed range operator (..). For each item, the function checks whether the item from someContainer is not equal to the corresponding item in anotherContainer. If the two items are not equal, then the two containers do not match, and the function returns false. + +如果具有相同的元素个数,函数通过`for-in`循环和半闭区间操作(..)来迭代`someContainer`中的所有元素。循环中,`someContainer`中的元素是否和`anotherContainer`中的对应元素相同。如果有不相同的,函数返回`false`。 + +If the loop finishes without finding a mismatch, the two match, and the function returns true. + +如果循环过程中没有一个不相同的,则`containers`相等,结果返回`true`。 + +Here’s how the `allItemsMatch` function looks in action: + +这里演示了`allItemsMatch`函数运算的过程: + + var stackOfStrings = Stack() + stackOfStrings.push("uno") + stackOfStrings.push("dos") + stackOfStrings.push("tres") + var arrayOfStrings = ["uno", "dos", "tres"] + if allItemsMatch(stackOfStrings, arrayOfStrings) { + println("All items match.") + } else { + println("Not all items match.") + } + // prints "All items match." + +The example above creates a Stack instance to store String values, and pushes three strings onto the stack. The example also creates an Array instance initialized with an array literal containing the same three strings as the stack. Even though the stack and the array are of a different type, they both conform to the Container protocol, and both contain the same type of values. You can therefore call the allItemsMatch function with these two containers as its arguments. In the example above, the allItemsMatch function correctly reports that all of the items in the two containers match. + +上边的例子中创建一个`Stack`实例存储字符串值,然后`push`三个字符串到堆栈中。同样创建一个数组实例初始化为包含三个字符串,和堆栈元素相同。尽管堆栈和数组是不同的数据类型,但是他们遵循相同的协议,并且包含相同的数据类型,相同的数据值。所以你可以调用`allItemsMatch`去比较两者。在上边的例子中,`allItemsMatch`函数会返回两者包含的所有元素相匹配。 From b2647efda07edf4a6189f4d31bf43c910fe2a13c Mon Sep 17 00:00:00 2001 From: crazygx Date: Mon, 30 Jun 2014 20:53:35 +0800 Subject: [PATCH 209/261] type casting reviewed --- src/chapter2/18_Type_Casting.md | 52 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/chapter2/18_Type_Casting.md b/src/chapter2/18_Type_Casting.md index 384d367..83837f7 100644 --- a/src/chapter2/18_Type_Casting.md +++ b/src/chapter2/18_Type_Casting.md @@ -7,11 +7,11 @@ Type casting in Swift is implemented with the is and as operators. These two ope You can also use type casting to check whether a type conforms to a protocol, as described in Checking for Protocol Conformance. # 类型检查 -类型检查是检查实例类型的方法,并且可以用来类型转换,可以让实例找到自己所在的继承树,以及在继承树中上下转换类型。 +类型检查的目的是为了检查实例的类型,并且可以用来类型转换,可以让实例找到自己所在的继承树,以及在继承树中上下转换类型。 类型检查使用`is`和`as`操作符来实现。这两个操作符提供了一种简单明了的方式来进行类型检查和类型转换。 -你还可以使用类型检查来检查类型是否符合接口,以及是否和接口描述保持一致 ,就像[Checking for Protocol Conformance](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_363)描述的那样。 +你还可以使用类型检查来检查类型是否符合接口,以及是否和接口描述保持一致 ,如[Checking for Protocol Conformance](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_363)小节所述。 ##Defining a Class Hierarchy for Type Casting @@ -21,9 +21,9 @@ The first snippet defines a new base class called MediaItem. This class provides ## 为类型检查定义一个继承树 -你可以使用类型检查来检查一个实例的具体类型,也可以把实例转化为继承树中的另一种类型。下面的三个代码片段定义的类层次结构和包含这些类的实例数组,作为类型转换的一个例子使用。 +你可以使用类型检查来检查一个实例的具体类型,也可以把实例转化为继承树中的另一种类型。下面的三个代码片段定义一个类的继承关系和包含这些类实例的数组,作为类型转换的一个例子使用。 -第一个片段定义了一个名为`MediaItem`新的基类。这个类提供基本功能。具体来说,它声明一个`String`类型的`name`属性,以及一个`init`名称初始值设定项。 (假设所有的媒体项目,包括所有的电影和歌曲,将有一个名称。) +第一个片段定义了一个名为`MediaItem`的基类。这个类提供数字媒体处理库中其他类的基本功能。具体来说,它声明一个`String`类型的`name`属性,以及一个叫`init`的初始化方法。 (假设所有的媒体项目,包括所有的电影和歌曲,将有一个名称。) class MediaItem { var name: String @@ -33,7 +33,7 @@ The first snippet defines a new base class called MediaItem. This class provides } The next snippet defines two subclasses of MediaItem. The first subclass, Movie, encapsulates additional information about a movie or film. It adds a director property on top of the base MediaItem class, with a corresponding initializer. The second subclass, Song, adds an artist property and initializer on top of the base class: -接下来的代码定义了`MediaItem`的两个子类。第一个子类,`Movie`,封装了有关`Movie`或`Movie`的附加信息。它增加了一个属性`director`,还有相应的初始化方法。第二个`Song`,增加了一个`artist`和初始化方法: +接下来的代码定义了`MediaItem`的两个子类。第一个子类`Movie`,封装了有关`Movie`的附加信息。它增加了属性`director`及其初始化方法。第二个子类`Song`,增加了属性`artist`及其初始化方法: class Movie: MediaItem { var director: String @@ -52,7 +52,7 @@ The next snippet defines two subclasses of MediaItem. The first subclass, Movie, } The final snippet creates a constant array called library, which contains two Movie instances and three Song instances. The type of the library array is inferred by initializing it with the contents of an array literal. Swift’s type checker is able to deduce that Movie and Song have a common superclass of MediaItem, and so it infers a type of MediaItem[] for the library array: -最后的代码创建一个常量数组叫做`library`,其中包含两个`Movie`实例和三首`Song`的实例。`library`数组的类型是由它里面包含的内容决定的。Swift能够识别出`Movie`和`Song`有MediaItem一个共同的父类,所以它会推断出`library`是一个`MediaItem[] `类型的数组。 +最后的代码创建一个常量数组`library`,其中包含两个`Movie`实例和三首`Song`的实例。`library`数组的类型是由它里面包含的内容决定的。Swift能够识别出`Movie`和`Song`有MediaItem一个共同的父类,所以它会推断出`library`是一个`MediaItem[] `类型的数组。 let library = [ Movie(name: "Casablanca", director: "Michael Curtiz"), @@ -64,7 +64,7 @@ The final snippet creates a constant array called library, which contains two Mo // the type of "library" is inferred to be MediaItem[] The items stored in library are still Movie and Song instances behind the scenes. However, if you iterate over the contents of this array, the items you receive back are typed as MediaItem, and not as Movie or Song. In order to work with them as their native type, you need to check their type, or downcast them to a different type, as described below. -在系统里存储在`library`中的项目仍然是`Movie`和`Song`实例。但是,如果你遍历这个数组,您会收到回项目类型为`MediaItem`,而不是`Movie`或`Song`。为了使用他们原来的类型,你需要检查它们的类型,或将它们向下转换为不同的类型,如下所述。 +`library`中的子元素仍然是`Movie`或`Song`的实例。但是,如果你遍历这个数组,返回的是`MediaItem`类型的实例,而不是`Movie`或`Song`。为了使用他们自身的类型,你需要检查它们的类型,或将它们向下转换为不同的类型,如下所述。 ##Checking Type @@ -74,9 +74,9 @@ The example below defines two variables, movieCount and songCount, which count t ## 检查类型 -使用类型检查运算符(`is`)来检查一个实例是否是一个子类的类型。如果是,则返回`true`,否则返回`false` +使用类型检查运算符(`is`)来检查一个实例是否是一个类的子类。如果是,则返回`true`,否则返回`false`。 -下面的例子定义了两个变量,`movieCount`和`songCount`,用来计算数组中`Movie` 和`Song` 的数量。 +下面的例子定义了两个变量,`movieCount`和`songCount`,用来统计数组中`Movie` 和`Song` 的数量。 var movieCount = 0 var songCount = 0 @@ -98,7 +98,7 @@ item is Movie returns true if the current MediaItem is a Movie instance and fals 这个例子遍历了数组中的所有元素,每一次循环,都会把数组中的一个实例赋值给`item`。 -如果`item`是`Movie`类型,则返回 `true`否则返回`false`,同样,也会检查`item`是否是`Song`类型。最后, `movieCount`和`songCount`就能统计出到底每个类型的数量。 +如果`item`是`Movie`类型,则返回 `true`否则返回`false`。同样,也会检查`item`是否是`Song`类型。最后,`movieCount`和`songCount`即为每个类型的实例数。 ##Downcasting @@ -110,23 +110,23 @@ Because downcasting can fail, the type cast operator comes in two different form ## 向下转型 有时候,一些实例的类型是它父类的类型,这个时候你就需要使用`as`操作符进行向下转型。 -因为向下转型可能会失败,类型转换操作符带有两种不同形式。可选形式( optional form)` as? `返回一个你试图下转成的类型的可选值(optional value)。强制形式 `as` 把试图向下转型和强制解包(force-unwraps)结果作为一个混合动作。 +因为向下转型可能会失败,类型转换操作符带有两种不同形式。可选形式( optional form)` as? `返回一个你试图下转成的类型的可选值(optional value)。强制形式 `as` 则会先向下转型并把转型结果强制解包(force-unwraps)。 Use the optional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast. Use the forced form of the type cast operator (as) only when you are sure that the downcast will always succeed. This form of the operator will trigger a runtime error if you try to downcast to an incorrect class type. -当你不确定向下转型能否成功时,使用`as?`,当转化失败时,他会返回`nil `,这样你就能判断是否转换成功。 +当你不确定向下转型能否成功时,使用`as?`,转型失败时返回`nil `。这样你就能判断是否转型成功。 -当你对类型确定的对象进行向下转型时,使用`as`,当转化失败时,他会抛出一个错误。 +当你对类型确定的对象进行向下转型时,使用`as`,转型失败就会抛错。 The example below iterates over each MediaItem in library, and prints an appropriate description for each item. To do this, it needs to access each item as a true Movie or Song, and not just as a MediaItem. This is necessary in order for it to be able to access the director or artist property of a Movie or Song for use in the description. In this example, each item in the array might be a Movie, or it might be a Song. You don’t know in advance which actual class to use for each item, and so it is appropriate to use the optional form of the type cast operator (as?) to check the downcast each time through the loop: -下面的例子,迭代了`library`里的每一个` MediaItem` ,并打印出适当的描述。要这样做,`item`需要真正作为`Movie` 或 `Song`的类型来使用。不仅仅是作为 `MediaItem`。为了能够使用`Movie` 或 `Song`的 `director` 或 `artist`属性,这是必要的。 +如下例,我们的目的是遍历`library`里的每一个` MediaItem` ,并打印出正确的描述信息。为了达到这个目的,`item`需要真正作为`Movie` 或 `Song`的类型来使用,而非仅仅是 `MediaItem`。因为我们在打印描述信息时,必须要用到`Movie`的`director`属性或 `Song`的`artist`属性。 -在这个示例中,数组中的每一个`item`可能是 `Movie` 或 `Song`。 事前你不知道每个`item`的真实类型,所以这里使用可选形式的类型转换 (`as?`)去检查循环里的每次下转。 +数组中的每一个`item`可能是 `Movie` 或 `Song`。 事先你不知道每个`item`的真实类型,所以使用可选形式的类型转换 (`as?`)去检查每次向下转型。 for item in library { if let movie = item as? Movie { @@ -143,13 +143,13 @@ In this example, each item in the array might be a Movie, or it might be a Song. // Song: 'Never Gonna Give You Up', by Rick Astley The example starts by trying to downcast the current item as a Movie. Because item is a MediaItem instance, it’s possible that it might be a Movie; equally, it’s also possible that it might a Song, or even just a base MediaItem. Because of this uncertainty, the as? form of the type cast operator returns an optional value when attempting to downcast to a subclass type. The result of item as Movie is of type Movie?, or “optional Movie”. -示例首先试图将 `item` 下转为 `Movie`。因为 `item` 是一个 `MediaItem` 类型的实例,它可能是一个`Movie`;同样,它可能是一个 `Song`,或者仅仅是基类 `MediaItem`。因为不确定,`as?`形式试图下转时返还一个可选值。 `item as Movie` 的返回值是`Movie?`类型或 “optional Movie”。 +示例中,因为 `item` 是一个 `MediaItem` 类型的实例,它可能是一个`Movie`,所以我们首先试图将 `item` 下转为 `Movie`。同样,它也可能是一个 `Song`,或者仅仅是基类 `MediaItem`。所以,`as?`形式试图下转时返还一个可选值。 `item as Movie` 的返回值是`Movie?`类型或 “optional Movie”。 Downcasting to Movie fails when applied to the two Song instances in the library array. To cope with this, the example above uses optional binding to check whether the optional Movie actually contains a value (that is, to find out whether the downcast succeeded.) This optional binding is written “if let movie = item as? Movie”, which can be read as: “Try to access item as a Movie. If this is successful, set a new temporary constant called movie to the value stored in the returned optional Movie.” -当把数组`library`中的两个`Song`对象进行向下转型为`Movie`时,会转型失败。为了解决这个问题,示例使用了一个临时的赋值来检查是否转型成功。临时赋值的写法是`if let movie = item as? Movie`,这句话的意思是“尝试把`item`转型为`Movie`,如果转型成功,则把转化后的对象存储在一个临时的变量`movie`中” +把数组`library`中的两个`Song`对象进行向下转型为`Movie`时,会转型失败。所以,使用临时赋值来检查是否转型成功。临时赋值的写法是`if let movie = item as? Movie`,意思就是“尝试把`item`转型为`Movie`,如果转型成功,则把转化后的对象存储在临时变量`movie`中“。 If the downcasting succeeds, the properties of movie are then used to print a description for that Movie instance, including the name of its director. A similar principle is used to check for Song instances, and to print an appropriate description (including artist name) whenever a Song is found in the library. @@ -161,7 +161,7 @@ If the downcasting succeeds, the properties of movie are then used to print a de >注意 ->实际上,类型转换并没有对对象进行修改,它底层仍然保持一致,只是使用时,被当作一种类型来处理和访问。 +>实际上,类型转换并没有对实例进行修改,只是使用时,被当作一种类型来处理和访问。 ##Type Casting for Any and AnyObject @@ -178,8 +178,8 @@ Use Any and AnyObject only when you explicitly need the behavior and capabilitie `Swift` 提供了两种特殊类型,用来表示非特定类型。 -`AnyObject`可以表示任何类类型的实例。 -`Any` 可以代表任何类型的实例,除了函数类型。 +`AnyObject`表示任何类类型的实例。 +`Any` 表示任何类型的实例,函数类型除外。 注意: 只有当你确定需要使用`Any`和`AnyObject`的特性的时候,再使用它们。一般情况下,最好还是指定具体的类型。 @@ -188,7 +188,7 @@ Use Any and AnyObject only when you explicitly need the behavior and capabilitie When working with Cocoa APIs, it is common to receive an array with a type of AnyObject[], or “an array of values of any object type”. This is because Objective-C does not have explicitly typed arrays. However, you can often be confident about the type of objects contained in such an array just from the information you know about the API that provided the array. ### AnyObject -当使用Cocoa APIs的时候,经常接收到一个AnyObject的数组,它里面可以放入任何类型。这是因为Object-C 没有确定类型的数组。尽管如此,通过对API的学习和了解,你仍然可以放心的使用这种API。 +使用Cocoa APIs时,返回值为AnyObject类型的数组很常见。这是因为Objective-C 没有确定类型的数组。尽管如此,如果对具体API熟悉的话,你仍然可以放心的使用这个API。 In these situations, you can use the forced version of the type cast operator (as) to downcast each item in the array to a more specific class type than AnyObject, without the need for optional unwrapping. @@ -197,7 +197,7 @@ The example below defines an array of type AnyObject[] and populates this array 在这些情况下,您可以使用as 把AnyObject转化为一个具体的类型,而不需要进行拆包。 -下面的例子定义了一个类型为AnyObject[]的数组,并填充了三个Movie类型的对象。 +下面的例子定义了一个类型为AnyObject[]的数组,包含三个Movie类型的对象。 let someObjects: AnyObject[] = [ Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"), @@ -218,7 +218,7 @@ Because this array is known to contain only Movie instances, you can downcast an // Movie: 'Alien', dir. Ridley Scott For an even shorter form of this loop, downcast the someObjects array to a type of Movie[] instead of downcasting each item: -上面的代码可以简写,你可以直接把数组进行转型而不用对数组中的每一个对象进行转型。 +上面的代码可以简写,你可以直接把数组转型而不用对数组中的每一个对象转型。 for movie in someObjects as Movie[] { println("Movie: '\(movie.name)', dir. \(movie.director)") @@ -233,7 +233,7 @@ Here’s an example of using Any to work with a mix of different types, includin ### Any -下面的例子中,使用了`Any`和其他多种混合类型,包括一些非类类型。在这个例子中,我们创建了一个`things`数组用来存储任何类型的元素。 +下面的例子中,使用了`Any`来处理包含了多种混合类型,甚至一些非类类型的场景。在这个例子中,我们创建了一个`things`数组用来存储任何类型的元素。 var things = Any[]() @@ -252,7 +252,7 @@ You can use the is and as operators in a switch statement’s cases to discover `things`数组包含两个`int`值,两个`Double`值,一个字符串值,一个元组,和一个Movie对象。 -你可以在`switch`语句中使用`is`和`as`操作符来确定数组中`Any`和`AnyObject`变量的的具体类型。下面的例子遍历了数组`things`中的每一个元素,并确定了他们的类型。为了打印元素的值,一些`switch` 语句把元素赋值给一个指定的类型。 +你可以在`switch`语句中使用`is`和`as`操作符来确定数组中`Any`和`AnyObject`变量的的具体类型。如下遍历数组`things`中的每一个元素,并确定他们的类型。为了打印元素的值,一些`switch` 语句把元素赋值给一个指定的类型。 for thing in things { switch thing { @@ -290,4 +290,4 @@ You can use the is and as operators in a switch statement’s cases to discover >注意 -> 这个示例使用 `as` 而不是 `as?` 来进行类型转换,因为在`switch`1上下文中,类型检查时安全的。 +> 这个示例使用 `as` 而不是 `as?` 来进行类型转换,因为在`switch`上下文中,类型检查是安全的。 From 7e6b582125963f3576a687174f8b302af09755aa Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Tue, 1 Jul 2014 09:42:25 +0800 Subject: [PATCH 210/261] =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/06_Functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chapter2/06_Functions.md b/src/chapter2/06_Functions.md index cd97784..d76f541 100644 --- a/src/chapter2/06_Functions.md +++ b/src/chapter2/06_Functions.md @@ -40,7 +40,7 @@ All of this information is rolled up into the function’s definition, which is The definition describes what the function does, what it expects to receive, and what it returns when it is done. The definition makes it easy for the function to be called elsewhere in your code in a clear and unambiguous way: -函数定义描述了函数是做什么的,期望接收什么和执行结束后返回什么。这个定义使得在代码中的任何地方可以清晰明确地调用函数变得简单。 +函数定义描述了函数是做什么的,期望接收什么和执行结束后返回什么。这样在代码中的任何地方都可以清楚明确地调用函数,而这种函数定义使这些变得更简单。 ```js println(sayHello("Anna")) @@ -73,7 +73,7 @@ println(sayHelloAgain("Anna")) // prints "Hello again, Anna!” ``` -# Function Parameters and Return Values 函数参数和返回值 +# Function Parameters and Return Values 函数的参数和返回值 Function parameters and return values are extremely flexible in Swift. You can define anything from a simple utility function with a single unnamed parameter to a complex function with expressive parameter names and different parameter options. From 7857c01e232be01c0d9e48128d27ebfc4ecc1bb6 Mon Sep 17 00:00:00 2001 From: Jayson Date: Tue, 1 Jul 2014 13:17:51 +0800 Subject: [PATCH 211/261] Update 05_Control_Flow.md --- src/chapter2/05_Control_Flow.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index 94e6fbb..268a3b4 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -95,8 +95,7 @@ for name in names { You can also iterate over a dictionary to access its key-value pairs. Each item in the dictionary is returned as a (key, value) tuple when the dictionary is iterated, and you can decompose the (key, value) tuple’s members as explicitly named constants for use within in the body of the for-in loop. Here, the dictionary’s keys are decomposed into a constant called animalName, and the dictionary’s values are decomposed into a constant called legCount: -你也同样可以遍历字典中的key-value。遍历时,字典中的每个元素都以```(key,value)```元组结构返回,你也可以在```for-in```中将元组中的key,value当做常量显式的分解出来。这里,key被分解为为常量```animalName```,value被分解为 -```legCount```: +你也同样可以遍历字典中的key-value。遍历时,字典中的每个元素都以```(key,value)```元组结构返回,你也可以在```for-in```中将元组中的key,value当做常量显式的分解出来。这里,key被分解为为常量```animalName```,value被分解为```legCount```: ``` “let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] From a475891937ded197b8f6bcf68555fa3dd0738b6c Mon Sep 17 00:00:00 2001 From: Jayson Date: Tue, 1 Jul 2014 13:20:02 +0800 Subject: [PATCH 212/261] Update 05_Control_Flow.md --- src/chapter2/05_Control_Flow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index 268a3b4..ef17bc9 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -108,7 +108,7 @@ for (animalName, legCount) in numberOfLegs { ``` -Items in a Dictionary may not necessarily be iterated in the same order as they were inserted. The contents of a Dictionary are inherently unordered, and iterating over them does not guarantee the order in which they will be retrieved. For more on arrays and dictionaries, see Collection Types.) +Items in a Dictionary may not necessarily be iterated in the same order as they were inserted. The contents of a Dictionary are inherently unordered, and iterating over them does not guarantee the order in which they will be retrieved. For more on arrays and dictionaries, see Collection Types. ```Dictionary```中的元素的顺序在被遍历时可能和我们插入它的顺序不同,这是由于```Dictionary```自身就是无序的,它在被遍历时无法保证元素的顺序。想了解更多关于数组和字典的内容,请查阅[集合类型](link)一章。 From 0295c0c4125e705eb4532b82bc1bfc2f36a43268 Mon Sep 17 00:00:00 2001 From: Jayson Date: Tue, 1 Jul 2014 13:21:34 +0800 Subject: [PATCH 213/261] Update 05_Control_Flow.md --- src/chapter2/05_Control_Flow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index ef17bc9..1e4c245 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -110,7 +110,7 @@ for (animalName, legCount) in numberOfLegs { Items in a Dictionary may not necessarily be iterated in the same order as they were inserted. The contents of a Dictionary are inherently unordered, and iterating over them does not guarantee the order in which they will be retrieved. For more on arrays and dictionaries, see Collection Types. -```Dictionary```中的元素的顺序在被遍历时可能和我们插入它的顺序不同,这是由于```Dictionary```自身就是无序的,它在被遍历时无法保证元素的顺序。想了解更多关于数组和字典的内容,请查阅[集合类型](link)一章。 +Dictionary中的元素的顺序在被遍历时可能和我们插入它的顺序不同,这是由于```Dictionary```自身就是无序的,它在被遍历时无法保证元素的顺序。想了解更多关于数组和字典的内容,请查阅[集合类型](link)一章。 In addition to arrays and dictionaries, you can also use the for-in loop to iterate over the Character values in a string: From 0988b688d6f9007f5e6275f6943d32434b78ae70 Mon Sep 17 00:00:00 2001 From: jayson Date: Tue, 1 Jul 2014 13:22:47 +0800 Subject: [PATCH 214/261] =?UTF-8?q?=E5=8A=A0=E5=85=A5=E8=8B=B1=E6=96=87?= =?UTF-8?q?=E5=AF=B9=E7=85=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/05_Control_Flow.md | 342 ++++++++++++++++++++++++++++---- 1 file changed, 301 insertions(+), 41 deletions(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index ad9eccd..014cc30 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -1,24 +1,39 @@ # 控制流(Control Flow) -## by moxin.xt +Swift provides all the familiar control flow constructs of C-like languages. These include for and while loops to perform a task multiple times; if and switch statements to execute different branches of code based on certain conditions; and statements such as break and continue to transfer the flow of execution to another point in your code. Swift提供类似C语言的控制流语法,比如```for```和```while```循环;```if```和```switch```的条件判断语句语句以及``` break```,```continue```这种跳出循环的语句。 +In addition to the traditional for-condition-increment loop found in C, Swift adds a for-in loop that makes it easy to iterate over arrays, dictionaries, ranges, strings, and other sequences. + Swift除了支持类似C语言这种```for-condition-increment```的语句外,还支持```for-in```这种循环语句,可以轻松的遍历数组,字典,字符串等序列。 +Swift’s switch statement is also considerably more powerful than its counterpart in C. The cases of a switch statement do not “fall through” to the next case in Swift, avoiding common C errors caused by missing break statements. Cases can match many different types of pattern, including range matches, tuples, and casts to a specific type. Matched values in a switch case can be bound to temporary constants or variables for use within the case’s body, and complex matching conditions can be expressed with a where clause for each case. + Swift的```switch```语句和C语言相比很强大,它不会像C语言那样,因为在case的分支中忘记写break而执行了下一条case的语句。同时case语句可以进行不同类型的模式匹配,包括区间匹配,元组匹配和特定类型描述。```switch```语句中待匹配的值可以绑定到临时变量或常量上,便于```case```中得代码访问,同时,一些复杂的匹配条件可已通过```where```关键字来补充。 #For循环 +A for loop performs a set of statements a certain number of times. Swift provides two kinds of for loop: + ```for```循环可以将一段代码执行若干次。Swift提供两种```for```循环: +for-in performs a set of statements for each item in a range, sequence, collection, or progression. +for-condition-increment performs a set of statements until a specific condition is met, typically by incrementing a counter each time the loop ends. + * ```for-in```遍历并返回序列或集合中的每一个元素,执行一段代码 * ```for-condition-increment```在符合某种条件下(通常是在每次循环结束时对计数器+1),返回序列或集合中的每一个元素,执行一段代码。 ##For-In -你可以使用```for-in```来遍历集合里的元素;一定范围内的数字;数组中的元素或者字符串中的字符。下面这个例子可以打印出一个5次循环的结果: +You use the for-in loop to iterate over collections of items, such as ranges of numbers, items in an array, or characters in a string. + +你可以使用```for-in```来遍历集合里的元素;一定范围内的数字;数组中的元素或者字符串中的字符。 + +This example prints the first few entries in the five-times-table: + +下面这个例子可以打印出一个5次循环的结果: ``` for index in 1...5{ @@ -29,17 +44,21 @@ for index in 1...5{ // 3 times 5 is 15 // 4 times 5 is 20 // 5 times 5 is 25 - ``` +The collection of items being iterated is a closed range of numbers from 1 to 5 inclusive, as indicated by the use of the closed range operator (...). The value of index is set to the first number in the range (1), and the statements inside the loop are executed. In this case, the loop contains only one statement, which prints an entry from the five-times-table for the current value of index. After the statement is executed, the value of index is updated to contain the second value in the range (2), and the println function is called again. This process continues until the end of the range is reached. + 我们首先通过(```...```)语句创建了一个数字集合,然后枚举集合中的每个元素,```index```值首先被赋值为range(```1```),然后执行循环体内的代码,上面这个例子中循环体内只有一行代码,作用是打印出```index```的值。当这行代码执行完后,```index```值会被更新,被赋值为range(```2```),```println```再次被调用,如此反复,直到循环结束。 +In the example above, index is a constant whose value is automatically set at the start of each iteration of the loop. As such, it does not have to be declared before it is used. It is implicitly declared simply by its inclusion in the loop declaration, without the need for a let declaration keyword. + 上面例子中```index```是个常量,在每次循环开始的时候会被自动赋值,因此它不需要在使用前通过```let```声明,因为它会被```for-in```隐式声明。 - 注意 +>注意 - 常量```index```的作用域只存在于循环体内。如果你想在循环体外查看```index```的值或者使用它 - 你需要在循环开始前声明它。 +>常量```index```的作用域只存在于循环体内。如果你想在循环体外查看```index```的值或者使用它,你需要在循环开始前声明它。 + +If you don’t need each value from the range, you can ignore the values by using an underscore in place of a variable name: 如果你在遍历某个集合时并不关心集合中的元素,你可以通过下划线来代替集合中的元素变量名: @@ -53,9 +72,14 @@ for _ in 1...power { println("\(base) to the power of \(power) is \(answer)") // prints "3 to the power of 10 is 59049” ``` + +This example calculates the value of one number to the power of another (in this case, 3 to the power of 10). It multiplies a starting value of 1 (that is, 3 to the power of 0) by 3, ten times, using a half-closed loop that starts with 0 and ends with 9. This calculation doesn’t need to know the individual counter values each time through the loop—it simply needs to execute the loop the correct number of times. The underscore character _ (used in place of a loop variable) causes the individual values to be ignored and does not provide access to the current value during each iteration of the loop. + 这个例子用来计算某个数字的某次方(这里是计算3的10次方)。它用起始值1乘以3,循环10次。这种计算并不需要知道当前是第几次循环(循环的计数器),只需要保证它执行次数是正确的即可。 -我们还可以使用```for-in```遍历数组中的元素: +Use the for-in loop with an array to iterate over its items:我们还可以 + +使用```for-in```遍历数组中的元素: ``` “let names = ["Anna", "Alex", "Brian", "Jack"] @@ -68,7 +92,11 @@ for name in names { // Hello, Jack!” ``` -你也同样可以遍历字典中的key-value。遍历时,字典中的每个元素都以```(key,value)```元组结构返回,你也可以在```for-in```中将元组中的key,value当做常量显式的分解出来。这里,key被分解为为常量```animalName```,value被分解为```legCount```: + +You can also iterate over a dictionary to access its key-value pairs. Each item in the dictionary is returned as a (key, value) tuple when the dictionary is iterated, and you can decompose the (key, value) tuple’s members as explicitly named constants for use within in the body of the for-in loop. Here, the dictionary’s keys are decomposed into a constant called animalName, and the dictionary’s values are decomposed into a constant called legCount: + +你也同样可以遍历字典中的key-value。遍历时,字典中的每个元素都以```(key,value)```元组结构返回,你也可以在```for-in```中将元组中的key,value当做常量显式的分解出来。这里,key被分解为为常量```animalName```,value被分解为 +```legCount```: ``` “let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] @@ -80,7 +108,12 @@ for (animalName, legCount) in numberOfLegs { // cats have 4 legs” ``` -```Dictionary```中的元素的顺序在被遍历时可能和我们插入它的顺序不同,这是由于```Dictionary```自身就是无序的,它在被遍历时无法保证元素的顺序。想了解更多关于数组和字典的内容,请查阅Collection Type一章。 + +Items in a Dictionary may not necessarily be iterated in the same order as they were inserted. The contents of a Dictionary are inherently unordered, and iterating over them does not guarantee the order in which they will be retrieved. For more on arrays and dictionaries, see Collection Types.) + +```Dictionary```中的元素的顺序在被遍历时可能和我们插入它的顺序不同,这是由于```Dictionary```自身就是无序的,它在被遍历时无法保证元素的顺序。想了解更多关于数组和字典的内容,请查阅[集合类型](link)一章。 + +In addition to arrays and dictionaries, you can also use the for-in loop to iterate over the Character values in a string: 除了数组和字典,你同样可以使用```for-in```来遍历字符串中的```Character```: @@ -97,6 +130,8 @@ for (animalName, legCount) in numberOfLegs { ``` ## For-Condition-Increment +In addition to for-in loops, Swift supports traditional C-style for loops with a condition and an incrementer: + 除了使用```for-in```这种循环语句,Swift还提供了传统的C风格的``for```循环语句,通常它需要一个循环执行条件和一个累加器: ``` @@ -107,14 +142,25 @@ for (animalName, legCount) in numberOfLegs { // index is 1 // index is 2 ``` + +Here’s the general form of this loop format: + 下面是这种语法通用的语句: for ```initialization```;```condition```;```increment```{ ```statements``` } +Semicolons separate the three parts of the loop’s definition, as in C. However, unlike C, Swift doesn’t need parentheses around the entire “initialization; condition; increment” block. + 和C语言一样,循环语句被分号分割为3部分。但是和C语言不同的是,Swift不需要使用括号将"initialization;condition;increment"包围起来。 +The loop is executed as follows: + +1,When the loop is first entered, the initialization expression is evaluated once, to set up any constants or variables that are needed for the loop. +2,The condition expression is evaluated. If it evaluates to false, the loop ends, and code execution continues after the for loop’s closing brace (}). If the expression evaluates to true, code execution continues by executing the statements inside the braces. +3,After all statements are executed, the increment expression is evaluated. It might increase or decrease the value of a counter, or set one of the initialized variables to a new value based on the outcome of the statements. After the increment expression has been evaluated, execution returns to step 2, and the condition expression is evaluated again. + 循环执行顺序如下: 1,循环开始时执行一次initialization语句,初始化循环使用的常量或变量。 @@ -123,6 +169,8 @@ for ```initialization```;```condition```;```increment```{ 3,当循环体内的代码被执行完时,increment语句被执行。通常情况是增加或减少计数器的值,然后执行第2步,condition语句会被再次执行。 +The loop format and execution process described above is shorthand for (and equivalent to) the outline below: + 上面的for循环结构也可以如下表示: ```initialization``` @@ -131,6 +179,8 @@ while ```condition``` { ```increment``` } +Constants and variables declared within the initialization expression (such as var index = 0) are only valid within the scope of the for loop itself. To retrieve the final value of index after the loop ends, you must declare index before the loop’s scope begins: + 在for循环初始化时创建的变量或者常量只在循环体内有效,如果想获取循环结束时的```index```值,你必须将```index```显式的声明到循环语句前: ``` @@ -143,12 +193,18 @@ for index = 0; index < 3; ++index { // index is 2 println("The loop statements were executed \(index) times") // prints "The loop statements were executed 3 times” - ``` +Note that the final value of index after this loop is completed is 3, not 2. The last time the increment statement ++index is called, it sets index to 3, which causes index < 3 to equate to false, ending the loop. + 注意循环结束时,```index```值是```3```而不是```2```。当```++index```被最后一次执行时,```index```被赋值为```3```,这回导致```index<3```返回```false```,结束循环。 ##While循环 +A while loop performs a set of statements until a condition becomes false. These kinds of loops are best used when the number of iterations is not known before the first iteration “begins. Swift provides two kinds of while loop: + +while evaluates its condition at the start of each pass through the loop. +do-while evaluates its condition at the end of each pass through the loop. + 一个```while```语句会循环执行一段代码直到条件变为```false```。这种循环语句在处理循环次数不确定的情况时非常有效。Swift提供两种```while```循环: * ```while```语句会在执行循环提前判断执行条件。 @@ -156,6 +212,10 @@ println("The loop statements were executed \(index) times") ###while +A while loop starts by evaluating a single condition. If the condition is true, a set of statements is repeated until the condition becomes false. + +Here’s the general form of a while loop: + 一个```while```循环从判断执行条件开始。如果条件为```true```,则循环执行循环体内的代码,知道条件变为```false```。下面是通用的```while```语法格式: ``` @@ -163,10 +223,20 @@ while condition { statements } ``` + +This example plays a simple game of Snakes and Ladders (also known as Chutes and Ladders): + 下面是一个简单的Snakes and Ladders游戏(也叫Chutes and Ladders) 【图】 +The rules of the game are as follows: + +The board has 25 squares, and the aim is to land on or beyond square 25. +Each turn, you roll a six-sided dice and move by that number of squares, following the horizontal path indicated by the dotted arrow above. +If your turn ends at the bottom of a ladder, you move up that ladder. +If your turn ends at the head of a snake, you move down that snake. + 游戏规则如下: * 板子上有25个方块,你的目标是到达或超过第25个方格。 @@ -174,12 +244,17 @@ while condition { * 如果在你的回合结束时,你恰好到了梯子的尾部,你可以沿着梯子爬上去。 * 如果在你的回合结束时,你恰好到了蛇的头部,则你会沿着蛇身滑下去。 +The game board is represented by an array of Int values. Its size is based on a constant called finalSquare, which is used to initialize the array and also to check for a win condition later in the example. The board is initialized with 26 zero Int values, not 25 (one each at indices 0 through 25 inclusive): + 游戏的板子可以看做是一个```Int```型的数组。大小由常量```finalSquare```决定,这个常量也会用来初始化数组和判断获胜条件。数组被初始化为26个0,注意不是25(数组范围从0到25): ``` let finalSquare = 25 var board = Int[](count: finalSquare + 1, repeatedValue: 0)” ``` + +Some squares are then set to have more specific values for the snakes and ladders. Squares with a ladder base have a positive number to move you up the board, whereas squares with a snake head have a negative number to move you back down the board: + 板子上的许多方格用来被指定为梯子或者蛇。如果是梯子,那么这个方格的值为正数,如果是蛇,则方格的值为负数: ``` @@ -187,8 +262,12 @@ board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 ``` +Square 3 contains the bottom of a ladder that moves you up to square 11. To represent this, board[03] is equal to +08, which is equivalent to an integer value of 8 (the difference between 3 and 11). The unary plus operator (+i) balances with the unary minus operator (-i), and numbers lower than 10 are padded with zeros so that all board definitions align. (Neither stylistic tweak is strictly necessary, but they lead to neater code.) + 第三个方格被认定为是梯子的底部,它会让你走到第11个方格。为了表达这个意思,```board[03]```被复制为```+08```,它等价于整数8,考虑到所有的数字均为2位数,为了对齐和美观,(```+i```)用来和(```-i```)保持一致。 +The player’s starting square is “square zero”, which is just off the bottom left corner of the board. The first dice roll always moves the player on to the board: + 玩家从板子左下角的第0号方块开始,第一次掷骰子会将玩家移动到: ``` @@ -206,15 +285,32 @@ while square < finalSquare { } println("Game over!") ``` + +This example uses a very simple approach to dice rolling. Instead of a random number generator, it starts with a diceRoll value of 0. Each time through the while loop, diceRoll is incremented with the prefix increment operator (++i), and is then checked to see if it has become too large. The return value of ++diceRoll is equal to the value of diceRoll after it is incremented. Whenever this return value equals 7, the dice roll has become too large, and is reset to a value of 1. This gives a sequence of diceRoll values that is always 1, 2, 3, 4, 5, 6, 1, 2 and so on. + 这个例子用了一个非常简单的方式来掷骰子。我们没有采用每次产生一个随机数的方法,取而代之的是我们先给```diceRoll```赋值为0,然后在每次while循环的过程中对```diceRoll```加1,然后检测它的值是否等于7,让它等于7的时候,再将它重置为1。这样,产生的一系列```diceRoll```的值为1,2,3,4,5,6,1,2...。 +After rolling the dice, the player moves forward by diceRoll squares. It’s possible that the dice roll may have moved the player beyond square 25, in which case the game is over. To cope with this scenario, the code checks that square is less than the board array’s count property before adding the value stored in board[square] onto the current square value to move the player up or down any ladders or snakes. + 在掷完骰子后,玩家前进```diceRoll```个方格。玩家在前进的过程中很可能超过25,这种情况下游戏会结束。为了解决这种情况,当```square```在累加```board[quare]```的值前,会检查```square```的值是否小于```board.count```的值,同样它也会规避由数组越界带来的错误。 +Had this check not been performed, board[square] might try to access a value outside the bounds of the board array, which would trigger an error. If square is now equal to 26, the code would try to check the value of board[26], which is larger than the size of the array. + +由于做了这种校验,当board[square]发生数组越界的情况时,会引发错误。例如,如果当前方格的值为26,代码会试图访问board[26],显然这个访问会引发数组越界。 + +The current while loop execution then ends, and the loop’s condition is checked to see if the loop should be executed again. If the player has moved on or beyond square number 25, the loop’s condition evaluates to false, and the game ends. + 然后```while```循环体结束,这时会再次判断循环执行条件,如果玩家已经前进到了25或者越过了25,那么循环条件会返回```false```,游戏结束。 +A while loop is appropriate in this case because the length of the game is not clear at the start of the while loop. Instead, the loop is executed until a particular condition is satisfied + 显然在上面这情况下,使用```while```循环是非常合适的,因为循环次数不确定,只能根据循环条件来判断是否要终止循环。 ###Do-While + +The other variation of the while loop, known as the do-while loop, performs a single pass through the loop block first, before considering the loop’s condition. It then continues to repeat the loop until the condition is false. + +Here’s the general form of a do-while loop: 另一个```while```循环的变种是```do-while```语句,它首先执行一次循环,然后在判断循环执行条件。如此反复,直到循环条件返回```false```。 下面是```do-while```语句的格式: @@ -225,6 +321,7 @@ do { } while condition” ``` +Here’s the Snakes and Ladders example again, written as a do-while loop rather than a while loop. The values of finalSquare, board, square, and diceRoll are initialized in exactly the same way as with a while loop: 还是上面的蛇和梯子的例子,我们来使用```do-while```实现,初始化变量的过程同```while```循环: @@ -237,6 +334,11 @@ var square = 0 var diceRoll = 0 ``` + +In this version of the game, the first action in the loop is to check for a ladder or a snake. No ladder on the board takes the player straight to square 25, and so it is not possible to win the game by moving up a ladder. Therefore, it is safe to check for a snake or a ladder as the first action in the loop. + +At the start of the game, the player is on “square zero”. board[0] always equals 0, and has no effect: + 这次,我们首先来判断第一次遇到的是梯子还是蛇。因为没有梯子会把玩家直接送到25,所以这个判断是安全的。开始时,玩家的位置在"0",```board[0]```的值永远为0: ``` @@ -250,20 +352,28 @@ do { } while square < finalSquare println("Game over!") ``` +After the code checks for snakes and ladders, the dice is rolled, and the player is moved forward by diceRoll squares. The current loop execution then ends. 在判断遇到的时梯子还是蛇之后,我们掷骰子,玩家前进```diceRoll```个格子。当前循环结束。 +The loop’s condition (while square < finalSquare) is the same as before, but this time it is not evaluated until the end of the first run through the loop. The structure of the do-while loop is better suited to this game than the while loop in the previous example. In the do-while loop above, square += board[square] is always executed immediately after the loop’s while condition confirms that square is still on the board. This behavior removes the need for the array bounds check seen in the earlier version of the game. + 这里的循环条件(```while square < finalSquare```)和前面相同,但它会在循环结束后被执行。```do-while```循环结构比前面的```while```更适合这个游戏。使用```do-while```时,```square+=board[square]```会立刻被执行,它省去了上个例子中对数组越界的判断。 ##条件语句 + +It is often useful to execute different pieces of code based on certain conditions. You might want to run an extra piece of code when an error occurs, or to display a message when a value becomes too high or too low. To do this, you make parts of your code conditional. + 通常情况下我们需要在满足某种条件时执行一段代码或者在出错时执行另一段代码,也可能需要在某个值过大或过小时打印输出一些提示信息。这都需要你在代码中加入判断条件。 -Swift提供了两种条件判断的语句,它们是```if```和```switch```。 +Swift provides two ways to add conditional branches to your code, known as the if statement and the switch statement. Typically, you use the if statement to evaluate simple conditions with only a few possible outcomes. The switch statement is better suited to more complex conditions with multiple possible permutations, and is useful in situations where pattern-matching can help select an appropriate code branch to execute. -通常情况下,在条件分支比较少时,你使用```if```语句,```switch```语句用来处理复杂的判断条件和过多的条件分支,此外```switch```在模式匹配上非常有用。 +Swift提供了两种条件判断的语句,它们是```if```和```switch```。通常情况下,在条件分支比较少时,你使用```if```语句,```switch```语句用来处理复杂的判断条件和过多的条件分支,此外```switch```在模式匹配上非常有用。 ###If +In its simplest form, the if statement has a single if condition. It executes a set of statements only if that condition is true: + ```If```语句很简单,当判断条件为```true```时,执行一段代码: ``` @@ -273,7 +383,12 @@ if temperatureInFahrenheit <= 32 { } // prints "It's very cold. Consider wearing a scarf. ``` -上面的例子会判断温度是否小于等于32华氏度。如果是,打印一条消息。 + +The preceding example checks whether the temperature is less than or equal to 32 degrees Fahrenheit (the freezing point of water). If it is, a message is printed. Otherwise, no message is printed, and code execution continues after the if statement’s closing brace. + +上面的例子会判断温度是否小于等于32华氏度。如果是,打印一条消息,否则,则没有信息输出,执行if代码段后面的代码。 + +The if statement can provide an alternative set of statements, known as an else clause, for when the if condition is false. These statements are indicated by the else keyword: ```if```语句通常和```else```搭配使用,当```if```语句返回```false```时,```else```分支的代码会被执行: @@ -287,8 +402,13 @@ if temperatureInFahrenheit <= 32 { // prints "It's not that cold. Wear a t-shirt. ``` +One of these two branches is always executed. Because the temperature has increased to 40 degrees Fahrenheit, it is no longer cold enough to advise wearing a scarf, and so the else branch is triggered instead. + +这种情况下```if```和```else```两个分支中的一个一定会被执行到。因为温度已经升高到40华氏度,不需要再建议带围巾了,因此else语句的代码段被执行。 + +You can chain multiple if statements together, to consider additional clauses: -这种情况下```if```和```else```两个分支中的一个一定会被执行到,你也可以将多个```if```语句连起来使用: +你也可以将多个```if```语句连起来使用: ``` temperatureInFahrenheit = 90 @@ -301,7 +421,12 @@ if temperatureInFahrenheit <= 32 { } // prints "It's really warm. Don't forget to wear sunscreen. ``` -这里,多了一个```if```语句用来判断特定的温度范围。最后的```else```语句是可选的: + +Here, an additional if statement is added to respond to particularly warm temperatures. The final else clause remains, and prints a response for any temperatures that are neither too warm nor too cold. + +这里,多了一个```if```语句用来判断特定的温度范围。仍然有一个```else```在最后面,当温度既不高又不低得情况下打印出相应的信息: + +最后的```else```语句是可选的,如果它所在的分支不不需要执行,则可以将它排除: ``` temperatureInFahrenheit = 72 @@ -311,12 +436,19 @@ if temperatureInFahrenheit <= 32 { println("It's really warm. Don't forget to wear sunscreen.") } ``` +In this example, the temperature is neither too cold nor too warm to trigger the if or else if conditions, and so no message is printed. 在这个例子中,温度不满足```if```和```else if ```的执行条件,因此没有信息会被打印出来。 ###Switch -```switch```语句会将一个值和多种模式进行匹配。匹配成功则执行该条件所对应的代码。```switch```是一种可以替换```if```进行条件判断的语句。```switch```的语法格式如下: +A switch statement considers a value and compares it against several possible matching patterns. It then executes an appropriate block of code, based on the first pattern that matches successfully. A switch statement provides an alternative to the if statement for responding to multiple potential states. + +一条```switch```语句会将一个值和多种模式进行匹配。匹配成功则执行该条件所对应的代码。```switch```是一种可以替换```if```进行条件判断的语句。 + +In its simplest form, a switch statement compares a value against one or more values of the same type: + +最简单的```switch```的语法是用来比较一个或多个类型相同的值: ``` switch some value to consider { @@ -329,12 +461,22 @@ default: otherwise, do something else } ``` + +Every switch statement consists of multiple possible cases, each of which begins with the case keyword. In addition to comparing against specific values, Swift provides several ways for each case to specify more complex matching patterns. These options are described later in this section. + 每个```switch```语句都对应多个```case```语句。除了可以用```case```语句来比较具体的值以外,Swift提供了许多复杂的模式匹配,下一小节会详细介绍。 +The body of each switch case is a separate branch of code execution, in a similar manner to the branches of an if statement. The switch statement determines which branch should be selected. This is known as switching on the value that is being considered. + ```switch```语句内包含多个代码执行分支,这点和```if```语句很像。```switch```语句决定了那个分支会被执行,通常是根据变量值来决定的。 +Every switch statement must be exhaustive. That is, every possible value of the type being considered must be matched by one of the switch cases. If it is not appropriate to provide a switch case for every possible value, you can define a default catch-all case to cover any values that are not addressed explicitly. This catch-all case is indicated by the keyword default, and must always appear last. + + 每个```switch```语句必须是完整的,意思是它提供的分支条件必须能涵盖所有情况,你可以定义一个默认的分支条件用来处理一些意外的条件。这种分支通常用关键字```default```表示,并且它必须是最后一个分支条件。 +This example uses a switch statement to consider a single lowercase character called someCharacter: + 这个例子使用```switch```语句类匹配一个小写字母变量```someCharacter```: ``` @@ -350,19 +492,27 @@ default: } // prints "e is a vowel” ``` +The switch statement’s first case matches all five lowercase vowels in the English language. Similarly, its second case matches all lowercase English consonants. + ```switch```语句的第一个```case```分支是匹配五个元音字母。同理,第二个```case```分支用来匹配所有的字符常量。 +It is not practical to write all other possible characters as part of a switch case, and so this switch statement provides a default case to match all other characters that are not vowels or consonants. This provision ensures that the switch statement is exhaustive. + 通常来说列举出所有的字符不太现实,因此```switch```语句提供了```default```分支用来匹配所有其它的字符,这确保了```switch```语句的完整性。 ###没有隐式贯穿 +In contrast with switch statements in C and Objective-C, switch statements in Swift do not fall through the bottom of each case and into the next one by default. Instead, the entire switch statement finishes its execution as soon as the first matching switch case is completed, without requiring an explicit break statement. This makes the switch statement safer and easier to use than in C, and avoids executing more than one switch case by mistake. 和C语言或Objective-C相比,Swift中的```switch```语句在执行完一条```case```分支的代码后,则认为```switch```语句执行完毕。在某个```case```分支没有```break```的情况下,不会继续执行下一条```case```分支的代码。这比C语言更简单和安全。 - 注意: - 你也可以在```case```分支代码执行前使用```break```语句来跳出这个分支,详见后面的章节。 -每条```case```分支的函数体必须至少包含一行可执行代码。下面的代码是不合法的: +>注意: +>你也可以在```case```分支代码执行前使用```break```语句来跳出这个分支,详见后面的[switch语句中break一节](link)。 + +The body of each case must contain at least one executable statement. It is not valid to write the following code, because the first case is empty: + +每条```case```分支的函数体必须至少包含一行可执行代码。下面的代码是不合法的,因为第一条case分支的函数体为空: ``` let anotherCharacter: Character = "a" @@ -376,8 +526,12 @@ default: // this will report a compile-time error ``` +Unlike a switch statement in C, this switch statement does not match both "a" and "A". Rather, it reports a compile-time error that case "a": does not contain any executable statements. This approach avoids accidental fallthrough from one case to another, and makes for safer code that is clearer in its intent. + 和C语言不同,```switch```语句不会既匹配`"a"`又匹配`"A"`。遇到这种情况,编译器会给出错误提示。这条规则会避免意外的执行了其它分支的代码。 +Multiple matches for a single switch case can be separated by commas, and can be written over multiple lines if the list is long: + 一条```case```分支也可以匹配多个判断条件,用逗号隔开: ``` @@ -387,12 +541,14 @@ value 2: statements } ``` - 注意 - 对于```switch```语句的某个case分支,你可以通过使用```fallthrough```关键字来强制贯穿改```case```分支。 - 更对细节在Fallthrough一节有所介绍 +>注意 +>对于```switch```语句的某个case分支,你可以通过使用```fallthrough```关键字来强制贯穿改```case```分支。 +>更对细节在[Fallthrough](link)一节有所介绍 ###区间匹配 +Values in switch cases can be checked for their inclusion in a range. This example uses number ranges to provide a natural-language count for numbers of any size: + ```switch```语句的```case```分支可以是一个值区间同样支持范围匹配。下面这个例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式: ``` @@ -421,8 +577,12 @@ println("There are \(naturalCount) \(countedThings).") ###元组 +You can use tuples to test multiple values in the same switch statement. Each element of the tuple can be tested against a different value or range of values. Alternatively, use the underscore (_) identifier to match any possible value. + 你可以使用元组在同一个```switch```语句中测试多个值。元组中的每个元素可以是一个区间,也可以是不同的值。我们使用(_)来匹配任何可能的值。 +The example below takes an (x, y) point, expressed as a simple tuple of type (Int, Int), and categorizes it on the graph that follows the example: + 下面的例子使用一个元组类型(```Int```,```Int```)的点(x,y)并用图标来描述它的分布: ``` @@ -445,14 +605,23 @@ default: 【图】 +The switch statement determines if the point is at the origin (0, 0); on the red x-axis; on the orange y-axis; inside the blue 4-by-4 box centered on the origin; or outside of the box. + ```switch```语句用来判断这个点是否在原点;红色的X轴上;橘黄色的Y轴上;在蓝色的4x4的盒子内,还是在盒子外面。 +Unlike C, Swift allows multiple switch cases to consider the same value or values. In fact, the point (0, 0) could match all four of the cases in this example. However, if multiple matches are possible, the first matching case is always used. The point (0, 0) would match case (0, 0) first, and so all other matching cases would be ignored. + 不像C语言,Swift支持不同的```case```分支匹配同一个结果,在这个例子中,点(0,0)满足所有4个分之条件。这种情况下只有第一条```case```语句被执行。点(0,0)会首先匹配第一条```case(0,0)```,后面的```case```语句会被忽略掉。 ###值绑定(Value Bindings) -```switch```语句允许在一个```case```分支中,将待匹配的值绑定到一些常量或临时变量上。这就是值绑定。 -下面的例子将使用值绑定的方法重写上面的代码: +A switch case can bind the value or values it matches to temporary constants or variables, for use in the body of the case. This is known as value binding, because the values are “bound” to temporary constants or variables within the case’s body. + +```switch```语句允许在一个```case```分支中,将待匹配的值绑定到一些常量或临时变量上。这样就可以在case分支的代码段中使用这些变量或常量,这就是值绑定。 + +The example below takes an (x, y) point, expressed as a tuple of type (Int, Int) and categorizes it on the graph that follows: + +下面的例子将定义一个(Int,Int)型的元组变量(x,y),并归类它在图中的位置: ``` let anotherPoint = (2, 0) @@ -469,21 +638,35 @@ case let (x, y): ``` 【图】 +The switch statement determines if the point is on the red x-axis, on the orange y-axis, or elsewhere, on neither axis. + 上面我们通过```switch```语句判断了```anotherPoint```这个点是否在红色的X,y轴上或者在非轴上的任意位置。 +The three switch cases declare placeholder constants x and y, which temporarily take on one or both tuple values from anotherPoint. The first case, case (let x, 0), matches any point with a y value of 0 and assigns the point’s x value to the temporary constant x. Similarly, the second case, case (0, let y), matches any point with an x value of 0 and assigns the point’s y value to the temporary constant y. + 上面三条```case```语句使用临时变量```x```,```y```来匹配```anotherPoint```中的值。第一条```case(let x, 0)```语句用来匹配所有```y```值为0的点,并把该点的```x```值赋值给常量```x```。同理,```case(0,let y)```匹配所有```x```值为0的点,并把该点得```y```值赋给常量```y```。 +Once the temporary constants are declared, they can be used within the case’s code block. Here, they are used as shorthand for printing the values with the println function. + 临时变量被声明后,它就可以用在```case```分支的代码中。本例中```x```,```y```在```println```方法中被打印出来。 +Note that this switch statement does not have a default case. The final case, case let (x, y), declares a tuple of two placeholder constants that can match any value. As a result, it matches all possible remaining values, and a default case is not needed to make the switch statement exhaustive. + 注意到上面的```switch```语句并没有```default```分支,原因是最后一条```case let(x,y)```涵盖了所有其他情况,因此我们不需要再写一个```default```分支了。 +In the example above, x and y are declared as constants with the let keyword, because there is no need to modify their values within the body of the case. However, they could have been declared as variables instead, with the var keyword. If this had been done, a temporary variable would have been created and initialized with the appropriate value. Any changes to that variable would only have an effect within the body of the case. + 在上面的例子中,我们通过```let```关键字将```x```,```y```声明为常量,原因是我们不需要修改他们的值。同样我们也可以用```var```关键字声明他们为变量,如果把它们声明为变量则需要为他们指定合适的初始值。任何对于它们值的修改也仅仅局限在```case```分支的代码中有效。 ###Where +A switch case can use a where clause to check for additional conditions. + 在```case```语句的条件分支中可以使用```where```关键字增加附加条件的判断。 -还是上面的例子: +The example below categorizes an (x, y) point on the following graph: + +还是上面的例子,用来归类(x,y)点所在图中得位置: ``` let yetAnotherPoint = (1, -1) @@ -499,14 +682,22 @@ case let (x, y): ``` 【图】 -上面的```switch```语句用来检测```yetAnotherPoint```这个点是否在绿色或紫色的对角线上。 +The switch statement determines if the point is on the green diagonal line where x == y, on the purple diagonal line where x == -y, or neither. + +上面的```switch```语句用来检测```yetAnotherPoint```这个点是否在绿色(x==y)或紫色(x==-y)的对角线上。 + +The three switch cases declare placeholder constants x and y, which temporarily take on the two tuple values from point. These constants are used as part of a where clause, to create a dynamic filter. The switch case matches the current value of point only if the where clause’s condition evaluates to true for that value. 上面的三条```switch```语句声明了常量```x```和```y```用来临时保存```yetAnotherPoint```中的坐标值。这两个常量同时也被```where```用来创建一个过滤条件。只有当```where```的过滤条件返回```true```时,```case```分支的代码才会被执行。 +As in the previous example, the final case matches all possible remaining values, and so a default case is not needed to make the switch statement exhaustive. + 和上面的例子一样```default```分支在这个例子中也可以被忽略。 ###控转移语句 +Control transfer statements change the order in which your code is executed, by transferring control from one piece of code to another. Swift has four control transfer statements: + 控制转移语句会改变代码执行的顺序。Swift提供了4个控制转移语句: * continue @@ -514,17 +705,24 @@ case let (x, y): * fallthrough * return -我们下面将会讨论```control```,```break````,```return```语句,```return```将会在函数一章讨论。 +The control, break and fallthrough statements are described below. The return statement is described in Functions. + +我们下面将会讨论```control```,```break````,```return```语句,```return```将会在[函数](link)一章讨论。 ###continue +The continue statement tells a loop to stop what it is doing and start again at the beginning of the next iteration through the loop. It says “I am done with the current loop iteration” without leaving the loop altogether. + ```continue```用来终止当前循环并开始执行下一次循环。它会说“本次循环结束了”,但并不会跳出循环。 - 注意: - 在```for-condition-increment```一节,即使执行了```continue```,循环的累加器仍会自动加1。 - 循环会继续,仅仅是循环体内的代码不会被执行。 +>注意: +>在```for-condition-increment```一节,即使执行了```continue```,循环的累加器仍会自动加1。 +>循环会继续,仅仅是循环体内的代码不会被执行。 + +The following example removes all vowels and spaces from a lowercase string to create a cryptic puzzle phrase: + 下面的例子会移除一个小写字符串中所有的原因字母: ``` @@ -541,26 +739,37 @@ for character in puzzleInput { println(puzzleOutput) // prints "grtmndsthnklk ``` +The code above calls the continue keyword whenever it matches a vowel or a space, causing the current iteration of the loop to end immediately and to jump straight to the start of the next iteration. This behavior enables the switch block to match (and ignore) only the vowel and space characters, rather than requiring the block to match every character that should get printed. 在上面的代码中,一旦出现元音字母,当前循环就会被终止,并重新开始下一次循环。这会让```switch```语句去匹配元音字符或空字符时不做处理,而不是让每一个匹配到的字符都被打印出来。 ###break +The break statement ends execution of an entire control flow statement immediately. The break statement can be used inside a switch statement or loop statement when you want to terminate the execution of the switch or loop statement earlier than would otherwise be the case. + ```break```语句会立刻终止当前执行的整个控制流。```break```可被用在```switch```语句里面或循环中用来提前结束控制流。 ###循环体内的break -当在循环体内执行```break```时,会退出整个循环,代码从循环体后面的第一行开始执行。 +When used inside a loop statement, break ends the loop’s execution immediately, and transfers control to the first line of code after the loop’s closing brace (}). No further code from the current iteration of the loop is executed, and no further iterations of the loop are started. + +当在循环体内执行```break```时,会退出整个循环,代码从循环体后面的第一行开始执行,break语句后面的代码将不会执行,下一次循环也不会开始。 ###Switch语句中得break +When used inside a switch statement, break causes the switch statement to end its execution immediately, and to transfer control to the first line of code after the switch statement’s closing brace (}). + 当在```switch```中使用```break```时,会立即终止改```switch``代码块的执行,并且跳转到```switch```代码块结束的大括号(```}```)后的第一行代码。 +This behavior can be used to match and ignore one or more cases in a switch statement. Because Swift’s switch statement is exhaustive and does not allow empty cases, it is sometimes necessary to deliberately match and ignore a case in order to make your intentions explicit. You do this by writing the break statement as the entire body of the case you want to ignore. When that case is matched by the switch statement, the break statement inside the case ends the switch + 这种行为可被用来忽略或跳过```switch```中的某个```case```。由于Swift要求```switch```的分支条件必须完整并且不允许空的```case```分支,因此在有些情况下使用```break```特意跳出某个分支会很必要。你可以通过在```case```的代码快中加入```break````来达到这个效果。当```case```分支的代码块被执行时,```break```会终止```switch```语句的执行。 - 注意: - 当```switch```的一个分支仅仅包含注释时,编译器会给出错误提示。 - 注释并不是真正的代码,他不能达到忽略这个```case```分支的作用。有哪次还是需要使用```break```。 +>注意: +>当```switch```的一个分支仅仅包含注释时,编译器会给出错误提示。 +>注释并不是真正的代码,他不能达到忽略这个```case```分支的作用。有哪次还是需要使用```break```。 + +The following example switches on a Character value and determines whether it represents a number symbol in one of four languages. Multiple values are covered in a single switch case for brevity: 下面这个例子用来判断一个字符的值是否是数字符号。为了简便,多个值被包含到一个分支中: @@ -587,16 +796,27 @@ if let integerValue = possibleIntegerValue { // prints "The integer value of 三 is 3." ``` + +This example checks numberSymbol to determine whether it is a Latin, Arabic, Chinese, or Thai symbol for the numbers 1 to 4. If a match is found, one of the switch statement’s cases sets an optional Int? variable called possibleIntegerValue to an appropriate integer value. + 这个例子用来判断```numberSymbol```是否是拉丁文,阿拉伯文,中文或泰语中的1到4之一。如果被匹配到,该```switch```分支语句给```Int?```类型变量```possibleIntegerValue```设置一个整数值。 +After the switch statement completes its execution, the example uses optional binding to determine whether a value was found. The possibleIntegerValue variable has an implicit initial value of nil by virtue of being an optional type, and so the optional binding will succeed only if possibleIntegerValue was set to an actual value by one of the switch statement’s first four cases. + 当switch代码块执行完后,接下来的代码先判断```possibleIntegerValue``是否被绑定成功。因为是可选类型的缘故,```possibleIntegerValue```有一个隐式的初始值nil,所以仅仅当```possibleIntegerValue```曾被switch代码块的前四个分支中的某个设置过一个值时,可选的绑定将会被判定为成功。 +It is not practical to list every possible Character value in the example above, so a default case provides a catchall for any characters that are not matched. This default case does not need to perform any action, and so it is written with a single break statement as its body. As soon as the default statement is matched, the break statement ends the switch statement’s execution, and code execution continues from the if let statement. + 在上面的例子中,想要把```Character```所有的的可能性都枚举出来是不现实的,所以使用```default```分支来包含所有上面没有匹配到字符的情况。由于这个```default```分支不需要执行任何动作,所以它只写了一条```break```语句。一旦落入到```default```分支中后,```break```语句就完成了该分支的所有代码操作,代码继续向下,开始执行```if let```语句。 ###Fallthrough +Switch statements in Swift do not fall through the bottom of each case and into the next one. Instead, the entire switch statement completes its execution as soon as the first matching case is completed. By contrast, C requires you to insert an explicit break statement at the end of every switch case to prevent fallthrough. Avoiding default fallthrough means that Swift switch statements are much more concise and predictable than their counterparts in C, and thus they avoid executing multiple switch cases by mistake. + Swift中的Switch语句不会从上到下进入每一个case分支。相反,一旦有一个case分支被匹配成功,整个state语句就结束执行了。相比之下,在C语言中,为了防止switch语句会贯穿执行每一个case分支,你需要在每个case分支的末尾插入```break```语句。和C语言相比,Swift支持这种避免贯穿行为会让```switch```语句更简洁和更安全也能规避错误执行多个case分支的情况。 +If you really need C-style fallthrough behavior, you can opt in to this behavior on a case-by-case basis with the fallthrough keyword. The example below uses fallthrough to create a textual description of a number: + 如果你一定要使用C风格的贯穿(fallthrough)机制,你可以在每个需要支持该特性的case分支中使用```fallthrough```关键字。下面这个例子展示了如何使用```fallthrough```来实现对数字的文本描述: ``` @@ -612,22 +832,36 @@ default: println(description) // prints "The number 5 is a prime number, and also an integer. ``` + +This example declares a new String variable called description and assigns it an initial value. The function then considers the value of integerToDescribe using a switch statement. If the value of integerToDescribe is one of the prime numbers in the list, the function appends text to the end of description, to note that the number is prime. It then uses the fallthrough keyword to “fall into” the default case as well. The default case adds some extra text to the end of the description, and the switch statement is complete. + 这个例子中声明了一个叫```description```的```string```类型的变量,并且为其赋了初值。然后这个函数通过```switch```语句来判断```integerToDescribe```的值。如果```integerToDescribe```的值为数组中的一个素数,则该函数会为```decription```后面追加一段文本用来提示改数字式质数。然后会使用```fallthrough```关键字来执行```default```中的代码。在```default```分支中会为```description```后面继续追加一段文本。至此,```switch```语句才算执行完成。 +If the value of integerToDescribe is not in the list of known prime numbers, it is not matched by the first switch case at all. There are no other specific cases, and so integerToDescribe is matched by the catchall default case. + 如果```integerToDescribe```的值不在这组质数当中,则它不会和第一条```case```语句匹配。由于没有其它的分支存在,所以```integerToDescribe```会落入```default```分支。 +After the switch statement has finished executing, the number’s description is printed using the println function. In this example, the number 5 is correctly identified as a prime number. + 当```switch```语句执行完成后,关于这个数字的描述会通过```println```函数打印出来。在这个例子中,数字```5```被正确的识别为一个质数。 - 注意: - 和C语言的```switch```语句一样,```fallthrough```不会检查它落入执行的```case```分支的条件是否匹配, - 它只是简单的执行下一条```case```(或```default```)中的代码。 +>注意: +>和C语言的```switch```语句一样,```fallthrough```不会检查它落入执行的```case```分支的条件是否匹配, +>它只是简单的执行下一条```case```(或```default```)中的代码。 ###Labeled语句 +You can nest loops and switch statements inside other loops and switch statements in Swift to create complex control flow structures. However, loops and switch statements can both use the break statement to end their execution prematurely. Therefore, it is sometimes useful to be explicit about which loop or switch statement you want a break statement to terminate. Similarly, if you have multiple nested loops, it can be useful to be explicit about which loop the continue statement should affect. + 在```swift```中,可以在循环或```switch```函数中嵌套循环或```switch```函数来实现比较复杂的控制流结构。但是,在循环或```switch```函数中可以使用```break```语句提前终止其执行过程。因此,有些时候显示的调用```break```来标识终止循环或```switch```是非常有好处的。类似的,如果一个循环中嵌套了多个循环,使用```continue```来标识其影响的循环体也是很有用的。 +To achieve these aims, you can mark a loop statement or switch statement with a statement label, and use this label with the break statement or continue statement to end or continue the execution of the labeled statement. + 为了实现上面的目标,你可以通过标签来标识某个循环或```switch```语句。使用```break```或```continue```时,带上这个标签,这个标签可以用来结束或执行被标记的代码段。 +A labeled statement is indicated by placing a label on the same line as the statement’s introducer keyword, followed by a colon. Here’s an example of this syntax for a while loop, although the principle is the same for all loops and switch statements + + 标签语句通常被放到一些关键字的前面,通过分号隔开。下面是一个通过标签来标记```while```语句的例子,循环或```switch```语句和它类似: ``` @@ -637,16 +871,23 @@ label name: while condition { ``` +The following example uses the break and continue statements with a labeled while loop for an adapted version of the Snakes and Ladders game that you saw earlier in this chapter. This time around, the game has an extra rule: + 下面这个例子将使用```break```和```continue```,配合带标签的```while```循环,该循环和前面的梯子和蛇的例子一直。这次,该游戏新增加了一条规则 * 为了胜利,你必须恰好到达第25个格子中 +If a particular dice roll would take you beyond square 25, you must roll again until you roll the exact number needed to land on square 25. + 如果某一次掷骰子会把你带到超过25的地方,必须重新掷骰子,直到你恰好到达第25号格子的位子 +The game board is the same as before:” 游戏的棋盘和前面的一样: 【图】 +The values of finalSquare, board, square, and diceRoll are initialized in the same way as before: + ```finalSquare```,```board```,```square```和```diceRoll```的值和之前初始化的值相同: ``` @@ -658,8 +899,12 @@ var square = 0 var diceRoll = 0 ``` +This version of the game uses a while loop and a switch statement to implement the game’s logic. The while loop has a statement label called gameLoop, to indicate that it is the main game loop for the Snakes and Ladders game. + 这个版本会使用```while```循环和```switch```语句来实现游戏的逻辑。```while```循环有个标签叫做```gameLoop```,用来表示这个循环是这个游戏的主循环。 +The while loop’s condition is while square != finalSquare, to reflect that you must land exactly on square 25: + ```while```循环的条件是```while square != finalSquare```用来表示你必须正好落在第25个格子中: ``` @@ -681,20 +926,35 @@ gameLoop: while square != finalSquare { println("Game over!") ``` +The dice is rolled at the start of each loop. Rather than moving the player immediately, a switch statement is used to consider the result of the move, and to work out if the move is allowed: -在每个循环开始前都需要掷骰子,与之前立刻移动玩家不同,这次利用```switch```语句计算每次掷骰子产生的结果,从而决定玩家是否可以移动: +在每个循环开始前都需要掷骰子,与之前立刻移动玩家不同,这次利用```switch```语句计算每次掷骰子产生的结果,从而决 +定玩家是否可以移动: + +If the dice roll will move the player onto the final square, the game is over. The break gameLoop statement transfers control to the first line of code outside of the while loop, which ends the game. * 如果掷骰子的结果恰好将玩家移动到最后的方格中,那么游戏结束。```break gameLoop```会将代码跳到循环后的第一条语句,继续执行后面的代码。 +If the dice roll will move the player beyond the final square, the move is invalid, and the player needs to roll again. The continue gameLoop statement ends the current while loop iteration and begins the next iteration of the loop. + * 如果掷骰子的结果将玩家移动到超过最后一个方格的位置,那么这次结果是无效的,玩家需要重新掷骰子。```continue gameLoop```会将当前循环终止并重新开始下一次循环。 +In all other cases, the dice roll is a valid move. The player moves forward by diceRoll squares, and the game logic checks for any snakes and ladders. The loop then ends, and control returns to the while condition to decide whether another turn is required + * 在所有其余的情况中,掷骰子的结果是有效的,玩家会前进```diceRoll```个格子,游戏的逻辑会检测是否遇到梯子或者蛇。循环结束时,代码将回到```while```条件判定检查是否要进行下一次循环。 - 注意: +NOTE + +If the break statement above did not use the gameLoop label, it would break out of the switch statement, not the while statement. Using the gameLoop label makes it clear which control statement should be terminated. + +Note also that it is not strictly necessary to use the gameLoop label when calling continue gameLoop to jump to the next iteration of the loop. There is only one loop in the game, and so there is no ambiguity as to which loop the continue statement will affect. However, there is no harm in using the gameLoop label with the continue statement. Doing so is consistent with the label’s use alongside the break statement, and helps make the game’s logic clearer to read and understand. + +>注意: - 如果```break```语句没有使用```gameLoop```标签,那么它将会中断```switch```代码块而不是```while```。 使用```gameLoop```标签可以更直观的体现循环在哪里被终止的。 +>如果```break```语句没有使用```gameLoop```标签,那么它将会中断```switch```代码块而不是```while```。 +>使用```gameLoop```标签可以更直观的体现循环在哪里被终止的。 - 我们还注意到,跳到下一次循环的语句:```continue gameLoop```并不一定要使用```gameLoop```标签。由于代码中只 有一个循环,因此```continue```语句是没有歧义的,但是在这里使用```gameLoop```标签也是没有任何坏处的。在```break```旁边加上标签可以保证代码的一致性,是代码逻辑更清楚,更容易被人读懂和理解。 +>我们还注意到,跳到下一次循环的语句:```continue gameLoop```并不一定要使用```gameLoop```标签。由于代码中只有一个循环,因此```continue```语句是没有歧义的,但是在这里使用```gameLoop```标签也是没有任何坏处的。在```break```旁边加上标签可以保证代码的一致性,是代码逻辑更清楚,更容易被人读懂和理解。 From 2b98ab23bc28e43d9603415bd5b8b0f2ccf2a449 Mon Sep 17 00:00:00 2001 From: jayson Date: Tue, 1 Jul 2014 13:26:35 +0800 Subject: [PATCH 215/261] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/05_Control_Flow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index 014cc30..94e6fbb 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -17,7 +17,7 @@ Swift的```switch```语句和C语言相比很强大,它不会像C语言那样 A for loop performs a set of statements a certain number of times. Swift provides two kinds of for loop: -```for```循环可以将一段代码执行若干次。Swift提供两种```for```循环: +for循环可以将一段代码执行若干次。Swift提供两种for循环: for-in performs a set of statements for each item in a range, sequence, collection, or progression. for-condition-increment performs a set of statements until a specific condition is met, typically by incrementing a counter each time the loop ends. From 13f9036ffac1882ab7e1a26cf615f67bd152928f Mon Sep 17 00:00:00 2001 From: jayson Date: Tue, 1 Jul 2014 14:01:43 +0800 Subject: [PATCH 216/261] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/05_Control_Flow.md | 223 ++++++++++++++++---------------- 1 file changed, 111 insertions(+), 112 deletions(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index 94e6fbb..a9c650e 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -17,7 +17,7 @@ Swift的```switch```语句和C语言相比很强大,它不会像C语言那样 A for loop performs a set of statements a certain number of times. Swift provides two kinds of for loop: -for循环可以将一段代码执行若干次。Swift提供两种for循环: +`for`循环可以将一段代码执行若干次。Swift提供两种`for`循环: for-in performs a set of statements for each item in a range, sequence, collection, or progression. for-condition-increment performs a set of statements until a specific condition is met, typically by incrementing a counter each time the loop ends. @@ -52,11 +52,11 @@ The collection of items being iterated is a closed range of numbers from 1 to 5 In the example above, index is a constant whose value is automatically set at the start of each iteration of the loop. As such, it does not have to be declared before it is used. It is implicitly declared simply by its inclusion in the loop declaration, without the need for a let declaration keyword. -上面例子中```index```是个常量,在每次循环开始的时候会被自动赋值,因此它不需要在使用前通过```let```声明,因为它会被```for-in```隐式声明。 +上面例子中`index`是个常量,在每次循环开始的时候会被自动赋值,因此它不需要在使用前通过`let`声明,因为它会被`for-in`隐式声明。 >注意 ->常量```index```的作用域只存在于循环体内。如果你想在循环体外查看```index```的值或者使用它,你需要在循环开始前声明它。 +>常量`index`的作用域只存在于循环体内。如果你想在循环体外查看`index`的值或者使用它,你需要在循环开始前声明它。 If you don’t need each value from the range, you can ignore the values by using an underscore in place of a variable name: @@ -79,10 +79,10 @@ This example calculates the value of one number to the power of another (in this Use the for-in loop with an array to iterate over its items:我们还可以 -使用```for-in```遍历数组中的元素: +使用`for-in`遍历数组中的元素: ``` -“let names = ["Anna", "Alex", "Brian", "Jack"] +let names = ["Anna", "Alex", "Brian", "Jack"] for name in names { println("Hello, \(name)!") } @@ -95,11 +95,10 @@ for name in names { You can also iterate over a dictionary to access its key-value pairs. Each item in the dictionary is returned as a (key, value) tuple when the dictionary is iterated, and you can decompose the (key, value) tuple’s members as explicitly named constants for use within in the body of the for-in loop. Here, the dictionary’s keys are decomposed into a constant called animalName, and the dictionary’s values are decomposed into a constant called legCount: -你也同样可以遍历字典中的key-value。遍历时,字典中的每个元素都以```(key,value)```元组结构返回,你也可以在```for-in```中将元组中的key,value当做常量显式的分解出来。这里,key被分解为为常量```animalName```,value被分解为 -```legCount```: +你也同样可以遍历字典中的key-value。遍历时,字典中的每个元素都以`(key,value)`元组结构返回,你也可以在`for-in`中将元组中的key,value当做常量显式的分解出来。这里,key被分解为为常量`animalName`,value被分解为`legCount`: ``` -“let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] +let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] for (animalName, legCount) in numberOfLegs { println("\(animalName)s have \(legCount) legs") } @@ -111,14 +110,14 @@ for (animalName, legCount) in numberOfLegs { Items in a Dictionary may not necessarily be iterated in the same order as they were inserted. The contents of a Dictionary are inherently unordered, and iterating over them does not guarantee the order in which they will be retrieved. For more on arrays and dictionaries, see Collection Types.) -```Dictionary```中的元素的顺序在被遍历时可能和我们插入它的顺序不同,这是由于```Dictionary```自身就是无序的,它在被遍历时无法保证元素的顺序。想了解更多关于数组和字典的内容,请查阅[集合类型](link)一章。 +`Dictionary`中的元素的顺序在被遍历时可能和我们插入它的顺序不同,这是由于`Dictionary`自身就是无序的,它在被遍历时无法保证元素的顺序。想了解更多关于数组和字典的内容,请查阅[集合类型](link)一章。 In addition to arrays and dictionaries, you can also use the for-in loop to iterate over the Character values in a string: -除了数组和字典,你同样可以使用```for-in```来遍历字符串中的```Character```: +除了数组和字典,你同样可以使用`for-in`来遍历字符串中的`Character`: ``` -“for character in "Hello" { +for character in "Hello" { println(character) } // H @@ -132,10 +131,10 @@ In addition to arrays and dictionaries, you can also use the for-in loop to iter In addition to for-in loops, Swift supports traditional C-style for loops with a condition and an incrementer: -除了使用```for-in```这种循环语句,Swift还提供了传统的C风格的``for```循环语句,通常它需要一个循环执行条件和一个累加器: +除了使用`for-in`这种循环语句,Swift还提供了传统的C风格的`for`循环语句,通常它需要一个循环执行条件和一个累加器: ``` -“for var index = 0; index < 3; ++index { +for var index = 0; index < 3; ++index { println("index is \(index)") } // index is 0 @@ -147,8 +146,8 @@ Here’s the general form of this loop format: 下面是这种语法通用的语句: -for ```initialization```;```condition```;```increment```{ -```statements``` +for `initialization`;`condition`;`increment`{ +`statements` } Semicolons separate the three parts of the loop’s definition, as in C. However, unlike C, Swift doesn’t need parentheses around the entire “initialization; condition; increment” block. @@ -165,7 +164,7 @@ The loop is executed as follows: 1,循环开始时执行一次initialization语句,初始化循环使用的常量或变量。 -2,condition语句被执行,如果结果为```false```循环结束,执行循环体后面的代码。如果condition语句结果为```true```,继续执行循环体内的代码 +2,condition语句被执行,如果结果为`false`循环结束,执行循环体后面的代码。如果condition语句结果为`true`,继续执行循环体内的代码 3,当循环体内的代码被执行完时,increment语句被执行。通常情况是增加或减少计数器的值,然后执行第2步,condition语句会被再次执行。 @@ -173,15 +172,15 @@ The loop format and execution process described above is shorthand for (and equi 上面的for循环结构也可以如下表示: -```initialization``` -while ```condition``` { -```statements``` -```increment``` +`initialization` +while `condition` { +`statements` +`increment` } Constants and variables declared within the initialization expression (such as var index = 0) are only valid within the scope of the for loop itself. To retrieve the final value of index after the loop ends, you must declare index before the loop’s scope begins: -在for循环初始化时创建的变量或者常量只在循环体内有效,如果想获取循环结束时的```index```值,你必须将```index```显式的声明到循环语句前: +在for循环初始化时创建的变量或者常量只在循环体内有效,如果想获取循环结束时的`index`值,你必须将`index`显式的声明到循环语句前: ``` var index: Int @@ -196,7 +195,7 @@ println("The loop statements were executed \(index) times") ``` Note that the final value of index after this loop is completed is 3, not 2. The last time the increment statement ++index is called, it sets index to 3, which causes index < 3 to equate to false, ending the loop. -注意循环结束时,```index```值是```3```而不是```2```。当```++index```被最后一次执行时,```index```被赋值为```3```,这回导致```index<3```返回```false```,结束循环。 +注意循环结束时,`index`值是`3`而不是`2`。当`++index`被最后一次执行时,`index`被赋值为`3`,这回导致`index<3`返回`false`,结束循环。 ##While循环 @@ -205,10 +204,10 @@ A while loop performs a set of statements until a condition becomes false. These while evaluates its condition at the start of each pass through the loop. do-while evaluates its condition at the end of each pass through the loop. -一个```while```语句会循环执行一段代码直到条件变为```false```。这种循环语句在处理循环次数不确定的情况时非常有效。Swift提供两种```while```循环: +一个`while`语句会循环执行一段代码直到条件变为`false`。这种循环语句在处理循环次数不确定的情况时非常有效。Swift提供两种`while`循环: -* ```while```语句会在执行循环提前判断执行条件。 -* ```do-while```语句会在执行完循环体内代码后判断执行条件。 +* `while`语句会在执行循环提前判断执行条件。 +* `do-while`语句会在执行完循环体内代码后判断执行条件。 ###while @@ -216,7 +215,7 @@ A while loop starts by evaluating a single condition. If the condition is true, Here’s the general form of a while loop: -一个```while```循环从判断执行条件开始。如果条件为```true```,则循环执行循环体内的代码,知道条件变为```false```。下面是通用的```while```语法格式: +一个`while`循环从判断执行条件开始。如果条件为`true`,则循环执行循环体内的代码,知道条件变为`false`。下面是通用的`while`语法格式: ``` while condition { @@ -246,7 +245,7 @@ If your turn ends at the head of a snake, you move down that snake. The game board is represented by an array of Int values. Its size is based on a constant called finalSquare, which is used to initialize the array and also to check for a win condition later in the example. The board is initialized with 26 zero Int values, not 25 (one each at indices 0 through 25 inclusive): -游戏的板子可以看做是一个```Int```型的数组。大小由常量```finalSquare```决定,这个常量也会用来初始化数组和判断获胜条件。数组被初始化为26个0,注意不是25(数组范围从0到25): +游戏的板子可以看做是一个`Int`型的数组。大小由常量`finalSquare`决定,这个常量也会用来初始化数组和判断获胜条件。数组被初始化为26个0,注意不是25(数组范围从0到25): ``` let finalSquare = 25 @@ -264,7 +263,7 @@ board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 ``` Square 3 contains the bottom of a ladder that moves you up to square 11. To represent this, board[03] is equal to +08, which is equivalent to an integer value of 8 (the difference between 3 and 11). The unary plus operator (+i) balances with the unary minus operator (-i), and numbers lower than 10 are padded with zeros so that all board definitions align. (Neither stylistic tweak is strictly necessary, but they lead to neater code.) -第三个方格被认定为是梯子的底部,它会让你走到第11个方格。为了表达这个意思,```board[03]```被复制为```+08```,它等价于整数8,考虑到所有的数字均为2位数,为了对齐和美观,(```+i```)用来和(```-i```)保持一致。 +第三个方格被认定为是梯子的底部,它会让你走到第11个方格。为了表达这个意思,`board[03]`被复制为`+08`,它等价于整数8,考虑到所有的数字均为2位数,为了对齐和美观,(`+i`)用来和(`-i`)保持一致。 The player’s starting square is “square zero”, which is just off the bottom left corner of the board. The first dice roll always moves the player on to the board: @@ -288,11 +287,11 @@ println("Game over!") This example uses a very simple approach to dice rolling. Instead of a random number generator, it starts with a diceRoll value of 0. Each time through the while loop, diceRoll is incremented with the prefix increment operator (++i), and is then checked to see if it has become too large. The return value of ++diceRoll is equal to the value of diceRoll after it is incremented. Whenever this return value equals 7, the dice roll has become too large, and is reset to a value of 1. This gives a sequence of diceRoll values that is always 1, 2, 3, 4, 5, 6, 1, 2 and so on. -这个例子用了一个非常简单的方式来掷骰子。我们没有采用每次产生一个随机数的方法,取而代之的是我们先给```diceRoll```赋值为0,然后在每次while循环的过程中对```diceRoll```加1,然后检测它的值是否等于7,让它等于7的时候,再将它重置为1。这样,产生的一系列```diceRoll```的值为1,2,3,4,5,6,1,2...。 +这个例子用了一个非常简单的方式来掷骰子。我们没有采用每次产生一个随机数的方法,取而代之的是我们先给`diceRoll`赋值为0,然后在每次while循环的过程中对`diceRoll`加1,然后检测它的值是否等于7,让它等于7的时候,再将它重置为1。这样,产生的一系列`diceRoll`的值为1,2,3,4,5,6,1,2...。 After rolling the dice, the player moves forward by diceRoll squares. It’s possible that the dice roll may have moved the player beyond square 25, in which case the game is over. To cope with this scenario, the code checks that square is less than the board array’s count property before adding the value stored in board[square] onto the current square value to move the player up or down any ladders or snakes. -在掷完骰子后,玩家前进```diceRoll```个方格。玩家在前进的过程中很可能超过25,这种情况下游戏会结束。为了解决这种情况,当```square```在累加```board[quare]```的值前,会检查```square```的值是否小于```board.count```的值,同样它也会规避由数组越界带来的错误。 +在掷完骰子后,玩家前进`diceRoll`个方格。玩家在前进的过程中很可能超过25,这种情况下游戏会结束。为了解决这种情况,当`square`在累加`board[quare]`的值前,会检查`square`的值是否小于`board.count`的值,同样它也会规避由数组越界带来的错误。 Had this check not been performed, board[square] might try to access a value outside the bounds of the board array, which would trigger an error. If square is now equal to 26, the code would try to check the value of board[26], which is larger than the size of the array. @@ -300,20 +299,20 @@ Had this check not been performed, board[square] might try to access a value out The current while loop execution then ends, and the loop’s condition is checked to see if the loop should be executed again. If the player has moved on or beyond square number 25, the loop’s condition evaluates to false, and the game ends. -然后```while```循环体结束,这时会再次判断循环执行条件,如果玩家已经前进到了25或者越过了25,那么循环条件会返回```false```,游戏结束。 +然后`while`循环体结束,这时会再次判断循环执行条件,如果玩家已经前进到了25或者越过了25,那么循环条件会返回`false`,游戏结束。 A while loop is appropriate in this case because the length of the game is not clear at the start of the while loop. Instead, the loop is executed until a particular condition is satisfied -显然在上面这情况下,使用```while```循环是非常合适的,因为循环次数不确定,只能根据循环条件来判断是否要终止循环。 +显然在上面这情况下,使用`while`循环是非常合适的,因为循环次数不确定,只能根据循环条件来判断是否要终止循环。 ###Do-While The other variation of the while loop, known as the do-while loop, performs a single pass through the loop block first, before considering the loop’s condition. It then continues to repeat the loop until the condition is false. Here’s the general form of a do-while loop: -另一个```while```循环的变种是```do-while```语句,它首先执行一次循环,然后在判断循环执行条件。如此反复,直到循环条件返回```false```。 +另一个`while`循环的变种是`do-while`语句,它首先执行一次循环,然后在判断循环执行条件。如此反复,直到循环条件返回`false`。 -下面是```do-while```语句的格式: +下面是`do-while`语句的格式: ``` do { @@ -323,7 +322,7 @@ do { ``` Here’s the Snakes and Ladders example again, written as a do-while loop rather than a while loop. The values of finalSquare, board, square, and diceRoll are initialized in exactly the same way as with a while loop: -还是上面的蛇和梯子的例子,我们来使用```do-while```实现,初始化变量的过程同```while```循环: +还是上面的蛇和梯子的例子,我们来使用`do-while`实现,初始化变量的过程同`while`循环: ``` let finalSquare = 25 @@ -339,7 +338,7 @@ In this version of the game, the first action in the loop is to check for a ladd At the start of the game, the player is on “square zero”. board[0] always equals 0, and has no effect: -这次,我们首先来判断第一次遇到的是梯子还是蛇。因为没有梯子会把玩家直接送到25,所以这个判断是安全的。开始时,玩家的位置在"0",```board[0]```的值永远为0: +这次,我们首先来判断第一次遇到的是梯子还是蛇。因为没有梯子会把玩家直接送到25,所以这个判断是安全的。开始时,玩家的位置在"0",`board[0]`的值永远为0: ``` do { @@ -354,11 +353,11 @@ println("Game over!") ``` After the code checks for snakes and ladders, the dice is rolled, and the player is moved forward by diceRoll squares. The current loop execution then ends. -在判断遇到的时梯子还是蛇之后,我们掷骰子,玩家前进```diceRoll```个格子。当前循环结束。 +在判断遇到的时梯子还是蛇之后,我们掷骰子,玩家前进`diceRoll`个格子。当前循环结束。 The loop’s condition (while square < finalSquare) is the same as before, but this time it is not evaluated until the end of the first run through the loop. The structure of the do-while loop is better suited to this game than the while loop in the previous example. In the do-while loop above, square += board[square] is always executed immediately after the loop’s while condition confirms that square is still on the board. This behavior removes the need for the array bounds check seen in the earlier version of the game. -这里的循环条件(```while square < finalSquare```)和前面相同,但它会在循环结束后被执行。```do-while```循环结构比前面的```while```更适合这个游戏。使用```do-while```时,```square+=board[square]```会立刻被执行,它省去了上个例子中对数组越界的判断。 +这里的循环条件(`while square < finalSquare`)和前面相同,但它会在循环结束后被执行。`do-while`循环结构比前面的`while`更适合这个游戏。使用`do-while`时,`square+=board[square]`会立刻被执行,它省去了上个例子中对数组越界的判断。 ##条件语句 @@ -368,13 +367,13 @@ It is often useful to execute different pieces of code based on certain conditio Swift provides two ways to add conditional branches to your code, known as the if statement and the switch statement. Typically, you use the if statement to evaluate simple conditions with only a few possible outcomes. The switch statement is better suited to more complex conditions with multiple possible permutations, and is useful in situations where pattern-matching can help select an appropriate code branch to execute. -Swift提供了两种条件判断的语句,它们是```if```和```switch```。通常情况下,在条件分支比较少时,你使用```if```语句,```switch```语句用来处理复杂的判断条件和过多的条件分支,此外```switch```在模式匹配上非常有用。 +Swift提供了两种条件判断的语句,它们是`if`和`switch`。通常情况下,在条件分支比较少时,你使用`if`语句,`switch`语句用来处理复杂的判断条件和过多的条件分支,此外`switch`在模式匹配上非常有用。 ###If In its simplest form, the if statement has a single if condition. It executes a set of statements only if that condition is true: -```If```语句很简单,当判断条件为```true```时,执行一段代码: +`If`语句很简单,当判断条件为`true`时,执行一段代码: ``` var temperatureInFahrenheit = 30 @@ -390,7 +389,7 @@ The preceding example checks whether the temperature is less than or equal to 32 The if statement can provide an alternative set of statements, known as an else clause, for when the if condition is false. These statements are indicated by the else keyword: -```if```语句通常和```else```搭配使用,当```if```语句返回```false```时,```else```分支的代码会被执行: +`if`语句通常和`else`搭配使用,当`if`语句返回`false`时,`else`分支的代码会被执行: ``` temperatureInFahrenheit = 40 @@ -404,11 +403,11 @@ if temperatureInFahrenheit <= 32 { ``` One of these two branches is always executed. Because the temperature has increased to 40 degrees Fahrenheit, it is no longer cold enough to advise wearing a scarf, and so the else branch is triggered instead. -这种情况下```if```和```else```两个分支中的一个一定会被执行到。因为温度已经升高到40华氏度,不需要再建议带围巾了,因此else语句的代码段被执行。 +这种情况下`if`和`else`两个分支中的一个一定会被执行到。因为温度已经升高到40华氏度,不需要再建议带围巾了,因此else语句的代码段被执行。 You can chain multiple if statements together, to consider additional clauses: -你也可以将多个```if```语句连起来使用: +你也可以将多个`if`语句连起来使用: ``` temperatureInFahrenheit = 90 @@ -424,9 +423,9 @@ if temperatureInFahrenheit <= 32 { Here, an additional if statement is added to respond to particularly warm temperatures. The final else clause remains, and prints a response for any temperatures that are neither too warm nor too cold. -这里,多了一个```if```语句用来判断特定的温度范围。仍然有一个```else```在最后面,当温度既不高又不低得情况下打印出相应的信息: +这里,多了一个`if`语句用来判断特定的温度范围。仍然有一个`else`在最后面,当温度既不高又不低得情况下打印出相应的信息: -最后的```else```语句是可选的,如果它所在的分支不不需要执行,则可以将它排除: +最后的`else`语句是可选的,如果它所在的分支不不需要执行,则可以将它排除: ``` temperatureInFahrenheit = 72 @@ -438,17 +437,17 @@ if temperatureInFahrenheit <= 32 { ``` In this example, the temperature is neither too cold nor too warm to trigger the if or else if conditions, and so no message is printed. -在这个例子中,温度不满足```if```和```else if ```的执行条件,因此没有信息会被打印出来。 +在这个例子中,温度不满足`if`和`else if`的执行条件,因此没有信息会被打印出来。 ###Switch A switch statement considers a value and compares it against several possible matching patterns. It then executes an appropriate block of code, based on the first pattern that matches successfully. A switch statement provides an alternative to the if statement for responding to multiple potential states. -一条```switch```语句会将一个值和多种模式进行匹配。匹配成功则执行该条件所对应的代码。```switch```是一种可以替换```if```进行条件判断的语句。 +一条`switch`语句会将一个值和多种模式进行匹配。匹配成功则执行该条件所对应的代码。`switch`是一种可以替换`if`进行条件判断的语句。 In its simplest form, a switch statement compares a value against one or more values of the same type: -最简单的```switch```的语法是用来比较一个或多个类型相同的值: +最简单的`switch`的语法是用来比较一个或多个类型相同的值: ``` switch some value to consider { @@ -464,20 +463,20 @@ default: Every switch statement consists of multiple possible cases, each of which begins with the case keyword. In addition to comparing against specific values, Swift provides several ways for each case to specify more complex matching patterns. These options are described later in this section. -每个```switch```语句都对应多个```case```语句。除了可以用```case```语句来比较具体的值以外,Swift提供了许多复杂的模式匹配,下一小节会详细介绍。 +每个`switch`语句都对应多个`case`语句。除了可以用`case`语句来比较具体的值以外,Swift提供了许多复杂的模式匹配,下一小节会详细介绍。 The body of each switch case is a separate branch of code execution, in a similar manner to the branches of an if statement. The switch statement determines which branch should be selected. This is known as switching on the value that is being considered. -```switch```语句内包含多个代码执行分支,这点和```if```语句很像。```switch```语句决定了那个分支会被执行,通常是根据变量值来决定的。 +`switch`语句内包含多个代码执行分支,这点和`if`语句很像。`switch`语句决定了那个分支会被执行,通常是根据变量值来决定的。 Every switch statement must be exhaustive. That is, every possible value of the type being considered must be matched by one of the switch cases. If it is not appropriate to provide a switch case for every possible value, you can define a default catch-all case to cover any values that are not addressed explicitly. This catch-all case is indicated by the keyword default, and must always appear last. -每个```switch```语句必须是完整的,意思是它提供的分支条件必须能涵盖所有情况,你可以定义一个默认的分支条件用来处理一些意外的条件。这种分支通常用关键字```default```表示,并且它必须是最后一个分支条件。 +每个`switch`语句必须是完整的,意思是它提供的分支条件必须能涵盖所有情况,你可以定义一个默认的分支条件用来处理一些意外的条件。这种分支通常用关键字`default`表示,并且它必须是最后一个分支条件。 This example uses a switch statement to consider a single lowercase character called someCharacter: -这个例子使用```switch```语句类匹配一个小写字母变量```someCharacter```: +这个例子使用`switch`语句类匹配一个小写字母变量`someCharacter`: ``` let someCharacter: Character = "e" @@ -494,25 +493,25 @@ default: ``` The switch statement’s first case matches all five lowercase vowels in the English language. Similarly, its second case matches all lowercase English consonants. -```switch```语句的第一个```case```分支是匹配五个元音字母。同理,第二个```case```分支用来匹配所有的字符常量。 +`switch`语句的第一个`case`分支是匹配五个元音字母。同理,第二个`case`分支用来匹配所有的字符常量。 It is not practical to write all other possible characters as part of a switch case, and so this switch statement provides a default case to match all other characters that are not vowels or consonants. This provision ensures that the switch statement is exhaustive. -通常来说列举出所有的字符不太现实,因此```switch```语句提供了```default```分支用来匹配所有其它的字符,这确保了```switch```语句的完整性。 +通常来说列举出所有的字符不太现实,因此`switch`语句提供了`default`分支用来匹配所有其它的字符,这确保了`switch`语句的完整性。 ###没有隐式贯穿 In contrast with switch statements in C and Objective-C, switch statements in Swift do not fall through the bottom of each case and into the next one by default. Instead, the entire switch statement finishes its execution as soon as the first matching switch case is completed, without requiring an explicit break statement. This makes the switch statement safer and easier to use than in C, and avoids executing more than one switch case by mistake. -和C语言或Objective-C相比,Swift中的```switch```语句在执行完一条```case```分支的代码后,则认为```switch```语句执行完毕。在某个```case```分支没有```break```的情况下,不会继续执行下一条```case```分支的代码。这比C语言更简单和安全。 +和C语言或Objective-C相比,Swift中的`switch`语句在执行完一条`case`分支的代码后,则认为`switch`语句执行完毕。在某个`case`分支没有`break`的情况下,不会继续执行下一条`case`分支的代码。这比C语言更简单和安全。 >注意: ->你也可以在```case```分支代码执行前使用```break```语句来跳出这个分支,详见后面的[switch语句中break一节](link)。 +>你也可以在`case`分支代码执行前使用`break`语句来跳出这个分支,详见后面的[switch语句中break一节](link)。 The body of each case must contain at least one executable statement. It is not valid to write the following code, because the first case is empty: -每条```case```分支的函数体必须至少包含一行可执行代码。下面的代码是不合法的,因为第一条case分支的函数体为空: +每条`case`分支的函数体必须至少包含一行可执行代码。下面的代码是不合法的,因为第一条case分支的函数体为空: ``` let anotherCharacter: Character = "a" @@ -528,11 +527,11 @@ default: Unlike a switch statement in C, this switch statement does not match both "a" and "A". Rather, it reports a compile-time error that case "a": does not contain any executable statements. This approach avoids accidental fallthrough from one case to another, and makes for safer code that is clearer in its intent. -和C语言不同,```switch```语句不会既匹配`"a"`又匹配`"A"`。遇到这种情况,编译器会给出错误提示。这条规则会避免意外的执行了其它分支的代码。 +和C语言不同,`switch`语句不会既匹配`"a"`又匹配`"A"`。遇到这种情况,编译器会给出错误提示。这条规则会避免意外的执行了其它分支的代码。 Multiple matches for a single switch case can be separated by commas, and can be written over multiple lines if the list is long: -一条```case```分支也可以匹配多个判断条件,用逗号隔开: +一条`case`分支也可以匹配多个判断条件,用逗号隔开: ``` switch some value to consider { @@ -542,14 +541,14 @@ value 2: } ``` >注意 ->对于```switch```语句的某个case分支,你可以通过使用```fallthrough```关键字来强制贯穿改```case```分支。 +>对于`switch`语句的某个case分支,你可以通过使用`fallthrough`关键字来强制贯穿改`case`分支。 >更对细节在[Fallthrough](link)一节有所介绍 ###区间匹配 Values in switch cases can be checked for their inclusion in a range. This example uses number ranges to provide a natural-language count for numbers of any size: -```switch```语句的```case```分支可以是一个值区间同样支持范围匹配。下面这个例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式: +`switch`语句的`case`分支可以是一个值区间同样支持范围匹配。下面这个例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式: ``` let count = 3_000_000_000_000 @@ -579,11 +578,11 @@ println("There are \(naturalCount) \(countedThings).") You can use tuples to test multiple values in the same switch statement. Each element of the tuple can be tested against a different value or range of values. Alternatively, use the underscore (_) identifier to match any possible value. -你可以使用元组在同一个```switch```语句中测试多个值。元组中的每个元素可以是一个区间,也可以是不同的值。我们使用(_)来匹配任何可能的值。 +你可以使用元组在同一个`switch`语句中测试多个值。元组中的每个元素可以是一个区间,也可以是不同的值。我们使用(_)来匹配任何可能的值。 The example below takes an (x, y) point, expressed as a simple tuple of type (Int, Int), and categorizes it on the graph that follows the example: -下面的例子使用一个元组类型(```Int```,```Int```)的点(x,y)并用图标来描述它的分布: +下面的例子使用一个元组类型(`Int`,`Int`)的点`(x,y)`并用图标来描述它的分布: ``` let somePoint = (1, 1) @@ -607,21 +606,21 @@ default: The switch statement determines if the point is at the origin (0, 0); on the red x-axis; on the orange y-axis; inside the blue 4-by-4 box centered on the origin; or outside of the box. -```switch```语句用来判断这个点是否在原点;红色的X轴上;橘黄色的Y轴上;在蓝色的4x4的盒子内,还是在盒子外面。 +`switch`语句用来判断这个点是否在原点;红色的X轴上;橘黄色的Y轴上;在蓝色的4x4的盒子内,还是在盒子外面。 Unlike C, Swift allows multiple switch cases to consider the same value or values. In fact, the point (0, 0) could match all four of the cases in this example. However, if multiple matches are possible, the first matching case is always used. The point (0, 0) would match case (0, 0) first, and so all other matching cases would be ignored. -不像C语言,Swift支持不同的```case```分支匹配同一个结果,在这个例子中,点(0,0)满足所有4个分之条件。这种情况下只有第一条```case```语句被执行。点(0,0)会首先匹配第一条```case(0,0)```,后面的```case```语句会被忽略掉。 +不像C语言,Swift支持不同的`case`分支匹配同一个结果,在这个例子中,点(0,0)满足所有4个分之条件。这种情况下只有第一条`case`语句被执行。点(0,0)会首先匹配第一条`case(0,0)`,后面的`case`语句会被忽略掉。 ###值绑定(Value Bindings) A switch case can bind the value or values it matches to temporary constants or variables, for use in the body of the case. This is known as value binding, because the values are “bound” to temporary constants or variables within the case’s body. -```switch```语句允许在一个```case```分支中,将待匹配的值绑定到一些常量或临时变量上。这样就可以在case分支的代码段中使用这些变量或常量,这就是值绑定。 +`switch`语句允许在一个`case`分支中,将待匹配的值绑定到一些常量或临时变量上。这样就可以在case分支的代码段中使用这些变量或常量,这就是值绑定。 -The example below takes an (x, y) point, expressed as a tuple of type (Int, Int) and categorizes it on the graph that follows: +The example below takes an `(x, y)` point, expressed as a tuple of type` (Int, Int) `and categorizes it on the graph that follows: -下面的例子将定义一个(Int,Int)型的元组变量(x,y),并归类它在图中的位置: +下面的例子将定义一个`(Int,Int)`型的元组变量`(x,y)`,并归类它在图中的位置: ``` let anotherPoint = (2, 0) @@ -640,33 +639,33 @@ case let (x, y): The switch statement determines if the point is on the red x-axis, on the orange y-axis, or elsewhere, on neither axis. -上面我们通过```switch```语句判断了```anotherPoint```这个点是否在红色的X,y轴上或者在非轴上的任意位置。 +上面我们通过`switch`语句判断了`anotherPoint`这个点是否在红色的X,y轴上或者在非轴上的任意位置。 The three switch cases declare placeholder constants x and y, which temporarily take on one or both tuple values from anotherPoint. The first case, case (let x, 0), matches any point with a y value of 0 and assigns the point’s x value to the temporary constant x. Similarly, the second case, case (0, let y), matches any point with an x value of 0 and assigns the point’s y value to the temporary constant y. -上面三条```case```语句使用临时变量```x```,```y```来匹配```anotherPoint```中的值。第一条```case(let x, 0)```语句用来匹配所有```y```值为0的点,并把该点的```x```值赋值给常量```x```。同理,```case(0,let y)```匹配所有```x```值为0的点,并把该点得```y```值赋给常量```y```。 +上面三条`case`语句使用临时变量`x`,`y`来匹配`anotherPoint`中的值。第一条`case(let x, 0)`语句用来匹配所有`y`值为0的点,并把该点的`x`值赋值给常量`x`。同理,`case(0,let y)`匹配所有`x`值为0的点,并把该点得```y```值赋给常量`y`。 Once the temporary constants are declared, they can be used within the case’s code block. Here, they are used as shorthand for printing the values with the println function. -临时变量被声明后,它就可以用在```case```分支的代码中。本例中```x```,```y```在```println```方法中被打印出来。 +临时变量被声明后,它就可以用在`case`分支的代码中。本例中`x`,`y`在`println`方法中被打印出来。 Note that this switch statement does not have a default case. The final case, case let (x, y), declares a tuple of two placeholder constants that can match any value. As a result, it matches all possible remaining values, and a default case is not needed to make the switch statement exhaustive. -注意到上面的```switch```语句并没有```default```分支,原因是最后一条```case let(x,y)```涵盖了所有其他情况,因此我们不需要再写一个```default```分支了。 +注意到上面的`switch`语句并没有`default`分支,原因是最后一条`case let(x,y)`涵盖了所有其他情况,因此我们不需要再写一个`default`分支了。 In the example above, x and y are declared as constants with the let keyword, because there is no need to modify their values within the body of the case. However, they could have been declared as variables instead, with the var keyword. If this had been done, a temporary variable would have been created and initialized with the appropriate value. Any changes to that variable would only have an effect within the body of the case. -在上面的例子中,我们通过```let```关键字将```x```,```y```声明为常量,原因是我们不需要修改他们的值。同样我们也可以用```var```关键字声明他们为变量,如果把它们声明为变量则需要为他们指定合适的初始值。任何对于它们值的修改也仅仅局限在```case```分支的代码中有效。 +在上面的例子中,我们通过`let`关键字将`x`,`y`声明为常量,原因是我们不需要修改他们的值。同样我们也可以用`var`关键字声明他们为变量,如果把它们声明为变量则需要为他们指定合适的初始值。任何对于它们值的修改也仅仅局限在`case`分支的代码中有效。 ###Where A switch case can use a where clause to check for additional conditions. -在```case```语句的条件分支中可以使用```where```关键字增加附加条件的判断。 +在`case`语句的条件分支中可以使用`where`关键字增加附加条件的判断。 The example below categorizes an (x, y) point on the following graph: -还是上面的例子,用来归类(x,y)点所在图中得位置: +还是上面的例子,用来归类`(x,y)`点所在图中得位置: ``` let yetAnotherPoint = (1, -1) @@ -684,15 +683,15 @@ case let (x, y): The switch statement determines if the point is on the green diagonal line where x == y, on the purple diagonal line where x == -y, or neither. -上面的```switch```语句用来检测```yetAnotherPoint```这个点是否在绿色(x==y)或紫色(x==-y)的对角线上。 +上面的`switch`语句用来检测`yetAnotherPoint`这个点是否在绿色(x==y)或紫色(x==-y)的对角线上。 The three switch cases declare placeholder constants x and y, which temporarily take on the two tuple values from point. These constants are used as part of a where clause, to create a dynamic filter. The switch case matches the current value of point only if the where clause’s condition evaluates to true for that value. -上面的三条```switch```语句声明了常量```x```和```y```用来临时保存```yetAnotherPoint```中的坐标值。这两个常量同时也被```where```用来创建一个过滤条件。只有当```where```的过滤条件返回```true```时,```case```分支的代码才会被执行。 +上面的三条`switch`语句声明了常量`x`和`y`用来临时保存`yetAnotherPoint`中的坐标值。这两个常量同时也被`where`用来创建一个过滤条件。只有当`where`的过滤条件返回`true`时,`case`分支的代码才会被执行。 As in the previous example, the final case matches all possible remaining values, and so a default case is not needed to make the switch statement exhaustive. -和上面的例子一样```default```分支在这个例子中也可以被忽略。 +和上面的例子一样`default`分支在这个例子中也可以被忽略。 ###控转移语句 @@ -707,7 +706,7 @@ Control transfer statements change the order in which your code is executed, by The control, break and fallthrough statements are described below. The return statement is described in Functions. -我们下面将会讨论```control```,```break````,```return```语句,```return```将会在[函数](link)一章讨论。 +我们下面将会讨论`control`,`break`,`return`语句,`return`将会在[函数](link)一章讨论。 @@ -715,10 +714,10 @@ The control, break and fallthrough statements are described below. The return st The continue statement tells a loop to stop what it is doing and start again at the beginning of the next iteration through the loop. It says “I am done with the current loop iteration” without leaving the loop altogether. -```continue```用来终止当前循环并开始执行下一次循环。它会说“本次循环结束了”,但并不会跳出循环。 +`continue`用来终止当前循环并开始执行下一次循环。它会说“本次循环结束了”,但并不会跳出循环。 >注意: ->在```for-condition-increment```一节,即使执行了```continue```,循环的累加器仍会自动加1。 +>在`for-condition-increment`一节,即使执行了`continue`,循环的累加器仍会自动加1。 >循环会继续,仅仅是循环体内的代码不会被执行。 The following example removes all vowels and spaces from a lowercase string to create a cryptic puzzle phrase: @@ -741,33 +740,33 @@ println(puzzleOutput) ``` The code above calls the continue keyword whenever it matches a vowel or a space, causing the current iteration of the loop to end immediately and to jump straight to the start of the next iteration. This behavior enables the switch block to match (and ignore) only the vowel and space characters, rather than requiring the block to match every character that should get printed. -在上面的代码中,一旦出现元音字母,当前循环就会被终止,并重新开始下一次循环。这会让```switch```语句去匹配元音字符或空字符时不做处理,而不是让每一个匹配到的字符都被打印出来。 +在上面的代码中,一旦出现元音字母,当前循环就会被终止,并重新开始下一次循环。这会让`switch`语句去匹配元音字符或空字符时不做处理,而不是让每一个匹配到的字符都被打印出来。 ###break The break statement ends execution of an entire control flow statement immediately. The break statement can be used inside a switch statement or loop statement when you want to terminate the execution of the switch or loop statement earlier than would otherwise be the case. -```break```语句会立刻终止当前执行的整个控制流。```break```可被用在```switch```语句里面或循环中用来提前结束控制流。 +`break`语句会立刻终止当前执行的整个控制流。`break`可被用在`switch`语句里面或循环中用来提前结束控制流。 ###循环体内的break When used inside a loop statement, break ends the loop’s execution immediately, and transfers control to the first line of code after the loop’s closing brace (}). No further code from the current iteration of the loop is executed, and no further iterations of the loop are started. -当在循环体内执行```break```时,会退出整个循环,代码从循环体后面的第一行开始执行,break语句后面的代码将不会执行,下一次循环也不会开始。 +当在循环体内执行`break`时,会退出整个循环,代码从循环体后面的第一行开始执行,break语句后面的代码将不会执行,下一次循环也不会开始。 ###Switch语句中得break When used inside a switch statement, break causes the switch statement to end its execution immediately, and to transfer control to the first line of code after the switch statement’s closing brace (}). -当在```switch```中使用```break```时,会立即终止改```switch``代码块的执行,并且跳转到```switch```代码块结束的大括号(```}```)后的第一行代码。 +当在`switch`中使用`break`时,会立即终止改`switch`代码块的执行,并且跳转到`switch`代码块结束的大括号(`}`)后的第一行代码。 This behavior can be used to match and ignore one or more cases in a switch statement. Because Swift’s switch statement is exhaustive and does not allow empty cases, it is sometimes necessary to deliberately match and ignore a case in order to make your intentions explicit. You do this by writing the break statement as the entire body of the case you want to ignore. When that case is matched by the switch statement, the break statement inside the case ends the switch -这种行为可被用来忽略或跳过```switch```中的某个```case```。由于Swift要求```switch```的分支条件必须完整并且不允许空的```case```分支,因此在有些情况下使用```break```特意跳出某个分支会很必要。你可以通过在```case```的代码快中加入```break````来达到这个效果。当```case```分支的代码块被执行时,```break```会终止```switch```语句的执行。 +这种行为可被用来忽略或跳过`switch`中的某个`case`。由于Swift要求`switch`的分支条件必须完整并且不允许空的`case`分支,因此在有些情况下使用`break`特意跳出某个分支会很必要。你可以通过在`case`的代码快中加入`break`来达到这个效果。当`case`分支的代码块被执行时,`break`会终止`switch`语句的执行。 >注意: ->当```switch```的一个分支仅仅包含注释时,编译器会给出错误提示。 ->注释并不是真正的代码,他不能达到忽略这个```case```分支的作用。有哪次还是需要使用```break```。 +>当`switch`的一个分支仅仅包含注释时,编译器会给出错误提示。 +>注释并不是真正的代码,他不能达到忽略这个`case`分支的作用。有哪次还是需要使用`break`。 The following example switches on a Character value and determines whether it represents a number symbol in one of four languages. Multiple values are covered in a single switch case for brevity: @@ -799,25 +798,25 @@ if let integerValue = possibleIntegerValue { This example checks numberSymbol to determine whether it is a Latin, Arabic, Chinese, or Thai symbol for the numbers 1 to 4. If a match is found, one of the switch statement’s cases sets an optional Int? variable called possibleIntegerValue to an appropriate integer value. -这个例子用来判断```numberSymbol```是否是拉丁文,阿拉伯文,中文或泰语中的1到4之一。如果被匹配到,该```switch```分支语句给```Int?```类型变量```possibleIntegerValue```设置一个整数值。 +这个例子用来判断`numberSymbol`是否是拉丁文,阿拉伯文,中文或泰语中的1到4之一。如果被匹配到,该`switch`分支语句给`Int?`类型变量`possibleIntegerValue`设置一个整数值。 After the switch statement completes its execution, the example uses optional binding to determine whether a value was found. The possibleIntegerValue variable has an implicit initial value of nil by virtue of being an optional type, and so the optional binding will succeed only if possibleIntegerValue was set to an actual value by one of the switch statement’s first four cases. -当switch代码块执行完后,接下来的代码先判断```possibleIntegerValue``是否被绑定成功。因为是可选类型的缘故,```possibleIntegerValue```有一个隐式的初始值nil,所以仅仅当```possibleIntegerValue```曾被switch代码块的前四个分支中的某个设置过一个值时,可选的绑定将会被判定为成功。 +当switch代码块执行完后,接下来的代码先判断`possibleIntegerValue`是否被绑定成功。因为是可选类型的缘故,`possibleIntegerValue`有一个隐式的初始值nil,所以仅仅当`possibleIntegerValue`曾被switch代码块的前四个分支中的某个设置过一个值时,可选的绑定将会被判定为成功。 It is not practical to list every possible Character value in the example above, so a default case provides a catchall for any characters that are not matched. This default case does not need to perform any action, and so it is written with a single break statement as its body. As soon as the default statement is matched, the break statement ends the switch statement’s execution, and code execution continues from the if let statement. -在上面的例子中,想要把```Character```所有的的可能性都枚举出来是不现实的,所以使用```default```分支来包含所有上面没有匹配到字符的情况。由于这个```default```分支不需要执行任何动作,所以它只写了一条```break```语句。一旦落入到```default```分支中后,```break```语句就完成了该分支的所有代码操作,代码继续向下,开始执行```if let```语句。 +在上面的例子中,想要把`Character`所有的的可能性都枚举出来是不现实的,所以使用`default`分支来包含所有上面没有匹配到字符的情况。由于这个`default`分支不需要执行任何动作,所以它只写了一条`break`语句。一旦落入到`default`分支中后,`break`语句就完成了该分支的所有代码操作,代码继续向下,开始执行`if let`语句。 ###Fallthrough Switch statements in Swift do not fall through the bottom of each case and into the next one. Instead, the entire switch statement completes its execution as soon as the first matching case is completed. By contrast, C requires you to insert an explicit break statement at the end of every switch case to prevent fallthrough. Avoiding default fallthrough means that Swift switch statements are much more concise and predictable than their counterparts in C, and thus they avoid executing multiple switch cases by mistake. -Swift中的Switch语句不会从上到下进入每一个case分支。相反,一旦有一个case分支被匹配成功,整个state语句就结束执行了。相比之下,在C语言中,为了防止switch语句会贯穿执行每一个case分支,你需要在每个case分支的末尾插入```break```语句。和C语言相比,Swift支持这种避免贯穿行为会让```switch```语句更简洁和更安全也能规避错误执行多个case分支的情况。 +Swift中的Switch语句不会从上到下进入每一个case分支。相反,一旦有一个case分支被匹配成功,整个state语句就结束执行了。相比之下,在C语言中,为了防止switch语句会贯穿执行每一个case分支,你需要在每个case分支的末尾插入`break`语句。和C语言相比,Swift支持这种避免贯穿行为会让`switch`语句更简洁和更安全也能规避错误执行多个case分支的情况。 If you really need C-style fallthrough behavior, you can opt in to this behavior on a case-by-case basis with the fallthrough keyword. The example below uses fallthrough to create a textual description of a number: -如果你一定要使用C风格的贯穿(fallthrough)机制,你可以在每个需要支持该特性的case分支中使用```fallthrough```关键字。下面这个例子展示了如何使用```fallthrough```来实现对数字的文本描述: +如果你一定要使用C风格的贯穿(fallthrough)机制,你可以在每个需要支持该特性的case分支中使用`fallthrough`关键字。下面这个例子展示了如何使用`fallthrough`来实现对数字的文本描述: ``` let integerToDescribe = 5 @@ -835,34 +834,34 @@ println(description) This example declares a new String variable called description and assigns it an initial value. The function then considers the value of integerToDescribe using a switch statement. If the value of integerToDescribe is one of the prime numbers in the list, the function appends text to the end of description, to note that the number is prime. It then uses the fallthrough keyword to “fall into” the default case as well. The default case adds some extra text to the end of the description, and the switch statement is complete. -这个例子中声明了一个叫```description```的```string```类型的变量,并且为其赋了初值。然后这个函数通过```switch```语句来判断```integerToDescribe```的值。如果```integerToDescribe```的值为数组中的一个素数,则该函数会为```decription```后面追加一段文本用来提示改数字式质数。然后会使用```fallthrough```关键字来执行```default```中的代码。在```default```分支中会为```description```后面继续追加一段文本。至此,```switch```语句才算执行完成。 +这个例子中声明了一个叫`description`的`string`类型的变量,并且为其赋了初值。然后这个函数通过`switch`语句来判断`integerToDescribe`的值。如果`integerToDescribe`的值为数组中的一个素数,则该函数会为`decription`后面追加一段文本用来提示改数字式质数。然后会使用`fallthrough`关键字来执行`default`中的代码。在`default`分支中会为`description`后面继续追加一段文本。至此,`switch`语句才算执行完成。 If the value of integerToDescribe is not in the list of known prime numbers, it is not matched by the first switch case at all. There are no other specific cases, and so integerToDescribe is matched by the catchall default case. -如果```integerToDescribe```的值不在这组质数当中,则它不会和第一条```case```语句匹配。由于没有其它的分支存在,所以```integerToDescribe```会落入```default```分支。 +如果`integerToDescribe`的值不在这组质数当中,则它不会和第一条`case`语句匹配。由于没有其它的分支存在,所以`integerToDescribe`会落入`default`分支。 After the switch statement has finished executing, the number’s description is printed using the println function. In this example, the number 5 is correctly identified as a prime number. -当```switch```语句执行完成后,关于这个数字的描述会通过```println```函数打印出来。在这个例子中,数字```5```被正确的识别为一个质数。 +当`switch`语句执行完成后,关于这个数字的描述会通过`println`函数打印出来。在这个例子中,数字`5`被正确的识别为一个质数。 >注意: ->和C语言的```switch```语句一样,```fallthrough```不会检查它落入执行的```case```分支的条件是否匹配, ->它只是简单的执行下一条```case```(或```default```)中的代码。 +>和C语言的`switch`语句一样,`fallthrough`不会检查它落入执行的`case`分支的条件是否匹配, +>它只是简单的执行下一条`cast(或`default`)中的代码。 ###Labeled语句 You can nest loops and switch statements inside other loops and switch statements in Swift to create complex control flow structures. However, loops and switch statements can both use the break statement to end their execution prematurely. Therefore, it is sometimes useful to be explicit about which loop or switch statement you want a break statement to terminate. Similarly, if you have multiple nested loops, it can be useful to be explicit about which loop the continue statement should affect. -在```swift```中,可以在循环或```switch```函数中嵌套循环或```switch```函数来实现比较复杂的控制流结构。但是,在循环或```switch```函数中可以使用```break```语句提前终止其执行过程。因此,有些时候显示的调用```break```来标识终止循环或```switch```是非常有好处的。类似的,如果一个循环中嵌套了多个循环,使用```continue```来标识其影响的循环体也是很有用的。 +在`swift`中,可以在循环或`switch`函数中嵌套循环或`switch`函数来实现比较复杂的控制流结构。但是,在循环或`switch`函数中可以使用`break`语句提前终止其执行过程。因此,有些时候显示的调用`break`来标识终止循环或`switch`是非常有好处的。类似的,如果一个循环中嵌套了多个循环,使用`continue`来标识其影响的循环体也是很有用的。 To achieve these aims, you can mark a loop statement or switch statement with a statement label, and use this label with the break statement or continue statement to end or continue the execution of the labeled statement. -为了实现上面的目标,你可以通过标签来标识某个循环或```switch```语句。使用```break```或```continue```时,带上这个标签,这个标签可以用来结束或执行被标记的代码段。 +为了实现上面的目标,你可以通过标签来标识某个循环或`switch`语句。使用`break`或`continue`时,带上这个标签,这个标签可以用来结束或执行被标记的代码段。 A labeled statement is indicated by placing a label on the same line as the statement’s introducer keyword, followed by a colon. Here’s an example of this syntax for a while loop, although the principle is the same for all loops and switch statements -标签语句通常被放到一些关键字的前面,通过分号隔开。下面是一个通过标签来标记```while```语句的例子,循环或```switch```语句和它类似: +标签语句通常被放到一些关键字的前面,通过分号隔开。下面是一个通过标签来标记`while`语句的例子,循环或`switch`语句和它类似: ``` label name: while condition { @@ -873,7 +872,7 @@ label name: while condition { The following example uses the break and continue statements with a labeled while loop for an adapted version of the Snakes and Ladders game that you saw earlier in this chapter. This time around, the game has an extra rule: -下面这个例子将使用```break```和```continue```,配合带标签的```while```循环,该循环和前面的梯子和蛇的例子一直。这次,该游戏新增加了一条规则 +下面这个例子将使用`break`和`continue`,配合带标签的`while`循环,该循环和前面的梯子和蛇的例子一直。这次,该游戏新增加了一条规则 * 为了胜利,你必须恰好到达第25个格子中 @@ -888,7 +887,7 @@ The game board is the same as before:” The values of finalSquare, board, square, and diceRoll are initialized in the same way as before: -```finalSquare```,```board```,```square```和```diceRoll```的值和之前初始化的值相同: +`finalSquare`,`board`,`square`和`diceRoll`的值和之前初始化的值相同: ``` let finalSquare = 25 @@ -901,11 +900,11 @@ var diceRoll = 0 ``` This version of the game uses a while loop and a switch statement to implement the game’s logic. The while loop has a statement label called gameLoop, to indicate that it is the main game loop for the Snakes and Ladders game. -这个版本会使用```while```循环和```switch```语句来实现游戏的逻辑。```while```循环有个标签叫做```gameLoop```,用来表示这个循环是这个游戏的主循环。 +这个版本会使用`while`循环和`switch`语句来实现游戏的逻辑。`while`循环有个标签叫做`gameLoop`,用来表示这个循环是这个游戏的主循环。 The while loop’s condition is while square != finalSquare, to reflect that you must land exactly on square 25: -```while```循环的条件是```while square != finalSquare```用来表示你必须正好落在第25个格子中: +`while`循环的条件是`while square != finalSquare`用来表示你必须正好落在第25个格子中: ``` gameLoop: while square != finalSquare { @@ -928,20 +927,20 @@ println("Game over!") ``` The dice is rolled at the start of each loop. Rather than moving the player immediately, a switch statement is used to consider the result of the move, and to work out if the move is allowed: -在每个循环开始前都需要掷骰子,与之前立刻移动玩家不同,这次利用```switch```语句计算每次掷骰子产生的结果,从而决 +在每个循环开始前都需要掷骰子,与之前立刻移动玩家不同,这次利用`switch`语句计算每次掷骰子产生的结果,从而决 定玩家是否可以移动: If the dice roll will move the player onto the final square, the game is over. The break gameLoop statement transfers control to the first line of code outside of the while loop, which ends the game. -* 如果掷骰子的结果恰好将玩家移动到最后的方格中,那么游戏结束。```break gameLoop```会将代码跳到循环后的第一条语句,继续执行后面的代码。 +* 如果掷骰子的结果恰好将玩家移动到最后的方格中,那么游戏结束。`break gameLoop`会将代码跳到循环后的第一条语句,继续执行后面的代码。 If the dice roll will move the player beyond the final square, the move is invalid, and the player needs to roll again. The continue gameLoop statement ends the current while loop iteration and begins the next iteration of the loop. -* 如果掷骰子的结果将玩家移动到超过最后一个方格的位置,那么这次结果是无效的,玩家需要重新掷骰子。```continue gameLoop```会将当前循环终止并重新开始下一次循环。 +* 如果掷骰子的结果将玩家移动到超过最后一个方格的位置,那么这次结果是无效的,玩家需要重新掷骰子。`continue gameLoop`会将当前循环终止并重新开始下一次循环。 In all other cases, the dice roll is a valid move. The player moves forward by diceRoll squares, and the game logic checks for any snakes and ladders. The loop then ends, and control returns to the while condition to decide whether another turn is required -* 在所有其余的情况中,掷骰子的结果是有效的,玩家会前进```diceRoll```个格子,游戏的逻辑会检测是否遇到梯子或者蛇。循环结束时,代码将回到```while```条件判定检查是否要进行下一次循环。 +* 在所有其余的情况中,掷骰子的结果是有效的,玩家会前进`diceRoll`个格子,游戏的逻辑会检测是否遇到梯子或者蛇。循环结束时,代码将回到`while`条件判定检查是否要进行下一次循环。 NOTE @@ -951,10 +950,10 @@ Note also that it is not strictly necessary to use the gameLoop label when calli >注意: ->如果```break```语句没有使用```gameLoop```标签,那么它将会中断```switch```代码块而不是```while```。 ->使用```gameLoop```标签可以更直观的体现循环在哪里被终止的。 +>如果`break`语句没有使用`gameLoop`标签,那么它将会中断`switch`代码块而不是`while`。 +>使用`gameLoop`标签可以更直观的体现循环在哪里被终止的。 ->我们还注意到,跳到下一次循环的语句:```continue gameLoop```并不一定要使用```gameLoop```标签。由于代码中只有一个循环,因此```continue```语句是没有歧义的,但是在这里使用```gameLoop```标签也是没有任何坏处的。在```break```旁边加上标签可以保证代码的一致性,是代码逻辑更清楚,更容易被人读懂和理解。 +>我们还注意到,跳到下一次循环的语句:`continue gameLoop`并不一定要使用`gameLoop`标签。由于代码中只有一个循环,因此`continue`语句是没有歧义的,但是在这里使用`gameLoop`标签也是没有任何坏处的。在`break`旁边加上标签可以保证代码的一致性,是代码逻辑更清楚,更容易被人读懂和理解。 From 38fd1df4167a0b3ea911b31bee35bcb3c5481779 Mon Sep 17 00:00:00 2001 From: jayson Date: Tue, 1 Jul 2014 14:17:45 +0800 Subject: [PATCH 217/261] add pics --- src/chapter2/05_Control_Flow.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index a9c650e..7c03e2f 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -35,7 +35,7 @@ This example prints the first few entries in the five-times-table: 下面这个例子可以打印出一个5次循环的结果: -``` +```Java for index in 1...5{ println("\(index) times 5 is \(index * 5)") } @@ -62,7 +62,7 @@ If you don’t need each value from the range, you can ignore the values by usin 如果你在遍历某个集合时并不关心集合中的元素,你可以通过下划线来代替集合中的元素变量名: -``` +```Java let base = 3 let power = 10 var answer = 1 @@ -81,7 +81,7 @@ Use the for-in loop with an array to iterate over its items:我们还可以 使用`for-in`遍历数组中的元素: -``` +```Java let names = ["Anna", "Alex", "Brian", "Jack"] for name in names { println("Hello, \(name)!") @@ -97,7 +97,7 @@ You can also iterate over a dictionary to access its key-value pairs. Each item 你也同样可以遍历字典中的key-value。遍历时,字典中的每个元素都以`(key,value)`元组结构返回,你也可以在`for-in`中将元组中的key,value当做常量显式的分解出来。这里,key被分解为为常量`animalName`,value被分解为`legCount`: -``` +```Java let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] for (animalName, legCount) in numberOfLegs { println("\(animalName)s have \(legCount) legs") @@ -116,7 +116,7 @@ In addition to arrays and dictionaries, you can also use the for-in loop to iter 除了数组和字典,你同样可以使用`for-in`来遍历字符串中的`Character`: -``` +```Java for character in "Hello" { println(character) } @@ -133,7 +133,7 @@ In addition to for-in loops, Swift supports traditional C-style for loops with a 除了使用`for-in`这种循环语句,Swift还提供了传统的C风格的`for`循环语句,通常它需要一个循环执行条件和一个累加器: -``` +```Java for var index = 0; index < 3; ++index { println("index is \(index)") } @@ -182,7 +182,7 @@ Constants and variables declared within the initialization expression (such as v 在for循环初始化时创建的变量或者常量只在循环体内有效,如果想获取循环结束时的`index`值,你必须将`index`显式的声明到循环语句前: -``` +```Java var index: Int for index = 0; index < 3; ++index { println("index is \(index)") @@ -227,7 +227,7 @@ This example plays a simple game of Snakes and Ladders (also known as Chutes and 下面是一个简单的Snakes and Ladders游戏(也叫Chutes and Ladders) -【图】 +![](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/snakesAndLadders_2x.png) The rules of the game are as follows: @@ -602,7 +602,7 @@ default: ``` -【图】 +![](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/coordinateGraphSimple_2x.png) The switch statement determines if the point is at the origin (0, 0); on the red x-axis; on the orange y-axis; inside the blue 4-by-4 box centered on the origin; or outside of the box. @@ -635,7 +635,7 @@ case let (x, y): // prints "on the x-axis with an x value of 2 ``` -【图】 +![](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/coordinateGraphMedium_2x.png) The switch statement determines if the point is on the red x-axis, on the orange y-axis, or elsewhere, on neither axis. @@ -679,7 +679,7 @@ case let (x, y): } // prints "(1, -1) is on the line x == -y ``` -【图】 +![](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/coordinateGraphComplex_2x.png) The switch statement determines if the point is on the green diagonal line where x == y, on the purple diagonal line where x == -y, or neither. @@ -883,7 +883,7 @@ If a particular dice roll would take you beyond square 25, you must roll again u The game board is the same as before:” 游戏的棋盘和前面的一样: -【图】 +![](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/snakesAndLadders_2x.png) The values of finalSquare, board, square, and diceRoll are initialized in the same way as before: From 13387f4eeb5d54a21c985b75a4f4c67a05597d8d Mon Sep 17 00:00:00 2001 From: jayson Date: Tue, 1 Jul 2014 14:20:49 +0800 Subject: [PATCH 218/261] add java code style --- src/chapter2/05_Control_Flow.md | 50 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index 7c03e2f..ba006fc 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -217,7 +217,7 @@ Here’s the general form of a while loop: 一个`while`循环从判断执行条件开始。如果条件为`true`,则循环执行循环体内的代码,知道条件变为`false`。下面是通用的`while`语法格式: -``` +```Java while condition { statements } @@ -247,7 +247,7 @@ The game board is represented by an array of Int values. Its size is based on a 游戏的板子可以看做是一个`Int`型的数组。大小由常量`finalSquare`决定,这个常量也会用来初始化数组和判断获胜条件。数组被初始化为26个0,注意不是25(数组范围从0到25): -``` +```Java let finalSquare = 25 var board = Int[](count: finalSquare + 1, repeatedValue: 0)” ``` @@ -256,7 +256,7 @@ Some squares are then set to have more specific values for the snakes and ladder 板子上的许多方格用来被指定为梯子或者蛇。如果是梯子,那么这个方格的值为正数,如果是蛇,则方格的值为负数: -``` +```Java board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 @@ -269,7 +269,7 @@ The player’s starting square is “square zero”, which is just off the botto 玩家从板子左下角的第0号方块开始,第一次掷骰子会将玩家移动到: -``` +```Java var square = 0 var diceRoll = 0 while square < finalSquare { @@ -314,7 +314,7 @@ Here’s the general form of a do-while loop: 下面是`do-while`语句的格式: -``` +```Java do { statements } while condition” @@ -324,7 +324,7 @@ Here’s the Snakes and Ladders example again, written as a do-while loop rather 还是上面的蛇和梯子的例子,我们来使用`do-while`实现,初始化变量的过程同`while`循环: -``` +```Java let finalSquare = 25 var board = Int[](count: finalSquare + 1, repeatedValue: 0) board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 @@ -340,7 +340,7 @@ At the start of the game, the player is on “square zero”. board[0] always eq 这次,我们首先来判断第一次遇到的是梯子还是蛇。因为没有梯子会把玩家直接送到25,所以这个判断是安全的。开始时,玩家的位置在"0",`board[0]`的值永远为0: -``` +```Java do { // move up or down for a snake or ladder square += board[square] @@ -375,7 +375,7 @@ In its simplest form, the if statement has a single if condition. It executes a `If`语句很简单,当判断条件为`true`时,执行一段代码: -``` +```Java var temperatureInFahrenheit = 30 if temperatureInFahrenheit <= 32 { println("It's very cold. Consider wearing a scarf.") @@ -391,7 +391,7 @@ The if statement can provide an alternative set of statements, known as an else `if`语句通常和`else`搭配使用,当`if`语句返回`false`时,`else`分支的代码会被执行: -``` +```Java temperatureInFahrenheit = 40 if temperatureInFahrenheit <= 32 { println("It's very cold. Consider wearing a scarf.") @@ -409,7 +409,7 @@ You can chain multiple if statements together, to consider additional clauses: 你也可以将多个`if`语句连起来使用: -``` +```Java temperatureInFahrenheit = 90 if temperatureInFahrenheit <= 32 { println("It's very cold. Consider wearing a scarf.") @@ -427,7 +427,7 @@ Here, an additional if statement is added to respond to particularly warm temper 最后的`else`语句是可选的,如果它所在的分支不不需要执行,则可以将它排除: -``` +```Java temperatureInFahrenheit = 72 if temperatureInFahrenheit <= 32 { println("It's very cold. Consider wearing a scarf.") @@ -449,7 +449,7 @@ In its simplest form, a switch statement compares a value against one or more va 最简单的`switch`的语法是用来比较一个或多个类型相同的值: -``` +```Java switch some value to consider { case value 1: respond to value 1 @@ -478,7 +478,7 @@ This example uses a switch statement to consider a single lowercase character ca 这个例子使用`switch`语句类匹配一个小写字母变量`someCharacter`: -``` +```Java let someCharacter: Character = "e" switch someCharacter { case "a", "e", "i", "o", "u": @@ -513,7 +513,7 @@ The body of each case must contain at least one executable statement. It is not 每条`case`分支的函数体必须至少包含一行可执行代码。下面的代码是不合法的,因为第一条case分支的函数体为空: -``` +```Java let anotherCharacter: Character = "a" switch anotherCharacter { case "a": @@ -533,7 +533,7 @@ Multiple matches for a single switch case can be separated by commas, and can be 一条`case`分支也可以匹配多个判断条件,用逗号隔开: -``` +```Java switch some value to consider { case value 1, value 2: @@ -550,7 +550,7 @@ Values in switch cases can be checked for their inclusion in a range. This examp `switch`语句的`case`分支可以是一个值区间同样支持范围匹配。下面这个例子展示了如何使用区间匹配来输出任意数字对应的自然语言格式: -``` +```Java let count = 3_000_000_000_000 let countedThings = "stars in the Milky Way" var naturalCount: String @@ -584,7 +584,7 @@ The example below takes an (x, y) point, expressed as a simple tuple of type (In 下面的例子使用一个元组类型(`Int`,`Int`)的点`(x,y)`并用图标来描述它的分布: -``` +```Java let somePoint = (1, 1) switch somePoint { case (0, 0): @@ -622,7 +622,7 @@ The example below takes an `(x, y)` point, expressed as a tuple of type` (Int, I 下面的例子将定义一个`(Int,Int)`型的元组变量`(x,y)`,并归类它在图中的位置: -``` +```Java let anotherPoint = (2, 0) switch anotherPoint { case (let x, 0): @@ -667,7 +667,7 @@ The example below categorizes an (x, y) point on the following graph: 还是上面的例子,用来归类`(x,y)`点所在图中得位置: -``` +```Java let yetAnotherPoint = (1, -1) switch yetAnotherPoint { case let (x, y) where x == y: @@ -724,7 +724,7 @@ The following example removes all vowels and spaces from a lowercase string to c 下面的例子会移除一个小写字符串中所有的原因字母: -``` +```Java let puzzleInput = "great minds think alike" var puzzleOutput = "" for character in puzzleInput { @@ -772,7 +772,7 @@ The following example switches on a Character value and determines whether it re 下面这个例子用来判断一个字符的值是否是数字符号。为了简便,多个值被包含到一个分支中: -``` +```Java let numberSymbol: Character = "三" // Simplified Chinese for the number 3 var possibleIntegerValue: Int? switch numberSymbol { @@ -818,7 +818,7 @@ If you really need C-style fallthrough behavior, you can opt in to this behavior 如果你一定要使用C风格的贯穿(fallthrough)机制,你可以在每个需要支持该特性的case分支中使用`fallthrough`关键字。下面这个例子展示了如何使用`fallthrough`来实现对数字的文本描述: -``` +```Java let integerToDescribe = 5 var description = "The number \(integerToDescribe) is" switch integerToDescribe { @@ -863,7 +863,7 @@ A labeled statement is indicated by placing a label on the same line as the stat 标签语句通常被放到一些关键字的前面,通过分号隔开。下面是一个通过标签来标记`while`语句的例子,循环或`switch`语句和它类似: -``` +```Java label name: while condition { statements } @@ -889,7 +889,7 @@ The values of finalSquare, board, square, and diceRoll are initialized in the sa `finalSquare`,`board`,`square`和`diceRoll`的值和之前初始化的值相同: -``` +```Java let finalSquare = 25 var board = Int[](count: finalSquare + 1, repeatedValue: 0) board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 @@ -906,7 +906,7 @@ The while loop’s condition is while square != finalSquare, to reflect that you `while`循环的条件是`while square != finalSquare`用来表示你必须正好落在第25个格子中: -``` +```Java gameLoop: while square != finalSquare { if ++diceRoll == 7 { diceRoll = 1 } switch square + diceRoll { From 6b8caa976ea974bcf1b9c6b59b8ecc857b312589 Mon Sep 17 00:00:00 2001 From: jayson Date: Tue, 1 Jul 2014 14:23:03 +0800 Subject: [PATCH 219/261] no message --- src/chapter2/05_Control_Flow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter2/05_Control_Flow.md b/src/chapter2/05_Control_Flow.md index ba006fc..4130472 100644 --- a/src/chapter2/05_Control_Flow.md +++ b/src/chapter2/05_Control_Flow.md @@ -317,7 +317,7 @@ Here’s the general form of a do-while loop: ```Java do { statements -} while condition” +} while condition ``` Here’s the Snakes and Ladders example again, written as a do-while loop rather than a while loop. The values of finalSquare, board, square, and diceRoll are initialized in exactly the same way as with a while loop: From a150a6cdace017c94303009b37ed7d43bc213884 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Tue, 1 Jul 2014 19:31:33 +0800 Subject: [PATCH 220/261] =?UTF-8?q?gitbook=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- SUMMARY.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 SUMMARY.md diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100644 index 0000000..bef9842 --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1,41 @@ +# Summary + +* 欢迎使用 Swift + * [Swift 介绍](src/chapter1/01_About_Swift.md) + * [Swift 初见](src/chapter1/02_A_Swift_Tour.md) +* Swift 教程 + * [基础部分](src/chapter2/01_The_Basics.md) + * [基本操作符](src/chapter2/02_Basic_Operators.md) + * [字符串和字符](src/chapter2/03_Strings_and_Characters.md) + * [集合类型](src/chapter2/04_Collection_Types.md) + * [控制流](src/chapter2/05_Control_Flow.md) + * [函数](src/chapter2/06_Functions.md) + * [闭包](src/chapter2/07_Closures.md) + * [枚举](src/chapter2/08_Enumerations.md) + * [类和结构体](src/chapter2/09_Classes_and_Structures.md) + * [属性](src/chapter2/10_Properties.md) + * [方法](src/chapter2/11_Methods.md) + * [下标](src/chapter2/12_Subscripts.md) + * [继承](src/chapter2/13_Inheritance.md) + * [构造过程](src/chapter2/14_Initialization.md) + * [析构过程](src/chapter2/15_Deinitialization.md) + * [自动引用计数](src/chapter2/16_Automatic_Reference_Counting.md) + * [可选链](src/chapter2/17_Optional_Chaining.md) + * [类型转换](src/chapter2/18_Type_Casting.md) + * [嵌套类型](src/chapter2/19_Nested_Types.md) + * [扩展](src/chapter2/20_Extensions.md) + * [协议](src/chapter2/21_Protocols.md) + * [泛型](src/chapter2/22_Generics.md) + * [高级操作符](src/chapter2/23_Advanced_Operators.md) +* 语言参考 + * [关于语言参考](src/chapter3/01_About_the_Language_Reference.md) + * [词法结构](src/chapter3/02_Lexical_Structure.md) + * [类型](src/chapter3/03_Types.md) + * [表达式](src/chapter3/04_Expressions.md) + * [语句](src/chapter3/05_Statements.md) + * [声明](src/chapter3/06_Declarations.md) + * [属性](src/chapter3/07_Attributes.md) + * [模式](src/chapter3/08_Patterns.md) + * [泛型参数](src/chapter3/09_Generic_Parameters_and_Arguments.md) + * [语法总结](src/chapter3/10_Summary_of_the_Grammar.md) + From 31175513a0a156f274e16504a593bbe55bcfaa2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=96=E9=82=80?= Date: Tue, 1 Jul 2014 20:44:13 +0800 Subject: [PATCH 221/261] review the basics --- src/chapter2/01_The_Basics_reviewed.md | 1140 ++++++++++++++++++++++++ 1 file changed, 1140 insertions(+) create mode 100644 src/chapter2/01_The_Basics_reviewed.md diff --git a/src/chapter2/01_The_Basics_reviewed.md b/src/chapter2/01_The_Basics_reviewed.md new file mode 100644 index 0000000..af57fc6 --- /dev/null +++ b/src/chapter2/01_The_Basics_reviewed.md @@ -0,0 +1,1140 @@ +- ***加了删除线跟着后面的文本是我建议翻译的内容,加粗的文本是我建议应该有的文本,你可以看着merge。*** +- ***我对所有语法关键字、代码都加了markdown的代码标记*** + +# The Basics +# 基础部分 + +Swift is a new programming language for iOS and OS X app development. Nonetheless, many parts of Swift will be familiar from your experience of developing in C and Objective-C. + +Swift是一个用于iOS和OS X平台开发的新的编程语言。尽管如此,Swift在很多地方都会和你以往用C语言和Objective-C开发的经验类似。 + +Swift provides its own versions of all fundamental C and Objective-C types, including Int for integers; Double and Float for floating-point values; Bool for Boolean values; and String for textual data. Swift also provides powerful versions of the two primary collection types, Array and Dictionary, as described in Collection Types. + +***建议对语法关键字加上代码标记。*** + +Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值`Int`,浮点值`Double`和`Float`,布尔值`Bool`,以及文本值`String`。Swift还提供了两个强大的常见集合类型,数组和字典数组`Array`和字典`Dictionary`,见[集合类型](link)。 + +Like C, Swift uses variables to store and refer to values by an identifying name. Swift also makes extensive use of variables whose values cannot be changed. These are known as constants, and are much more powerful than constants in C. Constants are used throughout Swift to make code safer and clearer in intent when you work with values that do not need to change. + +***感觉括号就统一用中文的,会不会好点= =*** + +和C一样,Swift使用具有唯一名称的变量(variables)来储存和指向特定值。Swift还对那些值不能改变的变量进行了扩展,他们也被称为常量(Constants),Swift中的常量比C中的常量更加强大。在Swift中当你需要处理一些恒定不变的值的时候,使用常量(Constants)可以让代码更加安全和整洁。 + +In addition to familiar types, Swift introduces advanced types not found in Objective-C. These include tuples, which enable you to create and pass around groupings of values. Tuples can return multiple values from a function as a single compound value. + +除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,包括:元组(tuples),你可以创建和传递一组数值。元组(tuples)可以在函数中以一个复合值的形式返回多个数值。比如可以创建和传递一组数值的元组(tuples)。元组能在函数中以一个复合值的形式返回多个值。 + +Swift also introduces optional types, which handle the absence of a value. Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”. Optionals are similar to using nil with pointers in Objective-C, but they work for any type, not just classes. Optionals are safer and more expressive than nil pointers in Objective-C and are at the heart of many of Swift’s most powerful features. + +Swift还有可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用`nil`,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的`nil`,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大特性的核心。 + +Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This enables you to catch and fix errors as early as possible in the development process. + +可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(`String`),类型安全性会阻止你错误的给它赋一个整型(`Int`)的值。这让你在开发的过程中尽早的发现***和解决***问题。 + +# Constants and Variables +# 常量和变量 + +Constants and variables associate a name (such as maximumNumberOfLoginAttempts or welcomeMessage) with a value of a particular type (such as the number 10 or the string "Hello"). The value of a constant cannot be changed once it is set, whereas a variable can be set to a different value in the future. + +常量和变量对应一个变量名(如`maximumNumberOfLoginAttempts`或`welcomeMessage`)以及对应类型的值(如数字`10`或字符串`"Hello"`)将一个变量名(如`maximumNumberOfLoginAttempts`或`welcomeMessage`)和对应类型的值(如数字`10`或字符串`"Hello"`)进行关联。常量的值一旦设定就不能改变,变量的值可以改变。 + +# Declaring Constants and Variables +# 声明常量和变量 + +Constants and variables must be declared before they are used. You declare constants with the let keyword and variables with the var keyword. Here’s an example of how constants and variables can be used to track the number of login attempts a user has made: + +常量和变量必须在使用前声明。用`let`来声明常量,用`var`来声明变量。下面是一个用常量和变量来记录用户尝试登录次数的例子: + +``` +let maximumNumberOfLoginAttempts = 10 +var currentLoginAttempt = 0 ``` + +This code can be read as: + +这段代码可以解读为: + +“Declare a new constant called maximumNumberOfLoginAttempts, and give it a value of 10. Then, declare a new variable called currentLoginAttempt, and give it an initial value of 0.” + +声明一个新的常量,叫做“登录尝试次数的最大值”`maximumNumberOfLoginAttempts`(最大尝试登陆次数),值为`10`。声明一个新的变量,叫“当前尝试次数”做`currentLoginAttempt`(当前尝试登陆次数),初始值设为`0`。 + +In this example, the maximum number of allowed login attempts is declared as a constant, because the maximum value never changes. The current login attempt counter is declared as a variable, because this value must be incremented after each failed login attempt. + +在这个例子中,登录尝试次数的最大值最大尝试登陆次数被声明为常量,因为这个最大值不会改变,当前尝试次数当前尝试登陆次数被声明为变量,因为这个值在每次失败的登录尝试尝试登陆失败后都要增加。 + +You can declare multiple constants or multiple variables on a single line, separated by commas: + +你可以在同一行内声明多个常量或变量,用逗号分割: + +``` +var x = 0.0, y = 0.0, z = 0.0 +``` + +> NOTE + +> If a stored value in your code is not going to change, always declare it as a constant with the let keyword. Use variables only for storing values that need to be able to change. + +> 注意 + +> 当值不会改变时,永远用`let`声明常量。只在值需要改变的时候用变量。 + +# Type Annotations +# 类型批注 + +You can provide a type annotation when you declare a constant or variable, to be clear about the kind of values the constant or variable can store. Write a type annotation by placing a colon after the constant or variable name, followed by a space, followed by the name of the type to use. + +在声明常量和变量时,你可以提供一个类型批注,来表明这个常量或变量可以储存的值的类型。类型批注的格式是在常量或变量名后加一个冒号,接着是一个空格,接着是要***使***用的类型的名称。 + +This example provides a type annotation for a variable called welcomeMessage, to indicate that the variable can store String values: + +下面是一个叫`welcomeMessage`的变量的类型批注的例子,来说明这个变量可以储存字符串`String`(字符串)类型的值: + +``` +var welcomeMessage: String +``` + +The colon in the declaration means “…of type…,” so the code above can be read as: + +这个表达式声明中***的***冒号表示“类型是”,所以这段代码可以解读为: + +“Declare a variable called welcomeMessage that is of type String.” + +“声明一个叫`welcomeMessage`的变量,类型是`String`(字符串)。” + +The phrase “of type String” means “can store any String value.” Think of it as meaning “the type of thing” (or “the kind of thing”) that can be stored. + +“类型是`String`(字符串)”表示“可以储存任意的`String`(字符串)类型的值”。可以把它想作是它可以储存的“一个事物的类型”。 + +The welcomeMessage variable can now be set to any string value without error: + +变量`welcomeMessage`可以被赋值为任意`String`(字符串)类型的值,而不会报错: + +``` +welcomeMessage = "Hello" +``` + +> NOTE + +> It is rare that you need to write type annotations in practice. If you provide an initial value for a constant or variable at the point that it is defined, Swift can almost always infer the type to be used for that constant or variable, as described in Type Safety and Type Inference. In the welcomeMessage example above, no initial value is provided, and so the type of the welcomeMessage variable is specified with a type annotation rather than being inferred from an initial value. + +> 注意 + +> 在实践中你需要写类型批注的很少见很少需要写类型批注。如果你在定义一个常量或变量的时候时给了它一个初始值,Swift几乎总是可以推断出这个常量或变量使用的类型,参见[类型安全和类型推断](link)。在上面这个welcomeMessage的例子里,没有提供初始值,所以`welcomeMessage`这个变量的类型通过类型批注的形式指定,而不是通过从初始值推断而来。 + +# Naming Constants and Variables +# 命名常量和变量 + +You can use almost any character you like for constant and variable names, including Unicode characters: + +你可以使用几乎所有你喜欢的符号来命名常量和变量,包括unicode字符: + +``` +let π = 3.14159 +let 你好 = "你好世界" +let 🐶🐮 = "dogcow" +``` + +Constant and variable names cannot contain mathematical symbols, arrows, private-use (or invalid) Unicode code points, or line- and box-drawing characters. Nor can they begin with a number, although numbers may be included elsewhere within the name. + +常量和变量的命名不能包括数学运算符,箭头, 私有(或无效)的unicode码位, 或者线条(line-),以及制表符(box-drawing)字符。也不能以数字开头,尽管数字可以出现在变量名的其他位置。 + +Once you’ve declared a constant or variable of a certain type, you can’t redeclare it again with the same name, or change it to store values of a different type. Nor can you change a constant into a variable or a variable into a constant. + +一旦你声明了常量或变量为特定类型,你不能用同样的名称重新声明,不能改变它的储值类型,也不能把常量改为变量或变量改为常量。 + +> NOTE + +> If you need to give a constant or variable the same name as a reserved Swift keyword, you can do so by surrounding the keyword with back ticks (`) when using it as a name. However, you should avoid using keywords as names unless you have absolutely no choice. + +> 注意 + +> 如果你需要给一个常量或变量一个相同的名字作为swift的关键字,你可以在使用这个名字的时候用重音符(`)把关键字包围起来。然而,除非你没有别的选择,你应该避免使用关键字的方式来命名。 + +You can change the value of an existing variable to another value of a compatible type. In this example, the value of friendlyWelcome is changed from "Hello!" to "Bonjour!": + +你可以改变一个已经存在的变量的值,变成另一个适配类型的值将一个已经存在的变量的值改变成另一个适配类型的值。在下面的例子里,变量`friendlyWelcome`的值从`"Hello!"`变成了`"Bonjour!"`: + +``` +var friendlyWelcome = "Hello!" +friendlyWelcome = "Bonjour!" +// friendlyWelcome is now "Bonjour!" +``` + +``` +var friendlyWelcome = "Hello!" +friendlyWelcome = "Bonjour!" +// friendlyWelcome的值现在是"Bonjour!"了。 +``` + +Unlike a variable, the value of a constant cannot be changed once it is set. Attempting to do so is reported as an error when your code is compiled: + +和变量不同,常量的值一旦设定就不能更改。尝试更改会导致代码编译时报错。 + +``` +let languageName = "Swift" +languageName = "Swift++" +// this is a compile-time error - languageName cannot be changed +``` + +# Printing Constants and Variables +# 输出常量和变量 + +You can print the current value of a constant or variable with the println function: + +你可以用`printIn`函数输出常量和变量的当前值: + +``` +println(friendlyWelcome) +// prints "Bonjour!" +``` + +``` +println(friendlyWelcome) +// 输出 "Bonjour!" +``` + +println is a global function that prints a value, followed by a line break, to an appropriate output. If you are working in Xcode, for example, println prints its output in Xcode’s “console” pane. (A second function, print, performs the same task without appending a line break to the end of the value to be printed.) + +`printIn`是一个输出值的全局函数,为了得到良好的输出结果,输出后会加上一个空行。如果你使用的是Xcode,`printIn`会将结果输出到Xcode的调试信息栏。(另一个函数,`print`,会执行几乎相同的任务,除了不会在输出结果之后加空行以外。) + +The println function prints any String value you pass to it: + +`printIn`函数会输出任何你赋值的字符串传递给它的字符串(`String`)值: + +``` +println("This is a string") +// prints "This is a string" +``` + +The println function can print more complex logging messages, in a similar manner to Cocoa’s NSLog function. These messages can include the current values of constants and variables. + +`printIn`函数可以输出更复杂的记录信息,和Cocoa的`NSlog`函数类似。这些信息可以包含常量和变量的当前值。 + +Swift uses string interpolation to include the name of a constant or variable as a placeholder in a longer string, and to prompt Swift to replace it with the current value of that constant or variable. Wrap the name in parentheses and escape it with a backslash before the opening parenthesis: + +Swift使用字符串内插插值(string interpolation)的方式将常量或变量名以占位符的形式加入一个长的字符串中,并且提示Swift用常量或变量的当前值取代替它替换对应占位符。书写格式是将名字包裹在括号中并在前面加上反斜扛来转义: + +``` +println("The current value of friendlyWelcome is \(friendlyWelcome)") +// prints "The current value of friendlyWelcome is Bonjour!" +``` +``` +println("The current value of friendlyWelcome is \(friendlyWelcome)") +// 输出 "The current value of friendlyWelcome is Bonjour!" +``` + +> NOTE + +> All options you can use with string interpolation are described in String Interpolation. + +> 注意 + +> 关于字符串插值的详细参数,参见[字符串插值](link)。 + +# Comments +# 注释 + +Use comments to include non-executable text in your code, as a note or reminder to yourself. Comments are ignored by the Swift compiler when your code is compiled. + +将代码中不会执行的文本,笔记或者备忘用注释来表达。注释在***代码***编译时会被忽略。 + +Comments in Swift are very similar to comments in C. Single-line comments begin with two forward-slashes (//): + +Swift中的注释和C中的注释十分相似。单行的注释以两个正斜杠(```//```)开头: + +``` +// this is a comment +``` + +``` +// 这是一个注释 +``` + +You can also write multiline comments, which start with a forward-slash followed by an asterisk (/*) and end with an asterisk followed by a forward-slash (*/): + +你也可以写多行的注释,用一个正斜杠跟着一个星号开头(`/*`),用一个星号跟着一个正斜杠结束(`*/`): + +``` +/* this is also a comment, +but written over multiple lines */ +``` + +``` +/* 这还是一个注释, +但是是多行的 */ +``` + +Unlike multiline comments in C, multiline comments in Swift can be nested inside other multiline comments. You write nested comments by starting a multiline comment block and then starting a second multiline comment within the first block. The second block is then closed, followed by the first block: + +和C中的多行注释不同,Swift的多行注释可以嵌套在另一个多行注释内部。你可以这样写嵌套的注释:开始一个多行注释块,在第一块多行注释内部跟着开始第二个多行注释。第二个多行注释块结束,然后第一个多行注释块结束。 + +``` +/* this is the start of the first multiline comment +/* this is the second, nested multiline comment */ +this is the end of the first multiline comment */ +``` + +``` +/* 这是第一个多行注释开始 +/* 这是第二个,嵌套的多行注释 */ +这是第一个多行注释的结束 */ +``` + +Nested multiline comments enable you to comment out large blocks of code quickly and easily, even if the code already contains multiline comments. + +嵌套的多行注释让你可以简单快捷的注释一大段代码,即使这段代码之前已经有多行注释块。 + +# Semicolons +# 分号 + +Unlike many other languages, Swift does not require you to write a semicolon (;) after each statement in your code, although you can do so if you wish. Semicolons are required, however, if you want to write multiple separate statements on a single line: + +和其他很多语言不同,Swift并不要求你在代码的每一个语句之后写一个分号(`;`),尽管如果你愿意你可以这么做。然而,如果你想在一行里写多个独立的语句,分号是必要的。 + + let cat = "🐱"; println(cat) + // prints "🐱" + +# Integers +# 整数 + +Integers are whole numbers with no fractional component, such as 42 and -23. Integers are either signed (positive, zero, or negative) or unsigned (positive or zero). + +整数就是没有小数部分的完整数字,如`42`和`-23`。整数可以有符号(正数,0,或负数),也可以没有符号(正数或0)。 + +Swift provides signed and unsigned integers in 8, 16, 32, and 64 bit forms. These integers follow a naming convention similar to C, in that an 8-bit unsigned integer is of type UInt8, and a 32-bit signed integer is of type Int32. Like all types in Swift, these integer types have capitalized names. + +Swift提供8,16,32和64进制位的带符号和不带符号的整数类型。这些整数遵从和C类似的命名约定,在这个约定中,8进制位的无符号整数的类型为`UInt8`,而一个32进制位的有符号整数的类型是`Int32`。和Swift的所有类型一样,这些整数的类型是首字母大写的。 + +## Integer Bounds +## 整数边界 + +You can access the minimum and maximum values of each integer type with its min and max properties: + +你可以通过整数类型的`max`和`min`属性来访问它的最大值和最小值: + +``` +let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8 +let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8 +``` + +``` +let minValue = UInt8.min // 最小值是 0, 类型是 UInt8 +let maxValue = UInt8.max // 最大值是 255, 类型是 UInt8 +``` + +The values of these properties are of the appropriate-sized number type (such as UInt8 in the example above) and can therefore be used in expressions alongside other values of the same type. + +这些属性值是相应数字类型的合适范围(比如上面例子里的`UInt8`),因此它们可以在其他拥有相同类型值的表达式中沿用。 + +## Int +## 整数 + +In most cases, you don’t need to pick a specific size of integer to use in your code. Swift provides an additional integer type, Int, which has the same size as the current platform’s native word size: + +在大多数情况下,你不需要在代码中指定整数的范围。Swift提供了一个专门的整数类型`Int`,它和当前平台的原生长度范围相同。 + +* On a 32-bit platform, Int is the same size as Int32. +* On a 64-bit platform, Int is the same size as Int64. + +* 在32位的平台上,`Int`和`Int32`范围相同。 +* 在64位的平台上,`Int`和`Int64`范围相同。 + +Unless you need to work with a specific size of integer, always use Int for integer values in your code. This aids code consistency and interoperability. Even on 32-bit platforms, Int can store any value between -2,147,483,648 and 2,147,483,647, and is large enough for many integer ranges. + +如果你不需要处理特定的整数范围,请在代码中的整数值始终使用`Int`类型。这有助于代码的一致性和可复用性。即使在32位的平台上,`Int`类型可以储存从`-2,147,483,648`到`2,147,483,647`的整数,大多数情况下这足够用了。 + +## UInt +## 无符号整数 + +Swift also provides an unsigned integer type, UInt, which has the same size as the current platform’s native word size: + +Swift也提供了无符号整数类型,`UInt`,它和当前平台的原生长度范围相同。 + +* On a 32-bit platform, UInt is the same size as UInt32. +* On a 64-bit platform, UInt is the same size as UInt64. + +* 在32位的平台上,`UInt`和`UInt32`范围相同。 +* 在64位的平台上,`UInt`和`UInt64`范围相同。 + +> NOTE + +> Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference. + +> 注意 + +> 只在你需要特别指定无符号整数与当前平台原生长度范围相同时才使用`UInt`,否则,推荐使用`Int`,即使是你知道不会存储负值的时候。使用一致的`Int`整数类型有助于代码的复用,避免了不同数字类型之间的转换,并且匹配整数的类型推断和类型推断,详见[类型安全和类型推断](link)。 + +# Floating-Point Numbers +# 浮点型数字 + +Floating-point numbers are numbers with a fractional component, such as 3.14159, 0.1, and -273.15. + +浮点型数字是指有小数部分的数字,比如`3.14159`,`0.1`和`-273.15`。 + +Floating-point types can represent a much wider range of values than integer types, and can store numbers that are much larger or smaller than can be stored in an Int. Swift provides two signed floating-point number types: + +浮点类型比整数类型范围大很多,它可以储存比整数更大或者更小的数。Swift提供了两种有符号的浮点数类型: + +* Double represents a 64-bit floating-point number. Use it when floating-point values must be very large or particularly precise. +* Float represents a 32-bit floating-point number. Use it when floating-point values do not require 64-bit precision. + +* `Double`代表64位浮点数。当你需要特别大和特别精确的值的时候使用`Double`类型。 +* `Float`代表32位浮点数。当不需要像64位那么精确的时候使用`Float`就够了。 + +> NOTE + +> Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. + +> 注意 + +> `Double`有至少15位数字的精确度,而`Float`的精确度最少只有6位数字。根据业务需要的值的范围去选择合适的浮点类型。 + +# Type Safety and Type Inference +# 类型安全和类型推断 + +Swift is a type safe language. A type safe language encourages you to be clear about the types of values your code can work with. If part of your code expects a String, you can’t pass it an Int by mistake. + +Swift是一个类型安全的语言。一个类型安全的语言鼓励你声明代码中使用的值的类型。如果你期望这部分代码是`String`(字符串),你就不能错误的给它赋一个`Int`(整型)的值。 + +Because Swift is type safe, it performs type checks when compiling your code and flags any mismatched types as errors. This enables you to catch and fix errors as early as possible in the development process. + +因为Swift是类型安全的,它会在编译时运行类型检查,并且将所有不匹配的类型标记为错误。这让你可以在开发过程中今早的发现和修复问题。 + +Type-checking helps you avoid errors when you’re working with different types of values. However, this doesn’t mean that you have to specify the type of every constant and variable that you declare. If you don’t specify the type of value you need, Swift uses type inference to work out the appropriate type. Type inference enables a compiler to deduce the type of a particular expression automatically when it compiles your code, simply by examining the values you provide. + +当你处理不同类型的值的时候,类型检查帮助你避免错误。然而,这并不意味着你需要给每一个声明的常量和变量指定特定的类型。如果你没有指定特定的类型,Swift会使用类型推断来推断出合适的类型。当编译代码时,类型推断特性使得编译器可以简单的通过检查你提供的值来自动推断出特定表达式的类型。 + +Because of type inference, Swift requires far fewer type declarations than languages such as C or Objective-C. Constants and variables are still explicitly typed, but much of the work of specifying their type is done for you. + +因为有了类型推断,Swift与类似C和Objective-C的语言相比需要更少的类型声明。常量和变量同样会有准确的类型,但是大部分关于指定类型的工作Swift已经帮你做好了。 + +Type inference is particularly useful when you declare a constant or variable with an initial value. This is often done by assigning a literal value (or literal) to the constant or variable at the point that you declare it. (A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below.) + +当你声明一个有初始值的常量或变量的时候时类型推断特别实用。通常是当你声明一个常量和变量的时候你就给它赋一个字面量(literal value)。(字面量是会直接出现在源码里的值,比如下面例子里的`42`和`3.14159`。) + +For example, if you assign a literal value of 42 to a new constant without saying what type it is, Swift infers that you want the constant to be an Int, because you have initialized it with a number that looks like an integer: + +举个例子,如果你给一个新的常量赋了一个字面量`42`,但没有指定它的类型,Swift会推断你希望这个常量是一个整数类型(Int)`Int`(整数)类型,因为你用了一个像是整数的数字来初始化***变量***: + +``` +let meaningOfLife = 42 +// meaningOfLife is inferred to be of type Int +``` + +``` +let meaningOfLife = 42 +// meaningOfLife被推断为整数类型(Int) +``` + +Likewise, if you don’t specify a type for a floating-point literal, Swift infers that you want to create a Double: + +类似的,如果你没有特别指定一个浮点型的字面量,Swift会推断你需要一个`Double`类型的浮点数: + +``` +let pi = 3.14159 +// pi is inferred to be of type Double +``` + +``` +let pi = 3.14159 +// pi被推断为Double类型 +``` + +Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers. + +在推断浮点型的数字时,Swift总是会选择`Double`*类*型而不是`Float`*类型*。 + +If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context: + +如果你将整数型和浮点型的字面量相加,这种情况下会推断为`Double`类型: + +``` +let anotherPi = 3 + 0.14159 +// anotherPi is also inferred to be of type Double +``` + +``` +let anotherPi = 3 + 0.14159 +// anotherPi也被推断为Double类型 +``` + +The literal value of 3 has no explicit type in and of itself, and so an appropriate output type of Double is inferred from the presence of a floating-point literal as part of the addition. + +字面量`3`本身并没有准确的类型,因此是通过相加的元素中有一个浮点型的字面量推断出合适的输出类型为`Double`。 + +# Numeric Literals +# 数字字面量 + +Integer literals can be written as: + +整数字面量可以写成: + +* A decimal number, with no prefix +* A binary number, with a 0b prefix +* An octal number, with a 0o prefix +* A hexadecimal number, with a 0x prefix + +* 十进制的数字,不需要任何前缀 +* 二进制的数字,前缀是`0b` +* 八进制的数字,前缀是`0o` +* 十六进制的数字,前缀是`0x` + +All of these integer literals have a decimal value of 17: + +下面所有的整数字面量在十进制下的值都是`17`: + +``` +let decimalInteger = 17 +let binaryInteger = 0b10001 // 17 in binary notation +let octalInteger = 0o21 // 17 in octal notation +let hexadecimalInteger = 0x11 // 17 in hexadecimal notation +``` + +``` +let decimalInteger = 17 +let binaryInteger = 0b10001 // 二进制声明中的17 +let octalInteger = 0o21 // 八进制声明中的17 +let hexadecimalInteger = 0x11 // 十六进制声明中的17 +``` + +Floating-point literals can be decimal (with no prefix), or hexadecimal (with a 0x prefix). They must always have a number (or hexadecimal number) on both sides of the decimal point. They can also have an optional exponent, indicated by an uppercase or lowercase e for decimal floats, or an uppercase or lowercase p for hexadecimal floats. + +浮点型的字面量可以是十进制的(没有前缀),或者十六进制(前缀是`0x`)。在小数点两边都必须有数字(或十六进制数字符号)。它们也可以有一个可选的指数,在十进制中用大写或小写的`e`来表示,或者在十六进制中用大写或小写的`p`来表示。 + +For decimal numbers with an exponent of exp, the base number is multiplied by 10exp: + +在十进制数字中有一个的指数`exp`表示基数乘以10exp: + +* ```1.25e2``` means 1.25 × 102, or `125.0`. +* ```1.25e-2``` means 1.25 × 10-2, or `0.0125`. + +* ```1.25e2``` 表示 1.25 × 102,或者`125.0`. +* ```1.25e-2``` 表示 1.25 × 10-2,或者`0.0125` + +For hexadecimal numbers with an exponent of exp, the base number is multiplied by 2exp: + +在十六进制的数字中有一个的指数`exp`表示基数乘以2exp + +* 0xFp2 means 15 × 22, or 60.0. +* 0xFp-2 means 15 × 2-2, or 3.75. + +* 0xFp2 表示 15 × 22,或者 60.0. +* 0xFp-2 表示 15 × 2-2,或者 3.75. + +All of these floating-point literals have a decimal value of 12.1875: + +以下这些浮点字面量在十进制下的值都是`12.1875`: + +``` +let decimalDouble = 12.1875 +let exponentDouble = 1.21875e1 +let hexadecimalDouble = 0xC.3p0 +``` + +Numeric literals can contain extra formatting to make them easier to read. Both integers and floats can be padded with extra zeroes and can contain underscores to help with readability. Neither type of formatting affects the underlying value of the literal: + +数字字面量可以使用额外的格式让它们更易读。不论整数还是浮点数都可以添加额外的0,也可以增加下划线来增加可读性。这些格式都不会影响到这些字面量原本的值: + +``` +let paddedDouble = 000123.456 +let oneMillion = 1_000_000 +let justOverOneMillion = 1_000_000.000_000_1 +``` + +# Numeric Type Conversion +# 数字类型转换 + +Use the Int type for all general-purpose integer constants and variables in your code, even if they are known to be non-negative. Using the default integer type in everyday situations means that integer constants and variables are immediately interoperable in your code and will match the inferred type for integer literal values. + +在一般情况下对整数的常量或变量使用`Int`类型,即使是你知道不会存储负值的时候。总是使用默认的整数类型意味着你的代码中整数的常量和变量可以很好的协作,并且可以和整数字面量推断出的类型一致。 + +Use other integer types only when they are are specifically needed for the task at hand, because of explicitly-sized data from an external source, or for performance, memory usage, or other necessary optimization. Using explicitly-sized types in these situations helps to catch any accidental value overflows and implicitly documents the nature of the data being used. + +只在当前工作中有特殊需要的时候,才使用其他的整数类型,比如是从外部来源的需要指定精确度的数据,或者为了性能,内存使用量,或者其他必要的优化。在这些情况下使用指定精确度的数字类型可以帮助我们发现溢出值和暗示这个数据的特性。 + +## Integer Conversion +## 整数类型转换 + +The range of numbers that can be stored in an integer constant or variable is different for each numeric type. An Int8 constant or variable can store numbers between -128 and 127, whereas a UInt8 constant or variable can store numbers between 0 and 255. A number that will not fit into a constant or variable of a sized integer type is reported as an error when your code is compiled: + +不同整数类型的常量或变量可以储存不同范围的数字。一个`Int8`的常量或变量可以储存`-128`到`127`之间的数字,然而一个`UInt8`型的常量或变量可以储存从`0`到`255`之间的数字。如果一个数字不符合常量或变量的储值范围,编译的时候会报错: + +``` +let cannotBeNegative: UInt8 = -1 +// UInt8 cannot store negative numbers, and so this will report an error +// UInt8不能储存负数,所以这里会报错 +let tooBig: Int8 = Int8.max + 1 +// Int8 cannot store a number larger than its maximum value, +// and so this will also report an error +// Int8不能储存一个大于其最大值的数字 +// 所以这里同样会报错 +``` + +Because each numeric type can store a different range of values, you must opt in to numeric type conversion on a case-by-case basis. This opt-in approach prevents hidden conversion errors and helps make type conversion intentions explicit in your code. + +因为每一种数字类型可以储存不同范围的值,你必须根据具体的案例选择合适的数字类型转换。这种选择方式组织阻止了隐式的转换报错,并且让你的代码中的类型转换意图更明确。 + +To convert one specific number type to another, you initialize a new number of the desired type with the existing value. In the example below, the constant twoThousand is of type UInt16, whereas the constant one is of type UInt8. They cannot be added together directly, because they are not of the same type. Instead, this example calls UInt16(one) to create a new UInt16 initialized with the value of one, and uses this value in place of the original: + +要将一种特定类型转换成另一种,你需要用一个你想要的类型的新数字*值*来重新初始化。在下面的例子里,常量`twoThousand`是`UInt16`类型的,然而常量`one`是`UInt8`类型的。它们不能直接相加,因为它们类型不同。因此,这个例子调用了`UInt16(one)`来对常量`one`创建一个新的`UInt16`*类型的*初始值,然后用这个值来代替原来的值: + +``` +let twoThousand: UInt16 = 2_000 +let one: UInt8 = 1 +let twoThousandAndOne = twoThousand + UInt16(one) +``` + +Because both sides of the addition are now of type UInt16, the addition is allowed. The output constant (twoThousandAndOne) is inferred to be of type UInt16, because it is the sum of two UInt16 values. + +因为相加的两个数现在都是`UInt16`类型了,这样相加是允许的。输出结果的常量`twoThousandAndOne`被推断为`UInt16`类型,因为它是两个`UInt16`类型的值的和。 + +`SomeType(ofInitialValue)` is the default way to call the initializer of a Swift type and pass in an initial value. Behind the scenes, UInt16 has an initializer that accepts a UInt8 value, and so this initializer is used to make a new UInt16 from an existing UInt8. You can’t pass in any type here, however—it has to be a type for which UInt16 provides an initializer. Extending existing types to provide initializers that accept new types (including your own type definitions) is covered in Extensions. + +`SomeType(ofInitialValue)`是Swift初始化并赋予一个初值的默认方法。在语言内部,`UInt16`类型有一个初始值设定项会接受一个`UInt8`的值,然后这个初始值设定项是用来从已知的`UInt8`中创建一个新的`UInt16`的值。你不能传递任意类型,只能传入`UInt16`提供初始化的类型。扩展已有的类型来提供更多的初始化选项,来接受新的类型(包括自定义类型),见[扩展](link)。 + +## Integer and Floating-Point Conversion +## 整数和浮点数转换 + +Conversions between integer and floating-point numeric types must be made explicit: +整数和浮点数之间的类型转换必须是显性的: + +``` +let three = 3 +let pointOneFourOneFiveNine = 0.14159 +let pi = Double(three) + pointOneFourOneFiveNine +// pi equals 3.14159, and is inferred to be of type Double +// pi等于3.14159,它被推断为Double类型 +``` +Here, the value of the constant three is used to create a new value of type Double, so that both sides of the addition are of the same type. Without this conversion in place, the addition would not be allowed. + +在这里,常量`three`的值被用来创建一个新的`Double`型的值,所以相加的两个数都是同样的类型了,无须转换,这个加法是允许的。 + +The reverse is also true for floating-point to integer conversion, in that an integer type can be initialized with a Double or Float value: + +相对的,由浮点数到证书整数的转换也是可行的,也就是说一个整数类型可以被初始化为一个`Double`或者`Float`型的值: + +``` +let integerPi = Int(pi) +// integerPi equals 3, and is inferred to be of type Int +// integerPi等于3,它被推断为整数(Int)类型 +``` + +Floating-point values are always truncated when used to initialize a new integer value in this way. This means that 4.75 becomes 4, and -3.9 becomes -3. + +当浮点型的值初始化为一个新的整数型的值时,它的数值总是被截断的。这意味着`4.75`会成为`4`,而`-3.9`会成为`-3`。 + +> NOTE + +> The rules for combining numeric constants and variables are different from the rules for numeric literals. The literal value 3 can be added directly to the literal value 0.14159, because number literals do not have an explicit type in and of themselves. Their type is inferred only at the point that they are evaluated by the compiler. + +> 注意 + +> 数字的常量和变量相加的规则和数字字面量的规则是不一样的。字面量`3`可以和字面量`0.14159`直接相加,因为数字字面量本身并没有一个显式的类型声明。他们的类型是在编译器运行时被推断的。 + +# Type Aliases +# 类型别名 + +Type aliases define an alternative name for an existing type. You define type aliases with the typealias keyword. + +类型别名给已经存在的类型定义另一个名字。你用关键字`typealias`来定义类型别名。 + +Type aliases are useful when you want to refer to an existing type by a name that is contextually more appropriate, such as when working with data of a specific size from an external source: + +当你想用一个更合适的名字来命名一个已有类型的时候,类型别名是很有用的。比如当你处理一个外部来源的需要指定精确度的需要指定精确度的外部来源数据时: + +``` +typealias AudioSample = UInt16 +``` + +Once you define a type alias, you can use the alias anywhere you might use the original name: + +一旦你定义了类型别名,你就可以在任何你可以使用原始名字的地方使用这个别名: + +``` +var maxAmplitudeFound = AudioSample.min +// maxAmplitudeFound is now 0 +``` + +Here, AudioSample is defined as an alias for UInt16. Because it is an alias, the call to AudioSample.min actually calls UInt16.min, which provides an initial value of 0 for the maxAmplitudeFound variable. + +在这里这个例子中,`AudioSample`***被***定义为`UInt16`的一个别名。因为这是一个别名,调用`AudioSample.min`实际上是调用`UInt16.min`给变量`maxAmplitudeFound`赋了一个0的初始值初始值`0`。 + +# Booleans +# 布尔值 + +Swift has a basic Boolean type, called Bool. Boolean values are referred to as logical, because they can only ever be true or false. Swift provides two Boolean constant values, true and false: + +Swift有一个基本的布尔值类型,叫做`Bool`。布尔值可以用作逻辑判断,因为它们只有true和false“真”和“假”两个值。Swift提供两种布尔值常量,`true`和`false`: + +``` +let orangesAreOrange = true +let turnipsAreDelicious = false +``` + +The types of orangesAreOrange and turnipsAreDelicious have been inferred as Bool from the fact that they were initialized with Boolean literal values. As with Int and Double above, you don’t need to declare constants or variables as Bool if you set them to true or false as soon as you create them. Type inference helps make Swift code more concise and readable when it initializes constants or variables with other values whose type is already known. + +因为`orangesAreOrange`和`turnipsAreDelicious`有一个布尔的字面量作为初*使*值,它们的类型被推断为`Bool`。如果你在创建常量或变量的时候就把它们的值设为`true`或者`false`,你不需要声明它们的类型是`Bool`。当你赋予常量或变量一个类型已知的初值时,类型推断让Swift的代码更加准确和可读。 + +Boolean values are particularly useful when you work with conditional statements such as the if statement: + +在条件声明比如if语句中,布尔值布尔值在条件声明(比如:`if`语句)中特别有用: + +``` +if turnipsAreDelicious { + println("Mmm, tasty turnips!") +} else { + println("Eww, turnips are horrible.") +} +// prints "Eww, turnips are horrible." +``` + +Conditional statements such as the if statement are covered in more detail in Control Flow. + +关于条件声明(比如`if`语句)的更多细节会在Control Flow这一章节中详细讲解。 + +Swift’s type safety prevents non-Boolean values from being be substituted for Bool. The following example reports a compile-time error: + +Swift的类型安全会阻止一个非布尔值替换`Bool`值。下面的例子会在编译时报错: + +``` +let i = 1 +if i { + // this example will not compile, and will report an error + // 这个例子不会顺利编译,会报错 +} +``` + +However, the alternative example below is valid: + +然而,下面这个例子是有效的: + +``` +let i = 1 +if i == 1 { + // this example will compile successfully + // 这个例子会成功编译 +} +``` + +The result of the i == 1 comparison is of type Bool, and so this second example passes the type-check. Comparisons like i == 1 are discussed in Basic Operators. + +`i == 1`**的**比较结果是一个`Bool`类型的值,因此第二个例子通过了类型检查。类似`i == 1`的比较我们会在[Basic Operators](link)进行深入讨论。 + +As with other examples of type safety in Swift, this approach avoids accidental errors and ensures that the intention of a particular section of code is always clear. + +和其他Swift的类型安全的例子一样,这个例子这种检查避免了意外的错误并且保证了特定的某块代码的意图始终是明确的。 + +# Tuples +# 元组 + +Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other. + +元组将多个数值组合成一个单独的复合值。一个元组中的值可以是任何类型,不必是同一种类型。 + +In this example, (404, "Not Found") is a tuple that describes an HTTP status code. An HTTP status code is a special value returned by a web server whenever you request a web page. A status code of 404 Not Found is returned if you request a webpage that doesn’t exist. + +在这个例子里, `(404, "Not Found")` 是一个用来形容HttpHTTP状态码的元组。一个HttpHTTP状态码是当你请求一个网页的时候网页服务器的返回值。当你请求的网页不存在的时候会返回`404找不到网页``404 Not Found`的状态码。 + +``` +let http404Error = (404, "Not Found") +// http404Error is of type (Int, String), and equals (404, "Not Found") +``` + +``` +let http404Error = (404, "Not Found") +// http404Error的类型是(Int, String),值等于(404, "Not Found") +``` + +The (404, "Not Found") tuple groups together an Int and a String to give the HTTP status code two separate values: a number and a human-readable description. It can be described as “a tuple of type (Int, String)”. + +元组`(404, "Not Found")`将一个整数值`Int`和一个字符字符串`String`组合起来,给httpHTTP状态码赋予两个独立的值:一个机器语言的数字和一句人类语言的描述。它可以描述为”一个类型为 `(Int, String)`的元组“。 + +You can create tuples from any permutation of types, and they can contain as many different types as you like. There’s nothing stopping you from having a tuple of type (Int, Int, Int), or (String, Bool), or indeed any other permutation you require. + +你可以创建一个含任意类型组合的元组,它们可以包含任意多的类型。谁也不能阻止你创建一个`(Int, Int, Int)`类型或者`(String, Bool)`类型,又或者任意你想要的类型组合的元组。 + +You can decompose a tuple’s contents into separate constants or variables, which you then access as usual: + +你可以把一个元组的内容分解成独立的常量或变量,然后你就可以像平常一样调用引用它们: + +``` +let (statusCode, statusMessage) = http404Error +println("The status code is \(statusCode)") +// prints "The status code is 404" +println("状态码是 \(statusCode)") +// 输出”状态码是404“ +println("The status message is \(statusMessage)") +// prints "The status message is Not Found" +``` + +``` +let (statusCode, statusMessage) = http404Error +println("状态码是 \(statusCode)") +// 输出”状态码是404“ +println("状态信息是 \(statusMessage)") +// prints "状态信息是 Not Found" +``` + +If you only need some of the tuple’s values, ignore parts of the tuple with an underscore (_) when you decompose the tuple: + +如果你只需要元组的一部分值,当你分解元组的时候当你在分解元组时,只需要元祖的一部分值,可以使用下划线(`_`)来忽略元组的一部分值: + +``` +let (justTheStatusCode, _) = http404Error +println("The status code is \(justTheStatusCode)") +// prints "The status code is 404" +``` + +``` +let (justTheStatusCode, _) = http404Error +println("状态码是 \(justTheStatusCode)") +// prints "状态码是 404" +``` + +Alternatively, access the individual element values in a tuple using index numbers starting at zero: + +同样的,使用从`0`开始的序列可以调用引用元组中的一个单独元素的值。 + +``` +println("The status code is \(http404Error.0)") +// prints "The status code is 404" +println("The status message is \(http404Error.1)") +// prints "The status message is Not Found" +``` + +You can name the individual elements in a tuple when the tuple is defined: + +定义元组的时候,你可以给元素单独命名: + +``` +let http200Status = (statusCode: 200, description: "OK") +``` + +If you name the elements in a tuple, you can use the element names to access the values of those elements: + +如果你给元组中的元素命名了,你可以用这个名字来调用引用它们的值: + +``` +println("The status code is \(http200Status.statusCode)") +// prints "The status code is 200" +println("The status message is \(http200Status.description)") +// prints "The status message is OK" +``` + +Tuples are particularly useful as the return values of functions. A function that tries to retrieve a web page might return the (Int, String) tuple type to describe the success or failure of the page retrieval. By returning a tuple with two distinct values, each of a different type, the function provides more useful information about its outcome than if it could only return a single value of a single type. For more information, see Functions with Multiple Return Values. + +作为函数的返回值元组是很有用的。*这还没有翻译完哦~* + +> NOTE + +> Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple. For more information, see Classes and Structures. + +> 注意 + +> 当你处理一些相关数据的临时组合,元组是很有用的。如果你的数据结构超过了一个临时的范畴,用class或者structrue会比用元组tuple更合适。更多信息,参见[Classes and Structures](link)。 + +# Optionals +# 可选类型 + +You use optionals in situations where a value may be absent. An optional says: + +当值可能缺失的情况下,可以用可选类型(Options)。可选类型表示: + +- There is a value, and it equals x + +or + +- There isn’t a value at all + + +- 那里有一个值,它等于x + +或者 + +- 值不存在 + +> NOTE + +> The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structs, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there is a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants. + +> 注意 + +> 可选类型在C或者Objective-C中都不存在。在Objective-C中最接近的是一个返回一个对象的方法也可以返回一个`nil`值的能力,`nil`的意思是“有效对象的缺失”。然而,它只对对象有效,对`structs`,basic C types, or enumeration values*基本的C类型、或者枚举类型*都是无效的。对这些类型,Objective-C通常会返回一个特殊值(比如`NSNotFound`)来表示值缺失。这样的方式假定我们调用方法时它必须知道有一个特殊值,并且要记得去检查它。Siwft的可选类型让你可以给任意类型的值声明这个值缺失,不需要任何其它的特殊常量。 + +Here’s an example. Swift’s String type has a method called toInt, which tries to convert a String value into an Int value. However, not every string can be converted into an integer. The string "123" can be converted into the numeric value 123, but the string "hello, world" does not have an obvious numeric value to convert to. + +下面是一个例子。Siwft的字符串类型有一个`toInt`的方法,它会尝试将一个字符串类型转换成一个整数类型。然而,不是每一个字符串都可以转换成整数。字符串“123”`"123"`可以转换为数字量`123`,但是字符串`"Hello, world"`并没有一个明显的数字量可以转换。 + +The example below uses the toInt method to try to convert a String into an Int: + +下面这个例子用`toInt`方法尝试转换字符串到整数: + +``` +let possibleNumber = "123" +let convertedNumber = possibleNumber.toInt() +// convertedNumber is inferred to be of type "Int?", or "optional Int" +``` + +Because the toInt method might fail, it returns an optional Int, rather than an Int. An optional Int is written as Int?, not Int. The question mark indicates that the value it contains is optional, meaning that it might contain some Int value, or it might contain no value at all. (It can’t contain anything else, such as a Bool value or a String value. It’s either an Int, or it’s nothing at all.) + +因为`toInt`方法可能失败,它返回的是可以可选类型的整数,而不是一个整数。一个可选的整数表示为`Int?`,而不是`Int`。最后的问号表示这个值是可选的,意味着它可能包含整数类型的值,或者没有值。(它不能包括其它任何值,比如布尔值或者字符串。它要么是一个整数,要么就没有值。) + +## If Statements and Forced Unwrapping +## If语句和强制解析 + +You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to true; if it has no value at all, it evaluates to false. + +你可以使用`if`语句来判断一个可选类型是否有值。如果有值,它就等于`true`,如果没有值,就等于`false`。 + +Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value: + +一旦你确定可选类型是有值的,你可以在可选类型的名字后面加一个感叹号(!)`!`来调用它的值。这个感叹号的意思是:”我知道这个可选类型的值一定存在一个值,请使用这个值。“这叫做可选值的强制解析: + +``` +if convertedNumber { + println("\(possibleNumber) has an integer value of \(convertedNumber!)") +} else { + println("\(possibleNumber) could not be converted to an integer") +} +// prints "123 has an integer value of 123" +``` + +For more on the if statement, see Control Flow. + +更多*`if`语句的*信息,见[Control Flow](link)。 + +> NOTE + +> Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value. + +> 注意 + +> 如果你使用`!`来调用一个不存在的可选值,会报出实时运行时错误。在使用`!`强制解析可选值之前总是请确认这个可选值包含一个非`nil`的值。 + +## Optional Binding +## 可选值绑定 + +You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used with if and while statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action. if and while statements are described in more detail in Control Flow. + +你可以使用可选值绑定(optional binding)来找出一个可选类型是否包含值,如果包含,则可以把这个值作为一个临时常量或变量来使用。可选值绑定可以和`if`或`while`语句一起来检查可选值里面的值,并且解析到一个常量或变量中,所有这些都在一步操作中完成。更多关于`if`和`while`语句的信息,见[Control Flow](link)。 + +Write optional bindings for the if statement as follows: + +像这样给`if`语句写可选值绑定: + +``` +if let constantName = someOptional { + statements +} +``` + +You can rewrite the possibleNumber example from above to use optional binding rather than forced unwrapping: + +你可以用可选值绑定来代替强制解析来重写之前那个`possibleNumber`的例子: + +``` +if let actualNumber = possibleNumber.toInt() { + println("\(possibleNumber) has an integer value of \(actualNumber)") +} else { + println("\(possibleNumber) could not be converted to an integer") +} +// prints "123 has an integer value of 123" +``` + +This can be read as: + +这段代码可以解读为: + +“If the optional Int returned by possibleNumber.toInt contains a value, set a new constant called actualNumber to the value contained in the optional.” + +”如果可选整数值通过`possibleNumber.toInt`返回一个值,设定一个叫`actualNumber`的新常量来储存这个可选整数中的值。“ + +If the conversion is successful, the actualNumber constant becomes available for use within the first branch of the if statement. It has already been initialized with the value contained within the optional, and so there is no need to use the ! suffix to access its value. In this example, actualNumber is simply used to print the result of the conversion. + +如果这个转换是成功的,那么常量`actualNumber`在`if`语句的第一个分支就可用了。它已经用可选量中的值初始化了,所以现在不需要用`!`后缀来调用这个值。在这个例子中,`actualNumber`只是简单的用于输出转换结果。 + +You can use both constants and variables with optional binding. If you wanted to manipulate the value of actualNumber within the first branch of the if statement, you could write if var actualNumber instead, and the value contained within the optional would be made available as a variable rather than a constant. + +无论是常量还是变量你都可以使用可选值绑定。如果你希望对`if`语句第一个分支中`actualNumber`的值进行操作,你可以用`if var actualNumber`来声明,然后可选量中的值就会成为一个可用的变量而不是常量。 + +## nil +## nil + +You set an optional variable to a valueless state by assigning it the special value nil: + +给可选变量一个没有值的状态是通过给它赋予一个特殊值`nil`来完成的: +通过给可选变量赋予特殊值`nil`来表示没有值的状态: + +``` +var serverResponseCode: Int? = 404 +// serverResponseCode contains an actual Int value of 404 +serverResponseCode = nil +// serverResponseCode now contains no value +``` + +> NOTE + +> nil cannot be used with non-optional constants and variables. If a constant or variable in your code needs to be able to cope with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type. + +> 注意 + +> `nil`不能被用于可选类型之外的常量和变量。如果你的代码中的常量或变量需要处理值缺失的情况,总是用一个可选的合适类型来声明它。 + +If you define an optional constant or variable without providing a default value, the constant or variable is automatically set to nil for you: + +如果你定义一个可选的常量或变量,却没有赋初值,这个常量或变量会自动设*置*为`nil`: + +``` +var surveyAnswer: String? +// surveyAnswer is automatically set to nil +``` + +> NOTE + +> Swift’s nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a non-existent object. In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types. + +> 注意 + +> Swift的`nil`和Objective-C中的不完全一样。Objective-C中,`nil`是指向不存在对象*的指针*。而在Swift中,`nil`不止是一个指针——它是一个特定类型的值缺失。可选的任何类型都可以设为`nil`,不只是对象类型。 + +## Implicitly Unwrapped Optionals +## 隐式解析可选值 + +As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist. + +像之前说的,可选值意味着一个常量或变量允许“没有值”。可以通过`if`语句来判断可选值中是否有值存在,如果值存在则用可选值绑定来调用可选量的值。 + +Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time. + +有时候从程序的结构可以清楚的知道一个可选值在第一次值设定之后,它总是有值的。在这些情况下,把每次调用都检查并解析可选量的值去掉是很有用的,因为它们可以安全的被推断出它们总是有值的。 + +These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional. + +这些类型的可选值被定义为隐式解析可选值。当你创建可选值的时候,你可以通过写感叹号(String!)而不是问号(String?)的形式来表示一个隐式解析的可选值。 + +Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties. + +如果可选值在第一次定义之后就肯定存在值并且之后每一刻都肯定存在,这种情况下隐式解析可选值是很有用的。Swift中的隐式解析可选值的主要用法是在类的初始化过程中,参见[Unowned References and Implicitly Unwrapped Optional Properties](link)。 + +An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it is accessed. The following example shows the difference in behavior between an optional String and an implicitly unwrapped optional String: + +一个隐式解析可选值其实是一个普通的可选值,但它也可以像非可选的值那样使用,无须每次调用都解析可选量的值。下面的例子显示了一个普通的可选的字符串和一个隐式解析的可选字符串的区别: + +``` +let possibleString: String? = "An optional string." +println(possibleString!) // requires an exclamation mark to access its value +// prints "An optional string." + +let assumedString: String! = "An implicitly unwrapped optional string." +println(assumedString) // no exclamation mark is needed to access its value +// prints "An implicitly unwrapped optional string." +``` + +You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used. Rather than placing an exclamation mark after the optional’s name each time you use it, you place an exclamation mark after the optional’s type when you declare it. + +你可以把隐式解析可选值当作一个允许可选值每次都能自动解析的授权。你只需要当你声明的时候在可选量的类型后面放一个感叹号,而不用每次使用的时候都在可选值后面放感叹号。 + +> NOTE + +> If you try to access an implicitly unwrapped optional when it does not contain a value, you will trigger a runtime error. The result is exactly the same as if you place an exclamation mark after a normal optional that does not contain a value. + +> 注意 + +> 如果你试图调用一个没有值的隐式解析可选值,你会得到一个实时的运行时错误。这和你在一个普通的不含值的可选值后面放感叹号的结果是完全一样的。 + +You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value: + +你仍然可以把隐式解析可选值当作一个普通的可选值,来检查它是否含有值: + +``` +if assumedString { + println(assumedString) +} +// prints "An implicitly unwrapped optional string." +``` + +You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement: + +你同样可以对隐式解析可选值使用可选值绑定,在一行声明中来检查和解析它的值: + +``` +if let definiteString = assumedString { + println(definiteString) +} +// prints "An implicitly unwrapped optional string." +``` + +> NOTE + +> Implicitly unwrapped optionals should not be used when there is a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable. + +> 注意 + +> 当一个变量有可能是`nil`的情况下,不应当使用隐式解析可选值。如果在整个过程中检查一个变量是否有`nil`值,你应该用一个普通的可选值。 + +# Assertions +# 断言 + +Optionals enable you to check for values that may or may not exist, and to write code that copes gracefully with the absence of a value. In some cases, however, it is simply not possible for your code to continue execution if a value does not exist, or if a provided value does not satisfy certain conditions. In these situations, you can trigger an assertion in your code to end code execution and to provide an opportunity to debug the cause of the absent or invalid value. + +可选值让你可以检查一个值是否存在,并且优雅的处理值缺失的情况。然而,在一些情况下,如果值不存在或者值不满足指定的条件,你的程序就无法继续执行。在这些情况下,你可以在代码中触发一个断言,来中断代码的执行并且提供一个来调试为什么值缺失或无效的机会。 + +## Debugging with Assertions +## 用断言来调试 + +An assertion is a runtime check that a logical condition definitely evaluates to true. Literally put, an assertion “asserts” that a condition is true. You use an assertion to make sure that an essential condition is satisfied before executing any further code. If the condition evaluates to true, code execution continues as usual; if the condition evaluates to false, code execution ends, and your app is terminated. + +断言是判断一个逻辑条件是否为真的实时检查。基本上,一个断言就是“断定”(asserts)一个条件为真。你可以使用断言来确保在运行后续代码之前它的一个必要的条件是已经满足了的。如果这个条件为真,代码会正常执行,如果条件为否,代码会停止执行,并且你的app应用会终止。 + +If your code triggers an assertion while running in a debug environment, such as when you build and run an app in Xcode, you can see exactly where the invalid state occurred and query the state of your app at the time that the assertion was triggered. An assertion also lets you provide a suitable debug message as to the nature of the assert. + +如果你的代码在调试环境下触发了一个断言(比如当你在Xcode中创建并运行一个app的时候),你可以准确的看到非法语句出现的位置,也可以查询到当断言触发时app的状态。断言还允许你可以提供一个相应的调试信息。 + +You write an assertion by calling the global assert function. You pass the assert function an expression that evaluates to true or false and a message that should be displayed if the result of the condition is false: + +通过调用全局的断言assert函数来写一个断言。你给断言函数传入一个等于true或false的表达式会被解析为`true`或者`false`的表达式,当结果是false的时候,会显示出一条信息以及在解析为`false`时的提示信息: + +``` +let age = -3 +assert(age >= 0, "A person's age cannot be less than zero") +// this causes the assertion to trigger, because age is not >= 0 +``` + +In this example, code execution will continue only if age >= 0 evaluates to true, that is, if the value of age is non-negative. If the value of age is negative, as in the code above, then age >= 0 evaluates to false, and the assertion is triggered, terminating the application. + +在这个例子里,只有`age >= 0`为真的时候代码才会继续执行,也就是,如果`age`的值是非负数。在上面的代码中,如果`age`的值是负数,在上面的代码中,`age >= 0`的条件判断这个表达式解析为否,这个断言被触发,终止了这个程序。 + +Assertion messages cannot use string interpolation. The assertion message can be omitted if desired, as in the following example: + +断言信息不能使用字符串插值。如果你想,断言信息可以省略,像下面这个例子: + +``` +assert(age >= 0) +``` + +## When to Use Assertions +## 何时使用断言 + +Use an assertion whenever a condition has the potential to be false, but must definitely be true in order for your code to continue execution. Suitable scenarios for an assertion check include: + +如果在一个条件有可能为否,但只有它为真的时候代码才能继续执行,这时时,应该使用断言。适当的使用断言检查的*合适*场景包括: + +- An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high. +- A value is passed to a function, but an invalid value means that the function cannot fulfill its task. +- An optional value is currently nil, but a non-nil value is essential for subsequent code to execute successfully. + +- 一个整数类型的下标索引被传入一个自定义的下标实现,但是这个下标索引值太小或太大。 +- 一个值传入一个函数,但是如果传入不合法的值,这个函数就无法满足需求。 +- 一个可选值当前的值是`nil`,但是后续代码成功执行需要一个非`nil`值。 + +See also Subscripts and Functions. + +参见[Subscripts and Functions](link)。 + +> NOTE + +> Assertions cause your app to terminate and are not a substitute for designing your code in such a way that invalid conditions are unlikely to arise. Nonetheless, in situations where invalid conditions are possible, an assertion is an effective way to ensure that such conditions are highlighted and noticed during development, before your app is published. + +> 注意 + +> 断言会造成你的app终止,它并不能代替你设计代码来保证不合法情况不出现。尽管如此,当不合法的情况可能出现时,断言可以有效的保证在你的app正式发布之前,在的开发过程中这种不合法的情况就会被高亮并被注意到。 \ No newline at end of file From dd2280047f790ffad6d295226d260ca02ea3bc58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=96=E9=82=80?= Date: Tue, 1 Jul 2014 20:55:40 +0800 Subject: [PATCH 222/261] modify patterns by review --- src/chapter3/08_Patterns.md | 52 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/chapter3/08_Patterns.md b/src/chapter3/08_Patterns.md index 73cce02..935c705 100644 --- a/src/chapter3/08_Patterns.md +++ b/src/chapter3/08_Patterns.md @@ -3,11 +3,11 @@ A pattern represents the structure of a single value or a composite value. For example, the structure of a tuple ```(1, 2)``` is a comma-separated list of two elements. Because patterns represent the structure of a value rather than any one particular value, you can match them with a variety of values. For instance, the pattern (x, y) matches the tuple (1, 2) and any other two-element tuple. In addition matching a pattern with a value, you can extract part or all of a composite value and bind each part to a constant or variable name. -模式代表了单个值或者复合值的结构。例如,元组```(1, 2)```的结构是用逗号分隔的两个元素的列表。因为[to:由于]模式代表一种值的结构,而不是特定的某个值,你可以把模式和各种同类型的值进行匹配。比如,模式```(x, y)```可以匹配元组```(1, 2)```,以及任何含有两个元素的元组。除了将模式与一个[去掉“一个”]值匹配外,你可以从合成值中提取部分或全部,然后分别把各部分和一个常量或变量进行绑定。[to:并把各部分分别同常量或变量进行绑定]。 +模式代表了单个值或者复合值的结构。例如,元组`(1, 2)`的结构是用逗号分隔的两个元素的列表。由于模式代表一种值的结构,而不是特定的某个值,你可以把模式和各种同类型的值进行匹配。比如,模式`(x, y)`可以匹配元组`(1, 2)`,以及任何含有两个元素的元组。除了将模式与值匹配外,你可以从合成值中提取部分或全部,并把各部分分别同常量或变量进行绑定。 In Swift, patterns occur in variable and constant declarations (on their left-hand side), in ```for-in``` statements, and in ```switch``` statements (in their case labels). Although any pattern can occur in the case labels of a ```switch``` statement, in the other contexts, only wildcard patterns, identifier patterns, and patterns containing those two patterns can occur. -在Swift中,模式出现在变量和常量的声明(放在它们的左侧)、```for-in```语句及```switch```语句(放在其case标签内)中。尽管任何模式都可以出现在```switch```语句的case标签中,但在其他情况下,只有通配符模式、标识符模式和包含这两种模式的模式才能出现。 +在Swift中,模式出现在变量和常量的声明(放在它们的左侧)、`for-in`语句及`switch`语句(放在其case标签内)中。尽管任何模式都可以出现在`switch`语句的case标签中,但在其他情况下,只有通配符模式、标识符模式和包含这两种模式的模式才能出现。 You can specify a type annotation for a wildcard pattern, an identifier pattern, and a tuple pattern to constraint the pattern to match only values of a certain type. @@ -51,9 +51,9 @@ You can specify a type annotation for a wildcard pattern, an identifier pattern, ## Wildcard Pattern ## 通配符模式 -A wildcard pattern matches and ignores any value and consists of an underscore (_). Use a wildcard pattern when you don’t care about the values being matched against. For example, the following code iterates through the closed range ```1...3```, ignoring the current value of the range on each iteration of the loop: +A wildcard pattern matches and ignores any value and consists of an underscore (_). Use a wildcard pattern when you don’t care about the values being matched against. For example, the following code iterates through the closed range `1...3`, ignoring the current value of the range on each iteration of the loop: -通配符模式由一个下划线(_)组成,它会匹配并忽略任何值。当你不关心被匹配的值时,可以使用此模式。例如,下面这段代码对闭区间```1...3```进行了循环,并忽略了每次循环的区间当前值: +通配符模式由一个下划线(_)组成,它会匹配并忽略任何值。当你不关心被匹配的值时,可以使用此模式。例如,下面这段代码对闭区间`1...3`进行了循环,并忽略了每次循环的区间当前值: ``` for _ in 1...3 { @@ -80,9 +80,9 @@ for _ in 1...3 { ## Identifier Pattern ## 标识符模式 -An identifier pattern matches any value and binds the matched value to a variable or constant name. For example, in the following constant declaration, ```someValue``` is an identifier pattern that matches the value ```42``` of type ```Int```: +An identifier pattern matches any value and binds the matched value to a variable or constant name. For example, in the following constant declaration, `someValue` is an identifier pattern that matches the value `42` of type ```Int```: -标识符模式匹配任何值,并把匹配的值绑定到一个变量或常量。例如,在下面的常量声明中,```someValue```是一个标识符模式,其匹配了类型是```Int```的值```42```。[to:它匹配了Int类型的值42] +标识符模式匹配任何值,并把匹配的值绑定到一个变量或常量。例如,在下面的常量声明中,`someValue`是一个标识符模式,它匹配了`Int`类型的值`42`。 ``` let someValue = 42 @@ -94,11 +94,11 @@ let someValue = 42 When the match succeeds, the value ```42``` is bound (assigned) to the constant name ```someValue```. -当匹配成功时,值```42```被绑定(赋值)给了常量```someValue``` +当匹配成功时,值`42`被绑定(赋值)给了常量`someValue` When the pattern on the left-hand side of a variable or constant declaration is an identifier pattern, the identifier pattern is implicitly a subpattern of a value-binding pattern. -当一个变量或常量声明的左边是标识符模式时,标识符模式是隐式的值绑定模式。[to:标识符模式是值绑定模式的隐式子模式] +当一个变量或常量声明的左边是标识符模式时,标识符模式是值绑定模式的隐式子模式。 > GRAMMAR OF AN IDENTIFIER PATTERN > @@ -115,11 +115,11 @@ When the pattern on the left-hand side of a variable or constant declaration is A value-binding pattern binds matched values to variable or constant names. Value-binding patterns that bind a matched value to the name of a constant begin with the keyword ```let```; those that bind to the name of variable begin with the keyword ```var```. -值绑定模式绑定匹配的值到一个变量或常量[to:值绑定模式把匹配的值绑定到一个变量或常量上]。绑定匹配值给常量时[to:把匹配值绑定给常量时],以关键字```let```开头;绑定给变量时,则使用关键字```var```。 +值绑定模式把匹配的值绑定到一个变量或常量上。把匹配值绑定给常量时,以关键字`let`开头;绑定给变量时,则使用关键字`var`。 Identifiers patterns within a value-binding pattern bind new named variables or constants to their matching values. For example, you can decompose the elements of a tuple and bind the value of each element to a corresponding identifier pattern. -包含在值绑定模式中的标识符模式,会绑定新的变量或常量到其匹配的值[to:会把新命名的变量或常量绑定到它们匹配的值]。例如,你可以分解一个元组的元素,并把每个元素绑定到相应的标识符模式中。 +包含在值绑定模式中的标识符模式,会把新命名的变量或常量绑定到它们匹配的值。例如,你可以分解一个元组的元素,并把每个元素绑定到相应的标识符模式中。 ``` let point = (3, 2) @@ -143,7 +143,7 @@ case let (x, y): In the example above, ```let``` distributes to each identifier pattern in the tuple pattern ```(x, y)```. Because of this behavior, the ```switch``` cases ```case let (x, y):``` and ```case (let x, let y):``` match the same values. -在上面的例子中,```let```将元组模式```(x, y)```分配到各个标识符模式[to:let把元素分配给元组模式(x,y)的相应标识符模式]。因为这种行为[to:正是由于这种行为],```switch```语句中的```case let (x, y):```和```case (let x, let y):```匹配的值是一样的。 +在上面的例子中,`let`把元素分配给元组模式`(x,y)`的相应标识符模式。正是由于这种行为,`switch`语句中的`case let (x, y):`和`case (let x, let y):`匹配的值是一样的。 > GRAMMAR OF A VALUE-BINDING PATTERN > @@ -160,15 +160,15 @@ In the example above, ```let``` distributes to each identifier pattern in the tu A tuple pattern is a comma-separated list of zero or more patterns, enclosed in parentheses. Tuple patterns match values of corresponding tuple types. -元组模式是被一对圆括号包围、并以逗号分隔的列表,列表中可以包含零或多个模式[to:元组模式是被一对圆括号包围,含有零或多个模式,并用逗号分隔的列表]。元组模式会匹配相应元组类型的值。 +元组模式是被一对圆括号包围,含有零或多个模式,并用逗号分隔的列表。元组模式会匹配相应元组类型的值。 You can constrain a tuple pattern to match certain kinds of tuple types by using type annotations. For example, the tuple pattern ```(x, y): (Int, Int)``` in the constant declaration ``` let (x, y): (Int, Int) = (1, 2)``` matches only tuple types in which both elements are of type ``` Int``` . To constrain only some elements of a tuple pattern, provide type annotations directly to those individual elements. For example, the tuple pattern in ``` let (x: String, y)``` matches any two-element tuple type, as long as the first element is of type ``` String``` . -你可以使用类型注释来限制一个元组模式仅匹配某种类型的元组。例如,在常量声明```let (x, y): (Int, Int) = (1, 2)```中的元组模式```(x, y): (Int, Int)```只匹配两个元素都是```Int```类型的元组。如果仅需要限制元组模式中的某几个元素,直接对这几个元素提供类型注释即可。例如,在```let (x: String, y)```中的元组模式,将匹配[增加“任意”]包含两个元素且第一个元素类型是```String```的任意[去掉“任意”]元组。 +你可以使用类型注释来限制一个元组模式仅匹配某种类型的元组。例如,在常量声明`let (x, y): (Int, Int) = (1, 2)`中的元组模式`(x, y): (Int, Int)`只匹配两个元素都是`Int`类型的元组。如果仅需要限制元组模式中的某几个元素,直接对这几个元素提供类型注释即可。例如,在`let (x: String, y)`中的元组模式,将匹配任意包含两个元素且第一个元素类型是`String`的元组。 When a tuple pattern is used as the pattern in a ```for-in``` statement or in a variable or constant declaration, it can contain only wildcard patterns, identifier patterns, or other tuple patterns that contain those. For example, the following code isn’t valid because the element ```0``` in the tuple pattern ```(x, 0)``` is an expression pattern: -当元组模式["被用在"to“用于”]```for-in```语句、变量或常量声明中时,它只可以包含通配符模式、标识符模式或者其他包含这两种模式的模式。例如,下面这段代码是不正确的,因为元组模式```(x, 0)```中的元素```0```是一个[去掉“一个”]表达式模式: +当元组模式用于`for-in`语句、变量或常量声明中时,它只可以包含通配符模式、标识符模式或者其他包含这两种模式的模式。例如,下面这段代码是不正确的,因为元组模式`(x, 0)`中的元素`0`是表达式模式: ``` let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] @@ -188,7 +188,7 @@ for (x, 0) in points { The parentheses around a tuple pattern that contains a single element have no effect. The pattern matches values of that single element’s type. For example, the following are equivalent: -对于只包含一个元素的元组,包围元组的圆括号是不起作用的。模式会匹配该单个元素的类型。例如,下面的不同写法是等效的["等效的"to“等价的”]: +对于只包含一个元素的元组,包围元组的圆括号是不起作用的。模式会匹配该单个元素的类型。例如,下面的不同写法是等价的: ``` let a = 2 // a: Int = 2 @@ -225,11 +225,11 @@ let (a): Int = 2 // a: Int = 2 An enumeration case pattern matches a case of an existing enumeration type. Enumeration case patterns appear only in ```switch``` statement case labels. -枚举用例模式匹配现有枚举类型的某种用例。枚举用例模式仅在```switch```语句的case标签中出现。 +枚举用例模式匹配现有枚举类型的某种用例。枚举用例模式仅在`switch`语句的`case`标签中出现。 If the enumeration case you’re trying to match has any associated values, the corresponding enumeration case pattern must specify a tuple pattern that contains one element for each associated value. For an example that uses a ```switch``` statement to match enumeration cases containing associated values, see [Associated Values](). -如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。使用```switch```语句来匹配包含关联值的枚举用例的例子,请参阅[关联值](). +如果你准备匹配的枚举用例有任何关联的值,则相应的枚举用例模式必须指定一个包含每个关联值元素的元组模式。使用`switch`语句来匹配包含关联值的枚举用例的例子,请参阅[关联值](). > GRAMMAR OF AN ENUMERATION CASE PATTERN > @@ -246,7 +246,7 @@ If the enumeration case you’re trying to match has any associated values, the There are two type-casting patterns, the ```is``` pattern and the ```as``` pattern. Both type-casting patterns appear only in ```switch``` statement case labels. The ```is``` and ```as``` patterns have the following form: -有两种类型转换模式,分别是```is```模式和```as```模式。这两种模式均["均"to"都"]只出现在```switch```语句的case标签中。```is```模式和```as```模式有以下形式: +有两种类型转换模式,分别是`is`模式和`as`模式。这两种模式都只出现在`switch`语句的`case`标签中。`is`模式和`as`模式有以下形式: > is type > @@ -254,21 +254,21 @@ There are two type-casting patterns, the ```is``` pattern and the ```as``` patte   -> ```is``` type +> `is` type > -> pattern ```as``` type +> pattern `as` type The ```is``` pattern matches a value if the type of that value at runtime is the same as the type specified in the right-hand side of the ```is``` pattern—or a subclass of that type. The ```is``` pattern behaves like the ```is``` operator in that they both perform a type cast but discard the returned type. -如果一个值的类型在运行时(runtime)和```is```模式右边所指定的类型(或者那个类型的子类型)一致,```is```模式将会匹配这个值。```is```模式类似```is```操作符,它们都进行类型转换,但是抛弃了返回的类型。 +如果一个值的类型在运行时(runtime)和`is`模式右边所指定的类型(或者那个类型的子类型)一致,`is`模式将会匹配这个值。`is`模式类似`is`操作符,它们都进行类型转换,但是抛弃了返回的类型。 The ```as``` pattern matches a value if the type of that value at runtime is the same as the type specified in the right-hand side of the ```as``` pattern—or a subclass of that type. If the match succeeds, the type of the matched value is cast to the pattern specified in the left-hand side of the ```as``` pattern. -如果一个值的类型在运行时(runtime)和```as```模式右边所指定的类型(或者那个类型的子类型)一致,```as```模式将会匹配这个值。一旦匹配成功,匹配值的类型被转换成```as```模式左边所指定的模式。 +如果一个值的类型在运行时(runtime)和`as`模式右边所指定的类型(或者那个类型的子类型)一致,`as`模式将会匹配这个值。一旦匹配成功,匹配值的类型被转换成`as`模式左边所指定的模式。 For an example that uses a ```switch``` statement to match values with ```is``` and ```as``` patterns, see [Type Casting for Any and AnyObject](). -关于使用```switch```语句来匹配```is```模式和```as```模式值的例子,请参阅[Type Casting for Any and AnyObject]()。 +关于使用`switch`语句来匹配`is`模式和`as`模式值的例子,请参阅[Type Casting for Any and AnyObject]()。 > GRAMMAR OF A TYPE CASTING PATTERN > @@ -289,11 +289,11 @@ For an example that uses a ```switch``` statement to match values with ```is``` An expression pattern represents the value of an expression. Expression patterns appear only in ```switch``` statement case labels. -表达式模式代表了一个表达式的值。该模式只出现在```switch```语句的case标签中。 +表达式模式代表了一个表达式的值。该模式只出现在`switch`语句的`case`标签中。 The expression represented by the expression pattern is compared with the value of an input expression using the Swift standard library ```~=``` operator. The matches succeeds if the ```~=``` operator returns ```true```. By default, the ```~=``` operator compares two values of the same type using the ```==``` operator. It can also match an integer value with a range of integers in an ```Range``` object, as the following example shows: -由表达式模式所代表的表达式会使用Swift标准库中的```~=```操作符与输入表达式的值进行比较。如果```~=```操作符返回```true```,则匹配成功。默认情况下,```~=```操作符使用```==```操作符来比较两个相同类型的值。它也可以匹配一个整数值与一个```Range```对象中的整数范围,正如下面这个例子所示: +由表达式模式所代表的表达式会使用Swift标准库中的`~=`操作符与输入表达式的值进行比较。如果`~=`操作符返回`true`,则匹配成功。默认情况下,`~=`操作符使用`==`操作符来比较两个相同类型的值。它也可以匹配一个整数值与一个`Range`对象中的整数范围,正如下面这个例子所示: ``` let point = (1, 2) @@ -323,7 +323,7 @@ default: You can overload the ```~=``` operator to provide custom expression matching behavior. For example, you can rewrite the above example to compare the point expression with a string representations of points. -你可以重载```~=```操作符来提供自定义的表达式匹配行为。例如,你可以重写上面的例子来比较使用字符串所表达的点[你可以使用point的字符串形式来比较point表达式]。 +你可以重载`~=`操作符来提供自定义的表达式匹配行为。例如,你可以重写上面的例子来使用point的字符串形式来比较point表达式。 ``` // Overload the ~= operator to match a string with an integer From 8cde24b0a2f7a634aee954c1691e996464b25863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A0=96=E9=82=80?= Date: Tue, 1 Jul 2014 21:33:04 +0800 Subject: [PATCH 223/261] review basic --- src/chapter2/01_The_Basics.md | 40 ++--------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index ce56f8d..0996853 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -9,65 +9,29 @@ Swift provides its own versions of all fundamental C and Objective-C types, incl Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值Int,浮点值Double和Float,布尔值Bool,以及文本值String。Swift还提供了两个强大的常见集合类型,数组和字典,见[集合类型](link)。 -***建议对语法关键字加上代码标记 {*** - -Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值```Int```,浮点值```Double```和```Float```,布尔值```Bool```,以及文本值```String```。Swift还提供了两个强大的常见集合类型,```Array```(数组)和```Dictionary```(字典),见[集合类型](link to 集合类型)。 - -***}*** - Like C, Swift uses variables to store and refer to values by an identifying name. Swift also makes extensive use of variables whose values cannot be changed. These are known as constants, and are much more powerful than constants in C. Constants are used throughout Swift to make code safer and clearer in intent when you work with values that do not need to change. 和C一样,Swift使用具有唯一名称的变量(variables)来储存和指向特定值。Swift还对那些值不能改变的变量进行了扩展,他们也被称为常量(Constants),Swift中的常量比C中的常量更加强大。在Swift中当你需要处理一些恒定不变的值的时候,使用常量(Constants)可以让代码更加安全和整洁。 -***感觉括号就统一用中文,会不会好点= ={*** - -和C一样,Swift使用具有唯一名称的变量(variables)来储存和指向特定值。Swift还对那些值不能改变的变量进行了扩展,他们也被称为常量(Constants),Swift中的常量比C中的常量更加强大。在Swift中当你需要处理一些恒定不变的值的时候,使用常量(Constants)可以让代码更加安全和整洁。 - -***}*** - In addition to familiar types, Swift introduces advanced types not found in Objective-C. These include tuples, which enable you to create and pass around groupings of values. Tuples can return multiple values from a function as a single compound value. 除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,包括:元组(tuples),你可以创建和传递一组数值。元组(tuples)可以在函数中以一个复合值的形式返回多个数值。 -***加粗那句这样翻译感觉更通顺{*** - -除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,***比如可以创建和传递一组数值的元组(tuples)。元组能在函数中以一个复合值的形式返回多个值。*** - -***}*** - Swift also introduces optional types, which handle the absence of a value. Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”. Optionals are similar to using nil with pointers in Objective-C, but they work for any type, not just classes. Optionals are safer and more expressive than nil pointers in Objective-C and are at the heart of many of Swift’s most powerful features. Swift还有可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用nil,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的nil,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大的特性的核心。 -***对语法关键字加代码标记,一些细节调整 {*** - -Swift还引入了可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用```nil```,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的```nil```,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大特性的核心。 - -***}*** - -Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This enables you to catch and fix errors as early as possible in the development process. +Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This enables you to catch and fix errors as early as possible in the development prObjective Cess. 可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(String),类型安全性会阻止你错误的给它赋一个整型(Int)的值。这让你在开发的过程中尽早的发现问题。 -***对语法关键字加标记 {*** - -可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(```String```),类型安全性会阻止你错误的给它赋一个整型(```Int```)的值。这让你在开发过程中能尽早发现和解决问题。 - -***}*** - # Constants and Variables # 常量和变量 -Constants and variables associate a name (such as maximumNumberOfLoginAttempts or welcomeMessage) with a value of a particular type (such as the number 10 or the string "Hello"). The value of a constant cannot be changed once it is set, whereas a variable can be set to a different value in the future. +**Constants and variables associate a name (such as maximumNumberOfLoginAttempts or welcomeMessage) with a value of a particular type (such as the number 10 or the string "Hello"). The value of a constant cannot be changed once it is set, whereas a variable can be set to a different value in the future. 常量和变量对应一个变量名(如maximumNumberOfLoginAttempts或welcomeMessage)以及对应类型的值(如数字10或字符串"Hello")。常量的值一旦设定旧不能改变,变量的值可以改变。 -***对语法关键字加标记 {*** - -常量和变量对应一个变量名(如```maximumNumberOfLoginAttempts```或```welcomeMessage```)以及对应类型的值(如数字```10```或字符串```"Hello"```)。常量的值一旦设定就不能改变,变量的值可以改变。 - -***}*** - # Declaring Constants and Variables # 声明常量和变量 From fddb93c59e03d14cd2d69c4adfbf254fc42dc2ea Mon Sep 17 00:00:00 2001 From: Adams Date: Wed, 2 Jul 2014 09:41:07 +0800 Subject: [PATCH 224/261] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a8f82ee..b505ffc 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ The Swift Programming Language 中文化项目 * Swift 初见 [认领 by 容隽] [review by 闻西] * Swift 教程 * 基础部分 [已完成 by 琼雪] [review by 栖邀] - * 基本操作符 [认领 by 冰浠] + * 基本操作符 [认领 by 冰浠] [review by 姜天意] * 字符串和字符 [已完成 by 筱谷] [review by 尘境] * 集合类型 [认领 by 尘境] * 控制流 [认领 by 墨昕] @@ -30,7 +30,7 @@ The Swift Programming Language 中文化项目 * 可选链 [认领 by 重鱼] [review by 玩家] * 类型转换 [认领 by 孟志昂] [review by 耿霄] * 嵌套类型 [认领 by 祁涛] [review by 袁鹏] - * 扩展 [已完成 by 袁鹏] + * 扩展 [已完成 by 袁鹏] [review by 姜天意] * 协议 [认领 by 姜天意] [review by 重鱼] * 泛型 [已完成 by 晴时] [review by 隐若] * 高级操作符 [认领 by 林晚] [review by 周源] @@ -41,7 +41,7 @@ The Swift Programming Language 中文化项目 * 表达式 [认领 by 懂象] [review by 兰梦] * 语句 [认领 by 玩家] * 声明 [认领 by 墨峰] [review by 龙刚] - * 属性 [认领 by 隐若] + * 属性 [认领 by 隐若] [review by 姜天意] * 模式 [已完成 by 栖邀] [review by 紫溪] * 泛型参数 [认领 by 龙刚] [review by 墨峰] * 语法总结 [认领 by 无独] From aa474d709742d7eb9de0fbd127c09ccd09416267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B1=B3=E5=B0=94?= Date: Wed, 2 Jul 2014 11:04:51 +0800 Subject: [PATCH 225/261] update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b505ffc..907b55e 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The Swift Programming Language 中文化项目 * 集合类型 [认领 by 尘境] * 控制流 [认领 by 墨昕] * 函数 [已完成 by 紫溪] [review by 飞长] - * 闭包 [认领 by 闻西] + * 闭包 [认领 by 闻西] [review by 米尔] * 枚举 [已完成 by 灵吾] [review by 筱谷] * 类和结构体 [已完成 by 晓毒] * 属性 [认领 by 周源] [review by 林晚] From be5494197041af3ebc8781adf8f95d9390159cfd Mon Sep 17 00:00:00 2001 From: woiweb Date: Wed, 2 Jul 2014 13:20:19 +0800 Subject: [PATCH 226/261] Update 01_About_the_Language_Reference.md review --- .../01_About_the_Language_Reference.md | 45 +++++-------------- 1 file changed, 10 insertions(+), 35 deletions(-) diff --git a/src/chapter3/01_About_the_Language_Reference.md b/src/chapter3/01_About_the_Language_Reference.md index a95d021..7779aa3 100644 --- a/src/chapter3/01_About_the_Language_Reference.md +++ b/src/chapter3/01_About_the_Language_Reference.md @@ -1,61 +1,36 @@ -# Language Reference +# 语言参考 -## About the Language Reference ## 关于语言参考 -This part of the book describes the formal grammar of the Swift programming language.The grammar described here is intended to help you understand the language in more detail, rather than to allow you to directly implement a parser or compiler. - - 本书的该部分描述了Swift编程语言的正式语法。在此描述语法的目的是为了帮助你更详细的理解该语言,而不是让你直接实现一个解析器或编译器。 -The Swift language is relatively small, because many common types, functions, and operators that appear virtually everywhere in Swift code are actually defined in the Swift standard library. Although these types, functions, and operators are not part of the Swift language itself, they are used extensively in the discussions and code examples in this -part of the book. - -Swift语言相对较小,因为那些无处不在出现在Swift代码中的很多常见的类型,函数,和运算符实际上已经定义在了Swift的标准库中。虽然这些类型,函数,和运算符本身不是Swift语言的一部分,但它们被广泛应用于该书本部分的探讨和代码示例中。 +Swift语言相对较小,因为那些无处不在出现在Swift代码中的很多常见的类型,函数,和运算符实际上已经定义在了Swift的标准库中。虽然这些类型,函数,和运算符不是Swift语言本身的一部分,但它们被广泛应用于该书本部分的探讨和代码示例中。 -## How to Read the Grammar ## 如何阅读语法 -The notation used to describe the formal grammar of the Swift programming language follows a few conventions: 用于描述Swift编程语言正规语法的标记有如下几个约定: - * An arrow (→) is used to mark grammar productions and can be read as “can consist of.“ - -* 箭头(→)用于标记语法生产和可以理解为“可包括” - -* Syntactic categories are indicated by italic text and appear on both sides of a grammar production rule. +* 箭头(→)用于标记文法和可以理解为“可包括” * 语法范围以斜体文字表示,显示在语法规范的两侧。 -* Literal words and punctuation are indicated by boldface constant width text and appear only on the right-hand side of a grammar production rule. +* 文字和标点由固定宽度的粗体文字显示,并只出现在一个标记文法的右侧. -* 文字和标点由固定宽度的粗体文字显示,并只出现在一个语法生产规范的右侧. -* Alternative grammar productions are separated by vertical bars (|). When alternative productions are too long to read easily, they are broken into multiple grammar production rules on new lines. +* 替代标记文法式由竖线(|)分隔。当替代文法过长而不易阅读时,它们将在新行中变换为多个标记文法规范。 -* 替代语法产生式由竖线(|)分隔。当替代产生式过长而不易阅读时,它们将在新行中变换为多个语法产生式规范。 +* 在一些案例中,常规字体文本将用于描述右侧的标记文法规则。 -* In a few cases, regular font text is used to describe the right-hand side of a grammar production rule. - -* 在一些案例中,常规字体文本将用于描述右侧的语法产生式规则。 - -* Optional syntactic categories and literals are marked by a trailing subscript, opt. - -* 可选的句法范围和文字为在尾部以opt标识描述。 - -As an example, the grammar of a getter-setter block is defined as follows: +* 可选的句法范围和字面量则以尾部下标opt作为标识。 比如,getter-setter 区的语法定义如下: -> G R A M M A R O F A G E T T E R- S E T T E R B L O C K - -> getter-setter-block → { getter-clause setter-clause opt } |{ setter-clause getter clause -} +> GETTER-SETTER区语法 -This definition indicates that a getter-setter block can consist of a getter clause followed by an optional setter clause, enclosed in braces, or a setter clause followed by a getter clause, enclosed in braces. The grammar production above is equivalent to the following two productions, where the alternatives are spelled out explicitly: +> getter-setter-block → { getter-clause setter-clause opt } |{ setter-clause getter clause} 该定义表示,一个getter-setter方法块可由一个getter子句后跟一个可选的setter语句,括在大括号中。或者一个setter子句后跟一个getter子句,括在大括号中。上述语法产生式等价于下面的两个替代处已经明确拼写出的产生式。 -> G R A M M A R O F A G E T T E R S E T T E R B L O C K +> GETTER-SETTER区语法 > getter-setter-block → { getter-clause setter-clause opt } From 79ecc5b08eb43d23a0a3fcb7078ab0f1f8a8bd7e Mon Sep 17 00:00:00 2001 From: Neekey Date: Wed, 2 Jul 2014 17:55:32 +0800 Subject: [PATCH 227/261] =?UTF-8?q?review=20=E5=88=B0=20#=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E7=BA=A6=E6=9D=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/22_Generics.md | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/chapter2/22_Generics.md b/src/chapter2/22_Generics.md index 1cb5771..ff00776 100644 --- a/src/chapter2/22_Generics.md +++ b/src/chapter2/22_Generics.md @@ -145,17 +145,17 @@ Once specified, a type parameter can be used to define the type of a function’ You can provide more than one type parameter by writing multiple type parameter names within the angle brackets, separated by commas. -你可以在尖括号中通过逗号分隔的方式指定多个类型参数名称,来为函数提供多个类型参数的功能。 +你可以在尖括号中通过逗号分隔的方式指定多个类型参数名称,来为函数提供多个类型参数。 ‌ #Naming Type Parameters -#参数类型命名 +#类型参数命名 In simple cases where a generic function or generic type needs to refer to a single placeholder type (such as the swapTwoValues generic function above, or a generic collection that stores a single type, such as Array), it is traditional to use the single-character name T for the type parameter. However, you are can use any valid identifier as the type parameter name. -在一般的情况下,如果泛型函数或者泛型类型需要指定一个占位符(像上边的`swapTwoValues`泛型函数或者只包含单个类型的泛型集合,比如数组),通常会用一个字符T来代表参数类型。不过,你也可以用任意有效的标示符来表示参数类型。 +在一般的情况下,如果泛型函数或者泛型类型需要指定一个占位符(像上边的`swapTwoValues`泛型函数或者只包含单个类型的泛型集合,比如数组),通常会用一个字符T来代表参数类型。不过,你也可以用任意有效的标识符来表示参数类型。 If you are defining more complex generic functions, or generic types with multiple parameters, it can be useful to provide more descriptive type parameter names. For example, Swift’s Dictionary type has two type parameters—one for its keys and one for its values. If you were writing Dictionary yourself, you might name these two type parameters KeyType and ValueType to remind you of their purpose as you use them within your generic code. -如果你定义了复杂的泛型函数或者泛型类型,需要多个参数,使用更多的描述类型是有必要的。比如Swift中的字典类型就有两个参数,其中一个键,一个值。如果你自己写字典类型,你也许会定义两个类型`KeyType`和`ValueType`,用来记住在泛型代码中的作用。 +如果你正在定义更加复杂的泛型函数或者泛型类型,并需要多个参数,那么使用更具有描述性的类型参数名称就很有必要了。比如Swift中的字典类型就有两个参数,其中一个作为键,一个作为值。如果你实现来字典类型,你可以为这两个类型取名为`KeyType`和`ValueType`,从而提醒你这两个参数在泛型代码中的作用。 ``` NOTE @@ -169,11 +169,11 @@ Always give type parameters UpperCamelCase names (such as T and KeyType) to indi #泛型类型 In addition to generic functions, Swift enables you to define your own generic types. These are custom classes, structures, and enumerations that can work with any type, in a similar way to Array and Dictionary. -除了泛型函数,Swift可以定义自己的泛型类型。可以是自定义的类、结构、枚举类作用于任何类型。和数组及字段的方式相同。 +除了泛型函数,Swift可以让你定义自己的泛型类型。这些类型可以是自定义的类、结构和枚举,他们和数组以及字典一样,可以和其他任意类型一起工作。 This section shows you how to write a generic collection type called Stack. A stack is an ordered set of values, similar to an array, but with a more restricted set of operations than Swift’s Array type. An array allows new items to be inserted and removed at any location in the array. A stack, however, allows new items to be appended only to the end of the collection (known as pushing a new value on to the stack). Similarly, a stack allows items to be removed only from the end of the collection (known as popping a value off the stack). -这部分展示如何写泛型版本的堆栈。堆栈是一系类值域的集合,和数组类似,但是比数据的有更多的限制的集合。数组允许元素可以从任何位置插入或者删除。堆栈,只允许从集合的顶部插入元素(如同push一个值到堆栈)。同样的,堆栈只允许从集合的顶部删除一个元素(记为从堆栈pop出一个值)。 +本节将展示如何编写堆栈这样的泛型集合类型。堆栈是一个具有特定顺序的数值的集合,和数组类似,但是和数组相比,堆栈在操作上有更多的限制。数组允许元素可以从任何位置插入或者删除。而堆栈只允许添加新元素到集合的顶部(叫做push一个新值到堆栈)。同样的,堆栈只允许从集合的顶部删除一个元素(叫做从堆栈pop出一个值)。 ``` NOTE @@ -182,12 +182,12 @@ The concept of a stack is used by the UINavigationController class to model the ``` 注意 -堆栈的概念被用在`UINavigationController`类中,模拟试图控制器的导航结构。你调用`UINavigationController`的`pushViewController:animated: `方法添加一个视图到堆栈中,调用` popViewControllerAnimated:`方法从堆栈中删除一个试图。堆栈是非常有用的,当你需要一个严格的“先进先出”的方式来管理集合时。 +堆栈的概念被用在`UINavigationController`类中,作为视图控制器的导航结构的数据模型。你调用`UINavigationController`的`pushViewController:animated: `方法添加一个视图到堆栈中,调用` popViewControllerAnimated:`方法从堆栈中删除一个试图。当你需要一个严格的“先进先出”方式来管理集合时,堆栈是非常有用的。 ``` The illustration below shows the push / pop behavior for a stack: -下边图表展示的是堆栈的进入、进出特性: +下面的图表展示了堆栈的进入、退出操作: ![stack](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPushPop_2x.png) @@ -199,14 +199,14 @@ The illustration below shows the push / pop behavior for a stack: 5. After popping a value, the stack once again holds three values. 1.当前堆栈里有3个值 -2.第四个值从堆栈的顶部push进去 -3.现在堆栈中有4个值,其中最先进的在最顶部 +2.第四个值从堆栈的顶部被“push”进去 +3.现在堆栈中有4个值,其中最新的值在最顶部 4.堆栈最顶部的值被移除,或者叫“popped” 5.当推出一个值后,堆栈重新变成了三个值 Here’s how to write a non-generic version of a “stack, in this case for a stack of Int values -下边是如何写一个不是泛型版本的堆栈,这个例子中得堆栈是Int类型: +下面展示如何编写一个非泛型版本的堆栈,这个例子中的堆栈是Int类型: ``` struct IntStack { @@ -221,16 +221,16 @@ struct IntStack { ``` This structure uses an Array property called items to store the values in the stack. Stack provides two methods, push and pop, to push and pop values on and off the stack. These methods are marked as mutating, because they need to modify (or mutate) the structure’s items array. -这个结构中使用数组属性`items`去存储堆栈中的数据。堆栈提供两个方法`push` 和`pop`,用于推入数据到堆栈,或者从堆栈推出数据。这些方法定义为`mutating`类型,原因是需要修改结构中得items数组的值。 +这个结构中使用数组属性items来存储堆栈中的数据。堆栈提供了`push` 和`pop`两个方法,用于推入数据到堆栈,或者从堆栈推出数据。这些方法被标记为`mutating`,因为他们需要修改结构中的items数组的值。 The IntStack type shown above can only be “used with Int values, however. It would be much more useful to define a generic Stack class, that can manage a stack of any type of value. -上边的这个`IntStack`类型只能用于Int值。然而,定义泛型类型的堆栈类型,可以管理堆栈中得任意类型,是非常有用的。 +上边的这个`IntStack`类型只能用于Int值。如果定义一个可以管理任何数据类型的泛型类型的堆栈类型,可以管理堆栈中得任意类型,是非常有用的。 Here’s a generic version of the same code: -上边是相同代码的泛型版本: +下面是堆栈的泛型版本: ``` struct Stack { @@ -245,23 +245,23 @@ struct Stack { ``` Note how the generic version of Stack is essentially the same as the non-generic version, but with a placeholder type parameter called T instead of an actual type of Int. This “type parameter is written within a pair of angle brackets () immediately after the structure’s name. -可以注意到,除了使用T代替真实int类型之外,下边的泛型版本的堆栈结构和上边非泛型版本的基本上一样的。这种类型参数是在紧接着结构的名称后跟着一对尖括号(). +可以注意到,除了使用T作为占位符类型参数来代替真实int类型之外,泛型版本的堆栈结构和上边非泛型版本基本上是一样的。这个类型参数直接跟在结构的名称后并被一对尖括号包裹(). T defines a placeholder name for “some type T” to be provided later on. This future type can be referred to as “T” anywhere within the structure’s definition. In this case, T is used as a placeholder in three places: -`T`定义了一个名称为”某种类型T“的节点提供给后边用。这种将来类型可以在结构体定义中的任何地方表示为`T`。在这个例子中,`T`在如下的几个地方会被使用: +T作为一个占位符名称来代替后续实际会给定的“某种类型T”。这种将来类型可以在结构体定义中的任何地方使用`T`来表示。在这个例子中,`T`在如下三个位置作为占位符: 1. To create a property called items, which is initialized with an empty array of values of type T 2. To specify that the push method has a single parameter called item, which must be of type T 3. To specify that the value returned by the pop method will be a value of type T -1.创建成员变量`items`,被初始化为包含类型T的空数组 +1.创建成员变量`items`,并将它初始化为包含类型T的空数组 2.指定`push`方法有一个参数item,类型为T类型 3.指定`pop`方法返回结果类型为T You create instances of Stack in a similar way to Array and Dictionary, by writing the actual type to be used for this specific stack within angle brackets after the type name when creating a new instance with initializer syntax: -像创建Array和Dictionary一样,创建一个Stack实例,在初始化时,紧随类型名后边尖括号中写出实际用到的类型: +像创建Array和Dictionary一样,使用构造函数的语法来实例化Stack时,在类型名后边尖括号中写出实际用到的类型: ``` var stackOfStrings = Stack() @@ -274,7 +274,7 @@ stackOfStrings.push("cuatro") Here’s how stackOfStrings looks after pushing these four values on to the stack: -下边展示`stackOfStrings`是如何把四个值push进栈: +下边展示`stackOfStrings`如何把四个值push进栈: ![进栈](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPushedFourStrings_2x.png) @@ -294,26 +294,26 @@ Here’s how the stack looks after popping its top value: Because it is a generic type, Stack can be used to create a stack of any valid type in Swift, in a similar manner to Array and Dictionary. - 由于`Stack`是泛型类型,所以在Swift中可以用于创建任何有效类型的栈,方式同`Array`和`Dictionary`。 + 由于`Stack`是泛型类型,所以在Swift中可以用于创建任何合法类型的栈,方式同`Array`和`Dictionary`。 #Type Constraints #类型约束 The swapTwoValues function and the Stack type can work with any type. However, it is sometimes useful to enforce certain type constraints on the types that can be used with generic functions and generic types. Type constraints specify that a type parameter must inherit from a specific class, or conform to a particular protocol or protocol composition. -`swapTwoValues`函数和`Stack`类型可以作用于任何类型,不过,有的时候对泛型函数和泛型类型上做类型强制约束是非常有用的。类型约束指定参数类型必须继承一个指定类型参数或者遵循一个特定的协议或协议构成。 +`swapTwoValues`函数和`Stack`类型可以和任何类型一起使用,不过,有的时候对泛型函数和泛型类型中使用的类型进行相应的约束是非常有用的。类型约束指定参数类型必须继承一个指定的类或者遵循一个特定的协议或协议组合。 For example, Swift’s Dictionary type places a limitation on the types that can be used as keys for a dictionary. As described in Dictionaries, the type of a dictionary’s keys must be hashable. That is, it must provide a way to make itself uniquely representable. Dictionary needs its keys to be hashable so that it can check whether it already contains a value for a particular key. Without this requirement, Dictionary could not tell whether it should insert or replace a value for a particular key, nor would it be able to find a value for a given key that is already in the dictionary. -例如,Swift中的`Dictionary`对键值做了约束。在字典的描述中,字典的键值类型必须是可哈希的,就是说他必须有一种方法保证其是唯一的。`Dictionary`约定键值是可哈希的,是为了便于检查其是否已经包含某个特定键的值。如果没有这个约束,就不能告诉是否可以插入或者替换某个特定键的值,也不能查找到某个已经存储在字典中的特定值。 +例如,Swift中的`Dictionary`对键值做了约束。在字典的描述中,字典的键值类型必须是可散列的,就是说必须有一种方法能保证其每个键值都是唯一的。`Dictionary`对于键值可散列的要求,是为了便于检查其是否已经包含某个特定键的值。如果没有这个约束,就不能判断是否可以插入或者替换某个特定键的值,也不能查找到某个已经存储在字典中的特定值。 This requirement is enforced by a type constraint on the key type for Dictionary, which specifies that the key type must conform to the Hashable protocol, a special protocol defined in the Swift standard library. All of Swift’s basic types (such as String, Int, Double, and Bool) are hashable by default. -这个需求强制加上一个类型约束作用于Dictionary的键上,而且其键类型必须遵循Hashable协议(Swift 标准库中定义的一个特定协议)。所有的 Swift 基本类型(如String,Int,Double和 Bool)默认都是可哈希。 +这个需求以一个类型约束的形式被添加在Dictionary的键类型上,以此表明键的类型必须遵循Hashable协议(Swift 标准库中定义的一个特定协议)。所有的 Swift 基本类型(如String,Int,Double和 Bool)默认都是可散列的。 You can define your own type constraints when creating custom generic types, and these constraints provide much of the power of generic programming. Abstract concepts like Hashable characterize types in terms of their conceptual characteristics, rather than their explicit type. -当你创建自定义泛型类型时,你可以定义你自己的类型约束,当然,这些约束要支持泛型编程的强力特征中的多数。抽象概念如可哈希具有的类型特征是根据它们概念特征来界定的,而不是它们的直接类型特征。 +你可以在创建自定义泛型类型时,定义你自己的类型约束,这些类型约束为你提供了很多泛型编程的能力。像可散列这样的抽象概念,从概念层面为类型添加特征,而不是直接指定具体的类型。 ##Type Constraint Syntax From 4ffb312efedcdf013761115fce6e5fb2aa1427d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=AD=B1=E8=B0=B7?= Date: Wed, 2 Jul 2014 19:49:15 +0800 Subject: [PATCH 228/261] =?UTF-8?q?2.8=20Reviewed=20=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/08_Enumerations.md | 103 +++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 1 deletion(-) diff --git a/src/chapter2/08_Enumerations.md b/src/chapter2/08_Enumerations.md index 37ab965..09b272a 100644 --- a/src/chapter2/08_Enumerations.md +++ b/src/chapter2/08_Enumerations.md @@ -2,19 +2,34 @@ 枚举为一组相关值定义了一个通用的类型,使你能够在代码中使用这些值的同时保持类型安全。 +|| 枚举为一组相关的值定义了一个通用的类型,让我们能够在代码中安全地操作这些值。 + 如果你熟悉C语言,你就知道C语言里的枚举是给相关名称赋予一系列整型值。相比C语言,Swift中的枚举更灵活,并且不需要为每一个枚举成员指定一个值。如果枚举成员被赋予了值(也就是“原始值”),这个值可以是字符串、字符、任一整型值或者浮点类型的值。 +|| 如果对 C 语言比较熟悉,可能就会知道在 C 语言里枚举是给相关键值赋予一系列的整型值。但 Swift 的枚举更加灵活,而且不需要为每个枚举成员指定初始值。但如果枚举成员被赋予了初始值,这个值可以是字符、字符串、任何整型或浮点类型的值。 + 或者,枚举成员也可以成员值指定任一类型的关联值,就像其他语言的联合类型或者变体类型。你可以在一个枚举变量里定义一系列通用的相关成员,每一个成员都有一个相应类型的值与其关联。 +|| 此外,就像其它编程语言中的联合类型或变体类型一样,Swift 的枚举变量可以给每个成员指定单独的值类型。我们可以把一系列相关的值定义为一个枚举变量,而且每个枚举成员都有相应的值与其关联。 + 枚举作为Swift语言中的“一等公民”,采用了许多一贯只被类支持的特性,比如计算属性,以提供关于枚举变量当前值的额外信息,以及实例方法,以提供关于枚举变量所代表值的功能。枚举类型也支持为枚举成员定义初始化值,还有在原有实现上扩展以增加其功能,以及遵循协议提供标准功能。 +|| 枚举作为 Swift 的核心类型拥有强大的能力,它继承了很多一直以来只被类支持的特性,比如提供当前值之外更丰富信息的属性运算,或者用以展现该变量中所关联值的实例方法。枚举类型可以通过定义构造器为每个成员提供初始值,也可以在他们原始实现上扩展更多的功能,并通过遵循特定协议对外提供标准功能。 + + 关于这些特性的更多信息,请参考属性,方法,初始化,扩展,以及协议。 +|| 关于这些特性的更多信息,请参考[属性](),[方法](),[初始化](),[扩展](),以及[协议]()。 + ## 枚举语法 +## || 枚举类型的语法 + 你可以用enum关键字引入枚举类型,并把完整的定义用一对大括号包裹起来: +|| 我们可以用 `enum` 关键字定义枚举变量,并把完整的定义用一对大括号包裹起来: + ``` enum SomeEnumeration { // 枚举定义 @@ -23,6 +38,8 @@ enum SomeEnumeration { 以指南针的四个方位为例: +|| 以指南针的四个方位为例: + ``` enum CompassPoint { case North @@ -34,10 +51,16 @@ enum CompassPoint { 在枚举变量内定义的值(例如North、South、East、West)称为这一枚举变量的成员值或者成员。Case 关键字表明将被定义的新的一行成员值。 +|| 这些被枚举变量定义的值(如 North、South、East、West)被称作该枚举变量的成员。`case` 关键字表示这一行定义了新的成员值。 + > 注意:不像C和Objective-C,Swift语言中的枚举类型在创建时并不会被赋予一个默认的整型值。在上面的CompassPoints例子中,North、South、East、West并不是默认为0,1,2,3。相反,这些不同的枚举成员都是完备的值,并且以显式声明的CompassPoint作为其类型。 +> 注意:不像 C 或者 Objective-C,Swift 中的枚举类型不会在创建时被赋予一组初始的整型值。在上面的 `CompassPoint` 指南针例子中,`North`、`South`、`East`、`West` 并不是默认的 `0`,`1`,`2`,`3`。相反地,通过 `CompassPoint` 类型的显示声明,这些枚举成员会拥有各自独立的类型。 + 多个成员值可以用逗号分隔在同一行出现: +|| 多个成员值可以写在同一行,使用逗号分隔: + ``` enum Planet { case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune @@ -46,23 +69,31 @@ enum Planet { 每一个枚举变量都定义了一个全新的类型。和Swift中的其他类型一样,枚举变量的命名(比如CompassPoint和Planet)都需要以大写字母开头,并采用单数而不是复数形式,这样阅读时就一目了然了。 +|| 每个枚举变量都定义了一个全新的类型。和 Swift 中其它类型一样,枚举变量的命名(比如`CompassPoint` 和 `Planet`)都需要以大写字母开头,并采用单数而不是复数形式,这样阅读时就一目了然。 + ``` var directionToHead = CompassPoint.West ``` 当以CompassPoint其中一个值初始化时, 编译器将推断directionToHead的类型。而一旦把directionToHead以CompassPoint类型完成声明后,在设置它为CompassPoint其他值的时候,你就可以使用更为简短便捷的点语法了: +|| 当以 `CompassPoint` 其中一个值初始化时,编译器将推断 `directionToHead` 的类型。而一旦把 `directionToHead` 以 `CompassPoint` 类型声明后,就可以用很简单的方法设置它为 `CompassPoint` 的其它值: + ``` directionToHead = .East ``` directionToHead的类型已知了,因此你可以在赋值时省略类型。当遇到显式声明的枚举变量时,借助点语法可以使你的代码更具可读性。 +|| 一旦 `directionToHead` 的类型已知,我们就可以在赋值时忽略类型的指定。当遇到显式声明的枚举变量时,这种语法可以让代码更具可读性。 + ## 用Switch语句匹配枚举值 你可以通过Switch语句匹配某一枚举值: +|| 我们可以通过 `Switch` 语句匹配某个枚举值: + ``` directionToHead = .South switch directionToHead { @@ -80,12 +111,22 @@ case .West: 这段代码可以这样理解: +|| 这段代码可以这样理解: + “考虑directionToHead的值:当它等于.North时,打印 “Lots of planets have a north” ;当它等于.South时,打印 “Watch out for penguins” ”,后续省略。 +|| “对比 `directionToHead` 的值:如果它等于 `.North`,输出 "Lots of planets have a north";如果它等于 `.South`,正如此例,将输出 "Watch out for penguins"。” + +|| 以此类推。 + 就像在流程控制里所描述的那样,switch语句在确定枚举变量的值的时候要全面完备。如果删掉.West对应的情况,这段代码将不能通过编译,因为它没有考虑到完整的CompassPoint 成员列表。要求全面完备确保了枚举变量不会被意外忽略。 +|| 就像在 [流程控制]() 里描述的一样,`switch` 语句必须考虑到所有的枚举成员。在上面的例子中,如果 `case` 语句忽略了 `.West` 成员,代码编译将不会通过,因为它没照顾到所有 `CompassPoint` 的成员。这种严格的要求确保了每个枚举成员不会被意外地忽略。 + 当不能为每一个枚举变量都提供case关键字时,可以为 那些没有一一提到的枚举成员设置一个default关键字: +|| 当不能为每一个枚举成员都提供 `case` 语句时,可以给那些没有显式提到的成员设置一个 `default` 关键字: + ``` let somePlanet = Planet.Earth switch somePlanet { @@ -100,20 +141,32 @@ default: ## 相关值 +## || 相关值 + 上一节内容的例子展示了枚举成员是具有独立定义和独立类型的值。你可以为Planet.Earth设置一个常量或变量,以及后续做检验。但有时为枚举成员关联其他类型的值将会很有用。这让你能为枚举成员添加额外的配置信息,并允许其在每次使用时改变其信息内容。 +|| 上一节的例子展示了枚举成员是具有独立定义和独立类型的值。我们可以为 `Planet.Earth` 赋值为常量或变量,或者后面再调整。有时在每个枚举成员旁边关联值的类型会很有用,因为这可以让我们在声明枚举成员时附带更多额外的信息,而且允许我们在以后的每次使用过程中修改这些信息。 + 你能为Swift中的枚举变量定义任意给定类型的关联值,并且如果需要,这些关联值的类型可以根据枚举成员而不同。这样的枚举变量在其他编程语言中被称为可区分联合类型、带标签的联合类型或者变异类型。 +|| Swift 中的枚举类型可以存储任何指定类型的相关值,而且如果需要的话,每个枚举成员的类型都可以互不一样。这种枚举类型就像是在其它编程语言中被大众熟知的*鉴别联集*、*标签联合*或*变体类型*。 + 例如,假设一个存货清单跟踪系统需要跟踪两种带有不同条形码的产品。一种产品被打上UPC-A格式的一维条形码,这一格式使用0到9的数字。每个条形码包含一个“号码系统”数字,紧跟着十个“标识符”数字,最后还有一个“校验位”数字以验证该条形码是否被正确扫描了。 +|| 举个例子,在一个存货清单跟踪系统中需要跟踪两种带有不同条形码的产品。其中一些产品使用由数值 0 到 9 表示的一维条形码 UPC-A。这种条形码一开始会有一个指定进制的数值,然后紧跟 10 位标识符,最后会有一个校验位用来检查该条形码是否被正确地扫描。 + ![](http://gtms04.alicdn.com/tps/i4/TB1y.hbFFXXXXXibFXX.wCCNpXX-366-175.png) 另一种产品被打上QR格式的二维码,这一格式使用ISO 8859-1的任意字符,并且可以编码长达2953个字符的字符串。 +|| 而另一些产品则使用了 QR 格式的二维码,这一格式允许使用 ISO 8859-1 字符集的任意字符,并且可以表示长达 2953 个字符的字符串。 + ![](http://gtms01.alicdn.com/tps/i1/TB11AE1FFXXXXaSXXXX39VBMpXX-257-257.png) 如果我们的存货清单跟踪系统能分别以长度为三的整型数组的形式保存UPC-A格式,并以任意长度的字符串格式保存QR格式就好了。 +|| 如果我们的存货清单跟踪系统能同时以三个整型数组的形式储存 UPC-A 格式,并以任意长度的字符串格式保存QR格式的话,那就很方便了。 + ``` enum Barcode { case UPCA(Int, Int, Int) @@ -121,7 +174,9 @@ enum Barcode { } ``` -在Swift中,可以这样定义这两种产品条纹码的枚举变量: +在 Swift 中,可以这样定义这两种产品条纹码的枚举变量: + +|| 在 Swift 中,可以这样声明兼容两种产品条形码的枚举类型: ``` enum Barcode { @@ -132,28 +187,46 @@ enum Barcode { 这段代码可以这样理解: +|| 这段代码可以这样理解: + “定义一个叫Barcode的枚举类型,可包含关联长度为三的整型数组的UPCA 以及关联字符串的QRCode”。 +|| “声明一个叫 `Barcode` 的枚举类型,它包含了以三个整型数组(`Int`,`Int`,`Int`)的形式储存的 UPC,以及以字符串(`String`)形式存储的 `QRCode` ”。 + 这一定义不包含任何确切整型值或者字符串,它只定义Barcode.UPCA和Barcode.QRCode对应Barcode枚举变量和常量可以存储的关联值的类型。 +|| 这个声明不包含任何确切的整型值或者字符串,它只是在 `Barcode.UPCA` 和 `Barcode.QRCode` 的描述中定义了 `Barcode` 的枚举变量或常量允许使用的值类型。 + 现在条纹码可以使用任一类型创建: +|| 现在条形码可以通过任意一个类型创建: + ``` var productBarcode = Barcode.UPCA(8, 85909_51226, 3) ``` 这个例子创建了一个叫productBarcode的新变量,赋予它一个关联了(8, 8590951226, 3)数组的Barcode.UPCA。上面的“标识符”值中包含了一个下划线:85909_51226,让它作为条纹码更具可读性。 + +|| 这个例子创建了一个叫 `productBarcode` 的新变量,并赋予了它由三个数值数组关联的 `Barcode.UPCA` 成员值。在上面的 10 位标识符中出现了一个下划线 `85909_51226`,这是为了让它作为条形码更具可读性。 + 我们也可以赋予这个产品另外一个条纹码: +|| 或者,这个产品我们可以赋予它另外一种条形码: + + ``` productBarcode = .QRCode("ABCDEFGHIJKLMNOP") ``` 这时,原有的Barcode.UPCA和它的整型值被替换成新的Barcode.QRCode和字符串。类型为Barcode的常量和变量可以保存.UPCA或者.QRCode(以及它们的关联值),并且在任一给定时间内只能保存其中一个。 +|| 这时原有的 `Barcode.UPCA` 和它关联的数值会被替换成新的 `Barcode.QRCode` 字符串。已经被定义为 `Barcode` 类型的变量或常量允许使用 `.UPCA` 或者 `.QRCode` 类型存储数据,但同一时刻只能使用其中一种类型。 + 和之前一样,我们可以使用switch语句来检验不同类型的条纹码。然而这次,可以把关联值抽取出来作为switch语句的一部分。你可以抽取关联值作为一个常量(带有前缀let)或者变量(带有前缀var)以在switch语句的case主体内使用: +|| 和前面的一样,使用 `switch` 语句可以用来检查不同类型的条形码,但这次,我们可以把关联值抽取出来作为 `switch` 语句的一部分。我们可以把关联值以常量(使用前缀 `let`)或者变量(使用前缀 `var`)抽出,放在 `case` 内容里面。 + ``` switch productBarcode { case .UPCA(let numberSystem, let identifier, let check): @@ -166,6 +239,8 @@ case .QRCode(let productCode): 如果一个枚举成员所有的都能被抽取为常量,或者都能被抽取为变量,你可以在枚举成员名称前放一个let或者var作为注解,简单来说就是这样: +|| 如果一个枚举成员所有的关联类型都能被抽取为常量变量,则可以在枚举成员名称前放一个 `let` 或者`var` 声明,简单来说就是这样: + ``` switch productBarcode { case let .UPCA(numberSystem, identifier, check): @@ -179,10 +254,16 @@ case let .QRCode(productCode): ## 原始值 +## || 原始值 + 上面关联值小节里的条纹码的例子展示了枚举成员是如何声明其和不同类型的值相关联。作为关联值的替代,枚举成员也可以在初始化时预先设置默认值(也叫原始值),并且其类型保持相同。 +|| 在上面 [关联值]() 的例子中,描述了如何为每个枚举成员声明不同的存储类型。另外,所有枚举成员可以使用同一种类型预定义指定的值(一般称作 *原始值*)。 + 以下是一个例子展示命名的枚举成员和原始的ASCII码相关联: +|| 下面的例子展示的是在每个枚举成员旁边定义了 ASCII 原始值: + ``` enum ASCIIControlCharacter: Character { case Tab = "\t" @@ -193,12 +274,20 @@ case let .QRCode(productCode): 这里,一个名为ASCIIControlCharacter的枚举类型的原始值被定义为字符类型,并且被设置为一些更为常见的ASCII控制字符。关于字符可参考“字符串与字符”一章。 +|| 在这个例子里,一个名为 `ASCIIControlCharacter` 的枚举类型的值被定义为 `Character`,并给每个枚举成员预设了一些常见的 ASCII 字符。关于字符可参考 [字符串与字符]() 一章。 + 注意原始值和关联值并不一样。像这个例子中的三个ASCII码一样,原始值是你在代码中第一次定义枚举类型时就已设置的值,并且一个特定枚举成员的原始值始终不会改变。而关联值是你根据某一枚举成员创建一个常量或变量时才设置的值,并且每次创建时都可以不同。 +|| 注意原始值和关联值并不一样,就像这个例子中的三个 ASCII 码。原始值是在代码中第一次定义枚举类型时就已设置的值,并且一个特定枚举成员的原始值始终不会改变。而关联值是根据某一枚举成员创建一个常量或变量时才设置的值,并且每次创建时都可以不同。 + 原始值可以是字符串、字符,或者任一整型和浮点数类型。每个原始值在其枚举类型声明时都必须保持唯一。当整型被用作原始值时,如果一些枚举成员没有设置特定值,它们的原始值会自增。 +|| 原始值可以是字符串、字符,或者任一整型和浮点数类型。每个原始值在其枚举类型声明时都必须保持唯一。当整型被用作原始值时,如果一些枚举成员没有设置特定值,它们的原始值会自增。 + 下面的枚举类型是对之前Planet枚举类型的一个改良,使用整型的原始值代表每个星球离太阳距离大小的顺序。 +|| 下面的枚举类型是对之前 `Planet` 枚举类型的一个改良,使用整型的原始值代表每个星球距离太阳近远的顺序。 + ``` enum Planet: Int { case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune @@ -207,8 +296,12 @@ enum Planet: Int { 这里的自增意味着Planet.Venus的原始值为2,依此类推。 +|| 这里的自增意味着 `Planet.Venus` 的原始值为 2,依此类推。 + 你可以通过枚举成员的toRaw方法访问其原始值: +|| 我们可以通过枚举成员的 `toRaw` 方法访问其原始值: + ``` let earthsOrder = Planet.Earth.toRaw() // earthsOrder 为 3 @@ -216,6 +309,8 @@ let earthsOrder = Planet.Earth.toRaw() 你也可以通过枚举类型的fromRaw方法去试图查找带有某一特定原始值的枚举成员。这个例子通过其原始值为7找到了Uranus: +|| 也可以通过枚举类型的 `fromRaw` 方法去试图检索带有某一特定原始值的枚举成员。这个例子通过原始值为 7 找到了 `Uranus`: + ``` let possiblePlanet = Planet.fromRaw(7) // possiblePlanet类型为Planet?并且值等于Planet.Uranus @@ -223,8 +318,12 @@ let possiblePlanet = Planet.fromRaw(7) 然而,不是所有的int值都能匹配到一个星球。因此,fromRaw方法返回一个可选的枚举成员。以上的例子中,possiblePlanet的类型是”Planet?”或者”可选Planet”。 +|| 不过不是所有的 `Int` 值都会匹配到一个星球。所以,`fromRaw` 方法返回的是一个 *可选的* 枚举成员。上面的例子中,`possiblePlanet` 的类型是 `Planet?` 或者 ”可选 `Planet`” + 如果你试图查找位置为9的星球,fromRaw方法返回的这个可选Planet将为nil: +|| 如果试图检索位置为 9 的星球,`fromRaw` 方法返回的这个可选 `Planet` 将为 `nil`: + ``` let positionToFind = 9 if let somePlanet = Planet.fromRaw(positionToFind) { @@ -243,6 +342,8 @@ if let somePlanet = Planet.fromRaw(positionToFind) { 这个例子使用可选绑定试图访问原始值为9的星球。如果可以取回,if let somePlanet = Planet.fromRaw(9)这一语句将取回一个可选Planet并把它赋予somePlanet。而这种情况下是不可能取回一个位置为9的星球,因此,else分支就被执行了。 +|| 这个例子使用可选绑定试图访问原始值为 9 的星球。如果可以访问,则 `if let somePlanet = Planet.fromRaw(9)` 这一语句将一个可选 `Planet` 赋值给 `somePlanet`。但目前没有办法找到一个位置为 9 的星球,所以 `else` 分支就被执行了。 + From 9160eccfd79fa14abf0da29677a144f0f3fa0102 Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Wed, 2 Jul 2014 21:14:56 +0800 Subject: [PATCH 229/261] merge review - till tuples --- src/chapter2/01_The_Basics.md | 626 +++++++++----------------- src/chapter2/12_Subscripts_Chinese.md | 191 ++++++++ src/words.md | 2 +- 3 files changed, 399 insertions(+), 420 deletions(-) create mode 100644 src/chapter2/12_Subscripts_Chinese.md diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 0996853..91f4514 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -1,119 +1,76 @@ -# The Basics # 基础部分 -Swift is a new programming language for iOS and OS X app development. Nonetheless, many parts of Swift will be familiar from your experience of developing in C and Objective-C. - Swift是一个用于iOS和OS X平台开发的新的编程语言。尽管如此,Swift在很多地方都会和你以往用C语言和Objective-C开发的经验类似。 -Swift provides its own versions of all fundamental C and Objective-C types, including Int for integers; Double and Float for floating-point values; Bool for Boolean values; and String for textual data. Swift also provides powerful versions of the two primary collection types, Array and Dictionary, as described in Collection Types. - -Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值Int,浮点值Double和Float,布尔值Bool,以及文本值String。Swift还提供了两个强大的常见集合类型,数组和字典,见[集合类型](link)。 - -Like C, Swift uses variables to store and refer to values by an identifying name. Swift also makes extensive use of variables whose values cannot be changed. These are known as constants, and are much more powerful than constants in C. Constants are used throughout Swift to make code safer and clearer in intent when you work with values that do not need to change. - -和C一样,Swift使用具有唯一名称的变量(variables)来储存和指向特定值。Swift还对那些值不能改变的变量进行了扩展,他们也被称为常量(Constants),Swift中的常量比C中的常量更加强大。在Swift中当你需要处理一些恒定不变的值的时候,使用常量(Constants)可以让代码更加安全和整洁。 - -In addition to familiar types, Swift introduces advanced types not found in Objective-C. These include tuples, which enable you to create and pass around groupings of values. Tuples can return multiple values from a function as a single compound value. +Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值`Int`,浮点值`Double`和`Float`,布尔值`Bool`,以及文本值`String`。Swift还提供了两个强大的常见集合类型,数组`Array`和字典`Dictionary`,见[集合类型](link)。 -除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,包括:元组(tuples),你可以创建和传递一组数值。元组(tuples)可以在函数中以一个复合值的形式返回多个数值。 +和C一样,Swift使用具有唯一名称的变量(variables)来储存和指向特定值。Swift还对那些值不能改变的变量进行了扩展,他们也被称为常量(Constants),Swift中的常量比C中的常量更加强大。在Swift中当你需要处理一些恒定不变的值的时候,使用常量(Constants)可以让代码更加安全和整洁。 -Swift also introduces optional types, which handle the absence of a value. Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”. Optionals are similar to using nil with pointers in Objective-C, but they work for any type, not just classes. Optionals are safer and more expressive than nil pointers in Objective-C and are at the heart of many of Swift’s most powerful features. +除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,比如可以创建和传递一组数值的元组(tuples)。元组能在函数中以一个复合值的形式返回多个值。 -Swift还有可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用nil,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的nil,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大的特性的核心。 +Swift还有可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用`nil`,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的`nil`,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大特性的核心。 -Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This enables you to catch and fix errors as early as possible in the development prObjective Cess. +可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(`String`),类型安全性会阻止你错误的给它赋一个整型(`Int`)的值。这让你在开发的过程中尽早的发现***和解决***问题。 -可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(String),类型安全性会阻止你错误的给它赋一个整型(Int)的值。这让你在开发的过程中尽早的发现问题。 - -# Constants and Variables # 常量和变量 -**Constants and variables associate a name (such as maximumNumberOfLoginAttempts or welcomeMessage) with a value of a particular type (such as the number 10 or the string "Hello"). The value of a constant cannot be changed once it is set, whereas a variable can be set to a different value in the future. - -常量和变量对应一个变量名(如maximumNumberOfLoginAttempts或welcomeMessage)以及对应类型的值(如数字10或字符串"Hello")。常量的值一旦设定旧不能改变,变量的值可以改变。 +常量和变量将一个变量名(如`maximumNumberOfLoginAttempts`或`welcomeMessage`)和对应类型的值(如数字`10`或字符串`"Hello"`)进行关联。常量的值一旦设定就不能改变,变量的值可以。 -# Declaring Constants and Variables # 声明常量和变量 -Constants and variables must be declared before they are used. You declare constants with the let keyword and variables with the var keyword. Here’s an example of how constants and variables can be used to track the number of login attempts a user has made: - 常量和变量必须在使用前声明。用`let`来声明常量,用`var`来声明变量。下面是一个用常量和变量来记录用户尝试登录次数的例子: - let maximumNumberOfLoginAttempts = 10 - var currentLoginAttempt = 0 - -This code can be read as: +``` +let maximumNumberOfLoginAttempts = 10 +var currentLoginAttempt = 0 +``` 这段代码可以解读为: “Declare a new constant called maximumNumberOfLoginAttempts, and give it a value of 10. Then, declare a new variable called currentLoginAttempt, and give it an initial value of 0.” -声明一个新的常量,叫做“登录尝试次数的最大值”,值为10。声明一个新的变量,叫“当前尝试次数”,初始值设为0。 - -In this example, the maximum number of allowed login attempts is declared as a constant, because the maximum value never changes. The current login attempt counter is declared as a variable, because this value must be incremented after each failed login attempt. - -在这个例子中,登录尝试次数的最大值被声明为常量,因为这个最大值不会改变,当前尝试次数被声明为变量,因为这个值在每次失败的登录尝试之后都要增加。 +声明一个新的常量,叫做`maximumNumberOfLoginAttempts`(最大尝试登陆次数),值为`10`。声明一个新的变量,叫做`currentLoginAttempt`(当前尝试登陆次数),初始值设为`0`。 -You can declare multiple constants or multiple variables on a single line, separated by commas: +在这个例子中,最大尝试登陆次数被声明为常量,因为这个最大值不会改变,当前尝试登陆次数被声明为变量,因为这个值在每次尝试登陆失败后都要增加。 你可以在同一行内声明多个常量或变量,用逗号分割: - var x = 0.0, y = 0.0, z = 0.0 - -> NOTE - -> If a stored value in your code is not going to change, always declare it as a constant with the let keyword. Use variables only for storing values that need to be able to change. +``` +var x = 0.0, y = 0.0, z = 0.0 +``` > 注意 > 当值不会改变时,永远用`let`声明常量。只在值需要改变的时候用变量。 -# Type Annotations # 类型批注 -You can provide a type annotation when you declare a constant or variable, to be clear about the kind of values the constant or variable can store. Write a type annotation by placing a colon after the constant or variable name, followed by a space, followed by the name of the type to use. - -在声明常量和变量时,你可以提供一个类型批注,来表明这个常量或变量可以储存的值的类型。类型批注的格式是在常量或变量名后加一个冒号,接着是一个空格,接着是要用的类型的名称。 +在声明常量和变量时,你可以提供一个类型批注,来表明这个常量或变量可以储存的值的类型。类型批注的格式是在常量或变量名后加一个冒号,接着是一个空格,接着是要使用的类型的名称。 -This example provides a type annotation for a variable called welcomeMessage, to indicate that the variable can store String values: - -下面是一个叫`welcomeMessage`的变量的类型批注的例子,来说明这个变量可以储存字符串类型的值: +下面是一个叫`welcomeMessage`的变量的类型批注的例子,来说明这个变量可以储存`String`(字符串)类型的值: ``` var welcomeMessage: String ``` -The colon in the declaration means “…of type…,” so the code above can be read as: - -这个表达式中冒号表示:“类型是”,所以这段代码的可以解读为: - -“Declare a variable called welcomeMessage that is of type String.” - -“声明一个叫welcomeMessage的变量,类型是字符串。” - -The phrase “of type String” means “can store any String value.” Think of it as meaning “the type of thing” (or “the kind of thing”) that can be stored. +这个声明中的冒号表示“类型是”,所以这段代码可以解读为: -“类型是字符串”表示“可以储存任意的字符串类型的值”。可以把它想作是它可以储存的“一个事物的类型”。 +“声明一个叫`welcomeMessage`的变量,类型是`String`(字符串)。” -The welcomeMessage variable can now be set to any string value without error: +“类型是`String`(字符串)”表示“可以储存任意的`String`(字符串)类型的值”。可以把它想作是它可以储存的“一个事物的类型”。 -变量`welcomeMessage`可以被赋值为任意字符串类型的值,而不会报错: +变量`welcomeMessage`可以被赋值为任意`String`(字符串)类型的值,而不会报错: - welcomeMessage = "Hello" - -> NOTE - -> It is rare that you need to write type annotations in practice. If you provide an initial value for a constant or variable at the point that it is defined, Swift can almost always infer the type to be used for that constant or variable, as described in Type Safety and Type Inference. In the welcomeMessage example above, no initial value is provided, and so the type of the welcomeMessage variable is specified with a type annotation rather than being inferred from an initial value. +``` +welcomeMessage = "Hello" +``` > 注意 -> 在实践中你需要写类型批注的很少见。如果你在定义一个常量或变量的时候给了它一个初始值,Swift几乎总是可以推断出这个常量或变量使用的类型,参见[类型安全和类型推断](link)。在上面这个welcomeMessage的例子里,没有提供初始值,所以welcomeMessage这个变量的类型是通过类型批注的形式来指定,而不是通过初始值推断而来。 +> 在实践中你很少需要写类型批注。如果你在定义一个常量或变量时给了它一个初始值,Swift几乎总是可以推断出这个常量或变量使用的类型,参见[类型安全和类型推断](link)。在上面这个welcomeMessage的例子里,没有提供初始值,所以`welcomeMessage`这个变量的类型通过类型批注的形式指定,而不是从初始值推断而来。 -# Naming Constants and Variables # 命名常量和变量 -You can use almost any character you like for constant and variable names, including Unicode characters: - 你可以使用几乎所有你喜欢的符号来命名常量和变量,包括unicode字符: ``` @@ -122,13 +79,9 @@ let 你好 = "你好世界" let 🐶🐮 = "dogcow" ``` -Constant and variable names cannot contain mathematical symbols, arrows, private-use (or invalid) Unicode code points, or line- and box-drawing characters. Nor can they begin with a number, although numbers may be included elsewhere within the name. - 常量和变量的命名不能包括数学运算符,箭头, 私有(或无效)的unicode码位, 或者线条(line-),以及制表符(box-drawing)字符。也不能以数字开头,尽管数字可以出现在变量名的其他位置。 -Once you’ve declared a constant or variable of a certain type, you can’t redeclare it again with the same name, or change it to store values of a different type. Nor can you change a constant into a variable or a variable into a constant. - -一旦你声明了常量或变量的特定类型,你不能用同样的名称重新声明,也不能改变它的储值类型,亦不能把常量改为变量或变量改为常量。 +一旦你声明了常量或变量为特定类型,你不能用同样的名称重新声明,不能改变它的储值类型,也不能把常量改为变量或变量改为常量。 > NOTE @@ -140,20 +93,29 @@ Once you’ve declared a constant or variable of a certain type, you can’t red You can change the value of an existing variable to another value of a compatible type. In this example, the value of friendlyWelcome is changed from "Hello!" to "Bonjour!": -你可以改变一个已经存在的变量的值,变成另一个适配类型的值。在下面的例子里,变量`friendlyWelcome`的值从"Hello!"变成了"Bonjour!": +你可以改变一个已经存在的变量的值,变成另一个适配类型的值将一个已经存在的变量的值改变成另一个适配类型的值。在下面的例子里,变量`friendlyWelcome`的值从`"Hello!"`变成了`"Bonjour!"`: - var friendlyWelcome = "Hello!" - friendlyWelcome = "Bonjour!" - // friendlyWelcome is now "Bonjour!" - // friendlyWelcome的值现在是"Bonjour!"了。 +``` +var friendlyWelcome = "Hello!" +friendlyWelcome = "Bonjour!" +// friendlyWelcome is now "Bonjour!" +``` + +``` +var friendlyWelcome = "Hello!" +friendlyWelcome = "Bonjour!" +// friendlyWelcome的值现在是"Bonjour!"了。 +``` Unlike a variable, the value of a constant cannot be changed once it is set. Attempting to do so is reported as an error when your code is compiled: 和变量不同,常量的值一旦设定就不能更改。尝试更改会导致代码编译时报错。 - let languageName = "Swift" - languageName = "Swift++" - // this is a compile-time error - languageName cannot be changed +``` +let languageName = "Swift" +languageName = "Swift++" +// this is a compile-time error - languageName cannot be changed +``` # Printing Constants and Variables # 输出常量和变量 @@ -165,6 +127,10 @@ You can print the current value of a constant or variable with the println funct ``` println(friendlyWelcome) // prints "Bonjour!" +``` + +``` +println(friendlyWelcome) // 输出 "Bonjour!" ``` @@ -174,7 +140,7 @@ println is a global function that prints a value, followed by a line break, to a The println function prints any String value you pass to it: -`printIn`函数会输出任何你赋值的字符串: +`printIn`函数会输出任何你赋值的字符串传递给它的字符串(`String`)值: ``` println("This is a string") @@ -183,15 +149,18 @@ println("This is a string") The println function can print more complex logging messages, in a similar manner to Cocoa’s NSLog function. These messages can include the current values of constants and variables. -`printIn`函数可以输出更复杂的记录信息,和Cocoa的NSlog函数类似。这些信息可以包含常量和变量的当前值。 +`printIn`函数可以输出更复杂的记录信息,和Cocoa的`NSlog`函数类似。这些信息可以包含常量和变量的当前值。 Swift uses string interpolation to include the name of a constant or variable as a placeholder in a longer string, and to prompt Swift to replace it with the current value of that constant or variable. Wrap the name in parentheses and escape it with a backslash before the opening parenthesis: -Swift使用字符串内插(string interpolation)的方式将常量或变量名以占位符的形式加入一个长的字符串中,并且提示Swift用常量或变量的当前值取代替它。书写格式是将名字包裹在括号中并在前面加上反斜扛来转义: +Swift使用字符串内插插值(string interpolation)的方式将常量或变量名以占位符的形式加入一个长的字符串中,并且提示Swift用常量或变量的当前值取代替它替换对应占位符。书写格式是将名字包裹在括号中并在前面加上反斜扛来转义: ``` println("The current value of friendlyWelcome is \(friendlyWelcome)") // prints "The current value of friendlyWelcome is Bonjour!" +``` +``` +println("The current value of friendlyWelcome is \(friendlyWelcome)") // 输出 "The current value of friendlyWelcome is Bonjour!" ``` @@ -208,109 +177,70 @@ println("The current value of friendlyWelcome is \(friendlyWelcome)") Use comments to include non-executable text in your code, as a note or reminder to yourself. Comments are ignored by the Swift compiler when your code is compiled. -将代码中不会执行的文本,笔记或者备忘,用注释来表达。注释在编译时会被忽略。 - -Comments in Swift are very similar to comments in C. Single-line comments begin with two forward-slashes (//): - -Swift中的注释和C中的注释十分相似。单行的注释以两个正斜杠 (//)开头: +将代码中不会执行的文本,笔记或者备忘用注释来表达。注释在代码编译时会被忽略。 - // this is a comment - // 这是一个注释 +Swift中的注释和C中的注释十分相似。单行的注释以两个正斜杠(```//```)开头: -You can also write multiline comments, which start with a forward-slash followed by an asterisk (/*) and end with an asterisk followed by a forward-slash (*/): - -你也可以写多行的注释,用一个正斜杠跟着一个星号开头 (/*) ,用一个星号跟着一个正斜杠结束(*/): +``` +// 这是一个注释 +``` - /* this is also a comment, - but written over multiple lines */ - /* 这还是一个注释, - 但是是多行的 */ +你也可以写多行的注释,用一个正斜杠跟着一个星号开头(`/*`),用一个星号跟着一个正斜杠结束(`*/`): -Unlike multiline comments in C, multiline comments in Swift can be nested inside other multiline comments. You write nested comments by starting a multiline comment block and then starting a second multiline comment within the first block. The second block is then closed, followed by the first block: +``` +/* 这还是一个注释, +但是是多行的 */ +``` 和C中的多行注释不同,Swift的多行注释可以嵌套在另一个多行注释内部。你可以这样写嵌套的注释:开始一个多行注释块,在第一块多行注释内部跟着开始第二个多行注释。第二个多行注释块结束,然后第一个多行注释块结束。 - /* this is the start of the first multiline comment - /* this is the second, nested multiline comment */ - this is the end of the first multiline comment */ - /* 这是第一个多行注释开始 - /* 这是第二个,嵌套的多行注释 */ - 这是第一个多行注释的结束 */ - -Nested multiline comments enable you to comment out large blocks of code quickly and easily, even if the code already contains multiline comments. +``` +/* 这是第一个多行注释开始 +/* 这是第二个,嵌套的多行注释 */ +这是第一个多行注释的结束 */ +``` -嵌套的多行注释让你可以简单快捷的注释一大段代码,即使这块代码之前已经有多行注释块。 +嵌套的多行注释让你可以简单快捷的注释一大段代码,即使这段代码之前已经有多行注释块。 -# Semicolons # 分号 -Unlike many other languages, Swift does not require you to write a semicolon (;) after each statement in your code, although you can do so if you wish. Semicolons are required, however, if you want to write multiple separate statements on a single line: - -和其他很多语言不同,Swift并不要求你在代码的每一个语句之后写一个分号(;),尽管如果你愿意你可以这么做。然而,如果你想在一行里写多个独立的语句,分号是必要的。 +和其他很多语言不同,Swift并不要求你在代码的每一个语句之后写一个分号(`;`),尽管如果你愿意你可以这么做。然而,如果你想在一行里写多个独立的语句,分号是必要的。 let cat = "🐱"; println(cat) // prints "🐱" -# Integers # 整数 -Integers are whole numbers with no fractional component, such as 42 and -23. Integers are either signed (positive, zero, or negative) or unsigned (positive or zero). +整数就是没有小数部分的完整数字,如`42`和`-23`。整数可以有符号(正数,0,或负数),也可以没有符号(正数或0)。 -整数就是没有小数部分的完整的数字,如42和-23.整数可以有符号(正数,0,或负数),也可以没有符号(正数或0)。 +Swift提供8,16,32和64位的带符号和不带符号的整数类型。这些整数遵从和C类似的命名约定,在这个约定中,8位的无符号整数的类型为`UInt8`,而32位的有符号整数的类型是`Int32`。和Swift的所有类型一样,这些整数的类型是首字母大写的。 -Swift provides signed and unsigned integers in 8, 16, 32, and 64 bit forms. These integers follow a naming convention similar to C, in that an 8-bit unsigned integer is of type UInt8, and a 32-bit signed integer is of type Int32. Like all types in Swift, these integer types have capitalized names. - -Swift提供8,16,32和64进制的带符号和不带符号的整数类型。这些整数遵从和C类似的命名约定,在这个约定中,8进制的无符号整数的类型为`UInt8`,而一个32进制的有符号整数的类型是`Int32`。和Swift的所有类型一样,这些整数的类型是首字母大写的。 - -# Integer Bounds -# 整数边界 - -You can access the minimum and maximum values of each integer type with its min and max properties: +## 整数边界 你可以通过整数类型的`max`和`min`属性来访问它的最大值和最小值: - let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8 - let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8 - let minValue = UInt8.min // 最小值是 0, 类型是 UInt8 - let maxValue = UInt8.max // 最大值是 255, 类型是 UInt8 - -The values of these properties are of the appropriate-sized number type (such as UInt8 in the example above) and can therefore be used in expressions alongside other values of the same type. +``` +let minValue = UInt8.min // 最小值是 0, 类型是 UInt8 +let maxValue = UInt8.max // 最大值是 255, 类型是 UInt8 +``` 这些属性值是相应数字类型的合适范围(比如上面例子里的`UInt8`),因此它们可以在其他拥有相同类型值的表达式中沿用。 -# Int -# 整数 - -In most cases, you don’t need to pick a specific size of integer to use in your code. Swift provides an additional integer type, Int, which has the same size as the current platform’s native word size: - -在大多数情况下,你不需要在代码中指定整数的范围。Swift提供了一个专门的整数类型,`Int`,它和当前平台的原生长度范围相同。 - -On a 32-bit platform, Int is the same size as Int32. +## 整数 -在32位的平台上,`Int`和`Int32`范围相同。 +在大多数情况下,你不需要在代码中指定整数的范围。Swift提供了一个专门的整数类型`Int`,它和当前平台的原生长度范围相同。 -On a 64-bit platform, Int is the same size as Int64. +* 在32位的平台上,`Int`和`Int32`范围相同。 +* 在64位的平台上,`Int`和`Int64`范围相同。 -在64位的平台上,`Int`和`Int64`范围相同。 +如果你不需要处理特定的整数范围,请在代码中始终使用`Int`类型。这有助于代码的一致性和可复用性。即使在32位的平台上,`Int`类型可以储存从`-2,147,483,648`到`2,147,483,647`的整数,大多数情况下这足够用了。 -Unless you need to work with a specific size of integer, always use Int for integer values in your code. This aids code consistency and interoperability. Even on 32-bit platforms, Int can store any value between -2,147,483,648 and 2,147,483,647, and is large enough for many integer ranges. +## 无符号整数 -如果你不需要处理特定的整数范围,请在代码中的整数值使用`Int`类型。这有助于代码的一致性和可复用性。即使在32位的平台上,`Int`类型可以储存从-2,147,483,648到2,147,483,647的整数,大多数情况下这足够用了。 +Swift也提供了无符号整数类型,`UInt`,它和当前平台的原生长度范围相同。 -# UInt -# 无符号整数 - -Swift also provides an unsigned integer type, UInt, which has the same size as the current platform’s native word size: - -Swift也提供了无符号整数类型,`UInt`,它和当前平台的原生长度范围相同。 - -On a 32-bit platform, UInt is the same size as UInt32. - -在32位的平台上,`UInt`和`UInt32`范围相同。 - -On a 64-bit platform, UInt is the same size as UInt64. - -在64位的平台上,`UInt`和`UInt64`范围相同。 +* 在32位的平台上,`UInt`和`UInt32`范围相同。 +* 在64位的平台上,`UInt`和`UInt64`范围相同。 > NOTE @@ -318,26 +248,19 @@ On a 64-bit platform, UInt is the same size as UInt64. > 注意 -> 只在你需要特别指定无符号整数与当前平台原生长度范围相同时才使用`UInt`,否则,推荐使用`Int`,即使是你知道不会存储负值的时候。使用一致的`Int`整数类型有助于代码的服用,避免了不同数字类型之间的转换,并且匹配整数的类型推断,详见[类型安全和类型推断](link)。 +> 只在你需要特别指定无符号整数与当前平台原生长度范围相同时才使用`UInt`,否则,推荐使用`Int`,即使是你知道不会存储负值的时候。使用一致的`Int`整数类型有助于代码的复用,避免了不同数字类型之间的转换,并且和整数的类型推断结果一致,详见[类型安全和类型推断](link)。 -# Floating-Point Numbers # 浮点型数字 -Floating-point numbers are numbers with a fractional component, such as 3.14159, 0.1, and -273.15. - -浮点型数字是指有小数部分的数字,比如3.14159, 0.1 和 -273.15。 - -Floating-point types can represent a much wider range of values than integer types, and can store numbers that are much larger or smaller than can be stored in an Int. Swift provides two signed floating-point number types: +浮点型数字是指有小数部分的数字,比如`3.14159`,`0.1`和`-273.15`。 浮点类型比整数类型范围大很多,它可以储存比整数更大或者更小的数。Swift提供了两种有符号的浮点数类型: -Double represents a 64-bit floating-point number. Use it when floating-point values must be very large or particularly precise. - -`Double`代表64位浮点数。当你需要特别大和特别精确的值的时候使用`Double`类型。 +* Double represents a 64-bit floating-point number. Use it when floating-point values must be very large or particularly precise. +* Float represents a 32-bit floating-point number. Use it when floating-point values do not require 64-bit precision. -Float represents a 32-bit floating-point number. Use it when floating-point values do not require 64-bit precision. - -`Float`代表32位浮点数。当不需要像64位那么精确的时候使用`Float`就够了。 +* `Double`代表64位浮点数。当你需要特别大和特别精确的值的时候使用`Double`类型。 +* `Float`代表32位浮点数。当不需要像64位那么精确的时候使用`Float`就够了。 > NOTE @@ -345,117 +268,76 @@ Float represents a 32-bit floating-point number. Use it when floating-point valu > 注意 -> `Double`有至少15位数字的精确度,而`Float`的精确度最少只有6位数字。根据业务需要的值的范围去选择合适的浮点类型。 +> `Double`有至少15位数字的精确度,而`Float`的精确度只有至少6位数字。根据业务需要的值的范围去选择合适的浮点类型。 -# Type Safety and Type Inference # 类型安全和类型推断 -Swift is a type safe language. A type safe language encourages you to be clear about the types of values your code can work with. If part of your code expects a String, you can’t pass it an Int by mistake. - -Swift是一个类型安全的语言。一个类型安全的语言鼓励你声明代码中使用的值的类型。如果你期望这部分代码是字符串(String),你就不能错误的给它赋一个整型(Int)的值。 - -Because Swift is type safe, it performs type checks when compiling your code and flags any mismatched types as errors. This enables you to catch and fix errors as early as possible in the development process. +Swift是一个类型安全的语言。一个类型安全的语言鼓励你声明代码中使用的值的类型。如果你期望这部分代码是`String`(字符串),你就不能错误的给它赋一个`Int`(整型)的值。 -因为Swift是类型安全的,它会在编译时运行类型检查,并且将所有不匹配的类型标记为错误。这让你可以在开发过程中今早的发现和修复问题。 - -Type-checking helps you avoid errors when you’re working with different types of values. However, this doesn’t mean that you have to specify the type of every constant and variable that you declare. If you don’t specify the type of value you need, Swift uses type inference to work out the appropriate type. Type inference enables a compiler to deduce the type of a particular expression automatically when it compiles your code, simply by examining the values you provide. +因为Swift是类型安全的,它会在代码编译时运行类型检查,并且将所有不匹配的类型标记为错误。这让你可以在开发过程中今早的发现和修复问题。 当你处理不同类型的值的时候,类型检查帮助你避免错误。然而,这并不意味着你需要给每一个声明的常量和变量指定特定的类型。如果你没有指定特定的类型,Swift会使用类型推断来推断出合适的类型。当编译代码时,类型推断特性使得编译器可以简单的通过检查你提供的值来自动推断出特定表达式的类型。 -Because of type inference, Swift requires far fewer type declarations than languages such as C or Objective-C. Constants and variables are still explicitly typed, but much of the work of specifying their type is done for you. - 因为有了类型推断,Swift与类似C和Objective-C的语言相比需要更少的类型声明。常量和变量同样会有准确的类型,但是大部分关于指定类型的工作Swift已经帮你做好了。 -Type inference is particularly useful when you declare a constant or variable with an initial value. This is often done by assigning a literal value (or literal) to the constant or variable at the point that you declare it. (A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below.) - -当你声明一个有初始值的常量或变量的时候类型推断特别实用。通常是当你声明一个常量和变量的时候你就给它赋一个字面量(literal value)。(字面量是会直接出现在源码里的值,比如下面例子里的42和3.14159。) - -For example, if you assign a literal value of 42 to a new constant without saying what type it is, Swift infers that you want the constant to be an Int, because you have initialized it with a number that looks like an integer: - -举个例子,如果你给一个新的常量赋了一个字面量42,但没有说它的类型,Swift会推断你希望这个常量是一个整数类型(Int),因为你用了一个像是整数的数字来初始化: - - let meaningOfLife = 42 - // meaningOfLife is inferred to be of type Int - // meaningOfLife被推断为整数类型(Int) - -Likewise, if you don’t specify a type for a floating-point literal, Swift infers that you want to create a Double: +当你声明一个有初始值的常量或变量时类型推断特别实用。通常是当你声明一个常量和变量的时候你就给它赋一个字面量(literal value)。(字面量是会直接出现在源码里的值,比如下面例子里的`42`和`3.14159`。) -类似的,如果你没有特别指定一个浮点型的字面量,Swift会推断你需要一个Double类型的浮点数: +举个例子,如果你给一个新的常量赋了一个字面量`42`,但没有指定它的类型,Swift会推断你希望这个常量是一个`Int`(整数)类型,因为你用了一个像是整数的数字来初始化变量: - let pi = 3.14159 - // pi is inferred to be of type Double - // pi被推断为Double类型 - -Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers. +``` +let meaningOfLife = 42 +// meaningOfLife被推断为Int(整数)类型 +``` -在推断浮点型的数字时,Swift总是会选择Double型而不是Float。 +类似的,如果你没有特别指定一个浮点型的字面量,Swift会推断你需要一个`Double`类型的浮点数: -If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context: +``` +let pi = 3.14159 +// pi被推断为Double类型 +``` -如果你将整数型和浮点型的字面量相加,这种情况下会推断为Double类型: +在推断浮点型的数字时,Swift总是会选择`Double`类型而不是`Float`类型。 - let anotherPi = 3 + 0.14159 - // anotherPi is also inferred to be of type Double - // anotherPi也被推断为Double类型 +如果你将整数型和浮点型的字面量相加,这种情况下会推断为`Double`类型: -The literal value of 3 has no explicit type in and of itself, and so an appropriate output type of Double is inferred from the presence of a floating-point literal as part of the addition. +``` +let anotherPi = 3 + 0.14159 +// anotherPi也被推断为Double类型 +``` -字面量3本身并没有准确的类型,因此是通过相加的元素中有一个浮点型的字面量推断出合适的输出类型为Double. +字面量`3`本身并没有准确的类型,因此是通过相加的元素中有一个浮点型的字面量推断出合适的输出类型为`Double`。 -# Numeric Literals # 数字字面量 -Integer literals can be written as: - 整数字面量可以写成: -A decimal number, with no prefix -A binary number, with a 0b prefix -An octal number, with a 0o prefix -A hexadecimal number, with a 0x prefix -All of these integer literals have a decimal value of 17: - -十进制的数字,不需要任何前缀 -二进制的数字,前缀是0b -八进制的数字,前缀是0o -十六进制的数字,前缀是0x -下面所有的整数字面量在十进制下的值都是17: +* 十进制的数字,不需要任何前缀 +* 二进制的数字,前缀是`0b` +* 八进制的数字,前缀是`0o` +* 十六进制的数字,前缀是`0x` - let decimalInteger = 17 - let binaryInteger = 0b10001 // 17 in binary notation - let octalInteger = 0o21 // 17 in octal notation - let hexadecimalInteger = 0x11 // 17 in hexadecimal notation - - let decimalInteger = 17 - let binaryInteger = 0b10001 // 二进制声明中的17 - let octalInteger = 0o21 // 八进制声明中的17 - let hexadecimalInteger = 0x11 // 十六进制声明中的17 - - -Floating-point literals can be decimal (with no prefix), or hexadecimal (with a 0x prefix). They must always have a number (or hexadecimal number) on both sides of the decimal point. They can also have an optional exponent, indicated by an uppercase or lowercase e for decimal floats, or an uppercase or lowercase p for hexadecimal floats. - -浮点型的字面量可以是十进制的(没有前缀),或者十六进制(前缀是0x)。在小数点两边都必须有数字(或十六进制数字符号)。它们也可以有一个可选的指数,在十进制中用大写或小写的e来表示,或者在十六进制中用大写或小写的p来表示。 - -For decimal numbers with an exponent of exp, the base number is multiplied by 10exp: - -在十进制数字中有一个指数`exp`,表示基数乘以`10^exp`: +下面所有的整数字面量在十进制下的值都是`17`: ``` -1.25e2 means 1.25 × 102, or 125.0. -1.25e-2 means 1.25 × 10-2, or 0.0125. +let decimalInteger = 17 +let binaryInteger = 0b10001 // 二进制声明中的17 +let octalInteger = 0o21 // 八进制声明中的17 +let hexadecimalInteger = 0x11 // 十六进制声明中的17 ``` -For hexadecimal numbers with an exponent of exp, the base number is multiplied by 2exp: +浮点型的字面量可以是十进制的(没有前缀),或者十六进制(前缀是`0x`)。在小数点两边都必须有数字(或十六进制数字符号)。它们也可以有一个可选的指数,在十进制中用大写或小写的`e`来表示,在十六进制中用大写或小写的`p`来表示。 -在十六进制的数字中有一个指数`exp`,表示基数乘以`2^exp` +在十进制数字中的指数`exp`表示基数乘以10exp: -``` -0xFp2 means 15 × 22, or 60.0. -0xFp-2 means 15 × 2-2, or 3.75. -``` +* ```1.25e2``` 表示 1.25 × 102,或者`125.0`. +* ```1.25e-2``` 表示 1.25 × 10-2,或者`0.0125` + +在十六进制的数字中的指数`exp`表示基数乘以2exp + +* 0xFp2 表示 15 × 22,或者 60.0. +* 0xFp-2 表示 15 × 2-2,或者 3.75. -All of these floating-point literals have a decimal value of 12.1875: -以下这些浮点字面量在十进制下的值都是12.1875: +以下这些浮点字面量在十进制下的值都是`12.1875`: ``` let decimalDouble = 12.1875 @@ -463,9 +345,7 @@ let exponentDouble = 1.21875e1 let hexadecimalDouble = 0xC.3p0 ``` -Numeric literals can contain extra formatting to make them easier to read. Both integers and floats can be padded with extra zeroes and can contain underscores to help with readability. Neither type of formatting affects the underlying value of the literal: - -数字字面量可以使用额外的格式让它们更易读。不论整数还是浮点数都可以添加额外的0,也可以增加下划线来增加可读性。这些格式都不会影响到这些字面量原本的值: +数字字面量可以使用额外的格式让它们更易读。不论整数还是浮点数都可以添加额外的0,和下划线来增加可读性。这些格式都不会影响到这些字面量原本的值: ``` let paddedDouble = 000123.456 @@ -473,42 +353,27 @@ let oneMillion = 1_000_000 let justOverOneMillion = 1_000_000.000_000_1 ``` -# Numeric Type Conversion # 数字类型转换 -Use the Int type for all general-purpose integer constants and variables in your code, even if they are known to be non-negative. Using the default integer type in everyday situations means that integer constants and variables are immediately interoperable in your code and will match the inferred type for integer literal values. - -在一般情况下对整数的常量或变量使用`Int`类型,即使是你知道不会存储负值的时候。总是使用默认的整数类型意味着你的代码中整数的常量和变量是可以很好的协作的,并且可以和整数字面量推断出的类型一致。 - -Use other integer types only when they are are specifically needed for the task at hand, because of explicitly-sized data from an external source, or for performance, memory usage, or other necessary optimization. Using explicitly-sized types in these situations helps to catch any accidental value overflows and implicitly documents the nature of the data being used. +在一般情况下对整数的常量或变量使用`Int`类型,即使是你知道不会存储负值的时候。总是使用默认的`Int`(整数)类型意味着你的代码中整数的常量和变量可以很好的协作,并且和整数字面量推断出的类型一致。 -只在当前工作中有特殊的需要的时候,才使用其他的整数类型,比如是从外部来源的需要指定精确度的数据,或者为了性能,内存使用量,或者其他必要的优化。在这些情况下使用指定精确度的数字类型可以帮助我们发现溢出值和暗示这个数据的特性。 +只在当前工作中有特殊需要的时候,才使用其他的整数类型,比如是从外部来源的需要指定精确度的数据,或者为了性能,内存使用量,或者其他必要的优化。在这些情况下使用指定精确度的数字类型可以帮助我们发现溢出值和暗示这个数据的特性。 -## Integer Conversion ## 整数类型转换 -The range of numbers that can be stored in an integer constant or variable is different for each numeric type. An Int8 constant or variable can store numbers between -128 and 127, whereas a UInt8 constant or variable can store numbers between 0 and 255. A number that will not fit into a constant or variable of a sized integer type is reported as an error when your code is compiled: - -不同整数类型的常量或变量可以储存不同范围的数字。一个`Int8`的常量或变量可以储存-128到127之间的数字,然而一个`UInt8`型的常量或变量可以储存从0到255之间的数字。如果一个数字不符合常量或变量的储值范围,编译的时候会报错: +不同整数类型的常量或变量可以储存不同范围的数字。一个`Int8`的常量或变量可以储存`-128`到`127`之间的数字,然而一个`UInt8`型的常量或变量可以储存从`0`到`255`之间的数字。如果一个数字不符合常量或变量的储值范围,编译的时候会报错: ``` let cannotBeNegative: UInt8 = -1 -// UInt8 cannot store negative numbers, and so this will report an error // UInt8不能储存负数,所以这里会报错 let tooBig: Int8 = Int8.max + 1 -// Int8 cannot store a number larger than its maximum value, -// and so this will also report an error // Int8不能储存一个大于其最大值的数字 // 所以这里同样会报错 ``` -Because each numeric type can store a different range of values, you must opt in to numeric type conversion on a case-by-case basis. This opt-in approach prevents hidden conversion errors and helps make type conversion intentions explicit in your code. - -因为每一种数字类型可以储存不同范围的值,你必须根据具体的案例选择合适的数字类型转换。这种选择方式组织了隐式的转换报错,并且让你的代码中的类型转换意图更明确。 +因为每一种数字类型可以储存不同范围的值,你必须根据具体的案例选择合适的数字类型转换。这种方式阻止了隐式的转换报错,并且让代码中的类型转换意图更明确。 -To convert one specific number type to another, you initialize a new number of the desired type with the existing value. In the example below, the constant twoThousand is of type UInt16, whereas the constant one is of type UInt8. They cannot be added together directly, because they are not of the same type. Instead, this example calls UInt16(one) to create a new UInt16 initialized with the value of one, and uses this value in place of the original: - -要将一种特定类型转换成另一种,你需要用一个你想要的类型的新的数字来重新初始化。在下面的例子里,常量twoThousand是UInt16类型的,然而常量one是UInt8类型的。它们不能直接相加,因为i它们类型不同。因此,这个例子调用了UInt16(one)来对常量one创建一个新的UInt16初始值,然后用这个值来代替原来的值: +要将一种特定类型转换成另一种,你需要用一个你想要的类型的新数字值来重新初始化。在下面的例子里,常量`twoThousand`是`UInt16`类型的,然而常量`one`是`UInt8`类型的。它们不能直接相加,因为它们类型不同。因此,这个例子调用了`UInt16(one)`来对常量`one`创建一个新的`UInt16`类型的初始值,然后用这个值来代替原来的值: ``` let twoThousand: UInt16 = 2_000 @@ -516,99 +381,68 @@ let one: UInt8 = 1 let twoThousandAndOne = twoThousand + UInt16(one) ``` -Because both sides of the addition are now of type UInt16, the addition is allowed. The output constant (twoThousandAndOne) is inferred to be of type UInt16, because it is the sum of two UInt16 values. - -因为相加的两个数现在都是UInt16类型了,这样相加是允许的。输出结果的常量(twoThousandAndOne)被推断为UInt16类型,因为它是两个UInt16的类型的值的和。 +因为相加的两个数现在都是`UInt16`类型了,这样相加是允许的。输出结果的常量`twoThousandAndOne`被推断为`UInt16`类型,因为它是两个`UInt16`类型的值的和。 -SomeType(ofInitialValue) is the default way to call the initializer of a Swift type and pass in an initial value. Behind the scenes, UInt16 has an initializer that accepts a UInt8 value, and so this initializer is used to make a new UInt16 from an existing UInt8. You can’t pass in any type here, however—it has to be a type for which UInt16 provides an initializer. Extending existing types to provide initializers that accept new types (including your own type definitions) is covered in Extensions. +`SomeType(ofInitialValue)`是Swift初始化并赋予一个初值的默认方法。在语言内部,`UInt16`类型有一个初始值设定项会接受一个`UInt8`的值,然后这个初始值设定项是用来从已知的`UInt8`中创建一个新的`UInt16`的值。你不能传递任意类型,只能传入`UInt16`提供初始化的类型。扩展已有的类型来提供更多的初始化选项,来接受新的类型(包括自定义类型),见[扩展](link)。 -SomeType(ofInitialValue)是Swift初始化并赋予一个初值的默认方法。在语言内部,UInt16类型有一个初始值设定项会接受一个UInt8的值,然后这个初始值设定项是用来从已知的UInt8中创建一个新的UInt16的值。你不能传递任意类型,只能传入UInt16提供初始化的类型。扩展已有的类型来提供更多的初始化选项,来接受新的类型(包括自定义类型),见[扩展](link)。 - -## Integer and Floating-Point Conversion ## 整数和浮点数转换 -Conversions between integer and floating-point numeric types must be made explicit: 整数和浮点数之间的类型转换必须是显性的: ``` let three = 3 let pointOneFourOneFiveNine = 0.14159 let pi = Double(three) + pointOneFourOneFiveNine -// pi equals 3.14159, and is inferred to be of type Double // pi等于3.14159,它被推断为Double类型 ``` -Here, the value of the constant three is used to create a new value of type Double, so that both sides of the addition are of the same type. Without this conversion in place, the addition would not be allowed. - -在这里,常量three的值被用来创建一个新的Double型的值,所以相加的两个数都是同样的类型了,无须转换,这个加法是允许的。 +在这里,常量`three`的值被用来创建一个新的`Double`型的值,所以相加的两个数都是同样的类型了,无须转换,这个加法是允许的。 -The reverse is also true for floating-point to integer conversion, in that an integer type can be initialized with a Double or Float value: - -相对的,由浮点数到证书的转换也是可行的,也就是说一个整数类型可以被初始化为一个Double或者Float型的值: +相对的,由浮点数到整数的转换也是可行的,也就是说一个整数类型可以被初始化为一个`Double`或者`Float`型的值: ``` let integerPi = Int(pi) -// integerPi equals 3, and is inferred to be of type Int -// integerPi等于3,它被推断为整数(Int)类型 +// integerPi等于3,它被推断为整数(Int)类型 ``` -Floating-point values are always truncated when used to initialize a new integer value in this way. This means that 4.75 becomes 4, and -3.9 becomes -3. - -当浮点型的值初始化为一个新的整数型的值时,它的数值总是被截断的。这意味着4.75会成为4,而-3.9会成为-3。 - -> NOTE - -> The rules for combining numeric constants and variables are different from the rules for numeric literals. The literal value 3 can be added directly to the literal value 0.14159, because number literals do not have an explicit type in and of themselves. Their type is inferred only at the point that they are evaluated by the compiler. +当浮点型的值初始化为一个新的整数型的值时,它的数值总是被截断的。这意味着`4.75`会成为`4`,而`-3.9`会成为`-3`。 > 注意 -> 数字的常量和变量相加的规则和数字字面量的规则是不一样的。字面量3可以和字面量0.14159直接相加,因为数字字面量本身并没有一个显式的类型声明。他们的类型是在编译器运行时被推断的。 +> 数字的常量和变量相加的规则和数字字面量的规则是不一样的。字面量`3`可以和字面量`0.14159`直接相加,因为数字字面量本身并没有一个显式的类型声明。他们的类型是在编译器运行时被推断的。 -# Type Aliases # 类型别名 -Type aliases define an alternative name for an existing type. You define type aliases with the typealias keyword. - 类型别名给已经存在的类型定义另一个名字。你用关键字`typealias`来定义类型别名。 -Type aliases are useful when you want to refer to an existing type by a name that is contextually more appropriate, such as when working with data of a specific size from an external source: - -当你想用一个更合适的名字来命名一个已有的类型的时候,类型别名是很有用的,比如当你处理一个外部来源的需要指定精确度的数据时: +当你想用一个更合适的名字来命名一个已有类型的时候,类型别名是很有用的。比如当你处理需要指定精确度的外部来源数据时: ``` typealias AudioSample = UInt16 ``` -Once you define a type alias, you can use the alias anywhere you might use the original name: -一旦你定义了类型别名,你就可以在任何你可以使用原始名字的地方使用这个别名 +一旦你定义了类型别名,你就可以在任何你可以使用原始名字的地方使用这个别名: ``` var maxAmplitudeFound = AudioSample.min -// maxAmplitudeFound is now 0 +// maxAmplitudeFound的值是0 ``` Here, AudioSample is defined as an alias for UInt16. Because it is an alias, the call to AudioSample.min actually calls UInt16.min, which provides an initial value of 0 for the maxAmplitudeFound variable. -在这里,`AudioSample`定义为`UInt16`的一个别名。因为这是一个别名,调用`AudioSample.min`实际上是调用`UInt16.min`给变量maxAmplitudeFound赋了一个0的初始值。 +在这个例子中,`AudioSample`被定义为`UInt16`的一个别名。因为这是一个别名,调用`AudioSample.min`实际上是调用`UInt16.min`给变量`maxAmplitudeFound`赋了初始值`0`。 -# Booleans # 布尔值 -Swift has a basic Boolean type, called Bool. Boolean values are referred to as logical, because they can only ever be true or false. Swift provides two Boolean constant values, true and false: - -Swift有一个基本的布尔值类型,叫做Bool。布尔值可以当作逻辑判断,因为它们只有true或false两个值。Swift提供两种布尔值常量,true和false。 +Swift有一个基本的布尔值类型,叫做`Bool`。布尔值可以用作逻辑判断,因为它们只有“真”和“假”两个值。Swift提供两种布尔值常量,`true`和`false`: ``` let orangesAreOrange = true let turnipsAreDelicious = false ``` -The types of orangesAreOrange and turnipsAreDelicious have been inferred as Bool from the fact that they were initialized with Boolean literal values. As with Int and Double above, you don’t need to declare constants or variables as Bool if you set them to true or false as soon as you create them. Type inference helps make Swift code more concise and readable when it initializes constants or variables with other values whose type is already known. - -因为orangesAreOrange和turnipsAreDelicious有一个布尔的字面量作为初值,它们的类型被推断为Bool。如果你在创建常量或变量的时候就把它们的值设为true或者false,你不需要声明它们的类型是Bool。当你赋予常量或变量一个类型已知的初值时,类型推断让Swift的代码更加准确和可读。 - -Boolean values are particularly useful when you work with conditional statements such as the if statement: +因为`orangesAreOrange`和`turnipsAreDelicious`有一个布尔的字面量作为初始值,它们的类型被推断为`Bool`。如果你在创建常量或变量的时候就把它们的值设为`true`或者`false`,你不需要声明它们的类型是`Bool`。当你赋予常量或变量一个类型已知的初值时,类型推断让Swift的代码更加准确和可读。 -在条件声明比如if语句中,布尔值特别有用: +布尔值在条件声明(比如:`if`语句)中特别有用: ``` if turnipsAreDelicious { @@ -616,81 +450,53 @@ if turnipsAreDelicious { } else { println("Eww, turnips are horrible.") } -// prints "Eww, turnips are horrible." +// 输出 "Eww, turnips are horrible." ``` -Conditional statements such as the if statement are covered in more detail in Control Flow. +关于条件声明(比如`if`语句)的更多细节会在[Control Flow](link)这一章节中详细讲解。 -关于条件声明比如if语句的更多细节会在Control Flow这一章节中详细讲解。 - -Swift’s type safety prevents non-Boolean values from being be substituted for Bool. The following example reports a compile-time error: -Swift的类型安全会阻止一个非布尔值替换了Bool值。下面的例子会在编译时报错: +Swift的类型安全会阻止一个非布尔值替换`Bool`值。下面的例子会在编译时报错: ``` let i = 1 if i { - // this example will not compile, and will report an error // 这个例子不会顺利编译,会报错 } ``` -However, the alternative example below is valid: 然而,下面这个例子是有效的: ``` let i = 1 if i == 1 { - // this example will compile successfully // 这个例子会成功编译 } ``` The result of the i == 1 comparison is of type Bool, and so this second example passes the type-check. Comparisons like i == 1 are discussed in Basic Operators. -`i == 1`比较的结果是一个Bool类型的值,因此第二个例子通过了类型检查。类似`i == 1`的比较我们会在[Basic Operators](link)更深入讨论。 - -As with other examples of type safety in Swift, this approach avoids accidental errors and ensures that the intention of a particular section of code is always clear. +`i == 1`的比较结果是一个`Bool`类型的值,因此第二个例子通过了类型检查。类似`i == 1`的比较我们会在[Basic Operators](link)进行深入讨论。 -和其他Swift的类型安全的例子一样,这个例子避免了意外的错误并且保证了特定的某块代码的意图始终是明确的。 +和其他Swift的类型安全的例子一样,这种检查避免了意外的错误并且保证了特定的某块代码的意图始终是明确的。 -# Tuples # 元组 -Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other. - 元组将多个数值组合成一个单独的复合值。一个元组中的值可以是任何类型,不必是同一种类型。 In this example, (404, "Not Found") is a tuple that describes an HTTP status code. An HTTP status code is a special value returned by a web server whenever you request a web page. A status code of 404 Not Found is returned if you request a webpage that doesn’t exist. -在这个例子里, (404, "Not Found") 是一个用来形容Http状态码的元组。一个Http状态码是当你请求一个网页的时候网页服务器的返回值。当你请求的网页不存在的时候会返回`404找不到网页`的状态码。 +在这个例子里, `(404, "Not Found")` 是一个用来形容HTTP状态码的元组。HTTP状态码是当你请求一个网页的时候网页服务器的返回值。当你请求的网页不存在的时候会返回`404 Not Found`的状态码。 ``` let http404Error = (404, "Not Found") -// http404Error is of type (Int, String), and equals (404, "Not Found") // http404Error的类型是(Int, String),值等于(404, "Not Found") ``` -The (404, "Not Found") tuple groups together an Int and a String to give the HTTP status code two separate values: a number and a human-readable description. It can be described as “a tuple of type (Int, String)”. - -元组`(404, "Not Found")`将一个整数值Int和一个字符串组合起来,给http状态码赋予两个独立的值:一个机器语言的数字和一句人类语言的描述。它可以描述为”一个类型为 (Int, String)的元组“。 - -You can create tuples from any permutation of types, and they can contain as many different types as you like. There’s nothing stopping you from having a tuple of type (Int, Int, Int), or (String, Bool), or indeed any other permutation you require. +元组`(404, "Not Found")`将一个整数值`Int`和一个字符串`String`组合起来,给HTTP状态码赋予两个独立的值:一个机器语言的数字和一句人类语言的描述。它可以描述为”一个类型为 `(Int, String)`的元组“。 -你可以创建一个含任意类型组合的元组,它们可以包含任意多的类型。谁也不能阻止你创建一个(Int, Int, Int)类型或者(String, Bool)类型,又或者任意你想要的类型组合的元组。 +你可以创建一个含任意类型组合的元组,它们可以包含任意多的类型。谁也不能阻止你创建一个`(Int, Int, Int)`类型或者`(String, Bool)`类型,又或者任意你想要的类型组合的元组。 -You can decompose a tuple’s contents into separate constants or variables, which you then access as usual: - -你可以把一个元组的内容分解成独立的常量或变量,然后你就可以像平常一样调用它们: - -``` -let (statusCode, statusMessage) = http404Error -println("The status code is \(statusCode)") -// prints "The status code is 404" -println("状态码是 \(statusCode)") -// 输出”状态码是404“ -println("The status message is \(statusMessage)") -// prints "The status message is Not Found" -``` +你可以把一个元组的内容分解成独立的常量或变量,然后你就可以像平常一样引用它们: ``` let (statusCode, statusMessage) = http404Error @@ -699,10 +505,7 @@ println("状态码是 \(statusCode)") println("状态信息是 \(statusMessage)") // prints "状态信息是 Not Found" ``` - -If you only need some of the tuple’s values, ignore parts of the tuple with an underscore (_) when you decompose the tuple: - -如果你只需要元组的一部分值,当你分解元组的时候使用下划线(_)来忽略元组的一部分值: +当你在分解元组时,如果只需要元祖的一部分值,可以使用下划线(`_`)来忽略元组的一部分值: ``` let (justTheStatusCode, _) = http404Error @@ -710,15 +513,7 @@ println("The status code is \(justTheStatusCode)") // prints "The status code is 404" ``` -``` -let (justTheStatusCode, _) = http404Error -println("状态码是 \(justTheStatusCode)") -// prints "状态码是 404" -``` - -Alternatively, access the individual element values in a tuple using index numbers starting at zero: - -同样的,使用从0开始的序列可以调用元组中的一个单独元素的值。 +同样的,使用从`0`开始的序列可以引用元组中的一个单独元素的值。 ``` println("The status code is \(http404Error.0)") @@ -727,17 +522,13 @@ println("The status message is \(http404Error.1)") // prints "The status message is Not Found" ``` -You can name the individual elements in a tuple when the tuple is defined: - 定义元组的时候,你可以给元素单独命名: ``` let http200Status = (statusCode: 200, description: "OK") ``` -If you name the elements in a tuple, you can use the element names to access the values of those elements: - -如果你给元组中的元素命名了,你可以用这个名字来调用它们的值: +如果你给元组中的元素命名了,你可以用这个名字来引用它们的值: ``` println("The status code is \(http200Status.statusCode)") @@ -748,15 +539,11 @@ println("The status message is \(http200Status.description)") Tuples are particularly useful as the return values of functions. A function that tries to retrieve a web page might return the (Int, String) tuple type to describe the success or failure of the page retrieval. By returning a tuple with two distinct values, each of a different type, the function provides more useful information about its outcome than if it could only return a single value of a single type. For more information, see Functions with Multiple Return Values. -作为函数的返回值元组是很有用的。 - -> NOTE - -> Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple. For more information, see Classes and Structures. +作为函数的返回值元组是很有用的。一个试图获取网页的函数可能返回一个(Int, String)类型的元组来描述这个页面获取成功或失败的状态。通过返回一个含有两个不同类型值的元组,这个函数的结果相比只能返回一个单独类型值的函数提供了更多有用的信息。详见[Functions with Multiple Return Values]()。 > 注意 -> 当你处理一些相关数据的临时组合,元组是很有用的。如果你的数据结构超过了一个临时的范畴,用class或者structrue会比用元组tuple更合适。更多信息,参见[Classes and Structures](link)。 +> 当你处理一些相关数据的临时组合,元组是很有用的。它们不适合用于一些复杂的数据类型的创建。如果你的数据结构超过了一个临时的范畴,用class或者structrue会比用元组tuple更合适。更多信息,参见[Classes and Structures](link)。 # Optionals # 可选类型 @@ -771,7 +558,7 @@ or - There isn’t a value at all - + - 那里有一个值,它等于x 或者 @@ -784,11 +571,11 @@ or > 注意 -> 可选类型在C或者Objective-C中都不存在。在Objective-C中最接近的是一个返回一个对象的方法也可以返回一个nil值的能力,nil的意思是“有效对象的缺失”。然而,它只对对象有效,对structs, basic C types, or enumeration values都是无效的。对这些类型,Objective-C通常会返回一个特殊值(比如NSNotFound)来表示值缺失。这样的方式假定我们调用方法时它必须知道有一个特殊值,并且要记得去检查它。Siwft的可选类型让你可以给任意类型的值声明这个值缺失,不需要任何其它的特殊常量。 +> 可选类型在C或者Objective-C中都不存在。在Objective-C中最接近的是一个返回一个对象的方法也可以返回一个`nil`值的能力,`nil`的意思是“有效对象的缺失”。然而,它只对对象有效,对`structs`,basic C types, or enumeration values*基本的C类型、或者枚举类型*都是无效的。对这些类型,Objective-C通常会返回一个特殊值(比如`NSNotFound`)来表示值缺失。这样的方式假定我们调用方法时它必须知道有一个特殊值,并且要记得去检查它。Siwft的可选类型让你可以给任意类型的值声明这个值缺失,不需要任何其它的特殊常量。 Here’s an example. Swift’s String type has a method called toInt, which tries to convert a String value into an Int value. However, not every string can be converted into an integer. The string "123" can be converted into the numeric value 123, but the string "hello, world" does not have an obvious numeric value to convert to. -下面是一个例子。Siwft的字符串类型有一个toInt的方法,它会尝试将一个字符串类型转换成一个整数类型。然而,不是每一额字符串都可以转换成整数的。字符串“123”可以转换为数字量123,但是字符串"Hello, world"并没有一个明显的数字量可以转换。 +下面是一个例子。Siwft的字符串类型有一个`toInt`的方法,它会尝试将一个字符串类型转换成一个整数类型。然而,不是每一个字符串都可以转换成整数。字符串“123”`"123"`可以转换为数字量`123`,但是字符串`"Hello, world"`并没有一个明显的数字量可以转换。 The example below uses the toInt method to try to convert a String into an Int: @@ -802,18 +589,18 @@ let convertedNumber = possibleNumber.toInt() Because the toInt method might fail, it returns an optional Int, rather than an Int. An optional Int is written as Int?, not Int. The question mark indicates that the value it contains is optional, meaning that it might contain some Int value, or it might contain no value at all. (It can’t contain anything else, such as a Bool value or a String value. It’s either an Int, or it’s nothing at all.) -因为`toInt`方法可能失败,它返回的是可以可选类型的整数,而不是一个整数。一个可选的整数表示为`Int?`,而不是`Int`。最后的问号表示这个值是可选的,意味着它可能包含整数类型的值,或者它没有值。(它不能包括其它任何值,比如布尔值或者字符串。它要不是一个整数,要不就没有值。) +因为`toInt`方法可能失败,它返回的是可以可选类型的整数,而不是一个整数。一个可选的整数表示为`Int?`,而不是`Int`。最后的问号表示这个值是可选的,意味着它可能包含整数类型的值,或者没有值。(它不能包括其它任何值,比如布尔值或者字符串。它要么是一个整数,要么就没有值。) -# If Statements and Forced Unwrapping -# If语句和强制解析 +## If Statements and Forced Unwrapping +## If语句和强制解析 You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to true; if it has no value at all, it evaluates to false. -你可以使用if语句来判断一个可选类型是否有值。如果有值,它就等于true,如果没有值,就等于false。 +你可以使用`if`语句来判断一个可选类型是否有值。如果有值,它就等于`true`,如果没有值,就等于`false`。 Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value: -一旦你确定可选类型是有值的,你可以在可选类型的名字后面加一个感叹号(!)来调用它的值。这个感叹号的意思是:”我知道这个可选类型的值一定存在一个值,请使用这个值。“这叫做可选值的强制解析: +一旦你确定可选类型是有值的,你可以在可选类型的名字后面加一个感叹号(!)`!`来调用它的值。这个感叹号的意思是:”我知道这个可选类型的值一定存在一个值,请使用这个值。“这叫做可选值的强制解析: ``` if convertedNumber { @@ -826,7 +613,7 @@ if convertedNumber { For more on the if statement, see Control Flow. -更多信息,见[Control Flow](link)。 +更多*`if`语句的*信息,见[Control Flow](link)。 > NOTE @@ -834,18 +621,18 @@ For more on the if statement, see Control Flow. > 注意 -> 如果你使用!来调用一个不存在的可选值,会报出实时错误。在使用!强制解析可选值之前总是确认这个可选值包含一个非nil的值。 +> 如果你使用`!`来调用一个不存在的可选值,会报出实时运行时错误。在使用`!`强制解析可选值之前总是请确认这个可选值包含一个非`nil`的值。 -# Optional Binding -# 可选值绑定 +## Optional Binding +## 可选值绑定 You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used with if and while statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action. if and while statements are described in more detail in Control Flow. -你可以使用可选值绑定(optional binding)来找出一个可选类型是否包含值,如果包含,则可以把这个值作为一个临时常量或变量来使用。可选值绑定可以和if或while语句一起来检查可选值里面的值,并且解析到一个常量或变量中,所有这些都在一步操作中完成。更多关于if和while语句的信息,见[Control Flow](link)。 +你可以使用可选值绑定(optional binding)来找出一个可选类型是否包含值,如果包含,则可以把这个值作为一个临时常量或变量来使用。可选值绑定可以和`if`或`while`语句一起来检查可选值里面的值,并且解析到一个常量或变量中,所有这些都在一步操作中完成。更多关于`if`和`while`语句的信息,见[Control Flow](link)。 Write optional bindings for the if statement as follows: -像这样给if语句写可选值绑定: +像这样给`if`语句写可选值绑定: ``` if let constantName = someOptional { @@ -855,7 +642,7 @@ if let constantName = someOptional { You can rewrite the possibleNumber example from above to use optional binding rather than forced unwrapping: -你可以用可选值绑定来代替强制解析来重写之前那个possibleNumber的例子: +你可以用可选值绑定来代替强制解析来重写之前那个`possibleNumber`的例子: ``` if let actualNumber = possibleNumber.toInt() { @@ -872,22 +659,23 @@ This can be read as: “If the optional Int returned by possibleNumber.toInt contains a value, set a new constant called actualNumber to the value contained in the optional.” -”如果可选整数值通过possibleNumber.toInt返回一个值,设定一个叫actualNumber的新的常量来储存这个可选整数中的值。“ +”如果可选整数值通过`possibleNumber.toInt`返回一个值,设定一个叫`actualNumber`的新常量来储存这个可选整数中的值。“ If the conversion is successful, the actualNumber constant becomes available for use within the first branch of the if statement. It has already been initialized with the value contained within the optional, and so there is no need to use the ! suffix to access its value. In this example, actualNumber is simply used to print the result of the conversion. -如果这个转换是成功的,那么常量actualNumber在if语句的第一个分支就可用了。它已经用可选量中的值初始化了,所以现在不需要用!后缀来调用这个值。在这个例子中,actualNumber只是简单的用于输出转换结果。 +如果这个转换是成功的,那么常量`actualNumber`在`if`语句的第一个分支就可用了。它已经用可选量中的值初始化了,所以现在不需要用`!`后缀来调用这个值。在这个例子中,`actualNumber`只是简单的用于输出转换结果。 You can use both constants and variables with optional binding. If you wanted to manipulate the value of actualNumber within the first branch of the if statement, you could write if var actualNumber instead, and the value contained within the optional would be made available as a variable rather than a constant. -无论是常量还是变量你都可以使用可选值绑定。如果你希望对if语句第一个分支中actualNumber的值进行操作,你可以用if var actualNumber来声明,然后可选量中的值就会成为一个可用的变量而不是常量。 +无论是常量还是变量你都可以使用可选值绑定。如果你希望对`if`语句第一个分支中`actualNumber`的值进行操作,你可以用`if var actualNumber`来声明,然后可选量中的值就会成为一个可用的变量而不是常量。 -# nil -# nil +## nil +## nil You set an optional variable to a valueless state by assigning it the special value nil: -给可选变量一个没有值的状态是通过给它赋予一个特殊值nil来完成的: +给可选变量一个没有值的状态是通过给它赋予一个特殊值`nil`来完成的: +通过给可选变量赋予特殊值`nil`来表示没有值的状态: ``` var serverResponseCode: Int? = 404 @@ -902,11 +690,11 @@ serverResponseCode = nil > 注意 -> nil不能被用于可选类型之外的常量和变量。如果你的代码中的常量或变量需要处理值缺失的情况,总是用一个可选的合适类型来声明它。 +> `nil`不能被用于可选类型之外的常量和变量。如果你的代码中的常量或变量需要处理值缺失的情况,总是用一个可选的合适类型来声明它。 If you define an optional constant or variable without providing a default value, the constant or variable is automatically set to nil for you: -如果你定义一个可选的常量或变量,却没有赋初值,这个常量或变量会自动设为nil: +如果你定义一个可选的常量或变量,却没有赋初值,这个常量或变量会自动设*置*为`nil`: ``` var surveyAnswer: String? @@ -919,14 +707,14 @@ var surveyAnswer: String? > 注意 -> Swift的nil和Objective-C中的不完全一样。Objective-C中,nil是指向不存在的对象。而在Swift中,nil不知是一个指针——它是一个特定类型的值缺失。可选的任何类型都可以设为nil,不只是对象类型。 +> Swift的`nil`和Objective-C中的不完全一样。Objective-C中,`nil`是指向不存在对象*的指针*。而在Swift中,`nil`不止是一个指针——它是一个特定类型的值缺失。可选的任何类型都可以设为`nil`,不只是对象类型。 -# Implicitly Unwrapped Optionals -# 隐式解析可选值 +## Implicitly Unwrapped Optionals +## 隐式解析可选值 As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist. -像之前说的,可选值意味着一个常量或变量允许“没有值”。可以通过if语句来判断可选值中是否有值存在,如果值存在则用可选值绑定来调用可选量的值。 +像之前说的,可选值意味着一个常量或变量允许“没有值”。可以通过`if`语句来判断可选值中是否有值存在,如果值存在则用可选值绑定来调用可选量的值。 Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time. @@ -934,11 +722,11 @@ Sometimes it is clear from a program’s structure that an optional will always These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional. -这些类型的可选值被定义为隐式解析可选值。当你创建可选值的时候,你可以通过写感叹号(String!)而不是问号(String?)的形式来写一个隐式解析的可选值。 +这些类型的可选值被定义为隐式解析可选值。当你创建可选值的时候,你可以通过写感叹号(String!)而不是问号(String?)的形式来表示一个隐式解析的可选值。 Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties. -如果可选值在第一次定义之后就肯定存在值并且之后每一刻都肯定存在,这种情况下隐式解析可选值是很有用红的。Swift中的隐式解析可选值的主要用法是在类的初始化过程中,参见[Unowned References and Implicitly Unwrapped Optional Properties](link)。 +如果可选值在第一次定义之后就肯定存在值并且之后每一刻都肯定存在,这种情况下隐式解析可选值是很有用的。Swift中的隐式解析可选值的主要用法是在类的初始化过程中,参见[Unowned References and Implicitly Unwrapped Optional Properties](link)。 An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it is accessed. The following example shows the difference in behavior between an optional String and an implicitly unwrapped optional String: @@ -964,7 +752,7 @@ You can think of an implicitly unwrapped optional as giving permission for the o > 注意 -> 如果你试图调用一个没有值的隐式解析可选值,你会得到一个实时的错误。这和你在一个普通的不含值的可选值后面放感叹号的结果是完全一样的。 +> 如果你试图调用一个没有值的隐式解析可选值,你会得到一个实时的运行时错误。这和你在一个普通的不含值的可选值后面放感叹号的结果是完全一样的。 You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value: @@ -994,29 +782,29 @@ if let definiteString = assumedString { > 注意 -> 当一个变量有可能是nil的情况下,不应当使用隐式解析可选值。如果在整个过程中检查一个变量是否有nil值,你应该用一个普通的可选值。 +> 当一个变量有可能是`nil`的情况下,不应当使用隐式解析可选值。如果在整个过程中检查一个变量是否有`nil`值,你应该用一个普通的可选值。 # Assertions # 断言 Optionals enable you to check for values that may or may not exist, and to write code that copes gracefully with the absence of a value. In some cases, however, it is simply not possible for your code to continue execution if a value does not exist, or if a provided value does not satisfy certain conditions. In these situations, you can trigger an assertion in your code to end code execution and to provide an opportunity to debug the cause of the absent or invalid value. -可选值让你可以检查一个值是否存在,并且优雅的处理值缺失的情况。然而,在一些情况下,如果值不存在或者值不满足指定的条件,你的程序就无法继续执行。在这些情况下,你可以在代码中触发一个断言,来中断代码的执行并且提供一个调试为什么值缺失或无效的机会。 +可选值让你可以检查一个值是否存在,并且优雅的处理值缺失的情况。然而,在一些情况下,如果值不存在或者值不满足指定的条件,你的程序就无法继续执行。在这些情况下,你可以在代码中触发一个断言,来中断代码的执行并且提供一个来调试为什么值缺失或无效的机会。 ## Debugging with Assertions ## 用断言来调试 An assertion is a runtime check that a logical condition definitely evaluates to true. Literally put, an assertion “asserts” that a condition is true. You use an assertion to make sure that an essential condition is satisfied before executing any further code. If the condition evaluates to true, code execution continues as usual; if the condition evaluates to false, code execution ends, and your app is terminated. -断言是判断一个逻辑条件是否为真的实时检查。基本上,一个断言就是“断定”(asserts)一个条件为真。你可以使用断言来确保在运行后续代码之前它的一个必要的条件是已经满足了的。如果这个条件为真,代码会正常执行,如果条件为否,代码会停止执行,并且你的app会终止。 +断言是判断一个逻辑条件是否为真的实时检查。基本上,一个断言就是“断定”(asserts)一个条件为真。你可以使用断言来确保在运行后续代码之前它的一个必要的条件是已经满足了的。如果这个条件为真,代码会正常执行,如果条件为否,代码会停止执行,并且你的app应用会终止。 If your code triggers an assertion while running in a debug environment, such as when you build and run an app in Xcode, you can see exactly where the invalid state occurred and query the state of your app at the time that the assertion was triggered. An assertion also lets you provide a suitable debug message as to the nature of the assert. -如果你的代码值调试环境下触发了一个断言,比如当你在Xcode中创建并运行一个app的时候,你可以准确的看到非法语句出现的位置,也可以查询到当断言触发时app的状态。断言还允许你可以提供一个相应的调试信息。 +如果你的代码在调试环境下触发了一个断言(比如当你在Xcode中创建并运行一个app的时候),你可以准确的看到非法语句出现的位置,也可以查询到当断言触发时app的状态。断言还允许你可以提供一个相应的调试信息。 You write an assertion by calling the global assert function. You pass the assert function an expression that evaluates to true or false and a message that should be displayed if the result of the condition is false: -通过调用全局的断言函数来写一个断言。你给断言函数传入一个等于true或false的表达式,当结果是false的时候,会显示出一条信息: +通过调用全局的断言assert函数来写一个断言。你给断言函数传入一个等于true或false的表达式会被解析为`true`或者`false`的表达式,当结果是false的时候,会显示出一条信息以及在解析为`false`时的提示信息: ``` let age = -3 @@ -1026,11 +814,11 @@ assert(age >= 0, "A person's age cannot be less than zero") In this example, code execution will continue only if age >= 0 evaluates to true, that is, if the value of age is non-negative. If the value of age is negative, as in the code above, then age >= 0 evaluates to false, and the assertion is triggered, terminating the application. -在这个例子里,只有age >= 0为真的时候代码才会继续执行,也就是,如果age的值是非负数。如果age的值是负数,在上面的代码中,这个age >= 0的条件判断为否,这个断言被触发,终止了这个程序。 +在这个例子里,只有`age >= 0`为真的时候代码才会继续执行,也就是,如果`age`的值是非负数。在上面的代码中,如果`age`的值是负数,在上面的代码中,`age >= 0`的条件判断这个表达式解析为否,这个断言被触发,终止了这个程序。 Assertion messages cannot use string interpolation. The assertion message can be omitted if desired, as in the following example: -断言信息不能使用字符串插值。如果你想,断言信息是可以省略的,像下面这个例子: +断言信息不能使用字符串插值。如果你想,断言信息可以省略,像下面这个例子: ``` assert(age >= 0) @@ -1041,7 +829,7 @@ assert(age >= 0) Use an assertion whenever a condition has the potential to be false, but must definitely be true in order for your code to continue execution. Suitable scenarios for an assertion check include: -如果一个条件有可能为否,但只有它为真的时候代码才能继续执行,这时应该使用断言。适当的使用断言检查的场景包括: +如果在一个条件有可能为否,但只有它为真的时候代码才能继续执行,这时时,应该使用断言。适当的使用断言检查的*合适*场景包括: - An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high. - A value is passed to a function, but an invalid value means that the function cannot fulfill its task. @@ -1049,7 +837,7 @@ Use an assertion whenever a condition has the potential to be false, but must de - 一个整数类型的下标索引被传入一个自定义的下标实现,但是这个下标索引值太小或太大。 - 一个值传入一个函数,但是如果传入不合法的值,这个函数就无法满足需求。 -- 一个可选值当前的值是nil,但是后续代码成功执行需要一个非nil值。 +- 一个可选值当前的值是`nil`,但是后续代码成功执行需要一个非`nil`值。 See also Subscripts and Functions. @@ -1061,4 +849,4 @@ See also Subscripts and Functions. > 注意 -> 断言会造成你的app终止,它并不能代替你设计代码来保证不合法情况不出现。尽管如此,当不合法的情况可能出现时,断言可以有效的保证在你的app正式发布之前,在开发过程中这种不合法的情况就会被高亮并被注意到。f \ No newline at end of file +> 断言会造成你的app终止,它并不能代替你设计代码来保证不合法情况不出现。尽管如此,当不合法的情况可能出现时,断言可以有效的保证在你的app正式发布之前,在的开发过程中这种不合法的情况就会被高亮并被注意到。 \ No newline at end of file diff --git a/src/chapter2/12_Subscripts_Chinese.md b/src/chapter2/12_Subscripts_Chinese.md new file mode 100644 index 0000000..bb3d5c3 --- /dev/null +++ b/src/chapter2/12_Subscripts_Chinese.md @@ -0,0 +1,191 @@ +# 下标 (Subscripts) + +下标可以定义在类(Class)、结构体(structures)和枚举(enumerations)这些目标中,可以认为是访问对象、集合或序列的快捷方式。举例来说,用下标访问一个数组(Array)实例中的元素可以这样写 `someArray[index]` ,访问字典(Dictionary)实例中的元素可以这样写 `someDictionary[key]`,而不需要再调用实例的某个方法来获得元素的值。 + +对于同一个目标可以定义多个下标,通过索引值类型的不同来进行重载,而且索引值的个数可以是多个。 + +> 译者:这里下标重载在本小节中原文并没有任何演示 + +## 下标语法 + +下标允许你通过在实例后面的方括号中传入一个或者多个的索引值来对实例进行访问和赋值。语法类似于实例方法和实例属性的混合。与定义实例方法类似,定义下标使用`subscript`关键字,显式声明入参(一个或多个)和返回类型。与实例方法不同的是下标可以设定为读写或只读。这种方式又有点像实例属性的getter和setter: + +``` +subscript(index: Int) -> Int { + get { + // 返回与入参匹配的Int类型的值 + } + + set(newValue) { + // 执行赋值操作 + } +} +``` + +`newValue`的类型必须和下标定义的返回类型相同。与实例属性相同的是set的入参声明`newValue`就算不写,在set代码块中依然可以使用`newValue`这个变量来访问新赋的值。 + +与只读实例属性一样,可以直接将原本应该写在get代码块中的代码写在subscript中即可: + +``` +subscript(index: Int) -> Int { + // 返回与入参匹配的Int类型的值 +} +``` + +Here’s an example of a read-only subscript implementation, which defines a TimesTable structure to represent an n-times-table of integers: + +下面代码演示了一个在TimesTable结构体中使用只读下标的用法,该结构体用来展示传入整数的N倍。 + +``` +struct TimesTable { + let multiplier: Int + subscript(index: Int) -> Int { + return multiplier * index + } +} +let threeTimesTable = TimesTable(multiplier: 3) +println("3的6倍是\(threeTimesTable[6])") +// 输出 "3的6倍是18" +``` + +在上例中,通过TimesTable结构体创建了一个用来表示索引值三倍的实例。数值3作为结构体构造函数入参表示这个值将成为实例成员multiplier的值。 + +你可以通过下标来来得到结果,比如`threeTimesTable[6]`。这句话访问了threeTimesTable的第六个元素,返回18或者6的3倍。 + +> 提示 +> +> TimesTable例子是基于一个固定的数学公式。它并不适合开放写权限来对threeTimesTable[someIndex]进行赋值操作,这也是为什么下标只定义为只读的原因。 + +## 下标用法 + +下标根据使用场景不同也具有不同的含义。通常下标是用来访问集合(collection),列表(list)或序列(sequence)中元素的快捷方式。你可以为特定的类或结构体中自由的实现下标来提供合适的功能。 + +例如,Swift的字典(Dictionary)实现了通过下标来对其实例中存放的值进行存取操作。在字典中设值可以通过给字典提供一个符合字典索引类型的索引值的表达式赋一个与字典存放值类型匹配的值来做到: + +``` +var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] +numberOfLegs["bird"] = 2 +``` + +``` +var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4] +numberOfLegs["bird"] = 2 +``` + +上例定义一个名为numberOfLegs的变量并用一个字典表达式初始化出了包含三对键值的字典实例。numberOfLegs的字典存放值类型推断为`Dictionary`。字典实例创建完成之后通过下标的方式将整型值`2`赋值到字典实例的索引为`bird`的位置中。 + +更多关于字典(Dictionary)下标的信息请参考[字典的访问与修改](#) + +> 提示 +> +> Swift中Dictionary的下标实现中,在get部分返回值是`Int?`,也就是说不是每个字典的索引都能得到一个整型值,对于没有设过值的索引的访问返回的结果就是`nil`;同样想要从字典实例中删除某个索引下的值也只需要给这个索引赋值为`nil`即可。 + +## Subscript Options +## 下标选项 + +下标允许任意数量的入参索引,并且每个入参类型也没有限制。下标的返回值也可以是任何类型。下标可以使用变量参数和可变参数,但使用in-out参数或给参数设置默认值都是不允许的。 + +一个类或结构体可以根据自身需要提供多个下标实现,在定义下标时通过入参个类型进行区分,使用下标时会自动匹配合适的下标实现运行,这就是下标的重载。 + +一个下标入参是最常见的情况,但只要有合适的场景也可以定义多个下标入参。如下例定义了一个Matrix结构体,将呈现一个Double类型的二维数组。Matrix结构体的下标需要两个整型参数: + +``` +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 { + return row >= 0 && row < rows && column >= 0 && column < columns + } + subscript(row: Int, column: Int) -> Double { + get { + assert(indexIsValidForRow(row, column: column), "Index out of range") + return grid[(row * columns) + column] + } + set { + assert(indexIsValidForRow(row, column: column), "Index out of range") + grid[(row * columns) + column] = newValue + } + } +} +``` + +``` +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 { + return row >= 0 && row < rows && column >= 0 && column < columns + } + subscript(row: Int, column: Int) -> Double { + get { + assert(indexIsValidForRow(row, column: column), "Index out of range") + return grid[(row * columns) + column] + } + set { + assert(indexIsValidForRow(row, column: column), "Index out of range") + grid[(row * columns) + columns] = newValue + } + } +} +``` + +Matrix提供了一个两个入参的构造方法,入参分别是`rows`和`columns`,创建了一个足够容纳rows * columns个数的Double类型数组。为了存储,将数组的大小和数组每个元素初始值0.0,都传入数组的构造方法中来创建一个正确大小的新数组。关于数组的构造方法和析构方法请参考[Creating and Initializing an Array](#)。 + +你可以通过传入合适的row和column的数量来构造一个新的Matrix实例: + +``` +var matrix = Matrix(rows: 2, columns: 2) +``` + +上例中创建了一个新的两行两列的Matrix实例。在阅读顺序从左上到右下的Matrix实例中的数组实例grid是矩阵二维数组的扁平化存储: + +``` +// 示意图 +grid = [0.0, 0.0, 0.0, 0.0] + + col0 col1 +row0 [0.0, 0.0, +row1 0.0, 0.0] +``` + +将值赋给带有row和column下标的matrix实例表达式可以完成赋值操作,下标入参使用逗号分割 + +``` +matrix[0, 1] = 1.5 +matrix[1, 0] = 3.2 +``` + +上面两句话分别让matrix的右上值为1.5,坐下值为3.2: + +``` +[0.0, 1.5, + 3.2, 0.0] +``` + +Matrix下标的getter和setter中同时调用了下标入参的row和column是否有效的判断。为了方便进行断言,Matrix包含了一个名为indexIsValid的成员方法,用来确认入参的row或column值是否会造成数组越界: + +``` +func indexIsValidForRow(row: Int, column: Int) -> Bool { + return row >= 0 && row < rows && column >= 0 && column < columns +} +``` + +断言在下标越界时触发: + +``` +let someValue = matrix[2, 2] +// 断言将会触发,因为 [2, 2] 已经超过了matrix的最大长度 +``` + +> 译者:这里有个词Computed Properties 这里统一翻译为实例属性了 微软术语引擎里没有这个词 + diff --git a/src/words.md b/src/words.md index 89238e0..b43f4d7 100644 --- a/src/words.md +++ b/src/words.md @@ -12,7 +12,7 @@ - adopt - 适配。但是一般用于被动。如 `a protocol can be adopted by a class`: 协议可以被类适配。 - conform - 遵循。如果一个类适配了一个协议,我们就说这个类遵循这个协议。`this class conforms to that protocol`。 - literal value - 字面量 - A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below. - - as described in - 详见 - You can provide a default value for a stored property as part of its definition, as described in Default Property Values. +- access - 引用 - you can use the element names to access the values of those elements. - example - 示例 - The example below defines a structure called FixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created From 08804339af9d8ac29e4301410d5f63b0bf101638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=9C=9F=28028611=29?= Date: Wed, 2 Jul 2014 22:37:04 +0800 Subject: [PATCH 230/261] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=AD=E8=8B=B1?= =?UTF-8?q?=E6=96=87=E5=AF=B9=E7=85=A7=EF=BC=9B=E5=8F=8A=E7=AC=AC=E4=B8=80?= =?UTF-8?q?=E9=81=8Dreview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter3/10_Summary_of_the_Grammar.md | 1389 +++++++++++++++++---- 1 file changed, 1158 insertions(+), 231 deletions(-) diff --git a/src/chapter3/10_Summary_of_the_Grammar.md b/src/chapter3/10_Summary_of_the_Grammar.md index 7736c87..42ee069 100644 --- a/src/chapter3/10_Summary_of_the_Grammar.md +++ b/src/chapter3/10_Summary_of_the_Grammar.md @@ -1,45 +1,105 @@ +#Summary of the Grammar #语法总结 +##Statements ##语句 +###GRAMMAR OF A STATEMENT + +‌ statement → expression;opt + +‌ statement → declaration;opt + +‌ statement → loop-statement;opt + +‌ statement → branch-statement;opt + +‌ statement → labeled-statement + +‌ statement → control-transfer-statement;opt + +‌ statements → statementstatements opt + ###语句语法 -语句→表达式;可选 +语句 → 表达式 ;可选 -语句→声明;可选 +语句 → 声明 ;可选 -语句→循环语句;可选 +语句 → 循环语句 ;可选 -语句→分支语句;可选 +语句 → 分支语句 ;可选 -语句→标记语句;可选 +语句 → 标记语句 -语句→控制转移语句;可选 +语句 → 控制转移语句 ;可选 -多条语句→语句 多条语句;可选 +多条语句 → 语句 多条语句 可选 + +###GRAMMAR OF A LOOP STATEMENT + +‌ loop-statement → for-statement + +‌ loop-statement → for-in-statement + +‌ loop-statement → while-statement + +‌ loop-statement → do-while-statement ###循环语句语法 -循环语句 → for语句 +循环语句 → for 语句 + 循环语句 → for in 语句 + 循环语句 → while 语句 + 循环语句 → do-while 语句 +###GRAMMAR OF A FOR STATEMENT + +‌ for-statement → for for-init opt ;expression opt ; expression opt code-block + +‌ for-statement → for (for-init opt ;expression opt ; expression opt) code-block + +‌ for-init → variable-declaration expression-list + ###for 语句语法 -for语句 → for 初始条件 可选; 表达式 可选 ;表达式 可选 代码块 +for语句 → **for** for-初始条件 可选; 表达式 可选 ;表达式 可选 代码块 + +for语句 → **for** ( for-初始条件 可选; 表达式 可选 ;表达式 可选 ) 代码块 + +for-初始条件 → 变量声明 | 表达式列表 -for语句 → for ( 初始条件 可选; 表达式 可选 ;表达式 可选 ) 代码块 +###GRAMMAR OF A FOR-IN STATEMENT -for 初始条件 → 变量声明 | 表达式列表 +‌ for-in-statement → **for** pattern **in** expression code-block ###for-in 语句语法 for-in 语句 → for 模式 in 表达式代码块 +###GRAMMAR OF A WHILE STATEMENT + +‌ while-statement → while while-condition code-block + +‌ while-condition → expression declaration + ###while 语句语法 -while语句 → while while条件代码块 +while语句 → **while** while-条件 代码块 + +while-条件 → 表达式 | 声明 -while条件 →表达式 | 声明 +###GRAMMAR OF A DO-WHILE STATEMENT + +‌ do-while-statement → do code-block while while-condition ###do-while 语句语法 -do-while语句 → do 代码块 while while条件 +do-while语句 → **do** 代码块 **while** while-条件 + + +###GRAMMAR OF A BRANCH STATEMENT + +‌ branch-statement → if-statement + +‌ branch-statement → switch-statement ###分支语句语法 @@ -47,31 +107,67 @@ do-while语句 → do 代码块 while while条件 分支语句 → switch语句 +###GRAMMAR OF AN IF STATEMENT + +‌ if-statement → **if** if-condition code-block else-clause opt + +‌ if-condition → expression | declaration + +‌ else-clause → **else** code-block | **else** if-statement + ###if 语句语法 -if语句 → if if条件 代码块 else 子句 可选 +if语句 → if if-条件 代码块 else 子句 可选 + +if条件 → 表达式 | 申明 + +else子句 → else 代码块 | else if-语句 + +###GRAMMAR OF A SWITCH STATEMENT + +‌ switch-statement → switch expression{switch-casesopt} + +‌ switch-cases → switch-case switch-cases opt + +‌ switch-case → case-label statements | default-label statements + +‌ switch-case → case-label; | default-label; + +‌ case-label → case case-item-list: -if条件 → 表达式 | 什么 +‌ case-item-list → patternguard-clause opt | pattern guard-clause opt,case-item-list -else子句 → else 代码块 | else if语句 +‌ default-label → default: + +‌ guard-clause → whereguard-expression + +‌ guard-expression → expression ###switch语句语法 -switch语句 → switch 表达式 { switch-case列表 可选 } +switch语句 → **switch** 表达式 { switch-case列表 可选 } -switch-case列表 → switch-case 列表 可选 +switch-case列表 → switch-case switch-case列表 可选 switch-case → case标签 多条语句 | default标签 多条语句 switch-case → case标签 ; | default标签 ; -case标签 → case case项列表 : +case标签 → **case** case项列表 : + +case项列表 → 模式 监护子句 可选 | 模式 监护子句 可选 , case项列表 + +default标签 → **default** : -case项列表 → 模式 guard-clause 可选 | 模式 guard-clause 可选 , case项列表 +监护字句 → **where** 监护表达式 -default标签 → default : +监护表达式 → 表达式 -guard-clause → where guard-expression +###GRAMMAR OF A LABELED STATEMENT -guard-expression → 表达式 +‌labeled-statement → statement-label loop-statement | statement-label switch-statement +‌ +statement-label → label-name: +‌ +label-name → identifier ###标记语句语法 标记语句 → 语句标签 循环语句 | 语句标签 switch语句 @@ -80,29 +176,85 @@ guard-expression → 表达式 标签名称 → 标识符 +###GRAMMAR OF A CONTROL TRANSFER STATEMENT + +‌ control-transfer-statement → break-statement + +‌ control-transfer-statement → continue-statement + +‌ control-transfer-statement → fallthrough-statement + +‌ control-transfer-statement → return-statement + ###控制传递语句语法 -控制传递语句 → break语句 +控制传递语句 → break-语句 + +控制传递语句 → continue-语句 + +控制传递语句 → fallthrough-语句 + +控制传递语句 → return-语句 + +###GRAMMAR OF A BREAK STATEMENT + +‌ break-statement → breaklabel-name opt -控制传递语句 → continue语句 +###break 语句语法 +break语句 → **break** 标签名称 可选 -控制传递语句 → fallthrough语句 -控制传递语句 → return语句 +###GRAMMAR OF A CONTINUE STATEMENT -####break 语句语法 -break语句 → break 标签名称 可选 +‌ continue-statement → continue label-name opt -####continue 语句语法 -continue语句 → continue 标签名称 可选 +###continue 语句语法 +continue语句 → **continue** 标签名称 可选 -####fallthrough 语句语法 -fallthrough语句 → fallthrough +###GRAMMAR OF A FALLTHROUGH STATEMENT +‌ fallthrough-statement → fallthrough + +###fallthrough 语句语法 +fallthrough-语句 → **fallthrough** + +###GRAMMAR OF A RETURN STATEMENT + +‌ return-statement → return expression opt ####return 语句语法 -return语句 → return 表达式 可选 +return语句 → **return** 表达式 可选 + +##Generic Parameters and Arguments + + +##泛型和参数 + +###GRAMMAR OF A GENERIC PARAMETER CLAUSE + +‌ generic-parameter-clause → + +‌ generic-parameter-list → generic-parameter | generic-parameter,generic-parameter-list + +‌ generic-parameter → type-name + +‌ generic-parameter → type-name:type-identifier + +‌ generic-parameter → type-name:protocol-composition-type + +‌ requirement-clause → where requirement-list + +‌ requirement-list → requirement | requirement,requirement-list + +‌ requirement → conformance-requirement | same-type-requirement -###泛型参数 -泛型形参子句语法 泛型参数子句 → < 泛型参数列表 约束子句 可选 > +‌ conformance-requirement → type-identifier:type-identifier + +‌ conformance-requirement → type-identifier:protocol-composition-type + +‌ same-type-requirement → type-identifier==type-identifier + +###泛型形参子句语法 + +泛型参数子句 → < 泛型参数列表 约束子句 可选 > 泛型参数列表 → 泛形参数 | 泛形参数 , 泛型参数列表 @@ -112,7 +264,7 @@ return语句 → return 表达式 可选 泛形参数 → 类型名称 : 协议合成类型 -约束子句 → where 约束列表 +约束子句 → **where** 约束列表 约束列表 → 约束 | 约束 , 约束列表 @@ -124,6 +276,14 @@ return语句 → return 表达式 可选 同类型约束 → 类型标识 == 类型标识 +###GRAMMAR OF A GENERIC ARGUMENT CLAUSE + +‌ generic-argument-clause → + +‌ generic-argument-list → generic-argument | generic-argument,generic-argument-list + +‌ generic-argument → type + ###泛型参数子句语法 泛型参数子句 → < 泛型参数列表 > @@ -131,8 +291,46 @@ return语句 → return 表达式 可选 泛型参数 → 类型 -###声明 -声明语法 +##Declarations +##声明 +###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 → declarationdeclarations opt + +‌ declaration-specifiers → declaration-specifier declaration-specifiersopt + +‌ declaration-specifier → class | mutating | nonmutating | override | static | unowned | unowned(safe) | unowned(unsafe) | weak + + +###声明语法 声明 → 导入声明 @@ -166,25 +364,51 @@ return语句 → return 表达式 可选 声明描述符列表 → 声明描述符 声明描述符列表 可选 -声明描述符 → class | mutating | nonmutating | override | static | unowned | unowned(safe) | unowned(unsafe) | weak +声明描述符 → **class** | **mutating** | **nonmutating** | **override** | **static** | **unowned** | **unowned(safe) **| **unowned(unsafe)** | **weak** + +###GRAMMAR OF A TOP-LEVEL DECLARATION -####顶级声明语法 +‌ top-level-declaration → statements opt + +###顶级声明语法 顶级声明 → 多条语句 可选 +###GRAMMAR OF A CODE BLOCK + +‌ code-block → {statements opt} ###代码块语法 代码块 → { 多条语句 可选 } +###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 导入类型 可选 导入路径 +导入声明 → 属性列表 可选 **import** 导入类型 可选 导入路径 -导入类型 → typealias | struct | class | enum | protocol | var | func +导入类型 → **typealias** | **struct** | **class** | **enum** | **protocol** | **var** | **func** 导入路径 → 导入路径标识符 | 导入路径标识符 . 导入路径 导入路径标识符 → 标识符 | 运算符 +###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 ###常数声明语法 -常量声明 → 属性列表 可选 声明描述符(Specifiers)列表 可选 let 模式构造器列表 +常量声明 → 属性列表 可选 声明描述符列表 可选 **let** 模式构造器列表 模式构造器列表 → 模式构造器 | 模式构造器 , 模式构造器列表 @@ -192,6 +416,48 @@ return语句 → return 表达式 可选 构造器 → = 表达式 +###GRAMMAR OF A VARIABLE DECLARATION + +‌ variable-declaration → variable-declaration-head pattern-initializer-list + +‌ variable-declaration → variable-declaration-head variable-name type-annotationcode-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-clausesetter-clauseopt} + +‌ getter-setter-block → {setter-clausegetter-clause} + +‌ getter-clause → attributes opt getcode-block + +‌ setter-clause → attributes opt setsetter-nameoptcode-block + +‌ setter-name → (identifier) + +‌ getter-setter-keyword-block → {getter-keyword-clausesetter-keyword-clauseopt} + +‌ getter-setter-keyword-block → {setter-keyword-clausegetter-keyword-clause} + +‌ getter-keyword-clause → attributes opt get + +‌ setter-keyword-clause → attributes opt set + +‌ willSet-didSet-block → {willSet-clausedidSet-clauseopt} + +‌ willSet-didSet-block → {didSet-clausewillSet-clause} + +‌ willSet-clause → attributes opt willSetsetter-name opt code-block + +‌ didSet-clause → attributes opt didSetsetter-name opt code-block + ###变量声明语法 变量声明 → 变量声明头 模式构造器列表 @@ -199,11 +465,11 @@ return语句 → return 表达式 可选 变量声明 → 变量声明头 变量名 类型注解 getter-setter块 -变量声明 → 变量声明头 变量名 类型注解 getter-setter关键字(Keyword)块 +变量声明 → 变量声明头 变量名 类型注解 getter-setter关键字块 变量声明 → 变量声明头 变量名 类型注解 构造器 可选 willSet-didSet代码块 -变量声明头 → 属性列表 可选 声明描述符列表 可选 var +变量声明头 → 属性列表 可选 声明描述符列表 可选 **var** 变量名称 → 标识符 @@ -211,60 +477,103 @@ getter-setter块 → { getter子句 setter子句 可选 } getter-setter块 → { setter子句 getter子句 } -getter子句 → 属性列表 可选 get 代码块 +getter子句 → 属性列表 可选 **get** 代码块 + +setter子句 → 属性列表 可选 **set** setter名称 可选 代码块 + +setter名称 → **(** 标识符 **)** + +getter-setter关键字块 → **{** getter关键字子句 setter关键字子句 可选 **}** + +getter-setter关键字块 → **{ **setter关键字子句 getter关键字子句 **}** -setter子句 → 属性列表 可选 set setter名称 可选 代码块 +getter关键字子句 → 属性列表 可选 **get** -setter名称 → ( 标识符 ) +setter关键字子句 → 属性列表 可选 **set** -getter-setter关键字块 → { getter关键字子句 setter关键字子句 可选 } +willSet-didSet代码块 → **{** willSet子句 didSet子句 可选**}** -getter-setter关键字块 → { setter关键字子句 getter关键字子句 } +willSet-didSet代码块 → **{** didSet子句 willSet子句 **}** -getter关键字子句 → 属性列表 可选 get +willSet子句 → 属性列表 可选 **willSet** setter名称 可选 代码块 -setter关键字子句 → 属性列表 可选 set +didSet子句 → 属性列表 可选 **didSet** setter名称 可选 代码块 -willSet-didSet代码块 → { willSet子句 didSet子句 可选 } +###GRAMMAR OF A TYPE ALIAS DECLARATION -willSet-didSet代码块 → { didSet子句 willSet子句 } +‌ typealias-declaration → typealias-head typealias-assignment -willSet子句 → 属性列表 可选 willSet setter名称 可选 代码块 +‌ typealias-head → typealias typealias-name -didSet子句 → 属性列表 可选 didSet setter名称 可选 代码块 +‌ typealias-name → identifier -####类型别名声明语法 +‌ typealias-assignment → =type + +###类型别名声明语法 类型别名声明 → 类型别名头 类型别名赋值 -类型别名头 → typealias 类型别名名称 +类型别名头 → **typealias** 类型别名名称 类型别名名称 → 标识符 类型别名赋值 → = 类型 -####函数声明语法 + +###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-clauseparameter-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 + +###函数声明语法 函数声明 → 函数头 函数名 泛型参数子句 可选 函数签名 函数体 -函数头 → 属性列表 可选 声明描述符列表 可选 func +函数头 → 属性列表 可选 声明描述符列表 可选 **func** 函数名 → 标识符 | 运算符 -函数签名 → parameter-clauses 函数结果 可选 +函数签名 → 参数子句列表 函数结果 可选 函数结果 → → 属性列表 可选 类型 函数体 → 代码块 -parameter-clauses → 参数子句 parameter-clauses 可选 +参数子句列表 → 参数子句 参数子句列表 可选 -参数子句 → ( ) | ( 参数列表 ... 可选 ) +参数子句 → **( ) **| ( 参数列表 ... 可选 ) 参数列表 → 参数 | 参数 , 参数列表 -参数 → inout 可选 let 可选 # 可选 参数名 局部参数名 可选 类型注解 默认参数子句 可选 +参数 → **inout** 可选 **let** 可选 **#** 可选 参数名 局部参数名 可选 类型注解 默认参数子句 可选 -参数 → inout 可选 var # 可选 参数名 局部参数名 可选 类型注解 默认参数子句 可选 +参数 → **inout** 可选 **var** **#** 可选 参数名 局部参数名 可选 类型注解 默认参数子句 可选 参数 → 属性列表 可选 类型 @@ -274,6 +583,41 @@ parameter-clauses → 参数子句 parameter-clauses 可选 默认参数子句 → = 表达式 +###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-nametuple-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 caseraw-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 + + ###枚举声明语法 枚举声明 → 属性列表 可选 联合式枚举 | 属性列表 可选 原始值式枚举 @@ -281,13 +625,13 @@ parameter-clauses → 参数子句 parameter-clauses 可选 union-style-enum-members → union-style-enum-member union-style-enum-members 可选 -union-style-enum-member → 声明 | 联合式(Union Style)的枚举case子句 +union-style-enum-member → 声明 | 联合式的枚举case子句 -联合式(Union Style)的枚举case子句 → 属性列表 可选 case 联合式(Union Style)的枚举case列表 +联合式的枚举case子句 → 属性列表 可选 **case** 联合式的枚举case列表 -联合式(Union Style)的枚举case列表 → 联合式(Union Style)的case | 联合式(Union Style)的case , 联合式(Union Style)的枚举case列表 +联合式的枚举case列表 → 联合式的case | 联合式的case , 联合式的枚举case列表 -联合式(Union Style)的case → 枚举的case名 元组类型 可选 +联合式的case → 枚举的case名 元组类型 可选 枚举名 → 标识符 @@ -299,7 +643,7 @@ union-style-enum-member → 声明 | 联合式(Union Style)的枚举case子句 原始值式枚举成员 → 声明 | 原始值式枚举case子句 -原始值式枚举case子句 → 属性列表 可选 case 原始值式枚举case列表 +原始值式枚举case子句 → 属性列表 可选 **case** 原始值式枚举case列表 原始值式枚举case列表 → 原始值式枚举case | 原始值式枚举case , 原始值式枚举case列表 @@ -307,22 +651,59 @@ union-style-enum-member → 声明 | 联合式(Union Style)的枚举case子句 原始值赋值 → = 字面量 -####结构体声明语法 -结构体声明 → 属性列表 可选 struct 结构体名称 泛型参数子句 可选 类型继承子句 可选 结构体主体 +###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} +###结构体声明语法 +结构体声明 → 属性列表 可选 **struct** 结构体名称 泛型参数子句 可选 类型继承子句 可选 结构体主体 结构体名称 → 标识符 结构体主体 → { 声明列表 可选 } -####类声明语法 +###GRAMMAR OF A CLASS DECLARATION + +‌ class-declaration → attributes opt classclass-name generic-parameter-clause opt type-inheritance-clause opt class-body + +‌ class-name → identifier + +‌ class-body → {declarations opt} + +###类声明语法 类声明 → 属性列表 可选 class 类名 泛型参数子句 可选 类型继承子句 可选 类主体 类名 → 标识符 类主体 → { 声明列表 可选 } -####协议声明语法 -协议声明 → 属性列表 可选 protocol 协议名 类型继承子句 可选 协议主体 + +###GRAMMAR OF A PROTOCOL DECLARATION + +‌ 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-declarationprotocol-member-declarations opt + + +###协议声明语法 +协议声明 → 属性列表 可选 **protocol** 协议名 类型继承子句 可选 协议主体 协议名 → 标识符 @@ -338,72 +719,162 @@ union-style-enum-member → 声明 | 联合式(Union Style)的枚举case子句 协议成员声明 → 协议关联类型声明 -协议成员声明列表 → 协议成员声明 协议成员声明(Declarations)列表 可选 +协议成员声明列表 → 协议成员声明 协议成员声明列表 可选 + +###GRAMMAR OF A PROTOCOL PROPERTY DECLARATION + +‌ protocol-property-declaration → variable-declaration-head variable-name type-annotation getter-setter-keyword-block -####协议属性声明语法 -协议属性声明 → 变量声明头 变量名 类型注解 getter-setter关键字(Keyword)块 +###协议属性声明语法 +协议属性声明 → 变量声明头 变量名 类型注解 getter-setter关键字块 -####协议方法声明语法 -协议方法声明 → 函数头 函数名 泛型参数子句 可选 函数签名(Signature) +###GRAMMAR OF A PROTOCOL METHOD DECLARATION -####协议构造器声明语法 +‌ protocol-method-declaration → function-head function-namem generic-parameter-clause opt function-signature + +###协议方法声明语法 +协议方法声明 → 函数头 函数名 泛型参数子句 可选 函数签名 + + +###GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION + +‌ protocol-initializer-declaration → initializer-head generic-parameter-clause opt parameter-clause + +###协议构造器声明语法 协议构造器声明 → 构造器头 泛型参数子句 可选 参数子句 -####协议下标脚本声明语法 -协议下标脚本声明 → 下标脚本头 下标脚本结果(Result) getter-setter关键字(Keyword)块 +###GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION + +‌ protocol-subscript-declaration → subscript-head subscript-result getter-setter-keyword-block + +###协议下标脚本声明语法 +协议下标脚本声明 → 下标脚本头 下标脚本结果 getter-setter关键字块 -####协议关联类型声明语法 +###GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION + +‌ protocol-associated-type-declaration → typealias-head type-inheritance-clause opt typealias-assignment opt + +###协议关联类型声明语法 协议关联类型声明 → 类型别名头 类型继承子句 可选 类型别名赋值 可选 -####构造器声明语法 + +###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 + +###构造器声明语法 构造器声明 → 构造器头 泛型参数子句 可选 参数子句 构造器主体 -构造器头 → 属性列表 可选 convenience 可选 init +构造器头 → 属性列表 可选 **convenience** 可选 **init** 构造器主体 → 代码块 -####析构器声明语法 +###GRAMMAR OF A DEINITIALIZER DECLARATION -析构器声明 → 属性列表 可选 deinit 代码块 +‌ deinitializer-declaration → attributes opt deinitcode-block -####扩展声明语法 -扩展声明 → extension 类型标识 类型继承子句 可选 extension-主体 +###析构器声明语法 + +析构器声明 → 属性列表 可选 **deinit** 代码块 + +###GRAMMAR OF AN EXTENSION DECLARATION + +‌ extension-declaration → extensiontype-identifiertype-inheritance-clause opt extension-body + +‌ extension-body → {declarations opt} + +###扩展声明语法 +扩展声明 → **extension** 类型标识 类型继承子句 可选 extension-主体 extension-主体 → { 声明列表 可选 } -####下标脚本声明语法 +###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 → ->attributesopttype + +###下标脚本声明语法 下标脚本声明 → 下标脚本头 下标脚本结果 代码块 下标脚本声明 → 下标脚本头 下标脚本结果 getter-setter块 下标脚本声明 → 下标脚本头 下标脚本结果 getter-setter关键字块 -下标脚本头 → 属性列表 可选 subscript 参数子句 +下标脚本头 → 属性列表 可选 下表脚本参数子句 下标脚本结果 → → 属性列表 可选 类型 -####运算符声明语法 +###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 + +###运算符声明语法 运算符声明 → 前置运算符声明 | 后置运算符声明 | 中置运算符声明 -前置运算符声明 → 运算符 prefix 运算符 { } +前置运算符声明 → **operator prefix** 运算符 { } -后置运算符声明 → 运算符 postfix 运算符 { } +后置运算符声明 → **operator postfix** 运算符 { } -中置运算符声明 → 运算符 infix 运算符 { 中置运算符属性 可选 } +中置运算符声明 → **operator infix** 运算符 { 中置运算符属性 可选 } 中置运算符属性 → 优先级子句 可选 结和性子句 可选 -优先级子句 → precedence 优先级水平 +优先级子句 → **precedence** 优先级水平 优先级水平 → 数值 0 到 255 -结和性子句 → associativity 结和性 +结和性子句 → **associativity** 结和性 -结和性 → left | right | none +结和性 → **left** | **right** | **none** -###模式 -模式语法 +##Patterns +##模式 + +###GRAMMAR OF A PATTERN + +‌ pattern → wildcard-patterntype-annotation opt + +‌ pattern → identifier-patterntype-annotation opt + +‌ pattern → value-binding-pattern + +‌ pattern → tuple-patterntype-annotation opt + +‌ pattern → enum-case-pattern + +‌ pattern → type-casting-pattern + +‌ pattern → expression-pattern + +###模式语法 模式 → 通配符模式 类型注解 可选 @@ -419,40 +890,99 @@ extension-主体 → { 声明列表 可选 } 模式 → 表达式模式 -####通配符模式语法 +###GRAMMAR OF A WILDCARD PATTERN + +‌ wildcard-pattern → _ + +###通配符模式语法 + +通配符模式 → **_** -通配符模式 → _ +###GRAMMAR OF AN IDENTIFIER PATTERN + +‌ identifier-pattern → identifier ###标识符模式语法 标识符模式 → 标识符 -####值绑定模式语法 +###GRAMMAR OF A VALUE-BINDING PATTERN + +‌ value-binding-pattern → varpattern let pattern + +###值绑定模式语法 -值绑定模式 → var 模式 | let 模式 +值绑定模式 → **var** 模式 | **let** 模式 -####元组模式语法 +###GRAMMAR OF A TUPLE PATTERN + +‌ 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 + +###元组模式语法 元组模式 → ( 元组模式元素列表 可选 ) 元组模式元素列表 → 元组模式元素 | 元组模式元素 , 元组模式元素列表 元组模式元素 → 模式 -####枚举用例模式语法 +###GRAMMAR OF AN ENUMERATION CASE PATTERN + +‌ enum-case-pattern → type-identifier opt.enum-case-nametuple-pattern opt + +###枚举用例模式语法 枚举用例模式 → 类型标识 可选 . 枚举的case名 元组模式 可选 -####类型转换模式语法 + +###GRAMMAR OF A TYPE CASTING PATTERN + +‌ type-casting-pattern → is-pattern as-pattern + +‌ is-pattern → istype + +‌ as-pattern → patternastype +###类型转换模式语法 类型转换模式 → is模式 | as模式 -is模式 → is 类型 +is模式 → **is** 类型 + +as模式 → 模式 **as** 类型 -as模式 → 模式 as 类型 +###GRAMMAR OF AN EXPRESSION PATTERN -####表达式模式语法 +‌ expression-pattern → expression + +###表达式模式语法 表达式模式 → 表达式 -###属性 -####特性语法 +##Attributes +##属性 + +###GRAMMAR OF AN ATTRIBUTE + +‌ attribute → @ attribute-nameattribute-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 → Any identifier, keyword, literal, or operator + +‌ balanced-token → Any punctuation except (, ), [, ], {, or } +####属性语法 属性 → @ 属性名 属性参数子句 可选 属性名 → 标识符 @@ -463,30 +993,55 @@ as模式 → 模式 as 类型 平衡令牌列表 → 平衡令牌 平衡令牌列表 可选 -平衡令牌 → ( 平衡令牌列表 可选 ) +平衡令牌 → **(** 平衡令牌列表 可选 **)** -平衡令牌 → [ 平衡令牌列表 可选 ] +平衡令牌 → **[** 平衡令牌列表 可选 **]** -平衡令牌 → { 平衡令牌列表 可选 } +平衡令牌 → **{** 平衡令牌列表 可选 **}** 平衡令牌 → 任意标识符, 关键字, 字面量或运算符 -平衡令牌 → 任意标点除了(, ), [, ], {, 或 } +平衡令牌 → 任意标点除了**(, ), [, ], {,** 或 **}** + +##Expressions +##表达式 +###GRAMMAR OF AN EXPRESSION + +‌ expression → prefix-expressionbinary-expressions opt -###表达式 -####表达式语法 +‌ expression-list → expression | expression , expression-list + +###表达式语法 表达式 → 前置表达式 二元表达式列表 可选 -表达式列表 → 表达式 | 表达式 , 表达式列表 +表达式列表 → 表达式 | 表达式 **,** 表达式列表 + +GRAMMAR OF A PREFIX EXPRESSION + +‌ prefix-expression → prefix-operator opt postfix-expression +‌ prefix-expression → in-out-expression +‌ in-out-expression → & identifier -####前置表达式语法 +###前置表达式语法 前置表达式 → 前置运算符 可选 后置表达式 前置表达式 → 写入写出表达式 -写入写出表达式 → & 标识符 +写入写出表达式 → **&** 标识符 -####二元表达式语法 +###GRAMMAR OF A BINARY EXPRESSION + +‌ binary-expression → binary-operator prefix-expression + +‌ binary-expression → assignment-operator prefix-expression + +‌ binary-expression → conditional-operator prefix-expression + +‌ binary-expression → type-casting-operator + +‌ binary-expressions → binary-expression binary-expressionsopt + +###二元表达式语法 二元表达式 → 二元运算符 前置表达式 二元表达式 → 赋值运算符 前置表达式 @@ -497,16 +1052,46 @@ as模式 → 模式 as 类型 二元表达式列表 → 二元表达式 二元表达式列表 可选 -####赋值运算符语法 -赋值运算符 → = +###GRAMMAR OF AN ASSIGNMENT OPERATOR + +‌ assignment-operator → = +###赋值运算符语法 +赋值运算符 → **=** + +###GRAMMAR OF A CONDITIONAL OPERATOR + +‌ conditional-operator → ? expression : + +###三元条件运算符语法 +三元条件运算符 → **?** 表达式 **:** + +###GRAMMAR OF A TYPE-CASTING OPERATOR + +‌ type-casting-operator → is type | as ? opttype + +###类型转换运算符语法 +类型转换运算符 → **is** 类型 | **as ?** 可选 类型 + +###GRAMMAR OF A PRIMARY EXPRESSION -####三元条件运算符语法 -三元条件运算符 → ? 表达式 : +‌ primary-expression → identifiergeneric-argument-clause opt -####类型转换运算符语法 -类型转换运算符 → is 类型 | as ? 可选 类型 +‌ primary-expression → literal-expression -####主表达式语法 +‌ primary-expression → self-expression + +‌ primary-expression → superclass-expression + +‌ primary-expression → closure-expression + +‌ primary-expression → parenthesized-expression + +‌ primary-expression → implicit-member-expression + +‌ primary-expression → wildcard-expression + + +###主表达式语法 主表达式 → 标识符 泛型参数子句 可选 主表达式 → 字面量表达式 @@ -523,7 +1108,26 @@ as模式 → 模式 as 类型 主表达式 → 通配符表达式 -####字面量表达式语法 +###GRAMMAR OF A LITERAL EXPRESSION + +‌ literal-expression → literal + +‌ literal-expression → array-literal | dictionary-literal + +‌ literal-expression → __FILE__ | __LINE__ | __COLUMN__ | __FUNCTION__ + +‌ array-literal → [array-literal-items opt] + +‌ array-literal-items → array-literal-item,opt array-literal-item,array-literal-items + +‌ array-literal-item → expression + +‌ dictionary-literal → [dictionary-literal-items] [:] + +‌ dictionary-literal-items → dictionary-literal-item,opt dictionary-literal-item,dictionary-literal-items + +‌ dictionary-literal-item → expression:expression +###字面量表达式语法 字面量表达式 → 字面量 字面量表达式 → 数组字面量 | 字典字面量 @@ -542,57 +1146,130 @@ as模式 → 模式 as 类型 字典字面量项 → 表达式 : 表达式 -####Self 表达式语法 -self表达式 → self +###GRAMMAR OF A SELF EXPRESSION + +‌ self-expression → self + +‌ self-expression → self.identifier + +‌ self-expression → self[expression] + +‌ self-expression → self.init + +###Self 表达式语法 +self表达式 → **self** + +self表达式 → **self** **.** 标识符 -self表达式 → self . 标识符 +self表达式 → **self** [ 表达式 ] -self表达式 → self [ 表达式 ] +self表达式 → **self . init** -self表达式 → self . init +###GRAMMAR OF A SUPERCLASS EXPRESSION -####超类表达式语法 +‌ superclass-expression → superclass-method-expression | superclass-subscript-expression |superclass-initializer-expression +‌ +superclass-method-expression → super.identifier +‌ +superclass-subscript-expression → super[expression] +‌ +superclass-initializer-expression → super.init +###超类表达式语法 超类表达式 → 超类方法表达式 | 超类下标表达式 | 超类构造器表达式 -超类方法表达式 → super . 标识符 +超类方法表达式 → **super . **标识符 + +超类下标表达式 → **super [** 表达式 **]** + +超类构造器表达式 → **super . init** + +###GRAMMAR OF A CLOSURE EXPRESSION + +‌ closure-expression → {closure-signature opt statements} + +‌ closure-signature → parameter-clause function-result opt in + +‌ closure-signature → identifier-list function-result opt in + +‌ closure-signature → capture-listp arameter-clause function-result opt in -超类下标表达式 → super [ 表达式 ] +‌ closure-signature → capture-list identifier-list function-result opt in -超类构造器表达式 → super . init +‌ closure-signature → capture-list in -####闭包表达式语法 +‌ capture-list → [capture-specifierexpression] -闭包表达式 → { 闭包签名 可选 多条语句 } +‌ capture-specifier → weak unowned unowned(safe) unowned(unsafe) -闭包签名 → 参数子句 函数结果 可选 in +###闭包表达式语法 -闭包签名 → 标识符列表 函数结果 可选 in +闭包表达式 → **{** 闭包签名 可选 多条语句 **}** -闭包签名 → 捕获列表 参数子句 函数结果 可选 in +闭包签名 → 参数子句 函数结果 可选 **in** -闭包签名 → 捕获列表 标识符列表 函数结果 可选 in +闭包签名 → 标识符列表 函数结果 可选 **in** -闭包签名 → 捕获列表 in +闭包签名 → 捕获列表 参数子句 函数结果 可选 **in** -捕获列表 → [ 捕获说明符 表达式 ] +闭包签名 → 捕获列表 标识符列表 函数结果 可选 **in** -捕获说明符 → weak | unowned | unowned(safe) | unowned(unsafe) +闭包签名 → 捕获列表 **in** -####隐式成员表达式语法 -隐式成员表达式 → . 标识符 +捕获列表 → **[** 捕获说明符 表达式 **]** -圆括号表达式语法 +捕获说明符 → **weak** |**unowned** | **unowned(safe)** | **unowned(unsafe)** -圆括号表达式 → ( 表达式元素列表 可选 ) +###GRAMMAR OF A IMPLICIT MEMBER EXPRESSION + +‌ implicit-member-expression → .identifier +###隐式成员表达式语法 +隐式成员表达式 → **.** 标识符 + +###GRAMMAR OF A PARENTHESIZED EXPRESSION + +‌ parenthesized-expression → (expression-element-list opt) + +‌ expression-element-list → expression-element | expression-element,expression-element-list + +‌ expression-element → expression | identifier:expression + +###圆括号表达式语法 + +圆括号表达式 → **(**表达式元素列表 可选 **)** 表达式元素列表 → 表达式元素 | 表达式元素 , 表达式元素列表 -表达式元素 → 表达式 | 标识符 : 表达式 +表达式元素 → 表达式 | 标识符 **:** 表达式 -####通配符表达式语法 +###GRAMMAR OF A WILDCARD EXPRESSION + +‌ wildcard-expression → _ +###通配符表达式语法 通配符表达式 → _ -后置表达式语法 +###GRAMMAR OF A POSTFIX EXPRESSION + +‌ postfix-expression → primary-expression + +‌ postfix-expression → postfix-expressionpostfix-operator + +‌ postfix-expression → function-call-expression + +‌ postfix-expression → initializer-expression + +‌ postfix-expression → explicit-member-expression + +‌ postfix-expression → postfix-self-expression + +‌ postfix-expression → dynamic-type-expression + +‌ postfix-expression → subscript-expression + +‌ postfix-expression → forced-value-expression + +‌ postfix-expression → optional-chaining-expression + +###后置表达式语法 后置表达式 → 主表达式 @@ -612,41 +1289,128 @@ self表达式 → self . init 后置表达式 → 强制取值表达式 -后置表达式 → 可选链表达式 +后置表达式 → 可选表达式 + +###GRAMMAR OF A FUNCTION CALL EXPRESSION + +‌ function-call-expression → postfix-expressionparenthesized-expression -####函数调用表达式语法 +‌ function-call-expression → postfix-expressionparenthesized-expressionopttrailing-closure + +‌ trailing-closure → closure-expression +###函数调用表达式语法 函数调用表达式 → 后置表达式 圆括号表达式 函数调用表达式 → 后置表达式 圆括号表达式 可选 后置闭包 后置闭包 → 闭包表达式 -####构造器表达式语法 -构造器表达式 → 后置表达式 . init +###GRAMMAR OF AN INITIALIZER EXPRESSION + +‌ initializer-expression → postfix-expression .init +###构造器表达式语法 +构造器表达式 → 后置表达式 **. init** + +###GRAMMAR OF AN EXPLICIT MEMBER EXPRESSION + +‌ explicit-member-expression → postfix-expression . decimal-digit -####显式成员表达式语法 +‌ explicit-member-expression → postfix-expression . identifier generic-argument-clause opt + +###显式成员表达式语法 显示成员表达式 → 后置表达式 . 十进制数字 显示成员表达式 → 后置表达式 . 标识符 泛型参数子句 可选 -####后置Self 表达式语法 -后置self表达式 → 后置表达式 . self -####动态类型表达式语法 +###GRAMMAR OF A SELF EXPRESSION + +‌ postfix-self-expression → postfix-expression .self + +###后置Self 表达式语法 +后置self表达式 → 后置表达式 **. self** -动态类型表达式 → 后置表达式 . dynamicType +###GRAMMAR OF A DYNAMIC TYPE EXPRESSION -####附属脚本表达式语法 -附属脚本表达式 → 后置表达式 [ 表达式列表 ] +‌ dynamic-type-expression → postfix-expression . dynamicType -强制取值语法 +###动态类型表达式语法 -强制取值表达式 → 后置表达式 ! +动态类型表达式 → 后置表达式 **. dynamicType** -###可选链表达式语法 -可选链表达式 → 后置表达式 ? +###GRAMMAR OF A SUBSCRIPT EXPRESSION -####词法结构 -标识符语法 +‌ subscript-expression → postfix-expression [ expression-list ] + +###附属脚本表达式语法 +附属脚本表达式 → 后置表达式 **[** 表达式列表 **]** + +###GRAMMAR OF A FORCED-VALUE EXPRESSION + +‌ forced-value-expression → postfix-expression ! +###强制取值语法 + +强制取值表达式 → 后置表达式 **!** + +###GRAMMAR OF AN OPTIONAL-CHAINING EXPRESSION + +‌ optional-chaining-expression → postfix-expression ? +##可选表达式语法 +可选表达式 → 后置表达式 **?** + +##Lexical Structure +##词法结构 + +###GRAMMAR OF AN IDENTIFIER + +‌ identifier → identifier-head identifier-characters opt + +‌ identifier → ` identifier-head identifier-characters opt ` + +‌ identifier → implicit-parameter-name + +‌ identifier-list → identifier | identifier,identifier-list + +‌ identifier-head → Upper- or lowercase letter A through Z + +‌ identifier-head → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA + +‌ identifier-head → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF + +‌ identifier-head → U+0100–U+02FF, U+0370–U+167F,U+1681–U+180D, or U+180F–U+1DBF + +‌ identifier-head → U+1E00–U+1FFF + +‌ identifier-head → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F + +‌ identifier-head → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793 + +‌ identifier-head → U+2C00–U+2DFF or U+2E80–U+2FFF + +‌ identifier-head → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF + +‌ identifier-head → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44 + +‌ identifier-head → U+FE47–U+FFFD + +‌ identifier-head → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD + +‌ identifier-head → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD + +‌ identifier-head → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD + +‌ identifier-head → U+D0000–U+DFFFD or U+E0000–U+EFFFD + +‌ identifier-character → Digit 0 through 9 + +‌ identifier-character → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F + +‌ identifier-character → identifier-head + +‌ identifier-characters → identifier-characteridentifier-characters opt + +‌ implicit-parameter-name → $ decimal-digits + +###标识符语法 标识符 → 标识符头 标识符字符列表 可选 @@ -656,50 +1420,99 @@ self表达式 → self . init 标识符列表 → 标识符 | 标识符 , 标识符列表 -标识符头 → Upper- or lowercase letter A through Z +标识符头 → 大写或者 小写的字母 A 到 Z -标识符头 → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA +标识符头 → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, 或者 U+00B7–U+00BA -标识符头 → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF +标识符头 → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, 或者 U+00F8–U+00FF -标识符头 → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF +标识符头 → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, 或者 U+180F–U+1DBF 标识符头 → U+1E00–U+1FFF -标识符头 → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F +标识符头 → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, 或者 U+2060–U+206F -标识符头 → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793 +标识符头 → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, 或者 U+2776–U+2793 -标识符头 → U+2C00–U+2DFF or U+2E80–U+2FFF +标识符头 → U+2C00–U+2DFF 或者 U+2E80–U+2FFF -标识符头 → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF +标识符头 → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, 或者 U+3040–U+D7FF -标识符头 → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44 +标识符头 → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, 或者 U+FE30–U+FE44 标识符头 → U+FE47–U+FFFD -标识符头 → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD +标识符头 → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, 或者 U+40000–U+4FFFD -标识符头 → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD +标识符头 → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, 或者 U+80000–U+8FFFD -标识符头 → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD +标识符头 → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, 或者 U+C0000–U+CFFFD -标识符头 → U+D0000–U+DFFFD or U+E0000–U+EFFFD +标识符头 → U+D0000–U+DFFFD 或者 U+E0000–U+EFFFD -标识符字符 → 数值 0 到 9 +标识符字符 → 数字 0 到 9 -标识符字符 → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F +标识符字符 → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, 或者 U+FE20–U+FE2F 标识符字符 → 标识符头 标识符字符列表 → 标识符字符 标识符字符列表 可选 -隐式参数名 → $ 十进制数字列表 +隐式参数名 → **$** 十进制数字列表 + + +###GRAMMAR OF A LITERAL + +‌ literal → integer-literal | floating-point-literal | string-literal -####字面量语法 +###字面量语法 字面量 → 整型字面量 | 浮点数字面量 | 字符串字面量 -####整型字面量语法 + +###GRAMMAR OF AN INTEGER LITERAL + +‌ integer-literal → binary-literal + +‌ integer-literal → octal-literal + +‌ integer-literal → decimal-literal + +‌ integer-literal → hexadecimal-literal + +‌ binary-literal → 0b binary-digitbinary-literal-characters opt + +‌ binary-digit → Digit 0 or 1 + +‌ binary-literal-character → binary-digit _ + +‌ binary-literal-characters → binary-literal-characterbinary-literal-characters opt + +‌ octal-literal → 0ooctal-digitoctal-literal-characters opt + +‌ octal-digit → Digit 0 through 7 + +‌ octal-literal-character → octal-digit _ + +‌ octal-literal-characters → octal-literal-characteroctal-literal-characters opt + +‌ decimal-literal → decimal-digitdecimal-literal-characters opt + +‌ decimal-digit → Digit 0 through 9 + +‌ decimal-digits → decimal-digitdecimal-digits opt + +‌ decimal-literal-character → decimal-digit _ + +‌ decimal-literal-characters → decimal-literal-characterdecimal-literal-characters opt + +‌ hexadecimal-literal → 0xhexadecimal-digithexadecimal-literal-characters opt + +‌ hexadecimal-digit → Digit 0 through 9, a through f, or A through F + +‌ hexadecimal-literal-character → hexadecimal-digit _ + +‌ hexadecimal-literal-characters → hexadecimal-literal-characterhexadecimal-literal-characters opt +###整型字面量语法 整型字面量 → 二进制字面量 整型字面量 → 八进制字面量 @@ -708,17 +1521,17 @@ self表达式 → self . init 整型字面量 → 十六进制字面量 -二进制字面量 → 0b 二进制数字 二进制字面量字符列表 可选 +二进制字面量 → **0b** 二进制数字 二进制字面量字符列表 可选 -二进制数字 → 数值 0 到 1 +二进制数字 → 数字 0 到 1 二进制字面量字符 → 二进制数字 | _ 二进制字面量字符列表 → 二进制字面量字符 二进制字面量字符列表 可选 -八进制字面量 → 0o 八进字数字 八进制字符列表 可选 +八进制字面量 →** 0o** 八进字数字 八进制字符列表 可选 -八进字数字 → 数值 0 到 7 +八进字数字 → 数字 0 到 7 八进制字符 → 八进字数字 | _ @@ -726,7 +1539,7 @@ self表达式 → self . init 十进制字面量 → 十进制数字 十进制字符列表 可选 -十进制数字 → 数值 0 到 9 +十进制数字 → 数字 0 到 9 十进制数字列表 → 十进制数字 十进制数字列表 可选 @@ -734,15 +1547,35 @@ self表达式 → self . init 十进制字符列表 → 十进制字符 十进制字符列表 可选 -十六进制字面量 → 0x 十六进制数字 十六进制字面量字符列表 可选 +十六进制字面量 → **0x **十六进制数字 十六进制字面量字符列表 可选 -十六进制数字 → 数值 0 到 9, a through f, or A through F +十六进制数字 → 数字 0 到 9, a 到 f, or A 到 F 十六进制字符 → 十六进制数字 | _ 十六进制字面量字符列表 → 十六进制字符 十六进制字面量字符列表 可选 -####浮点型字面量语法 +###GRAMMAR OF A FLOATING-POINT LITERAL + +‌ floating-point-literal → decimal-literal decimal-fraction opt decimal-exponentopt + +‌ floating-point-literal → hexadecimal-literal hexadecimal-fraction opt hexadecimal-exponent + +‌ decimal-fraction → .decimal-literal + +‌ decimal-exponent → floating-point-esign opt decimal-literal + +‌ hexadecimal-fraction → .hexadecimal-literal opt + +‌ hexadecimal-exponent → floating-point-psign opt hexadecimal-literal + +‌ floating-point-e → e | E + +‌ floating-point-p → p | P + +‌ sign → + | - + +###浮点型字面量语法 浮点数字面量 → 十进制字面量 十进制分数 可选 十进制指数 可选 浮点数字面量 → 十六进制字面量 十六进制分数 可选 十六进制指数 @@ -755,36 +1588,69 @@ self表达式 → self . init 十六进制指数 → 浮点数p 正负号 可选 十六进制字面量 -浮点数e → e | E +浮点数e → **e** | **E** + +浮点数p → **p** | **P** + +正负号 → **+** |** -** + +###GRAMMAR OF A STRING LITERAL -浮点数p → p | P +‌ string-literal → "quoted-text" -正负号 → + | - +‌ quoted-text → quoted-text-item quoted-text opt -####字符型字面量语法 -字符串字面量 → " 引用文本 " +‌ quoted-text-item → escaped-character + +‌ quoted-text-item → \(expression) + +‌ quoted-text-item → Any Unicode extended grapheme cluster except ", \, U+000A, or U+000D + +‌ escaped-character → \0 \\ \t \n \r \" \' + +‌ escaped-character → \x hexadecimal-digit hexadecimal-digit + +‌ escaped-character → \u hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit + +‌ escaped-character → \U hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit + +###字符型字面量语法 +字符串字面量 → **"** 引用文本** "** 引用文本 → 引用文本条目 引用文本 可选 引用文本条目 → 转义字符 -引用文本条目 → ( 表达式 ) +引用文本条目 → **\(** 表达式 **)** + +引用文本条目 → 除了"­, \­, U+000A, 或者 U+000D外的所有Unicode的字符 + +转义字符 → **\0**| **\\** | **\t** | **\n** | **\r** | **\"** | **\'** + +转义字符 → **\x** 十六进制数字 十六进制数字 + +转义字符 → **\u** 十六进制数字 十六进制数字 十六进制数字 十六进制数字 + +转义字符 → **\U** 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 + +###GRAMMAR OF OPERATORS + +‌ operator → operator-character operator opt -引用文本条目 → 除了"­, \­, U+000A, or U+000D的所有Unicode的字符 +‌ operator-character → / = - + ! * % < > & | ^ ~ . -转义字符 → \0 | \ | \t | \n | \r | \" | \' -转义字符 → \x 十六进制数字 十六进制数字 +‌ binary-operator → operator -转义字符 → \u 十六进制数字 十六进制数字 十六进制数字 十六进制数字 +‌ prefix-operator → operator -转义字符 → \U 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 +‌ postfix-operator → operator -####运算符语法语法 +###运算符语法语法 运算符 → 运算符字符 运算符 可选 -运算符字符 → / | = | - | + | ! | * | % | < | > | & | | | ^ | ~ | . +运算符字符 → **/** | **=** | **-** | **+** | **!** | ***** | **%** | **<** | **>** | **&** | **|** | **^** | **~** | **.** 二元运算符 → 运算符 @@ -792,52 +1658,113 @@ self表达式 → self . init 后置运算符 → 运算符 -###类型 -####类型语法 +##Types +##类型 + +###GRAMMAR OF A TYPE + +‌ type → array-type | function-type | type-identifier | tuple-type | optional-type | implicitly-unwrapped-optional-type | protocol-composition-type | metatype-type + +###类型语法 类型 → 数组类型 | 函数类型 | 类型标识 | 元组类型 | 可选类型 | 隐式解析可选类型 | 协议合成类型 | 元型类型 -####类型注解语法 + +###GRAMMAR OF A TYPE ANNOTATION + +‌ type-annotation → :attributes opt type +###类型注解语法 类型注解 → : 属性列表 可选 类型 -####类型标识语法 +###GRAMMAR OF A TYPE IDENTIFIER + +‌ type-identifier → type-name generic-argument-clause opt type-name generic-argument-clauseopt.type-identifier + +‌ type-name → identifier +###类型标识语法 类型标识 → 类型名称 泛型参数子句 可选 | 类型名称 泛型参数子句 可选 . 类型标识 类名 → 标识符 -####元组类型语法 +###GRAMMAR OF A TUPLE TYPE + +‌ tuple-type → (tuple-type-body opt) + +‌ tuple-type-body → tuple-type-element-list...opt + +‌ tuple-type-element-list → tuple-type-element | tuple-type-element,tuple-type-element-list + +‌ tuple-type-element → attributes opt inout opt type inout opt element-nametype-annotation + +‌ element-name → identifier + +###元组类型语法 元组类型 → ( 元组类型主体 可选 ) 元组类型主体 → 元组类型的元素列表 ... 可选 元组类型的元素列表 → 元组类型的元素 | 元组类型的元素 , 元组类型的元素列表 -元组类型的元素 → 属性列表 可选 inout 可选 类型 | inout 可选 元素名 类型注解 +元组类型的元素 → 属性列表 可选 **inout** 可选 类型 | **inout** 可选 元素名 类型注解 元素名 → 标识符 -####函数类型语法 +###GRAMMAR OF A FUNCTION TYPE + +‌ function-type → type->type + +###函数类型语法 函数类型 → 类型 → 类型 -####数组类型语法 -数组类型 → 类型 [ ] | 数组类型 [ ] -####可选类型语法 -可选类型 → 类型 ? -隐式解析可选类型(Implicitly Unwrapped Optional Type)语法 +###GRAMMAR OF AN ARRAY TYPE + +‌ array-type → type | array-type +###数组类型语法 +数组类型 → 类型** [ ]** 数组类型 **[ ]** + +###GRAMMAR OF AN OPTIONAL TYPE + +‌ optional-type → type ? + +###可选类型语法 +可选类型 → 类型 **?** + +###GRAMMAR OF AN IMPLICITLY UNWRAPPED OPTIONAL TYPE + +‌ implicitly-unwrapped-optional-type → type ! + +###隐式解析可选类型语法 隐式解析可选类型 → 类型 ! -####协议合成类型语法 -协议合成类型 → protocol < 协议标识符列表 可选 > +###GRAMMAR OF A PROTOCOL COMPOSITION TYPE + +‌ protocol-composition-type → protocol +‌ + protocol-identifier-list → protocol-identifier protocol-identifier,protocol-identifier-list + +‌ protocol-identifier → type-identifier + +###协议合成类型语法 +协议合成类型 → **protocol** < 协议标识符列表 可选 > 协议标识符列表 → 协议标识符 | 协议标识符 , 协议标识符列表 协议标识符 → 类型标识 -####元类型语法 -元类型 → 类型 . Type | 类型 . Protocol +###GRAMMAR OF A METATYPE TYPE + +‌ metatype-type → type.Type type.Protocol +###元类型语法 +元类型 → 类型 **.** **Type** | 类型 **.** **Protocol** + +###GRAMMAR OF A TYPE INHERITANCE CLAUSE + +‌ type-inheritance-clause → :type-inheritance-list + +‌ type-inheritance-list → type-identifier | type-identifier,type-inheritance-list -####类型继承子句语法 +###类型继承子句语法 类型继承子句 → : 类型继承列表 类型继承列表 → 类型标识 | 类型标识 , 类型继承列表 From 7f21d6f342660a5d76457768f350d5be1b80c601 Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Thu, 3 Jul 2014 10:34:19 +0800 Subject: [PATCH 231/261] finish review 2_12 & add "computed propertie" to words.md --- src/chapter2/12_Subscripts.md | 2 +- src/words.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/chapter2/12_Subscripts.md b/src/chapter2/12_Subscripts.md index 719a184..de6f2e5 100644 --- a/src/chapter2/12_Subscripts.md +++ b/src/chapter2/12_Subscripts.md @@ -103,7 +103,7 @@ You can query the threeTimesTable instance by calling its subscript, as shown in > 提示 > -> TimesTable例子是基于一个固定的数学公式。它并不适合开放写权限来对threeTimesTable[someIndex]进行赋值操作,这也是为什么下标只定义为只读的原因。 +> TimesTable例子是基于一个固定的数学公式。它并不适合开放写权限来对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么下标只定义为只读的原因。 ## Subscript Usage ## 下标用法 diff --git a/src/words.md b/src/words.md index b43f4d7..17e4a8b 100644 --- a/src/words.md +++ b/src/words.md @@ -14,5 +14,6 @@ - literal value - 字面量 - A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below. - as described in - 详见 - You can provide a default value for a stored property as part of its definition, as described in Default Property Values. - access - 引用 - you can use the element names to access the values of those elements. +- computed propertie - 实例属性 - This behavior is communicated by a getter and setter in the same way as for computed properties: - example - 示例 - The example below defines a structure called FixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created From a3dfe6a8229635800cb8d883cea4aa34fde004c5 Mon Sep 17 00:00:00 2001 From: Henry Ge Date: Thu, 3 Jul 2014 11:16:05 +0800 Subject: [PATCH 232/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 907b55e..123cdd6 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ The Swift Programming Language 中文化项目 * 属性 [认领 by 隐若] [review by 姜天意] * 模式 [已完成 by 栖邀] [review by 紫溪] * 泛型参数 [认领 by 龙刚] [review by 墨峰] - * 语法总结 [认领 by 无独] + * 语法总结 [认领 by 无独] [review by 晗光] # 分工 * 西溪分会 10人 第一部分1-2章 第二部分1-8章 From 6b01c7a6993a3e8a025eac4e8a40ecf56130baca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=B1=B3=E5=B0=94?= Date: Thu, 3 Jul 2014 12:46:24 +0800 Subject: [PATCH 233/261] review --- src/chapter2/07_Closures.md | 196 +++++++++++++++++++----------------- 1 file changed, 104 insertions(+), 92 deletions(-) diff --git a/src/chapter2/07_Closures.md b/src/chapter2/07_Closures.md index d85fb6a..4f07c0a 100644 --- a/src/chapter2/07_Closures.md +++ b/src/chapter2/07_Closures.md @@ -2,15 +2,17 @@ Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages. -闭包是一个封闭的代码块,可以在你的程序中传递和使用。swift中的闭包跟objective-C和C语言中的block很类似,其他语言中的匿名函数也跟此相似。 +闭包是一个封闭的代码块,可以在你的程序中传递和使用。Swift中的闭包跟objective-C和C语言中的block很类似,其他语言中的匿名函数也跟此相似。 Closures can capture and store references to any constants and variables from the context in which they are defined. This is known as closing over those constants and variables, hence the name “closures”. Swift handles all of the memory management of capturing for you. -闭包可以将常量和变量从定义的地方通过捕获和指针引用保存起来,可以理解成将这些常量和变量封闭了起来,所以取名为“闭包”。swift会帮你处理所有闭包涉及的内存管理。 +在定义闭包的上下文环境中,闭包可以捕获和保存这个上下文环境中任何常量和变量的指针引用,可以理解成将这些常量和变量封闭了起来,所以取名为“闭包”。Swift会帮你处理所有闭包涉及的内存管理。 -> note: + +> Note: +> 注意: > Don’t worry if you are not familiar with the concept of “capturing”. It is explained in detail below in Capturing Values. -> 如果你还不是很熟悉“capturing”,这里有关于“capturing values”的细节。 +> 如果你还不是很熟悉“capturing”,下面有关于“capturing values”的细节。 Global and nested functions, as introduced in Functions, are actually special cases of closures. Closures take one of three forms: @@ -20,23 +22,23 @@ Global and nested functions, as introduced in Functions, are actually special ca * 全局函数是一种拥有函数名但是不会捕获任何值的闭包 * Nested functions are closures that have a name and can capture values from their enclosing function. -* 嵌套的函数是一种拥有函数名并且会捕获变量和常量得闭包 +* 嵌套的函数是一种拥有函数名并且会捕获外层函数中变量和常量的闭包 * Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context. * 闭包表达式是一种没有名字的闭包,他通过轻量简便的语法定义,可以从他们的上下文中捕获变量和常量 Swift’s closure expressions have a clean, clear style, with optimizations that encourage brief, clutter-free syntax in common scenarios. These optimizations include: -swift中的闭包表达式是一种非常简洁明了的语法,通过使用优化的闭包语法,使的一般场景中的代码显得非常的整洁,这些优化包含 +Swift中的闭包表达式是一种非常简洁明了的语法,通过使用优化的闭包语法,使得一般场景中的代码显得非常的整洁,这些优化包含 * Inferring parameter and return value types from context -* 从上下文中自动推断出返回值类型 +* 从上下文中自动推断出参数和返回值类型 * Implicit returns from single-expression closures * 单条语句的闭包自动获得隐式的返回 * Shorthand argument names -* 简化的参数名称(通过使用$0...$n来使用参数) +* 简化的参数名称(通过使用 $0...$n 来使用参数) * Trailing closure syntax * 返回类型后置语法(函数返回值类型位于函数声明的末端) @@ -45,43 +47,47 @@ swift中的闭包表达式是一种非常简洁明了的语法,通过使用优 Nested functions, as introduced in Nested Functions, are a convenient means of naming and defining self-contained blocks of code as part of a larger function. However, it is sometimes useful to write shorter versions of function-like constructs without a full declaration and name. This is particularly true when you work with functions that take other functions as one or more of their arguments. -嵌套的函数是一种自我包含的代码块,这是一种简单方便的方式,尤其在更大的函数中使用的时候。但是有时候通过一种更简洁的方式来定义函数会显得很实用,尤其在一些函数使用其他函数作为参数的时候。 +嵌套函数是一种在函数中独立的代码块,尤其在大型函数中,嵌套函数可以提供简便的命名和定义。但是有时候使用不带完整声明和命名的函数结构体会很实用,尤其在一些函数使用其他函数作为参数的时候。 Closure expressions are a way to write inline closures in a brief, focused syntax. Closure expressions provide several syntax optimizations for writing closures in their simplest form without loss of clarity or intent. The closure expression examples below illustrate these optimizations by refining a single example of the sort function over several iterations, each of which expresses the same functionality in a more succinct way. -     闭包表达式是一种简洁并且聚焦的方式来定义内联的闭包,闭包表达式提供几种优化过的语法来定义闭包,并且不会看起来有混淆和歧义。下面的闭包表达式例子定义一些简单的排序函数,每一种都通过更简洁明了的方式达到了同样的目的。 +闭包表达式是一种短小精悍的方式来定义内联的闭包,闭包表达式提供几种优化过的语法来定义闭包,并且不会看起来有混淆和歧义。下面的闭包表达式例子定义一些简单的排序函数,每一种都通过更简洁明了的方式达到了同样的目的。       ### The Sort Function 排序函数 Swift’s standard library provides a function called sort, which sorts an array of values of a known type, based on the output of a sorting closure that you provide. Once it completes the sorting process, the sort function returns a new array of the same type and size as the old one, with its elements in the correct sorted order. -     swift的标准库提供了一个函数叫做sort,通过你提供的排序闭包用来对数组中的元素进行排序。一旦完成排序,sort函数会返回一个跟以前类型和数量一样的数组,并且里面的元素都已经排列成正确的顺序。 +Swift 的标准库提供了一个函数叫做 sort,通过你提供的排序闭包用来对数组中的元素进行排序。一旦完成排序,sort 函数会返回一个跟以前类型和数量一样的数组,并且里面的元素都已经排列成正确的顺序。 The closure expression examples below use the sort function to sort an array of String values in reverse alphabetical order. Here’s the initial array to be sorted: -     下面的闭包表达式例子通过使用sort函数来对一个都是string类型的数组排序,数组的定义如下 +下面的闭包表达式例子通过使用sort函数来对一个都是 String 类型的数组排序,数组的定义如下: -```js -     let names = ["Chris","Alex","Ewa","Barry","Daniella"] +``` +let names = ["Chris","Alex","Ewa","Barry","Daniella"] ``` The sort function takes two arguments: -sort函数有2个参数 +sort 函数有2个参数 * An array of values of a known type. + +* 已知类型的数组 + * A closure that takes two arguments of the same type as the array’s contents, and returns a Bool value to say whether the first value should appear before or after the second value once the values are sorted. The sorting closure needs to return true if the first value should appear before the second value, and false otherwise. +* 这个闭包将两个相同类型的数组元素作为它的参数,然后返回一个布尔值用来表明,排序时第一个值是否应该排在第二个值的前面或者后面。如果第一个值应该出现在第二个值之前,这个闭包返回 true,否则返回 false。 This example is sorting an array of String values, and so the sorting closure needs to be a function of type (String, String) -> Bool. -这是一个对string类型的数组进行排序的例子,所以这个排序的闭包需要有以下类型(String,String) ->Bool. +这是一个对 String 类型的数组进行排序的例子,所以这个排序的闭包需要有以下类型 (String,String) ->Bool。 One way to provide the sorting closure is to write a normal function of the correct type, and to pass it in as the sort function’s second parameter: -函数名字加正确的类型是排序闭包的写法之一,然后在sort函数中作为第二个参数传入。 +函数名字加正确的类型是排序闭包的写法之一,然后在 sort 函数中作为第二个参数传入。 -```js +``` func backwards(s1:String,s2:String) -> Bool{ return s1>s2 } @@ -92,17 +98,17 @@ var reversed = sort(names,backwards) If the first string (s1) is greater than the second string (s2), the backwards function will return true, indicating that s1 should appear before s2 in the sorted array. For characters in strings, “greater than” means “appears later in the alphabet than”. This means that the letter "B" is “greater than” the letter "A", and the string "Tom" is greater than the string "Tim". This gives a reverse alphabetical sort, with "Barry" being placed before "Alex", and so on. -如果第一个字符串s1比第二个字符串s2比较值更大,函数backwards会返回true,这样在排序之后的数组中s1应该会排在s2之前,对于在字符串中的字符来说,“值大于”等于“在字符表中出现的更晚”,这意味着字符”B“比字符”A“的值更大,所以字符串”Tom“会比”Tim“更大。这个排序将会把字符表倒序排列,所以”Barry“会放在”Alex"之前。 +如果第一个字符串 s1 比第二个字符串 s2 比较值更大,函数 backwards 会返回 true,这样在排序之后的数组中 s1 应该会排在 s2 之前,对于在字符串中的字符来说,“值大于”等于“在字符表中出现的更晚”,这意味着字符”B“比字符”A“的值更大,所以字符串”Tom“会比 ”Tim“ 更大。这个排序将会把字符表倒序排列,所以 “Barry” 会放在 “Alex” 之前。 However, this is a rather long-winded way to write what is essentially a single-expression function (a > b). In this example, it would be preferable to write the sorting closure inline, using closure expression syntax. -然而这么繁重的写法在本质上只是一个表达式:a>b.在下面的例子里,使用闭包表达式写排序内联的闭包将会是更好的方式 +然而这么繁重的写法在本质上只是一个表达式:a>b。在下面的例子里,使用闭包表达式写排序内联的闭包将会是更好的方式。 ### Closure Expression Syntax 闭包表达式语法 Closure expression syntax has the following general form: -比表表达式语法定义如下: +闭包表达式语法定义如下: { (parameters) -> return type in statements @@ -114,43 +120,43 @@ Closure expression syntax has the following general form: Closure expression syntax can use constant parameters, variable parameters, and inout parameters. Default values cannot be provided. Variadic parameters can be used if you name the variadic parameter and place it last in the parameter list. Tuples can also be used as parameter types and return types. -闭包表达式语法可以使用常量,变量还有inout来作为参数,不能提供缺省参数,如果你要使用可选参数可以将它们定义在参数列表的结尾,tuples可以作为参数和返回值类型。 +闭包表达式语法可以使用常量,变量还有 inout 来作为参数,不能提供缺省参数,如果你要使用可选参数可以将它们定义在参数列表的结尾,tuples 可以作为参数和返回值类型。 The example below shows a closure expression version of the backwards function from earlier: -下面的例子是闭包表达式版本的backwords排序函数: +下面的例子是闭包表达式版本的 backwords 排序函数: -```js +``` reversed = sort(names,{(s1:String,s2:String) -> Bool in  return s1>s2}) ``` Note that the declaration of parameters and return type for this inline closure is identical to the declaration from the backwards function. In both cases, it is written as (s1: String, s2: String) -> Bool. However, for the inline closure expression, the parameters and return type are written inside the curly braces, not outside of them. -在这个表达式的定义和返回值类型跟前面的backwords函数完全相同,在这两个例子中,都是这样写的(s1:String,s2:String)->Bool,然而对于内联的闭包表达式,参数和返回值类型都写在大括号里面。 +在这个表达式的定义和返回值类型跟前面的 backwords 函数完全相同,在这两个例子中,都是这样写的(s1:String,s2:String)->Bool,然而对于内联的闭包表达式,参数和返回值类型都写在大括号里面。 The start of the closure’s body is introduced by the in keyword. This keyword indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin. -闭包语句的书写在关键字in之后,这个关键字表明的意思是:闭包表达式的参数和返回值类型已经定义结束,闭包的语句可以开始书写了。 +闭包语句的书写在关键字 in 之后,这个关键字表明的意思是:闭包表达式的参数和返回值类型已经定义结束,闭包的语句可以开始书写了。 Because the body of the closure is so short, it can even be written on a single line: 因为这个闭包的语句太短了,所以可以写在一行之内 -```js +``` reversed = sort(name,{(s1:String,s2:String) -> Bool in return s1 > s2 }) ``` This illustrates that the overall call to the sort function has remained the same. A pair of parentheses still wrap the entire set of arguments for the function. However, one of those arguments is now an inline closure. -这个表达式在sort函数中跟前面的例子得到的效果是完全一样的,一对圆括号包含了函数中所有的参数集。 +这个表达式在 sort 函数中跟前面的例子得到的效果是完全一样的,一对圆括号包含了函数中所有的参数集。 ### Inferring Type From Context 上下文推断返回值类型 Because the sorting closure is passed as an argument to a function, Swift can infer the types of its parameters and the type of the value it returns from the type of the sort function’s second parameter. This parameter is expecting a function of type (String, String) -> Bool. This means that the String, String, and Bool types do not need to be written as part of the closure expression’s definition. Because all of the types can be inferred, the return arrow (->) and the parentheses around the names of the parameters can also be omitted: -由于排序的闭包是作为函数的参数传入的,swift会根据sort函数的第二的参数类型来推断其参数参数和返回值的类型。这个参数期望的函数类型为(String,String)->Bool,这意味着String,String和BOOL类型并不强制需要在写闭包表达式里,因为所有类型都可以推断,返回的箭头->和他周围的参数名字都可以被省略 +由于排序的闭包是作为函数的参数传入的,Swift 会根据 sort 函数的第二个参数类型来推断其闭包参数和返回值的类型。这个参数期望的函数类型为 (String,String)->Bool,这意味着 String、 String 和BOOL类型并不强制需要在写闭包表达式里,因为所有类型都可以推断,返回的箭头 -> 和他周围的参数名字都可以被省略 -```js +```      reversed = sort(names,{s1,s2 in return s1 > s2)}) ``` @@ -160,48 +166,48 @@ It is always possible to infer parameter types and return type when passing a cl Nonetheless, you can make the types explicit if you wish, and doing so is encouraged if it avoids ambiguity for readers of your code. In the case of the sort function, the purpose of the closure is clear from the fact that sorting is taking place, and it is safe for a reader to assume that the closure is likely to be working with String values, because it is assisting with the sorting of an array of strings. -虽然如此,如果你愿意你可以明确的写出参数的类型,这样可以让你的代码阅读起来能减少歧义。 +虽然如此,如果你愿意你可以明确的写出参数的类型,这样可以让你的代码阅读起来能减少歧义。在排序的例子中,由于这个例子是用来给字符串数组排序的,这就使得这个闭包的目的很明显,而且对读者来说也很容易的就想到这个闭包是用来处理字符串的。 ### Implicit Returns from Single-Expression Closures 单表达式的隐式返回值 Single-expression closures can implicitly return the result of their single expression by omitting the return keyword from their declaration, as in this version of the previous example: -     单表达式的返回值可以通过隐藏return关键字来隐式返回结果,上面的表达式可以写成: +单表达式的返回值可以通过隐藏 return 关键字来隐式返回结果,上面的表达式可以写成: -```js -     reversed = sort(names,{s1,s2 in s1 > s2}) +``` +reversed = sort(names,{s1,s2 in s1 > s2}) ``` Here, the function type of the sort function’s second argument makes it clear that a Bool value must be returned by the closure. Because the closure’s body contains a single expression (s1 > s2) that returns a Bool value, there is no ambiguity, and the return keyword can be omitted. -    这个例子里面,sort的第二个参数类型定义了闭包的返回值是BOOL类型,而且闭包表达式中只包含了一个表达式 (s1 >s2)而且这个表达式返回BOOL类型,所以这里省略掉return没有歧义。 +这个例子里面,sort 的第二个参数类型定义了闭包的返回值是BOOL类型,而且闭包表达式中只包含了一个表达式 (s1 >s2)而且这个表达式返回 BOOL 类型,所以这里可以省略掉 return,并且不会产生歧义。 ### Shorthand Argument Names 参数名的缩写 Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on. -swift里为内联的参数提供了参数的缩写功能,你可以通过$0,$1,$2来调用闭包的参数。 +Swift 里为内联的参数提供了参数的缩写功能,你可以通过 $0,$1,$2 来调用闭包的参数。 If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body: -如果你在闭包表达式中使用参数名称的缩写,在闭包参数列表中就可以省略对其的定义,对应参数的类型将会通过函数参数的定义来推断,in关键字也可以被忽略掉: +如果你在闭包表达式中使用参数名称的缩写,在闭包参数列表中就可以省略对其的定义,对应参数的类型将会通过函数参数的定义来推断,in 关键字也可以被忽略掉: -```js -     reversed = sort(name,{$0>$1} ) +``` +reversed = sort(name,{$0>$1} ) ``` Here, $0 and $1 refer to the closure’s first and second String arguments. - 这个例子中,$0和$1表示闭包中的第一和第二个参数 +这个例子中,$0 和 $1 表示闭包中的第一和第二个参数 ### Operator Functions 运算符函数 There’s actually an even shorter way to write the closure expression above. Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a function that has two parameters of type String, and returns a value of type Bool. This exactly matches the function type needed for the sort function’s second parameter. Therefore, you can simply pass in the greater-than operator, and Swift will infer that you want to use its string-specific implementation: -实际上还有更精简的方式来书写上面的闭包表达式,swift的String类型对于大于号(>)做了特别的实现,作为函数接受两个String类型的参数,返回值是BOOL类型,刚好满足sort函数中第二个参数的函数类型定义,所以,你可以简单的将大于运算法传递进去,swift会推断你需要使用这个String的运算符函数 +实际上还有更精简的方式来书写上面的闭包表达式,Swift 的 String 类型对于大于号(>)做了运算符的扩展,作为函数接受两个 String 类型的参数,返回值是 BOOL 类型,刚好满足 sort 函数中第二个参数的函数类型定义,所以,你可以简单的将大于运算法传递进去,Swift会推断你需要使用这个 String 的运算符函数 -```js -     reversed = sort(names,>) +``` +reversed = sort(names,>) ``` For more about operator functions, see Operator Functions. @@ -214,7 +220,7 @@ If you need to pass a closure expression to a function as the function’s final 如果你需要将一个闭包表达式作为一个函数的最后一个参数传入,使用跟尾闭包的写法会更有可读性,尾闭包表达式全部写在函数最后的括号中。 -```js +``` func someFunctionThatTakesAClosure(closure: () -> ()) {     // function body goes here } @@ -231,33 +237,34 @@ someFunctionThatTakesAClosure() {     // trailing closure's body goes here } -```js +``` +> Note: > 注意: > If a closure expression is provided as the function’s only argument and you provide that expression as a trailing closure, you do not need to write a pair of parentheses () after the function’s name when you call the function. > 如果函数只有闭包表达式这一个参数,你可以在使用跟尾闭包的时候把()省略掉。 The string-sorting closure from the Closure Expression Syntax section above can be written outside of the sort function’s parentheses as a trailing closure: -上面的sort函数可以改写为 +上面的 sort 函数可以改写为 -```js -     reversed = sort(name){$0>$1} +``` +reversed = sort(name){$0>$1} ``` Trailing closures are most useful when the closure is sufficiently long that it is not possible to write it inline on a single line. As an example, Swift’s Array type has a map method which takes a closure expression as its single argument. The closure is called once for each item in the array, and returns an alternative mapped value (possibly of some other type) for that item. The nature of the mapping and the type of the returned value is left up to the closure to specify. -跟尾闭包的写法在一些闭包包体逻辑非常长的时候很有用,例如,swift中的array类型有一个map的方法,这个方法只需要一个闭包表达式作为其参数,这个闭包会对数组中每一个元素调用一次,然后返回该函数映射的值(也可能是不同的类型),具体的映射方式和返回值由闭包中的逻辑决定。 +跟尾闭包的写法在一些闭包包体逻辑非常长的时候很有用,例如,Swift 中的 array 类型有一个 map 的方法,这个方法只需要一个闭包表达式作为其参数,这个闭包会对数组中每一个元素调用一次,然后返回该函数映射的值(也可能是不同的类型),具体的映射方式和返回值由闭包中的逻辑决定。 After applying the provided closure to each array element, the map method returns a new array containing all of the new mapped values, in the same order as their corresponding values in the original array. -     当提供数组闭包函数之后,map方法将返回一个新的数组,数组中包含了与原数组一一对应的值 +将数组闭包函数应用到数组每个元素之后,map 方法将返回一个新的数组,数组中包含了与原数组一一对应的值 Here’s how you can use the map method with a trailing closure to convert an array of Int values into an array of String values. The array [16, 58, 510] is used to create the new array ["OneSix", "FiveEight", "FiveOneZero"]: -    在下面的例子中,你可以使用map函数和跟尾闭包来降数组中的Int值转换成String值。数组[16,58,510]用来创建新的数组[“OneSix”,”FiveEigh”,”FiveOneZero”]: +在下面的例子中,你可以使用map函数和跟尾闭包来降数组中的 Int 值转换成 String 值。数组 [16,58,510] 用来创建新的数组 [“OneSix”,”FiveEigh”,”FiveOneZero”]: -```js +``` let digitNames = [     0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",     5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine" @@ -270,9 +277,9 @@ The code above creates a dictionary of mappings between the integer digits and E You can now use the numbers array to create an array of String values, by passing a closure expression to the array’s map method as a trailing closure. Note that the call to numbers.map does not need to include any parentheses after map, because the map method has only one parameter, and that parameter is provided as a trailing closure: -现在你可以使用numers数组来创建一个对应的字符串数组,将一个闭包表达式作为跟尾闭包传递进数组的map函数,在写numbers.map方法的后面不需要添加括号,因为map方法只有一个参数,这个参数已经作为跟尾闭包的形式提供了 +现在你可以使用 numbers 数组来创建一个对应的字符串数组,将一个闭包表达式作为跟尾闭包传递进数组的 map 函数,在写 numbers。map 方法的后面不需要添加括号,因为 map 方法只有一个参数,这个参数已经作为跟尾闭包的形式提供了: -```js +``` let strings = numbers.map {     (var number) -> String in     var output = "" @@ -288,31 +295,32 @@ let strings = numbers.map { The map function calls the closure expression once for each item in the array. You do not need to specify the type of the closure’s input parameter, number, because the type can be inferred from the values in the array to be mapped. -map函数将会对数组中的每一个元素调用一次闭包表达式,你不需要制定闭包表达式的输入参数类型,number,因为这个类型可以通过数组中元素的类型来进行推断。 +map 函数将会对数组中的每一个元素调用一次闭包表达式,你不需要制定闭包表达式的输入参数类型,number,因为这个类型可以通过数组中元素的类型来进行推断。 In this example, the closure’s number parameter is defined as a variable parameter, as described in Constant and Variable Parameters, so that the parameter’s value can be modified within the closure body, rather than declaring a new local variable and assigning the passed number value to it. The closure expression also specifies a return type of String, to indicate the type that will be stored in the mapped output array. -这个例子中,闭包中的number参数定义成变量参数(具体参见constans and variable parameters),所以这个参数的值可以在闭包内进行修改。闭包表达式指定了返回值类型为String,表明存储应映射值的新数组类型为String +这个例子中,闭包中的 number 参数定义成变量参数(具体参见constans and variable parameters),所以这个参数的值可以在闭包内进行修改。闭包表达式指定了返回值类型为 String,表明存储应映射值的新数组类型为 String The closure expression builds a string called output each time it is called. It calculates the last digit of number by using the remainder operator (number % 10), and uses this digit to look up an appropriate string in the digitNames dictionary. -上面的闭包表达式每次被调用的时候创建了一个字符串返回,使用取余运算(number%10)计算最后一位数字并且利用digitNames字段获取对应的字符串。 +上面的闭包表达式每次被调用的时候创建了一个字符串返回,使用取余运算(number % 10) 计算最后一位数字并且用这个数字在 digitNames 字典中查找对应的字符串。 +> Note: > 注意: > The call to the digitNames dictionary’s subscript is followed by an exclamation mark (!), because dictionary subscripts return an optional value to indicate that the dictionary lookup can fail if the key does not exist. In the example above, it is guaranteed that number % 10 will always be a valid subscript key for the digitNames dictionary, and so an exclamation mark is used to force-unwrap the String value stored in the subscript’s optional return value. -> 字典digitNames的下表之后跟着一个惊叹号(!),因为字典下标返回了一个可选值,表明该Key对应的返回值可能不存在,在上面的例子中,number%10保证了在字典中总会有值对应,因此惊叹号强制取出存储在下表中的String类型 +> 字典 digitNames 的下标之后跟着一个惊叹号(!),因为字典下标返回了一个可选值,表明该 Key 对应的返回值可能不存在,在上面的例子中,number % 10 保证了在字典中总会有值对应,因此惊叹号强制取出存储在下标中的 String 类型的值 The string retrieved from the digitNames dictionary is added to the front of output, effectively building a string version of the number in reverse. (The expression number % 10 gives a value of 6 for 16, 8 for 58, and 0 for 510.) -从digitNames字段中获取的字符串添加进输出的前部,逆序的建立了一个字符串的数组版本。(再表达式number%10中,如果number为16,则返回6,58则返回8,510返回0) +从 digitNames 字典中获取的字符串添加进输出的前部,逆序的建立了一个字符串的数组版本。(在表达式 number % 10 中,如果 number 为16,则返回6,58则返回8,510返回0) The number variable is then divided by 10. Because it is an integer, it is rounded down during the division, so 16 becomes 1, 58 becomes 5, and 510 becomes 51. -number变量之后除以10,因为是整数,再计算过程中未除尽的部分会被忽略,因此16变成1,58变成5,510变成了51 +number 变量之后除以10,因为是整数,在计算过程中未除尽的部分会被忽略,因此16变成1,58变成5,510变成了51 The process is repeated until number /= 10 is equal to 0, at which point the output string is returned by the closure, and is added to the output array by the map function. -将整个过程重复,知道number/10变成0,这时闭包会将字符串输出,而map函数则将返回的字符串添加进一个新的映射数组中。 +将整个过程重复,直到 number / 10 变成 0,这时闭包会将字符串输出,而 map 函数则将返回的字符串添加进一个新的映射数组中。 The use of trailing closure syntax in the example above neatly encapsulates the closure’s functionality immediately after the function that closure supports, without needing to wrap the entire closure within the map function’s outer parentheses. @@ -322,46 +330,48 @@ The use of trailing closure syntax in the example above neatly encapsulates the A closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists. -     闭包可以从变量和常量定义的上下文中捕获他们的值,即使定义他们的域已经不存在了,闭包仍然可以访问和改变他们的值 +闭包可以从变量和常量定义的上下文中捕获他们的值,即使定义他们的域已经不存在了,闭包仍然可以访问和改变他们的值 The simplest form of a closure in Swift is a nested function, written within the body of another function. A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function. -     swift中嵌套函数是闭包最简形式,嵌套函数是定义在其他函数中的函数,它可以捕获外部函数中的所有参数和定义的常量和变量 +Swift 中嵌套函数是闭包最简形式,嵌套函数是定义在其他函数中的函数,它可以捕获外部函数中的所有参数和定义的常量和变量 Here’s an example of a function called makeIncrementor, which contains a nested function called incrementor. The nested incrementor function captures two values, runningTotal and amount, from its surrounding context. After capturing these values, incrementor is returned by makeIncrementor as a closure that increments runningTotal by amount each time it is called. -     这面的makeIncrementor的函数,包含了一个叫做incrementor的嵌套函数,嵌套函数incrementor从上下文中捕获了两个值,runningTotal和amount。之后makeIncrementor将incrementor作为闭包返回,每次调用incrementor时,都会以amount作为增量来增加runningTotal的值 +这里有一个 makeIncrementor 函数的例子,包含了一个叫做 incrementor 的嵌套函数,嵌套函数 incrementor 从上下文中捕获了两个值,runningTotal 和 amount。之后 makeIncrementor 将 incrementor 作为闭包返回,每次调用 incrementor 时,都会以 amount 作为增量来增加 runningTotal 的值 -```js +``` func makeIncrementor(forIncrement amount: Int) -> () -> Int { -var runningTotal = 0 -func incrementor() -> Int { -runningTotal += amount -return runningTotal -} -return incrementor + var runningTotal = 0 + func incrementor() -> Int { + runningTotal += amount + return runningTotal + } + return incrementor } ``` The return type of makeIncrementor is () -> Int. This means that it returns a function, rather than a simple value. The function it returns has no parameters, and returns an Int value each time it is called. To learn how functions can return other functions, see Function Types as Return Types. -makeIncrementor的返回值类型是()->Int,这表示返回一个函数。这个返回的函数没有其他参数并且每次调用都返回一个Int类型的值。要学习如何在函数中返回其他函数,参见Function Types as Return Types +makeIncrementor 的返回值类型是 () -> Int,这表示返回一个函数。这个返回的函数没有其他参数并且每次调用都返回一个 Int 类型的值。要学习如何在函数中返回其他函数,参见Function Types as Return Types The makeIncrementor function defines an integer variable called runningTotal, to store the current running total of the incrementor that will be returned. This variable is initialized with a value of 0. -makeIncrementor函数定义了一个整形变量叫做runningTotal.这个变量存储了当前函数的返回值,并且初始化为0. +makeIncrementor 函数定义了一个整形变量叫做 runningTotal。这个变量存储了当前函数的返回值,并且初始化为0。 The makeIncrementor function has a single Int parameter with an external name of forIncrement, and a local name of amount. The argument value passed to this parameter specifies how much runningTotal should be incremented by each time the returned incrementor function is called. +makeIncrementor 函数有一个单独的 Int 类型的变量,外部名称为 forIncrement,内部名称为 amount。这个参数的值用来表明,每次 incrementor 函数执行的时候,runningTotal 应该增加多少值。 + makeIncrementor defines a nested function called incrementor, which performs the actual incrementing. This function simply adds amount to runningTotal, and returns the result. -makeIncrementor定义了一个内嵌函数叫做incrementor,这个函数执行真正的递增逻辑。在这个函数中将amount的值增加到runningTotal中,然后返回它的值。 +makeIncrementor 定义了一个内嵌函数叫做 incrementor,这个函数执行真正的递增逻辑。在这个函数中将 amount 的值增加到 runningTotal 中,然后返回它的值。 When considered in isolation, the nested incrementor function might seem unusual: -如果单独拿出来看,内嵌函数incrementor看上起会有点奇怪 +如果单独拿出来看,内嵌函数 incrementor 看上起会有点奇怪: -```js +``` func incrementor() -> Int { runningTotal += amount return runningTotal @@ -370,33 +380,34 @@ func incrementor() -> Int { The incrementor function doesn’t have any parameters, and yet it refers to runningTotal and amount from within its function body. It does this by capturing the existing values of runningTotal and amount from its surrounding function and using them within its own function body. -Intrementor函数没有任何参数,他引用的变量runningTotal和amouint来自包含它的函数体,通过捕获外部环境中的变量来实现上面例子中的效果。 +intrementor 函数没有任何参数,他引用的变量 runningTotal 和 amouint 来自包含它的函数体,通过捕获外部环境中的变量来实现上面例子中的效果。 Because it does not modify amount, incrementor actually captures and stores a copy of the value stored in amount. This value is stored along with the new incrementor function. -因为没有修改amount参数,incrementor函数实际上是捕获和存储了一个amount的副本,这个值incrementor函数一起存储了起来。 +因为没有修改 amount 参数,incrementor 函数实际上是捕获和存储了一个 amount 的副本,这个值和 incrementor 函数一起存储了起来。 However, because it modifies the runningTotal variable each time it is called, incrementor captures a reference to the current runningTotal variable, and not just a copy of its initial value. Capturing a reference ensures sure that runningTotal does not disappear when the call to makeIncrementor ends, and ensures that runningTotal will continue to be available the next time that the incrementor function is called. -然后,因为它每次调用的时候都修改了runningTotal变量,incrementor捕获了一个指向当前runningTotal变量的引用,不单单只是拷贝了他的初始值。捕获一个引用确保了runningTotal变量不会在makeIncrementor调用结束的时候消失掉,而且确保变量runningTotal在下一次调用的时候也依然可以访问。 +然后,因为它每次调用的时候都修改了 runningTotal 变量,incrementor 捕获了一个指向当前 runningTotal 变量的引用,不单单只是拷贝了他的初始值。捕获一个变量的引用,可以确保 runningTotal 变量不会在 makeIncrementor 调用结束的时候消失掉,而且确保变量 runningTotal 在下一次调用的时候也依然可以访问。 +> Note: > 注意: > Swift determines what should be captured by reference and what should be copied by value. You don’t need to annotate amount or runningTotal to say that they can be used within the nested incrementor function. Swift also handles all memory management involved in disposing of runningTotal when it is no longer needed by the incrementor function. ->      swift会决定对一个值是保存它的拷贝还是引用。你不需要声明amount和runningTotal他们会在incrementor内嵌函数中使用。swift也会处理所有的内存管理,当runningTotal不再需要的时候会将它释放掉。 +> Swift 会决定对一个值是保存它的拷贝还是引用。你不需要声明 amount 和 runningTotal 他们会在incrementor内嵌函数中使用。Swift 也会处理所有的内存管理,当 runningTotal 不再需要的时候会将它释放掉。 Here’s an example of makeIncrementor in action: -这里是makeIncrementor的一个例子 +这里是 makeIncrementor 的一个例子: -```js +``` let incrementByTen = makeIncrementor(forIncrement: 10) ``` This example sets a constant called incrementByTen to refer to an incrementor function that adds 10 to its runningTotal variable each time it is called. Calling the function multiple times shows this behavior in action: -这个例子将一个叫做incrementByTen的常量保存10与runningTotal变量每次想加的引用。调用函数多次来查看结果: +这个例子将一个叫做 incrementByTen 的常量保存10与 runningTotal 变量每次想加的引用。调用函数多次来查看结果: -```js +``` incrementByTen() // returns a value of 10 incrementByTen() @@ -407,9 +418,9 @@ incrementByTen() If you create another incrementor, it will have its own stored reference to a new, separate runningTotal variable. In the example below, incrementBySeven captures a reference to a new runningTotal variable, and this variable is unconnected to the one captured by incrementByTen: -如果你创建另外一个incrementor,它会有一个新的引用于之前的runningTotal完全分离,下面这个例子里面incrementBySeven捕获了一个新的runningTotal变量,这个变量跟incrementByTen捕获的没有任何联系 +如果你创建另外一个 incrementor,它会有一个新的引用与之前的 runningTotal 完全分离,下面这个例子里面 incrementBySeven 捕获了一个新的 runningTotal 变量,这个变量跟 incrementByTen 捕获的没有任何联系 -```js +``` let incrementBySeven = makeIncrementor(forIncrement: 7) incrementBySeven() // returns a value of 7 @@ -417,25 +428,26 @@ incrementByTen() // returns a value of 40 ``` -> 注意 +> Note: +> 注意: > If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles. For more information, see Strong Reference Cycles for Closures. ->      如果你在闭包里访问了一个类实例的属性,闭包会捕获这个实例或者成员函数的引用,你会创建一个互相强引用的环,swift使用捕获列表来打破这个互相引用的环,详情请看Strong Reference Cycles for Closures. +> 如果你在闭包里访问了一个类实例的属性,闭包会捕获这个实例或者成员函数的引用,你会创建一个互相强引用的环,Swift 使用捕获列表来打破这个互相引用的环,详情请看 Strong Reference Cycles for Closures. ## Closures Are Reference Types 闭包都是引用类型 In the example above, incrementBySeven and incrementByTen are constants, but the closures these constants refer to are still able to increment the runningTotal variables that they have captured. This is because functions and closures are reference types. -     上面的例子里面incrementBySeven和incrementByTen都是常量,但是这些常量引用的闭包仍然可以增加他们捕获的runningTotal变量的值,这是因为函数和闭包都是引用类型。 +上面的例子里面 incrementBySeven 和 incrementByTen 都是常量,但是这些常量引用的闭包仍然可以增加他们捕获的 runningTotal 变量的值,这是因为函数和闭包都是引用类型。 Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure. In the example above, it is the choice of closure that incrementByTen refers to that is constant, and not the contents of the closure itself. -     任何时候当你将一个函数或者闭包赋值给一个常量或者变量,实际上你将这个闭包的引用设置给了这个常量或者变量。上面的例子中,变成常量的是这个闭包的引用,而不是只它的包体内包含的内容。 +任何时候当你将一个函数或者闭包赋值给一个常量或者变量,实际上你将这个闭包的引用设置给了这个常量或者变量。上面的例子中,变成常量的是这个闭包的引用,而不是它的闭包体内包含的内容。 This also means that if you assign a closure to two different constants or variables, both of those constants or variables will refer to the same closure: -     这意味着如果你将一个闭包赋值给两个不同的变量和常量,他们都会指向同一个闭包 +这意味着如果你将一个闭包赋值给两个不同的变量和常量,他们都会指向同一个闭包 -```js +```        let alsoIncrementByTen = incrementByTen                alsoIncrementByTen()                // returns a value of 50 From 82d3800c3a438413062a0117b2001b339d12d966 Mon Sep 17 00:00:00 2001 From: mofengfly Date: Thu, 3 Jul 2014 15:58:21 +0800 Subject: [PATCH 234/261] Update 09_Generic_Parameters_and_Arguments.md --- .../09_Generic_Parameters_and_Arguments.md | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/chapter3/09_Generic_Parameters_and_Arguments.md b/src/chapter3/09_Generic_Parameters_and_Arguments.md index 75d23da..76e375a 100644 --- a/src/chapter3/09_Generic_Parameters_and_Arguments.md +++ b/src/chapter3/09_Generic_Parameters_and_Arguments.md @@ -4,18 +4,18 @@ This chapter describes parameters and arguments for generic types, functions, and initializers. When you declare a generic type, function, or initializer, you specify the type parameters that the generic type, function, or initializer can work with. These type parameters act as placeholders that are replaced by actual concrete type arguments when an instance of a generic type is created or a generic function or initializer is called. -本章节介绍泛型类型、函数、初始构造器的参数。当你在声明泛型类型、函数或者初始化构造器时,你指定了它们能够使用的类型参数。这些类型参数起到了占位符的作用,在泛型类型的实例创建或者泛型方法、初始化构造器调用时,它们会被替换为实际的参数。 +本章节介绍泛型类型、函数、初始构造器的参数。当你在声明泛型类型、函数或者初始化构造器时,你指定了它们能够使用的类型参数。这些类型参数起到了占位符的作用,在泛型类型的实例创建或者泛型方法、初始化构造器调用时在创建泛型类型的实例或者调用泛型方法、初始化构造器时,它们会被替换为实际的参数。 For an overview of generics in Swift, see [Generics](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-XID_234). -关于Swift泛型的概述,可以详见[泛型](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-XID_234)。 +关于Swift泛型的概述,可以详见[泛型](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-XID_234)。 ## Generic Parameter Clause ## 泛型形参句式 A generic parameter clause specifies the type parameters of a generic type or function, along with any associated constraints and requirements on those parameters. A generic parameter clause is enclosed in angle brackets (<>) and has one of the following forms: -泛型参数句式指定了泛型类型或函数的参数类型,以及与这些参数相关的约束、依赖条件。泛型参数句式的内容用一对尖括号包围,并且是以下形式中的一种: +泛型参数句式指定了泛型类型或函数的参数类型,以及与这些参数相关的约束、依赖条件。泛型参数句式的内容用一对尖括号(<>)包围,并且是以下形式中的一种: ``` @@ -32,9 +32,12 @@ A generic parameter consists of a type parameter followed by an optional constra 泛型参数由类型形参组成,紧跟其后的是是一个可选的约束条件。类型形参只是一个占位符类型的名称(比如:T、U、V、KeyType、ValueType等)。You have access to the type parameters (and any of their associated types) in the rest of the type, function, or initializer declaration, including in the signature of the function or initializer. +reviewer注: 泛型参数由类型形参组成,紧跟其后的是是一个可选的约束条件。类型形参只是一个占位符类型的名称(比如:T、U、V、KeyType、ValueTyp等等)。在类型,函数或者初始化构造器的其余部分以及函数或初始化构造器的签名里,都可以访问类型参数(还有它的任何相关类型)。 + + The constraint specifies that a type parameter inherits from a specific class or conforms to a protocol or protocol composition. For instance, in the generic function below, the generic parameter T: Comparable indicates that any type argument substituted for the type parameter T must conform to the Comparable protocol. -约束条件指定了类型形参是继承自特定的类、符合某个协议或者协议的组件部分。比如,在下面的泛型函数中,泛型形参T: Comparable表明替换泛型类型形参的任何类型实参都必须符合Comparable协议。 +约束条件指定了类型形参是继承自特定的类、符合某个协议或者协议的组件部分。比如,在下面的泛型函数中,泛型形参`T: Comparable`表明替换泛型类型形参的任何类型实参都必须符合`Comparable`协议。 ``` func simpleMin(x: T, y: T) -> T { @@ -47,7 +50,7 @@ func simpleMin(x: T, y: T) -> T { Because Int and Double, for example, both conform to the Comparable protocol, this function accepts arguments of either type. In contrast with generic types, you don’t specify a generic argument clause when you use a generic function or initializer. The type arguments are instead inferred from the type of the arguments passed to the function or initializer. -比如,Int与Double都符合Comparable协议,所以这个函数接受任意一种实参类型。与泛型类型形参相反的是,当使用泛型方式或者初始构造器时,无需指定泛型实参的句式,实参由传入函数或初始化构造器的实际类型推断得出。 +比如,`Int`与`Double`都符合`Comparable`协议,所以这个函数接受任意一种实参类型。与泛型类型形参相反的是相比,当使用泛型方式或者初始构造器时,无需指定泛型实参的句式,实参由传入函数或初始化构造器的实际类型推断得出。 ``` @@ -60,15 +63,15 @@ simpleMin(3.14159, 2.71828) // T被推断是Double You can specify additional requirements on type parameters and their associated types by including a where clause after the generic parameter list. A where clause consists of the keyword where, followed by a comma-separated list of one or more requirements. -通过在泛型形参列表之后引入where句式,在类型形参及相关的类型上定义额外的依赖条件。where句式由where关键字和紧随其后的由逗号分隔的一个或多个依赖条件组成。 +通过在泛型形参列表之后引入where句式,可以在类型形参及相关的类型上定义额外的依赖条件。`where`句 式由`where`关键字和紧随其后的由逗号分隔的一个或多个依赖条件组成。 The requirements in a where clause specify that a type parameter inherits from a class or conforms to a protocol or protocol composition. Although the where clause provides syntactic sugar for expressing simple constraints on type parameters (for instance, T: Comparable is equivalent to T where T: Comparable and so on), you can use it to provide more complex constraints on type parameters and their associated types. For instance, you can express the constraints that a generic type T inherits from a class C and conforms to a protocol P as . -where句式的依赖条件指定了类型形参是继承自特定的类、符合某个协议或者协议的组成部分。尽管where句式提供了语法糖来简化表达类型形参的约束条件(比如,T: Comparable等同于T where T: Comparable等),但仍可以在类型形参和相关类型上提供复杂的约束条件。比如:泛型类型T继承自类C且符合协议P可以表达为``````。 +`where`句式的依赖条件指定了类型形参是继承自特定的类、符合某个协议或者协议的组成部分。尽管`where`句式提供了语法糖来简化表达类型形参的约束条件(比如,`T: Comparable`等同于`T where T: Comparable`等),但仍可以在类型形参和相关类型上提供复杂的约束条件。比如:泛型类型T继承自类C且符合协议P可以表达为``````。 As mentioned above, you can constrain the associated types of type parameters to conform to protocols. For example, the generic parameter clause specifies that T conforms to the Generator protocol and the associated type of T, T.Element, conforms to the Equatable protocol (T has the associated type Element because Generator declares Element and T conforms to Generator). -如上所述,可以约束类型形参的相关类形符合特定的协议。比如:泛型参数句式``````指定了T符合Generator协议,且T的Element类型符合Equatable协议(T有关联系的Element类型是因为Generator协议声明了Element,而T符合Generator协议)。 +如上所述,可以约束类型形参的相关类形符合特定的协议。比如:泛型参数句式``````指定了T符合`Generator`协议,且T的Element类型符合Equatable协议(T有关联系的Element类型是因为Generator协议声明了Element,而T符合Generator协议)。 You can also specify the requirement that two types be identical, using the == operator. For example, the generic parameter clause expresses the constraints that T and U conform to the Generator protocol and that their associated types must be identical. 你也可以用```==```运符符指定两种类型完全相等的依赖条件。比如,泛型形参句式``````表明T和U符合Generator协议,并且他们关联的类型必须完全相等的约束条件。 @@ -77,7 +80,7 @@ Any type argument substituted for a type parameter must meet all the constraints 所有实参在替换类型形参时必须实现所有的约束和依赖条件。 You can overload a generic function or initializer by providing different constraints, requirements, or both on the type parameters in the generic parameter clause. When you call an overloaded generic function or initializer, the compiler uses these constraints to resolve which overloaded function or initializer to invoke. -通过在泛型参数句式中为类型形参定义不同的约束条件、依赖条件来实现泛型函数、初始化构造器的重载。当调用重载的泛型函数或初始化构造器时,编译器会使用这些约束条件来实现它们的调用。 +通过在泛型参数句式中为类型形参定义不同的约束条件、依赖条件可以实现泛型函数、初始化构造器的重载。当调用重载的泛型函数或初始化构造器时,编译器会使用这些约束条件来实现它们的调用。 You can subclass a generic class, but the subclass must also be a generic class. 泛型类可以子类化,但子类也必须是一个泛型类。 @@ -110,7 +113,7 @@ A generic argument clause specifies the type arguments of a generic type. A gene The generic argument list is a comma-separated list of type arguments. A type argument is the name of an actual concrete type that replaces a corresponding type parameter in the generic parameter clause of a generic type. The result is a specialized version of that generic type. As an example, the Swift standard library defines a generic dictionary type as: -泛型实参列表是由一组逗号分隔组成的类型实参组成。类型实参是泛型参数句式中替换对应类型形参的具体实参的名称。由此得到此泛型类形的一个特定配置。比如,Swift标准库定义泛型字典类型是这样实现的: +泛型实参列表是由一组逗号分隔组成的类型实参组成。类型实参是泛型参数句式中替换对应类型形参的具体实参的名称一个实际的具体类型的名称,它会替换在泛型类型形参对应的类型参数。由此得到此泛型类形的一个特定配置。比如,Swift标准库定义泛型字典类型是这样实现的: ``` struct Dictionary: Collection, DictionaryLiteralConvertible { From 5604acdec68dcdb4e1f708d15f8f7e6a71a71fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=7B=E5=AD=9F=E5=BF=97=E6=98=82=7D=28=7B071545=7D=29?= Date: Thu, 3 Jul 2014 20:35:01 +0800 Subject: [PATCH 235/261] =?UTF-8?q?=E5=AD=9F=E5=BF=97=E6=98=82=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../16_Automatic_Reference_Counting.md | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/chapter2/16_Automatic_Reference_Counting.md b/src/chapter2/16_Automatic_Reference_Counting.md index 2b71e9d..2f2ef4c 100644 --- a/src/chapter2/16_Automatic_Reference_Counting.md +++ b/src/chapter2/16_Automatic_Reference_Counting.md @@ -85,7 +85,7 @@ Note that the message "John Appleseed is being initialized" is printed at the po Because the new Person instance has been assigned to the reference1 variable, there is now a strong reference from reference1 to the new Person instance. Because there is at least one strong reference, ARC makes sure that this Person is kept in memory and is not deallocated. 由于该Person实例被赋值给了变量reference1,因此建立了一个由reference1指向该Person实例的强引用。 -ARC会保证该Person实例保持在内存中不被销毁,因为它这满足了至少有一个强引用的条件。 +因为至少有一个强引用,所以ARC会保证该Person实例保持在内存中不被销毁,。 If you assign the same Person instance to two more variables, two more strong references to that instance are established: @@ -110,7 +110,7 @@ reference3 = nil ``` ARC does not deallocate the Person instance until the third and final strong reference is broken, at which point it is clear that you are no longer using the Person instance: -直到第三个也是最后一个强引用断开,即能够清楚的断定你不再需要该实例的时候,ARC才会销毁该Person实例。 +直到第三个也是最后一个强引用断开,即你明确不再需要该实例的时候,ARC才会销毁该Person实例。 ``` reference3 = nil @@ -125,11 +125,11 @@ In the examples above, ARC is able to track the number of references to the new However, it is possible to write code in which an instance of a class never gets to a point where it has zero strong references. This can happen if two class instances hold a strong reference to each other, such that each instance keeps the other alive. This is known as a strong reference cycle. -然而,我们可能会写出这样的代码,导致类实例永远不会有0个强引用。这种情况发生在两个类实例互相保持对方的强引用,以致于彼此都无法被销毁的时候。这就是所谓的循环强引用。 +然而,我们可能会写出这样的代码,导致类实例永远不会有0个强引用。这种情况发生在两个类实例互相持有对方的强引用,以致于彼此都无法被销毁的时候。这就是所谓的循环强引用。 You resolve strong reference cycles by defining some of the relationships between classes as weak or unowned references instead of as strong references. This process is described in Resolving Strong Reference Cycles Between Class Instances. However, before you learn how to resolve a strong reference cycle, it is useful to understand how such a cycle is caused. -你可以通过定义类之间的关系为弱引用或者无主引用的方式来解决循环强引用的问题。具体过程将在“解决类实例之间的循环强引用”中详述。不管怎样,在学习怎样解决循环强引用之前,很有必要了解一下它是如何产生的。 +你可以通过定义类之间的关系为弱引用或者无主引用的方式来解决循环强引用的问题。具体过程将在[解决类实例之间的循环强引用]()中详述。不管怎样,在学习怎样解决循环强引用之前,很有必要了解一下它是如何产生的。 Here’s an example of how a strong reference cycle can be created by accident. This example defines two classes called Person and Apartment, which model a block of apartments and its residents: @@ -212,7 +212,7 @@ number73 = nil Note that neither deinitializer was called when you set these two variables to nil. The strong reference cycle prevents the Person and Apartment instances from ever being deallocated, causing a memory leak in your app. -需要注意的是,你将john和number73设为nil时两个析构函数都没有被调用。循环强引用阻止了Person 和 Apartment类实例的销毁,这在你的App中导致了内存泄漏。 +需要注意的是,你将john和number73设为nil时两个析构函数都没有被调用。循环强引用阻止了Person 和 Apartment类实例的销毁,导致你的App发生了一个内存泄漏。 Here’s how the strong references look after you set the john and number73 variables to nil: @@ -284,7 +284,7 @@ class Apartment { ``` The strong references from the two variables (john and number73) and the links between the two instances are created as before: -两个变量(john和number73)的强引用以及两个实例之间的连接都与之前一样被创建: +然后跟之前一样,创建两个变量(john和number73)之间的强引用,并关联两个实例: ``` var john: Person? @@ -344,7 +344,7 @@ Like weak references, an unowned reference does not keep a strong hold on the in Because an unowned reference is non-optional, you don’t need to unwrap the unowned reference each time it is used. An unowned reference can always be accessed directly. However, ARC cannot set the reference to nil when the instance it refers to is deallocated, because variables of a non-optional type cannot be set to nil. -由于无主引用是非可选类型的,你不必在使用的时候解析它,它可以被直接访问。与弱引用不同,当无主引用指向的实例被销毁后,ARC不会将其指向nil。 +由于无主引用是非可选类型的,你不必在使用的时候解析它,它可以被直接访问。不过 ARC 无法在实例被销毁后将无主引用设为nil,因为非可选类型的变量不允许被赋值为nil。 > NOTE > @@ -354,15 +354,15 @@ Because an unowned reference is non-optional, you don’t need to unwrap the uno > 注意 > 在无主引用指向的实例被销毁后,如果依然试图访问该无主引用,你会触发运行时错误。使用无主引用,你需要确保引用指向的实例未被销毁。 -> 需要格外注意的是,在无主引用指向的实例被销毁后,若你依然试图访问该无主引用,Swift保证,你的app会毫无意外地直接崩溃。不是应该而是你必须避免这样的情况发生。 +> 需要格外注意的是,在无主引用指向的实例被销毁后,若你依然试图访问该无主引用,Swift保证,你的app会毫无意外地直接崩溃,而不会发生无法预期的行为。所以你应当避免这样的事情发生。 The following example defines two classes, Customer and CreditCard, which model a bank customer and a possible credit card for that customer. These two classes each store an instance of the other class as a property. This relationship has the potential to create a strong reference cycle. -接下来的例子定义了两个类,Customer和CreditCard,分别为银行客户和信用卡建立数据模型。这两个类将对方的实例保存为自己的属性。这在它们之间潜在地形成了循环强引用。 +接下来的例子定义了两个类,Customer和CreditCard,模拟了银行客户和信用卡。这两个类将对方的实例保存为自己的属性。这种关系会潜在的创造循环强引用。 The relationship between Customer and CreditCard is slightly different from the relationship between Apartment and Person seen in the weak reference example above. In this data model, a customer may or may not have a credit card, but a credit card will always be associated with a customer. To represent this, the Customer class has an optional card property, but the CreditCard class has a non-optional customer property. -Customer 与 CreditCard之间的关系与上文弱引用例子里提到的Apartment 和 Person之间的关系有些许不同。在这个数据模型里,一位客户可能有也可能没有信用卡,但是一张信用卡必然与某位银行客户关联。为了表示这种关系,Customer类声明了一个可选类型的属性card,但CreditCard类声明了一个非可选类型的属性customer。 +Customer 与 CreditCard之间的关系与上文弱引用例子里提到的Apartment 和 Person之间的关系有些许不同。在这个数据模型里,一位客户可能有也可能没有信用卡,但是一张信用卡必然与某位客户关联。为了表示这种关系,Customer类声明了一个可选类型的属性card,但CreditCard类声明了一个非可选类型的属性customer。 Furthermore, a new CreditCard instance can only be created by passing a number value and a customer instance to a custom CreditCard initializer. This ensures that a CreditCard instance always has a customer instance associated with it when the CreditCard instance is created. @@ -403,7 +403,7 @@ var john: Customer? You can now create a Customer instance, and use it to initialize and assign a new CreditCard instance as that customer’s card property: -现在创建Customer实例,并用它初始化CreditCard实例,同时,将CreditCard实例分配给Customer实例的card属性。 +现在创建Customer实例,并用它初始化CreditCard实例,同时,将CreditCard实例赋值给Customer实例的card属性。 ``` john = Customer(name: "John Appleseed") @@ -456,15 +456,15 @@ Customer和CreditCard的例子展示了一个属性的值允许为nil,而另 However, there is a third scenario, in which both properties should always have a value, and neither property should ever be nil once initialization is complete. In this scenario, it is useful to combine an unowned property on one class with an implicitly unwrapped optional property on the other class. -但是,还有第三种场景:就是两个属性都一直有值,并且一旦初始化完成他们就永远都不可能是nil的情况。这种情况下,在一个类中使用无主属性,在另一个类中使用隐式解析可选属性,是解决此类循环强引用问题的有效手段。 +但是,还有第三种场景:就是两个属性都一直有值,并且一旦初始化完成他们就永远都不可能是nil的情况。这种情况下,需要在一个类中使用无主属性,在另一个类中使用隐式解析可选属性。 This enables both properties to be accessed directly (without optional unwrapping) once initialization is complete, while still avoiding a reference cycle. This section shows you how to set up such a relationship. -只要初始化完成,这两个属性都是可以被直接访问的(没有可选类型的解析过程)同时也可以避免循环引用。这部分将向你介绍如何建立这种关系。 +只要初始化完成,这两个属性都是可以被直接访问的(不需要可选解析)同时也可以避免循环引用。这部分将向你介绍如何建立这种关系。 The example below defines two classes, Country and City, each of which stores an instance of the other class as a property. In this data model, every country must always have a capital city, and every city must always belong to a country. To represent this, the Country class has a capitalCity property, and the City class has a country property: -下面的例子定义了两个类,Country 和 City,它们彼此通过属性保存了对方的实例引用。在这个数据模型里,国家是必须有首都的,而一个城市也必须是属于某个国家的。为了表示这种关系,Country类声明了一个capitalCity属性,City类也声明了一个country属性: +下面的例子定义了两个类,Country 和 City,每个类将另外一个类的实例保存为属性。在这个数据模型里,国家是必须有首都的,而一个城市也必须是属于某个国家的。为了表示这种关系,Country类声明了一个capitalCity属性,City类也声明了一个country属性: ``` class Country { @@ -588,7 +588,7 @@ The asHTML property is named and used somewhat like an instance method. However, The HTMLElement class provides a single initializer, which takes a name argument and (if desired) a text argument to initialize a new element. The class also defines a deinitializer, which prints a message to show when an HTMLElement instance is deallocated. -HTMLElement类提供了单一的构造器,它需要传递两个参数来初始化一个新元素:name(若需要) 和 text。同时定义了析构函数,当HTMLElement的实例被销毁的时候会打印出一条提示信息。 +HTMLElement类提供了单一的构造器,它需要传递两个参数来初始化一个新元素:name(可选) 和 text。同时定义了析构函数,当HTMLElement的实例被销毁的时候会打印出一条提示信息。 Here’s how you use the HTMLElement class to create and print a new instance: From 502257e677be8c4a573b22c10170fb6aada71eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=98=E5=A2=83?= Date: Thu, 3 Jul 2014 20:40:22 +0800 Subject: [PATCH 236/261] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E6=B5=81=E7=9A=84review=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 并完成集合类型的链接添加。以及修改集合类型的完成状态。 --- README.md | 2 +- src/chapter2/03_Strings_and_Characters.md | 73 ++++++++++++----------- src/chapter2/04_Collection_Types.md | 4 +- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 907b55e..b633c7d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The Swift Programming Language 中文化项目 * 基础部分 [已完成 by 琼雪] [review by 栖邀] * 基本操作符 [认领 by 冰浠] [review by 姜天意] * 字符串和字符 [已完成 by 筱谷] [review by 尘境] - * 集合类型 [认领 by 尘境] + * 集合类型 [已完成 by 尘境] * 控制流 [认领 by 墨昕] * 函数 [已完成 by 紫溪] [review by 飞长] * 闭包 [认领 by 闻西] [review by 米尔] diff --git a/src/chapter2/03_Strings_and_Characters.md b/src/chapter2/03_Strings_and_Characters.md index 5012592..85392bf 100644 --- a/src/chapter2/03_Strings_and_Characters.md +++ b/src/chapter2/03_Strings_and_Characters.md @@ -3,21 +3,22 @@ A string is an ordered collection of characters, such as "hello, world" or "albatross". Swift strings are represented by the String type, which in turn represents a collection of values of Character type. -字符串指的是一组字符的有序集合,比如「hello, world」或者「albatoross」。在 Swift 里,字符串通过 `String` 类型表示,或者从另外一个角度来说,它是一组 `Character` 对象的值的集合。 +字符串指的是一组字符的有序集合[to: 字符串指的是一组有序的字符集合],比如「hello, world」或者「albatoross」。在 Swift 里,字符串通过 `String` 类型表示,或者从另外一个角度来说,它是一组 `Character` 对象的值的集合 [to: Swift 中的字符串用 `String` 类型来表示,反过来说,它是一组 `Character` 类型的值集]。 Swift’s String and Character types provide a fast, Unicode-compliant way to work with text in your code. The syntax for string creation and manipulation is lightweight and readable, with a similar syntax to C strings. String concatenation is as simple as adding together two strings with the + operator, and string mutability is managed by choosing between a constant or a variable, just like any other value in Swift. -Swift 的 `String` 和 `Character` 类型为代码里的字符操作提供了一种快速的、兼容 Unicode 的途径。跟 C 语言类似,在 Swift 里面新建和操作字符的语法十分简单易读。字符串的合并只需要在两个字符串中间见天一个 `+` 运算符,同时就像其它 Swift 值一样,可以通过定义字符串为常量或是变量来决定它是否可被修改。 +Swift 的 `String` 和 `Character` 类型为代码里的字符操作提供了一种快速的、兼容 Unicode 的途径。跟 C 语言类似,在 Swift 里面新建和操作字符的语法十分简单易读。字符串的合并只需要在两个字符串中间见天一个 `+` 运算符,同时就像其它 Swift 值一样,可以通过定义字符串为常量或是变量来决定它是否可被修改。 [to:字符串合并就像用`+`操作符相加两个字符串那么简单,另外,就像Swift里的其他值,可以通过定义字符串为常量还是变量来设置它是否可被修改。] Despite this simplicity of syntax, Swift’s String type is a fast, modern string implementation. Every string is composed of encoding-independent Unicode characters, and provides support for accessing those characters in various Unicode representations. -尽量语法十分简单,Swift 的 `String` 类型是一个快速且现代化的字符串实现。每个字符串都由一组独立编码的 Unicode 字符组成,并且对这些字符提供了多种可访问的 Unicode 编码形式。 +尽量语法十分简单,Swift 的 `String` 类型是一个快速且现代化的字符串实现。每个字符串都由一组独立编码的 Unicode 字符组成,并且对这些字符提供了多种可访问的 Unicode 编码形式。 [to:每个字符串由一组独立编码的 Unicode 字符组成,并提供了这些字符的多种可访问 Unicode 编码形式。] Strings can also be used to insert constants, variables, literals, and expressions into longer strings, in a process known as string interpolation. This makes it easy to create custom string values for display, storage, and printing. +[to:字符串还可以通过字符串插值这种方式插入常量、变量、字面量或表达式来变得更长。这使得创建用来展示、存储和打印的自定义字符串值变得简单。] > #### NOTE > @@ -37,11 +38,11 @@ Strings can also be used to insert constants, variables, literals, and expressio You can include predefined String values within your code as string literals. A string literal is a fixed sequence of textual characters surrounded by a pair of double quotes (""). -我们可以在代码的前面先定义一些字符串字面量。字符串字面量是由一对引号("")包裹的含有相对顺序的字符集合。 +我们可以在代码的前面先定义一些字符串字面量。 [to: 我们可以在代码中预定义`Sting`值为*字符串字面量*。] 字符串字面量是由一对引号("")包裹的含有相对顺序的字符集合。[to: 字符串字面量是由一对引号(`""`)包围的固定文本字符序列。] A string literal can be used to provide an initial value for a constant or variable: -字符串字面量可以给常量或者变量提供一个初始值: +字符串字面量可以给常量或者变量提供一个初始值[to:提供初始值]: let someString = "Some string literal value" @@ -66,7 +67,7 @@ String literals can include the following special characters: The code below shows an example of each kind of special character. The wiseWords constant contains two escaped double quote characters. The dollarSign, blackHeart, and sparklingHeart constants demonstrate the three different Unicode scalar character formats: -下面的代码中,对各种特殊字符举了一些例子。`wiseWords` 常量包含了两个被转义的引号字符。`dollarSign`、`blackHeart` 和 `sparklingHeart` 常量展示了三种不同类型的 Unicode 字符表示方式。 +下面的代码中,对各种特殊字符举了一些例子[to:给每种特殊字符各举了一个例子]。`wiseWords` 常量包含了两个被转义的引号字符。`dollarSign`、`blackHeart` 和 `sparklingHeart` 常量展示了三种不同类型的 Unicode 字符表示方式。 let wiseWords = "\"Imagination is more important than knowledge\" - Einstein" // "Imagination is more important than knowledge" - Einstein @@ -84,7 +85,7 @@ To create an empty String value as the starting point for building a longer stri var anotherEmptyString = String() // initializer syntax // these two strings are both empty, and are equivalent to each other -一般我们会初始化一个空白的字符串作为后面组装长字符串的基础,Swift 提供了两种初始化字符串的方式,第一种是给变量赋予一个空白的字符串字面量,第二种是通过新建实例的语法: +一般我们会初始化一个空白的字符串[to:空字符串]作为后面组装长字符串的基础,Swift 提供了两种初始化字符串的方式,第一种是给变量赋予一个空白的字符串字面量[to:空字符串字面量],第二种是通过新建实例的语法: var emptyString = "" // 空白的字符串字面量 @@ -138,7 +139,7 @@ You indicate whether a particular String can be modified (or mutated) by assigni > #### 需要注意 -> 这个地方跟 Objective-C 和 Cocoa 不一致,与前者不同,后者可以使用两种类型的字符串 `NSString` 和 `NSMutableString` 来区分该字符是否能被修改。 +> 这个地方跟 Objective-C 和 Cocoa 不一致,与前者不同,后者可以使用两种类型的字符串 `NSString` 和 `NSMutableString` 来区分该字符是否能被修改[to:这种方式与 Objective-C 和 Cocoa 有所不同,这两者通过设置字符串为 `NSString` 还是 `NSMutableString` 来区分该字符是否能被修改]。 ### Strings Are Value Types @@ -148,7 +149,7 @@ You indicate whether a particular String can be modified (or mutated) by assigni Swift’s String type is a value type. If you create a new String value, that String value is copied when it is passed to a function or method, or when it is assigned to a constant or variable. In each case, a new copy of the existing String value is created, and the new copy is passed or assigned, not the original version. Value types are described in Structures and Enumerations Are Value Types. -Swift 中的 `String` 类型属于值类型,也就是说你一旦把一个字符串传进一个方法或者函数里面,或者重新赋值到一个新的常量或变量时,字符串的值都会被复制一遍。详细来说就是,String 类型会把原来的字符串复制为一个新的拷贝,再进行传递和分配,传递后的字符串已经不是原来的那个。关于值类型的详细介绍会在 [Structures and Enumerations Are Value Types]()。 +Swift 中的 `String` 类型属于*值类型*,也就是说你一旦把一个字符串传进一个方法或者函数里面[to:传给一个方法或函数],或者重新赋值[to:给]一个新的常量或变量时,字符串的值都会被复制一遍。详细来说就是[to:在以上每种情况中,],String 类型会把原来的字符串复制为一个新的拷贝,再进行传递和分配,传递后的字符串已经不是原来的那个[to:传递的字符串不是最初的那个]。关于值类型的详细介绍会在[to:请参见] [Structures and Enumerations Are Value Types]()。 > #### NOTE @@ -157,16 +158,16 @@ Swift 中的 `String` 类型属于值类型,也就是说你一旦把一个字 > ### 需要注意 -> 这个行为和 Cocoa 里的 `NSString` 有所区别。每当实例化一个 `NSString` 对象之后,无论怎么在函数和方法之间传递,它都只是指向原来的值的引用,并不会每次复制这个字符串对象,除非你主动要求这么做。 +> 这个行为和 Cocoa 里的 `NSString` 有所 区别[to:不同]。 当实例化一个 `NSString` 对象之后,无论怎么在函数和方法之间传递,它都只是指向原来的值的引用[to:无论是把它传递给一个函数或方法,还是把它赋值给一个变量,我们传递或者赋值的是一个指向同一个 `NSString` 的引用]。并不会每次复制这个字符串对象,除非你主动要求这么做[to:除非我们特别要求,否则不会复制这个字符串对象]。 Swift’s copy-by-default String behavior ensures that when a function or method passes you a String value, it is clear that you own that exact String value, regardless of where it came from. You can be confident that the string you are passed will not be modified unless you modify it yourself. -Swift 这种默认复制的行为确保了每个方法或者函数里面接收到的字符串都完全属于这个方法或函数的,并不需要考虑它从哪来,这样就保证了字符串不会变动,除非主动修改它。 +Swift 这种默认复制的行为确保了每个方法或者函数里面接收到的字符串都完全属于这个方法或函数的,并不需要考虑它从哪来,这样就保证了字符串不会变动,除非主动修改它[to:这样就使得我们能够确保传递的字符串不会被修改,除非我们主动去修改它]。 Behind the scenes, Swift’s compiler optimizes string usage so that actual copying takes place only when absolutely necessary. This means you always get great performance when working with strings as value types. -实际上,Swift 的编译器优化了字符串的使用过程,只有绝对需要时才会产生复制的实际操作。这样就意味着 Swift 可以在字符串操作上和值类型保持一样的高性能。 +实际上,Swift 的编译器优化了字符串的使用 过程,只有绝对需要时才会产生复制的实际操作。这样就意味着 Swift 可以在字符串操作上和值类型保持一样的高性能。 ### Working with Characters @@ -175,7 +176,7 @@ Behind the scenes, Swift’s compiler optimizes string usage so that actual copy Swift’s String type represents a collection of Character values in a specified order. Each Character value represents a single Unicode character. You can access the individual Character values in a string by iterating over that string with a for-in loop: -Swift 的 `String` 类型是由一系列 `Character` 对象根据一定的顺序排列组成的。每个 `Character` 对象都对应着一个 Unicode 字符。我们可以用一个 `for-in` 循环逐个读取字符串中的 `Character` 对象: +Swift 的 `String` 类型是由一系列 `Character` 对象根据一定的顺序排列组成的[to:是一组有着特定顺序的 `Character` 序列]。每个 `Character` 对象都对应着[to:代表了]一个 Unicode 字符。我们可以用一个 `for-in` 循环逐个读取字符串中的 `Character` 对象[to:值]: for character in "Dog!🐶" { println(character) @@ -189,11 +190,11 @@ Swift 的 `String` 类型是由一系列 `Character` 对象根据一定的顺序 The for-in loop is described in For Loops. -`for-in` 循环的介绍在 [For Loops]()。 +`for-in` 循环的介绍在[to:介绍请参见] [For Loops]()。 Alternatively, create a stand-alone Character constant or variable from a single-character string literal by providing a Character type annotation: -此外,可以通过为一个单独的字符指定 `Character` 类型去定义一个独立的 `Character` 常量或者变量: +此外,可以通过为一个单独的字符指定 `Character` 类型去定义一个独立的 `Character` 常量或者变量[to:可以通过 `Character`类型声明单字符变量或常量]: let yenSign: Character = "¥" @@ -208,7 +209,7 @@ To retrieve a count of the characters in a string, call the global countElements println("unusualMenagerie has \(countElements(unusualMenagerie)) characters") // prints "unusualMenagerie has 40 characters" -如果需要计算一个字符串中字符的数量,可以通过调用全局方法 `countElements` 并把该字符串作为唯一的参数: +如果需要计算一个字符串中字符的数量,可以 通过 调用全局方法 `countElements` 并把该字符串作为唯一的参数: let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪" println("unusualMenagerie 拥有 \(countElements(unusualMenagerie)) 个字符") @@ -224,9 +225,9 @@ To retrieve a count of the characters in a string, call the global countElements > #### 需要注意 -> 不同的 Unicdoe 字符或者同一个 Unicode 字符的不同表示方式可能需要不同的内存大小进行存储。因此,在一个字符串中每个字符可能占用不同的内存大小。结果导致如果需要知道一个字符串的长度,必须通过迭代整个字符串中的字符才能计算出来。如果我们在处理一个超长字符串,必须要注意的是 `countElements` 方法会迭代整个字符串来精确计算该字符串的长度。 +> 不同的 Unicdoe 字符或者同一个 Unicode 字符的不同表示方式可能需要不同的内存大小进行存储。因此,在一个字符串中每个字符[to:一个字符串中的各个字符]可能占用不同的内存大小。结果导致[to:因此,]如果需要知道一个字符串的长度,必须通过迭代[to:遍历]整个字符串中的字符才能计算出来。如果我们在处理一个超长字符串,必须要注意的是 `countElements` 方法会迭代[to:遍历]整个字符串来精确计算该字符串的长度。 -> 另外需要注意的是,对于同一个字符串,通过执行 `countElements` 方法返回的字符串数量不一定和 `NSString` 使用 `length` 属性得到的值一样。因为 `NSString` 的 `length` 值是基于 `UTF-16` 十六位编码方式统计的,并未直接统计字符串里 Unicode 字符的数量。为了反映这个事实,Swift 里 `String` 对象的 `utf16count` 属性对应 `NSString` 类的 `length` 值。 +> 另外需要注意的是,对于同一个字符串,通过执行 `countElements` 方法返回的字符串数量不一定和 `NSString` 使用 `length` 属性得到的值一样。因为 `NSString` 的 `length` 值是基于 `UTF-16` 十六位编码方式[to:中的16位编码单元的数量来]统计的,并未直接统计字符串里 Unicode 字符的数量[to:而不是字符串里的 Unicode 字符的数量]。为了反映这个事实,Swift 里 `String` 对象的 `utf16count` 属性对应 `NSString` 类的 `length` 值。 ### Concatenating Strings and Characters @@ -309,7 +310,7 @@ In the example above, the value of multiplier is inserted into a string literal The value of multiplier is also part of a larger expression later in the string. This expression calculates the value of Double(multiplier) * 2.5 and inserts the result (7.5) into the string. In this case, the expression is written as \(Double(multiplier) * 2.5) when it is included inside the string literal. -`multiplier` 同时也在字符串后面的表达式中出现,这个表达式会被执行并把计算结果(7.5)插入到字符串中。在这个案例里面,该表达式被写成了 `\(Double(multiplier) * 2.5)` 并插在了字符串里面。 +`multiplier` 同时也在字符串后面的表达式中出现,这个表达式会被执行并把计算结果(7.5)插入到字符串中。在这个案例里面,该表达式被写成了 `\(Double(multiplier) * 2.5)` 并插在了字符串里面[to: 当被包含在字符串字面量中时,该表达式被写为 `\(Double(multiplier) * 2.5)`]。 ### Comparing Strings @@ -335,7 +336,7 @@ Two String values are considered equal if they contain exactly the same characte -如果两个字符串由相同的字符和一致的顺序组成,那就认为这两个字符串是完全相等的: +如果两个字符串由相同的字符和一致的顺序组成[to:包含的字符完全相同,并且这些字符的排列顺序也相同],那就认为这两个字符串是完全相等的: let quotation = "We're a lot alike, you and I." let sameQuotation = "We're a lot alike, you and I." @@ -350,7 +351,7 @@ Two String values are considered equal if they contain exactly the same characte To check whether a string has a particular string prefix or suffix, call the string’s hasPrefix and hasSuffix methods, both of which take a single argument of type String and return a Boolean value. Both methods perform a character-by-character comparison between the base string and the prefix or suffix string. -通过调用字符串的 `hasPrefix` 或 `hasSuffix` 来判断该字符串是否含有特定的前缀或后缀,这两个方法分别都接收一个字符串参数,结果返回布尔值。这两个方法会在字符串和需要对比的前缀或后缀进行逐字对比。 +通过调用字符串的 `hasPrefix` 或 `hasSuffix` [to:方法]来判断该字符串是否含有特定的前缀或后缀,这两个方法分别都接收一个字符串参数,结果[to:并]返回布尔值。这两个方法会在字符串和需要对比的前缀或后缀进行逐字对比。 The examples below consider an array of strings representing the scene locations from the first two acts of Shakespeare’s Romeo and Juliet: @@ -450,7 +451,7 @@ let whispered = normal.lowercaseString // whispered is equal to "could you help me, please?" ``` -可以通过字符串本身的 `uppercaseString` 或 `lowercaseString` 属性取得它的全大些或全小写版本: +[to:我们]可以通过字符串本身的 `uppercaseString` 或 `lowercaseString` 属性取得它的全大些或全小写版本[to:某个字符串的大写或小写版本]: ``` @@ -468,7 +469,7 @@ let whispered = normal.lowercaseString Unicode is an international standard for encoding and representing text. It enables you to represent almost any character from any language in a standardized form, and to read and write those characters to and from an external source such as a text file or web page. -Unicode 是一个用来编码和表示文本的国际标准。它允许我们用一个标准格式来表示世界上几乎所有的字符,并且提供了在类似文本文件或网页中读取和写入这些字符的能力。 +`Unicode` 是一个用来编码和表示文本的国际标准。它允许我们用 [to: 使得我们可以用] 一个标准格式来表示世界上几乎所有的字符,并且提供了在类似文本文件或网页中读取和写入这些字符的能力。 Swift’s String and Character types are fully Unicode-compliant. They support a number of different Unicode encodings, as described below. @@ -492,11 +493,13 @@ When a Unicode string is written to a text file or some other storage, these uni Swift provides several different ways to access Unicode representations of strings. -Swift 对 Unicode 字符提供了几种不同的访问方式。 +Swift 对 Unicode 字符提供了几种不同的访问方式。 +[to: Swift 提供了不同的方法来访问字符的Unicode形式。] You can iterate over the string with a for-in statement, to access its individual Character values as Unicode characters. This process is described in Working with Characters. -首先可以从字符串的逐字迭代中取得每个 `Character` 中的 Unicode 字符。这个过程在上面的 [字符处理]() 章节中有提到。 +首先可以从字符串的逐字迭代中取得每个 `Character` 中的 Unicode 字符。[to: 我们可以用 `for-in`语句遍历字符串来获取到字符串中每个`Character` 相应的 Unicode 字符。] 这个过程在上面的 [字符处理]() 章节中有提到。 + Alternatively, access a String value in one of three other Unicode-compliant representations: @@ -506,7 +509,7 @@ A collection of UTF-16 code units (accessed with the string’s utf16 property) A collection of 21-bit Unicode scalar values (accessed with the string’s unicodeScalars property) ``` -另外,还可以通过以下三种方式中的一种访问字符串中兼容 Unicode 的字符数据: +另外,还可以通过以下三种 方式中的一种访问字符串中兼容 Unicode 的字符数据[to:统一编码方式来访问一个 `String` 的值]: ``` 一组以 UTF-8 编码的单元 (通过字符串的 utf8 属性访问) @@ -516,7 +519,7 @@ A collection of 21-bit Unicode scalar values (accessed with the string’s unico Each example below shows a different representation of the following string, which is made up of the characters D, o, g, !, and the 🐶 character (DOG FACE, or Unicode scalar U+1F436): -下面的每个示例描述了以下字符串不同的几种表示方法,这个字符串由这几个字符组成:`D`、`o`、`g`、`!` 和 `🐶` 字符(`DOG FACE` 或者 Unicode 标量 `U+1F436`) +下面的每个示例 描述了[to: 给出了] 以下字符串不同的几种表示方法[to:的几种不同表示方法],这个字符串由这几个字符组成:`D`、`o`、`g`、`!` 和 `🐶` 字符(`DOG FACE` 或者 Unicode 标量 `U+1F436`) ``` let dogString = "Dog!🐶" @@ -527,7 +530,7 @@ let dogString = "Dog!🐶" You can access a UTF-8 representation of a String by iterating over its utf8 property. This property is of type UTF8View, which is a collection of unsigned 8-bit (UInt8) values, one for each byte in the string’s UTF-8 representation: -我们可以通过迭代访问字符串的 `utf8` 属性来获得该字符串的 `UTF-8` 编码形式。该属性的类型是 `UTF8View`,由一组无符号的 8 位数值(`UInt8`)组成,每个数值代表了字符串用 `UTF-8` 编码后的字节。 +我们可以通过 迭代访问[to:遍历] 字符串的 `utf8` 属性来获得该字符串的 `UTF-8` 编码形式。该属性的类型是 `UTF8View`,由一组无符号的 8 位数值(`UInt8`) [to: 8 位(`UInt8`)数值]组成,每个数值代表了字符串用 `UTF-8` 编码后的字节[to:每个字节都是字符串的 UTF-8 编码形式]。 ``` for codeUnit in dogString.utf8 { @@ -539,13 +542,13 @@ print("\n") In the example above, the first four decimal codeUnit values (68, 111, 103, 33) represent the characters D, o, g, and !, whose UTF-8 representation is the same as their ASCII representation. The last four codeUnit values (240, 159, 144, 182) are a four-byte UTF-8 representation of the DOG FACE character. -上面的例子中,前四位十进制的编码单元分别代表了 `D`、`o`、`g`、`!`,这几个字符的编码形式跟 ASCII 是一致的。最后四位编码单元(240,159,144,182)是一个 4 位的 UTF-8 编码表示形式,用来表示 `DOG FACE` 字符。 +上面的例子中,前四位十进制的编码单元[to: `(68, 111, 103, 33)`]分别代表了 `D`、`o`、`g`、`!`,这几个字符的编码形式跟 ASCII 是一致的[to:相同的]。最后四位编码单元(240,159,144,182)是一个 4 位的 UTF-8 编码表示形式,用来表示 `DOG FACE` 字符[to: 字符 `DOG FACE` 的 4 位 UTF-8 编码形式]。 #### UTF-16 You can access a UTF-16 representation of a String by iterating over its utf16 property. This property is of type UTF16View, which is a collection of unsigned 16-bit (UInt16) values, one for each 16-bit code unit in the string’s UTF-16 representation: -通过迭代访问字符串的 `utf16` 属性可以取得该字符串的 `UTF-16` 编码形式,该属性的类型是 `UTF16View`,即一组无符号 16 位数值(UInt16)的集合,每个数值代表了字符串用 `UTF-16` 编码后的字节。 +通过迭代访问[to:遍历]字符串的 `utf16` 属性可以取得该字符串的 `UTF-16` 编码形式,该属性的类型是 `UTF16View`,即一组无符号 16 位数值(UInt16)[to:16 位(UInt16)数值]的集合,每个数值代表了字符串用 `UTF-16` 编码后的字节[to:每个字节都是字符串的 UTF-16 编码形式]。 ``` for codeUnit in dogString.utf16 { @@ -557,11 +560,11 @@ print("\n") Again, the first four codeUnit values (68, 111, 103, 33) represent the characters D, o, g, and !, whose UTF-16 code units have the same values as in the string’s UTF-8 representation. -类似的,前四个编码单元(68,111,103,33)代表了前四个字符 `D`、`o`、`g` 和 `!`,这几个字符 `UTF-16` 和 `UTF-8` 拥有相同的表示方式。 +类似的,前四个编码单元(`68,111,103,33`)代表了前四个字符 `D`、`o`、`g` 和 `!`,这几个字符 `UTF-16` 和 `UTF-8` 拥有相同的表示方式[to: 的`UTF-16` 表示方式同 `UTF-8` 的一样]。 The fifth and sixth codeUnit values (55357 and 56374) are a UTF-16 surrogate pair representation of the DOG FACE character. These values are a lead surrogate value of U+D83D (decimal value 55357) and a trail surrogate value of U+DC36 (decimal value 56374). -第五个和第六个编码单元(55357 和 56374)则是 `DOG FACE` 字符的代理项。这两个数值由第一部分的 `U+D83D`(十进制 55357) 和 `U+DC36`(十进制 56374)组成。 +第五个和第六个`编码单元`(`55357` 和 `56374`)则是 `DOG FACE` 字符的代理项。这两个数值由第一部分的 `U+D83D`(十进制 55357) 和 `U+DC36`(十进制 56374)组成。 #### Unicode Scalars @@ -569,7 +572,7 @@ The fifth and sixth codeUnit values (55357 and 56374) are a UTF-16 surrogate pai You can access a Unicode scalar representation of a String value by iterating over its unicodeScalars property. This property is of type UnicodeScalarView, which is a collection of values of type UnicodeScalar. A Unicode scalar is any 21-bit Unicode code point that is not a lead surrogate or trail surrogate code point. -通过迭代字符串的 `unicodeScalars` 属性可以获得该字符串的 Unicode 标量表示形式。该属性的类型是 `UnicodeScalarView`,由一组 `UnicodeScalar` 类型的值组成。一个 Unicode 标量是一个完整的 21 位编码,既没有首码位,也没有尾码位。 +通过迭代[to:遍历]字符串的 `unicodeScalars` 属性可以获得该字符串的 Unicode 标量表示形式。该属性的类型是 `UnicodeScalarView`,由一组 `UnicodeScalar` 类型的值组成。一个 Unicode 标量是一个完整的 21 位编码,既没有首码位,也没有尾码位。 Each UnicodeScalar has a value property that returns the scalar’s 21-bit value, represented within a UInt32 value: @@ -585,11 +588,11 @@ print("\n") The value properties for the first four UnicodeScalar values (68, 111, 103, 33) once again represent the characters D, o, g, and !. The value property of the fifth and final UnicodeScalar, 128054, is a decimal equivalent of the hexadecimal value 1F436, which is equivalent to the Unicode scalar U+1F436 for the DOG FACE character. -前四个 `UnicodeScalar` 对象的 `value` 属性值(68,111,103,33)按照惯例还是代表着 `D`、`o`、`g` 和 `!` 四个字符。而第五个也就是最后一个 `UnicodeScalar` 数值 128054 的十六进制是 1F436,刚好等价于 `DOG FACE` 字符的 Unicode 标量 `U+1F436` +前四个 `UnicodeScalar` 对象的 `value` 属性值(`68,111,103,33`)按照惯例还是代表着 `D`、`o`、`g` 和 `!` 四个字符。而第五个也就是最后一个 `UnicodeScalar` 数值 128054 的十六进制是 1F436,刚好等价于 `DOG FACE` 字符的 Unicode 标量 `U+1F436` 。 As an alternative to querying their value properties, each UnicodeScalar value can also be used to construct a new String value, such as with string interpolation: -除了使用它们的 `value` 属性,每个 `UnicodeScalar` 对象也可以用来直接构造新的 `String` 对象,比如这里用的字符串插值方法: +除了使用它们的 `value` 属性,每个 `UnicodeScalar` 对象也可以用来直接构造新的 `String` 对象,比如这里用的字符串插值方法: ``` for scalar in dogString.unicodeScalars { diff --git a/src/chapter2/04_Collection_Types.md b/src/chapter2/04_Collection_Types.md index 66fc205..450e304 100644 --- a/src/chapter2/04_Collection_Types.md +++ b/src/chapter2/04_Collection_Types.md @@ -556,9 +556,9 @@ Immutability has a slightly different meaning for arrays, however. You are still 对数组来说,不可变的意义稍有不同。我们仍不允许有改变不可变数组的大小的行为,但是,我们*被*允许改变数组中某个现有索引对应的值。这使得Swift的`Array`类型能够在操作固定大小的数组时提供最佳性能。 -The mutability behavior of Swift’s `Array` type also affects how array instances are assigned and modified. For more information, see [Assignment and Copy Behavior for Collection Types](). +The mutability behavior of Swift’s `Array` type also affects how array instances are assigned and modified. For more information, see [Assignment and Copy Behavior for Collection Types](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/09_Classes_and_Structures.md#assignment-and-copy-behavior-for-collection-types). -Swift的`Array`类型的可变性还影响了数组实例是怎么被声明和修改的。更多介绍请参见[集合类型的声明和复制]()。 +Swift的`Array`类型的可变性还影响了数组实例是怎么被声明和修改的。更多介绍请参见[集合类型的声明和复制](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/09_Classes_and_Structures.md#%E9%9B%86%E5%90%88%E7%9A%84%E8%B5%8B%E5%80%BC%E4%B8%8E%E6%8B%B7%E8%B4%9D)。 >NOTE From f769953e1dc3054430f527c7620ab8c6d2047c3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=98=E5=A2=83?= Date: Thu, 3 Jul 2014 20:52:11 +0800 Subject: [PATCH 237/261] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 上一次提交的信息写错了。应该是完成字符串和字符章节的review --- src/chapter2/03_Strings_and_Characters.md | 90 +++++++++++------------ src/chapter2/04_Collection_Types.md | 50 ++++++------- 2 files changed, 70 insertions(+), 70 deletions(-) diff --git a/src/chapter2/03_Strings_and_Characters.md b/src/chapter2/03_Strings_and_Characters.md index 85392bf..6dff1b9 100644 --- a/src/chapter2/03_Strings_and_Characters.md +++ b/src/chapter2/03_Strings_and_Characters.md @@ -1,4 +1,4 @@ -## 字符和字符串 +# 字符和字符串 A string is an ordered collection of characters, such as "hello, world" or "albatross". Swift strings are represented by the String type, which in turn represents a collection of values of Character type. @@ -20,21 +20,21 @@ Strings can also be used to insert constants, variables, literals, and expressio [to:字符串还可以通过字符串插值这种方式插入常量、变量、字面量或表达式来变得更长。这使得创建用来展示、存储和打印的自定义字符串值变得简单。] -> #### NOTE +> ### NOTE > > Swift’s String type is bridged seamlessly to Foundation’s NSString class. If you are working with the Foundation framework in Cocoa or Cocoa Touch, the entire NSString API is available to call on any String value you create, in addition to the String features described in this chapter. You can also use a String value with any API that requires an NSString instance. > > For more information about using String with Foundation and Cocoa, see Using Swift with Cocoa and Objective-C. -> #### 需要注意 +> ### 需要注意 > Swift 的 `String` 类型无缝接入了 Foundation 的 `NSString` 类。如果你之前在 Cocoa 或 Cocoa Touch 中使用了 Foundation 框架,所有 `NSString` 的 API 都可以用在新的 `String` 实例对象上,而且 `String` 对象还额外添加了下文中提到的特性。同时也可以把 `String` 对象用在任何需要传入 `NSString` 实例为参数的 API 中。 > 更多关于 `String` 和 Foundation 或 Coca 使用方法的信息,请查看 [Using Swift with Cocoa and Objective-C]()。 -### String Literals +## String Literals -### 字符串字面量 +## 字符串字面量 You can include predefined String values within your code as string literals. A string literal is a fixed sequence of textual characters surrounded by a pair of double quotes (""). @@ -75,9 +75,9 @@ The code below shows an example of each kind of special character. The wiseWords let blackHeart = "\u2665" // ♥, Unicode 字符 U+2665 let sparklingHeart = "\U0001F496" // 💖, Unicode 字符 U+1F496 -### Initializing an Empty String +## Initializing an Empty String -### 初始化字符串 +## 初始化字符串 To create an empty String value as the starting point for building a longer string, either assign an empty string literal to a variable, or initialize a new String instance with initializer syntax: @@ -108,9 +108,9 @@ You can find out whether a String value is empty by checking its Boolean isEmpty // 会输出 "你看不到我" -### String Mutability +## String Mutability -### 字符串操作 +## 字符串操作 You indicate whether a particular String can be modified (or mutated) by assigning it to a variable (in which case it can be modified), or to a constant (in which case it cannot be modified): @@ -133,18 +133,18 @@ You indicate whether a particular String can be modified (or mutated) by assigni constantString += " and another Highlander" // 这段代码会在编译时报错,因为常量不能被修改 -> #### NOTE +> ### NOTE > This approach is different from string mutation in Objective-C and Cocoa, where you choose between two classes (NSString and NSMutableString) to indicate whether a string can be mutated. -> #### 需要注意 +> ### 需要注意 > 这个地方跟 Objective-C 和 Cocoa 不一致,与前者不同,后者可以使用两种类型的字符串 `NSString` 和 `NSMutableString` 来区分该字符是否能被修改[to:这种方式与 Objective-C 和 Cocoa 有所不同,这两者通过设置字符串为 `NSString` 还是 `NSMutableString` 来区分该字符是否能被修改]。 -### Strings Are Value Types +## Strings Are Value Types -### 字符串是值类型 +## 字符串是值类型 Swift’s String type is a value type. If you create a new String value, that String value is copied when it is passed to a function or method, or when it is assigned to a constant or variable. In each case, a new copy of the existing String value is created, and the new copy is passed or assigned, not the original version. Value types are described in Structures and Enumerations Are Value Types. @@ -152,11 +152,11 @@ Swift’s String type is a value type. If you create a new String value, that St Swift 中的 `String` 类型属于*值类型*,也就是说你一旦把一个字符串传进一个方法或者函数里面[to:传给一个方法或函数],或者重新赋值[to:给]一个新的常量或变量时,字符串的值都会被复制一遍。详细来说就是[to:在以上每种情况中,],String 类型会把原来的字符串复制为一个新的拷贝,再进行传递和分配,传递后的字符串已经不是原来的那个[to:传递的字符串不是最初的那个]。关于值类型的详细介绍会在[to:请参见] [Structures and Enumerations Are Value Types]()。 -> #### NOTE +> ### NOTE > This behavior differs from that of NSString in Cocoa. When you create an NSString instance in Cocoa, and pass it to a function or method or assign it to a variable, you are always passing or assigning a reference to the same single NSString. No copying of the string takes place, unless you specifically request it. -> ### 需要注意 +> ## 需要注意 > 这个行为和 Cocoa 里的 `NSString` 有所 区别[to:不同]。 当实例化一个 `NSString` 对象之后,无论怎么在函数和方法之间传递,它都只是指向原来的值的引用[to:无论是把它传递给一个函数或方法,还是把它赋值给一个变量,我们传递或者赋值的是一个指向同一个 `NSString` 的引用]。并不会每次复制这个字符串对象,除非你主动要求这么做[to:除非我们特别要求,否则不会复制这个字符串对象]。 @@ -170,9 +170,9 @@ Behind the scenes, Swift’s compiler optimizes string usage so that actual copy 实际上,Swift 的编译器优化了字符串的使用 过程,只有绝对需要时才会产生复制的实际操作。这样就意味着 Swift 可以在字符串操作上和值类型保持一样的高性能。 -### Working with Characters +## Working with Characters -### 字符处理 +## 字符处理 Swift’s String type represents a collection of Character values in a specified order. Each Character value represents a single Unicode character. You can access the individual Character values in a string by iterating over that string with a for-in loop: @@ -199,9 +199,9 @@ Alternatively, create a stand-alone Character constant or variable from a single let yenSign: Character = "¥" -### Counting Characters +## Counting Characters -### 计算字符个数 +## 计算字符个数 To retrieve a count of the characters in a string, call the global countElements function and pass in a string as the function’s sole parameter: @@ -216,23 +216,23 @@ To retrieve a count of the characters in a string, call the global countElements // hui输出 "unusualMenagerie 拥有 40 个字符" -> #### NOTE +> ### NOTE > Different Unicode characters and different representations of the same Unicode character can require different amounts of memory to store. Because of this, characters in Swift do not each take up the same amount of memory within a string’s representation. As a result, the length of a string cannot be calculated without iterating through the string to consider each of its characters in turn. If you are working with particularly long string values, be aware that the countElements function must iterate over the characters within a string in order to calculate an accurate character count for that string. > Note also that the character count returned by countElements is not always the same as the length property of an NSString that contains the same characters. The length of an NSString is based on the number of 16-bit code units within the string’s UTF-16 representation and not the number of Unicode characters within the string. To reflect this fact, the length property from NSString is called utf16count when it is accessed on a Swift String value. -> #### 需要注意 +> ### 需要注意 > 不同的 Unicdoe 字符或者同一个 Unicode 字符的不同表示方式可能需要不同的内存大小进行存储。因此,在一个字符串中每个字符[to:一个字符串中的各个字符]可能占用不同的内存大小。结果导致[to:因此,]如果需要知道一个字符串的长度,必须通过迭代[to:遍历]整个字符串中的字符才能计算出来。如果我们在处理一个超长字符串,必须要注意的是 `countElements` 方法会迭代[to:遍历]整个字符串来精确计算该字符串的长度。 > 另外需要注意的是,对于同一个字符串,通过执行 `countElements` 方法返回的字符串数量不一定和 `NSString` 使用 `length` 属性得到的值一样。因为 `NSString` 的 `length` 值是基于 `UTF-16` 十六位编码方式[to:中的16位编码单元的数量来]统计的,并未直接统计字符串里 Unicode 字符的数量[to:而不是字符串里的 Unicode 字符的数量]。为了反映这个事实,Swift 里 `String` 对象的 `utf16count` 属性对应 `NSString` 类的 `length` 值。 -### Concatenating Strings and Characters +## Concatenating Strings and Characters -### 字符和字符串的拼接 +## 字符和字符串的拼接 String and Character values can be added together (or concatenated) with the addition operator (+) to create a new String value: @@ -278,18 +278,18 @@ You can also append a String or Character value to an existing String variable w welcome += character1 // welcome now 现在是 "good morning!" -> #### NOTE +> ### NOTE > You can’t append a String or Character to an existing Character variable, because a Character value must contain a single character only. -> #### 需要注意 +> ### 需要注意 > 无法在 `Character` 对象后面追加任何 `String` 或 `Character` 字符,因为 `Character` 对象必须只有一个字符。 -### String Interpolation +## String Interpolation -### 字符串插值 +## 字符串插值 String interpolation is a way to construct a new String value from a mix of constants, variables, literals, and expressions by including their values inside a string literal. Each item that you insert into the string literal is wrapped in a pair of parentheses, prefixed by a backslash: @@ -313,17 +313,17 @@ The value of multiplier is also part of a larger expression later in the string. `multiplier` 同时也在字符串后面的表达式中出现,这个表达式会被执行并把计算结果(7.5)插入到字符串中。在这个案例里面,该表达式被写成了 `\(Double(multiplier) * 2.5)` 并插在了字符串里面[to: 当被包含在字符串字面量中时,该表达式被写为 `\(Double(multiplier) * 2.5)`]。 -### Comparing Strings +## Comparing Strings -### 字符串比较 +## 字符串比较 Swift provides three ways to compare String values: string equality, prefix equality, and suffix equality. Swift 提供了三种对比字符串的方式:全值比较、前缀比较和后缀比较。 -#### String Equality +### String Equality -#### 全值比较 +### 全值比较 Two String values are considered equal if they contain exactly the same characters in the same order: @@ -345,9 +345,9 @@ Two String values are considered equal if they contain exactly the same characte } // 运行后会输出 "这两个字符串是相等的" -#### Prefix and Suffix Equality +### Prefix and Suffix Equality -#### 前缀比较和后缀比较 +### 前缀比较和后缀比较 To check whether a string has a particular string prefix or suffix, call the string’s hasPrefix and hasSuffix methods, both of which take a single argument of type String and return a Boolean value. Both methods perform a character-by-character comparison between the base string and the prefix or suffix string. @@ -437,9 +437,9 @@ Similarly, use the hasSuffix method to count the number of scenes that take plac // 运行后输出: "6 mansion scenes; 2 cell scenes" -### Uppercase and Lowercase Strings +## Uppercase and Lowercase Strings -### 字符串的大小写转换 +## 字符串的大小写转换 You can access an uppercase or lowercase version of a string with its uppercaseString and lowercaseString properties: @@ -463,9 +463,9 @@ let whispered = normal.lowercaseString ``` -### Unicode +## Unicode -### Unicode 字符 +## Unicode 字符 Unicode is an international standard for encoding and representing text. It enables you to represent almost any character from any language in a standardized form, and to read and write those characters to and from an external source such as a text file or web page. @@ -475,9 +475,9 @@ Swift’s String and Character types are fully Unicode-compliant. They support a Swift 的 `String` 和 `Character` 类型完全兼容 Unicode ,并且提供了大量 Unicode 编码的支持,下面我们会提到这点。 -#### Unicode Terminology +### Unicode Terminology -#### Unicode 的术语 +### Unicode 的术语 Every character in Unicode can be represented by one or more unicode scalars. A unicode scalar is a unique 21-bit number (and name) for a character or modifier, such as U+0061 for LOWERCASE LATIN LETTER A ("a"), or U+1F425 for FRONT-FACING BABY CHICK ("🐥"). @@ -487,9 +487,9 @@ When a Unicode string is written to a text file or some other storage, these uni 当一个 Unicode 的字符串被写进文本文件或者其它存储形式时,这些 unicode 标量就会从几种 Unicode 制定的编码方式中选取其中一种把该字符串编码成小块的编码单元。这些编码方式包括了 `UTF-8` 格式(会把字符串编码成 8 位编码单元),`UTF-16` 格式(把字符串编码成 16 位编码单元)。 -#### Unicode Representations of Strings +### Unicode Representations of Strings -#### Unicode 字符串的表示方式 +### Unicode 字符串的表示方式 Swift provides several different ways to access Unicode representations of strings. @@ -526,7 +526,7 @@ let dogString = "Dog!🐶" ``` -#### UTF-8 +### UTF-8 You can access a UTF-8 representation of a String by iterating over its utf8 property. This property is of type UTF8View, which is a collection of unsigned 8-bit (UInt8) values, one for each byte in the string’s UTF-8 representation: @@ -544,7 +544,7 @@ In the example above, the first four decimal codeUnit values (68, 111, 103, 33) 上面的例子中,前四位十进制的编码单元[to: `(68, 111, 103, 33)`]分别代表了 `D`、`o`、`g`、`!`,这几个字符的编码形式跟 ASCII 是一致的[to:相同的]。最后四位编码单元(240,159,144,182)是一个 4 位的 UTF-8 编码表示形式,用来表示 `DOG FACE` 字符[to: 字符 `DOG FACE` 的 4 位 UTF-8 编码形式]。 -#### UTF-16 +### UTF-16 You can access a UTF-16 representation of a String by iterating over its utf16 property. This property is of type UTF16View, which is a collection of unsigned 16-bit (UInt16) values, one for each 16-bit code unit in the string’s UTF-16 representation: @@ -566,9 +566,9 @@ The fifth and sixth codeUnit values (55357 and 56374) are a UTF-16 surrogate pai 第五个和第六个`编码单元`(`55357` 和 `56374`)则是 `DOG FACE` 字符的代理项。这两个数值由第一部分的 `U+D83D`(十进制 55357) 和 `U+DC36`(十进制 56374)组成。 -#### Unicode Scalars +### Unicode Scalars -#### Unicode 标量 +### Unicode 标量 You can access a Unicode scalar representation of a String value by iterating over its unicodeScalars property. This property is of type UnicodeScalarView, which is a collection of values of type UnicodeScalar. A Unicode scalar is any 21-bit Unicode code point that is not a lead surrogate or trail surrogate code point. diff --git a/src/chapter2/04_Collection_Types.md b/src/chapter2/04_Collection_Types.md index 450e304..3179d1f 100644 --- a/src/chapter2/04_Collection_Types.md +++ b/src/chapter2/04_Collection_Types.md @@ -1,5 +1,5 @@ -##Collection Types -##集合类型 +# Collection Types +# 集合类型 Swift provides two *collection types*, known as arrays and dictionaries, for storing collections of values. Arrays store ordered lists of values of the same type. Dictionaries store unordered collections of values of the same type, which can be referenced and looked up through a unique identifier (also known as a *key*). @@ -18,8 +18,8 @@ Arrays and dictionaries in Swift are always clear about the types of values and >Swift的`Array`类型在赋值给常量和变量,还有传入函数和方法时与其他类型有所不同。获取更多信息请参见[Mutability of Collections](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/04_Collection_Types.md#mutability-of-collections)and[AssignmentCopy Behavior for Collection Types]()这两个章节。 -###Arrays -###数组 +## Arrays +## 数组 An *array* stores multiple values of the same type in an ordered list. The same value can appear in an array multiple times at different positions. *数组*在一个有序列表中存储了多个相同类型的数据。相同的数据可以多次出现在数组的不同位置。 @@ -28,14 +28,14 @@ Swift arrays are specific about the kinds of values they can store. They differ Swift数组能够存储的数据类型是确定的。这与Objective-C的类`NSArray`和`NSMutableArray`是不同的,这两个类能够存储任何一种类型的对象,并且不会提供它们返回的对象的任何信息。在Swift中,某个数组能够存储的数据类型是确定的,不是通过显式的类型声明,就是通过类型推断,不需要为class类型。假我们你创建了一个`Int`型的数组,那么就不能插入其他任何非`Int`型的值到这个数组中。Swift数组是类型安全的,并且它们能够包含的值也是明确的。 ‌ -####Array Type Shorthand Syntax -####数组类型缩写语法 +### Array Type Shorthand Syntax +### 数组类型缩写语法 The type of a Swift array is written in full as `Array`, where `SomeType` is the type that the array is allowed to store. You can also write the type of an array in shorthand form as `SomeType[]`. Although the two forms are functionally identical, the shorthand form is preferred, and is used throughout this guide when referring to the type of an array. Swift数组的类型的完整写法是`Array`, 这里的`SomeType`指的是数组能够存储的类型。我们也可以把它缩写为`SomeType[]`。这两种形式的数组在功能上完全相同,不过建议使用缩写的形式,本书中提到数组类型时都会以这种形式表示。 ‌ -####Array Literals -####数组字面量 +### Array Literals +### 数组字面量 You can initialize an array with an *array literal*, which is a shorthand way to write one or more values as an array collection. An array literal is written as a list of values, separated by commas, surrounded by a pair of square brackets: @@ -82,8 +82,8 @@ Because all values in the array literal are of the same type, Swift can infer th 因为数组字面量中所有的值的类型是相同的,Swift能够推断出`String[]`是`shoppingList`变量使用的正确类型。 ‌ -####Accessing and Modifying an Array -####获取和修改数组 +### Accessing and Modifying an Array +### 获取和修改数组 You access and modify an array through its methods and properties, or by using subscript syntax. 我们可以通过数组的方法、属性或下标语法来访问和修改数组。 @@ -221,8 +221,8 @@ let apples = shoppingList.removeLast() // the apples constant is now equal to the removed "Apples" string ``` -####Iterating Over an Array -####遍历数组 +### Iterating Over an Array +### 遍历数组 You can iterate over the entire set of values in an array with the `for-in` loop: 我们可以使用`for-in`循环来遍历数组中的所有数组项: @@ -256,8 +256,8 @@ For more about the `for-in` loop, see [For Loops](https://github.com/trans4fun/T 获取更多关于`for-in`循环的介绍,请参见[For循环](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF)。 -####Creating and Initializing an Array -####创建和初始化数组 +### Creating and Initializing an Array +### 创建和初始化数组 You can create an empty array of a certain type (without setting any initial values) using initializer syntax: 我们可以使用初始化语法来创建某一特定类型的空数组(没有设置任何初始值): @@ -307,8 +307,8 @@ var sixDoubles = threeDoubles + anotherThreeDoubles ``` -###Dictionaries -###字典 +## Dictionaries +## 字典 A *dictionary* is a container that stores multiple values of the same type. Each value is associated with a unique *key*, which acts as an identifier for that value within the dictionary. Unlike items in an array, items in a dictionary do not have a specified order. You use a dictionary when you need to look up values based on their identifier, in much the same way that a real-world dictionary is used to look up the definition for a particular word. *字典*是存储多重相同类型数值的容器。每个值和字典中作为值的唯一标识符的*键*(key)相关联。和数组中的数据项不同,字典中的数据项没有顺序。我们可以使用字典查找基于标识符的数据,就像在现实世界中可以用字典来查找某个特定字词的定义。 @@ -326,8 +326,8 @@ The only restriction is that `KeyType` must be *hashable*—that is, it must pro `KeyType`的唯一限制是它必须是*可哈希的*——也就是说,它必须提供一个方法来使得自己能够被唯一表示。所有的Swift基础类型(如`String`, `Int`, `Double`, 和`Bool`)默认都是可哈希的,所有的这些类型都能够被用来作为字典的键。没有关联数值的枚举类型(参见[Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md))也是默认可枚举的。 ‌ -####Dictionary Literals -####字典字面量 +### Dictionary Literals +### 字典字面量 You can initialize a dictionary with a *dictionary literal*, which has a similar syntax to the array literal seen earlier. A dictionary literal is a shorthand way to write one or more key-value pairs as a `Dictionary` collection. 你可以用*字典字面量*来初始化一个字典,这个和之前的数组字面量有着相似的语法。一个字典字面量是一个缩写的方式来表示作为`字典`集合的一个或多个键值对。 @@ -376,7 +376,7 @@ var airports = ["TYO": "Tokyo", "DUB": "Dublin"] Because all keys in the literal are of the same type as each other, and likewise all values are of the same type as each other, Swift can infer that `Dictionary` is the correct type to use for the `airports` dictionary. 由于字面量中的键和值都是相同类型的,因而Swift能够推断出`Dictionary` 是使用字典`airports`的正确类型。 ‌ -####Accessing and Modifying a Dictionary +### Accessing and Modifying a Dictionary You access and modify a dictionary through its methods and properties, or by using subscript syntax. As with an array, you can find out the number of items in a `Dictionary` by checking its read-only `count` property: 我们能够通过字典的方法和属性,以及下标语法来访问和修改字典。像数组那样,我们可以通过查询只读属性`count`来得到一个`字典`中数据项的数量。 @@ -452,8 +452,8 @@ if let removedValue = airports.removeValueForKey("DUB") { // prints "The removed airport's name is Dublin International. ``` -####Iterating Over a Dictionary -####字典遍历 +### Iterating Over a Dictionary +### 字典遍历 You can iterate over the key-value pairs in a dictionary with a `for-in` loop. Each item in the dictionary is returned as a (`key, value`) tuple, and you can decompose the tuple’s members into temporary constants or variables as part of the iteration: 我们可以用`for-in`循环遍历一个字典中的键值对。字典中的每个数据项返回相应的(`键, 值`)原则,我们可以把元组分解为临时常量或变量用于遍历: @@ -507,8 +507,8 @@ let airportNames = Array(airports.values) >Swift字典类型是无序的集合。遍历字典时键、值以及键值对的访问顺序是不确定的。 ‌ -####Creating an Empty Dictionary -####创建空字典 +### Creating an Empty Dictionary +### 创建空字典 As with arrays, you can create an empty `Dictionary` of a certain type by using initializer syntax: 如同字典,我们可以使用初始化语法创建一个特定类型的空`字典`。 @@ -541,8 +541,8 @@ namesOfIntegers = [:] >在后台,Swift数组和字典类型都是由*泛型集合*实现的。更多关于泛型类型和集合的介绍,请参见[Generics](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/22_Generics.md)。 ‌ -###Mutability of Collections -###集合的易变性 +## Mutability of Collections +## 集合的易变性 Arrays and dictionaries store multiple values together in a single collection. If you create an array or a dictionary and assign it to a variable, the collection that is created will be *mutable*. This means that you can change (or *mutate*) the size of the collection after it is created by adding more items to the collection, or by removing existing items from the ones it already contains. Conversely, if you assign an array or a dictionary to a constant, that array or dictionary is *immutable*, and its size cannot be changed. From 9986c037f3a9b6ef7aa89435c8cd64a8bfcde244 Mon Sep 17 00:00:00 2001 From: Henry Ge Date: Thu, 3 Jul 2014 21:36:34 +0800 Subject: [PATCH 238/261] Update 10_Summary_of_the_Grammar.md --- src/chapter3/10_Summary_of_the_Grammar.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/chapter3/10_Summary_of_the_Grammar.md b/src/chapter3/10_Summary_of_the_Grammar.md index 42ee069..a287a89 100644 --- a/src/chapter3/10_Summary_of_the_Grammar.md +++ b/src/chapter3/10_Summary_of_the_Grammar.md @@ -163,11 +163,11 @@ default标签 → **default** : ###GRAMMAR OF A LABELED STATEMENT -‌labeled-statement → statement-label loop-statement | statement-label switch-statement -‌ -statement-label → label-name: -‌ -label-name → identifier +‌ labeled-statement → statement-label loop-statement | statement-label switch-statement + +‌ statement-label → label-name: + +‌ label-name → identifier ###标记语句语法 标记语句 → 语句标签 循环语句 | 语句标签 switch语句 @@ -376,6 +376,7 @@ return语句 → **return** 表达式 可选 ###GRAMMAR OF A CODE BLOCK ‌ code-block → {statements opt} + ###代码块语法 代码块 → { 多条语句 可选 } @@ -407,6 +408,7 @@ return语句 → **return** 表达式 可选 ‌ pattern-initializer → pattern initializer opt ‌ initializer → =expression + ###常数声明语法 常量声明 → 属性列表 可选 声明描述符列表 可选 **let** 模式构造器列表 @@ -424,7 +426,7 @@ return语句 → **return** 表达式 可选 ‌ 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 getter-setter-keyword-block ‌ variable-declaration → variable-declaration-head variable-name type-annotation initializer opt willSet-didSet-block @@ -1740,8 +1742,8 @@ superclass-initializer-expression → super.init ###GRAMMAR OF A PROTOCOL COMPOSITION TYPE ‌ protocol-composition-type → protocol -‌ - protocol-identifier-list → protocol-identifier protocol-identifier,protocol-identifier-list + +‌ protocol-identifier-list → protocol-identifier protocol-identifier,protocol-identifier-list ‌ protocol-identifier → type-identifier From ab627a55eab9a557899c492fa522ef5129d19cea Mon Sep 17 00:00:00 2001 From: jty99 Date: Thu, 3 Jul 2014 23:32:55 +0800 Subject: [PATCH 239/261] review over --- src/chapter2/02_Basic_Operators.md | 347 +++++++++++++++++++++++------ 1 file changed, 274 insertions(+), 73 deletions(-) diff --git a/src/chapter2/02_Basic_Operators.md b/src/chapter2/02_Basic_Operators.md index fa66a09..8d230c2 100644 --- a/src/chapter2/02_Basic_Operators.md +++ b/src/chapter2/02_Basic_Operators.md @@ -1,48 +1,85 @@ ###基本运算符 -运算符是用来检查,改变或者合并值的一种提别的符号或者短语。举个例子,加号(+)将2个数字相加(i=1+2).更多复杂的逻辑和运算&&和i++,它是便捷的让i+1的一种方式。 +An operator is a special symbol or phrase that you use to check, change, or combine values. For example, the addition operator (+) adds two numbers together (as in let i = 1 + 2). More complex examples include the logical AND operator && (as in if enteredDoorCode && passedRetinaScan) and the increment operator ++i, which is a shortcut to increase the value of i by 1. -Swift 支持大部分标准 C 语言的运算符,且改进许多特性来减少常规编码错误。像等于号(=)不再返回一个值,以减少要判断相等运算符(==)的地方写成赋值符导致的错误。算术运算符(+,-,*,/,%等)会检测并不允许值溢出,以此来避免保存变量时由于变量大于或小于其类型所能承载的范围时导致的异常结果。当然允许你使用 Swift 的溢出运算符来实现溢出。详情参见溢出运算符。 +运算符(operator)是用来检查,改变或者合并值的一种特殊的符号或者短语。举个例子,加操作符(+)将2个数字相加(i=1+2).更复杂的如逻辑与运算符`&&`,以及缩写形式的,表达i的值加1的自增运算符`i++`。 -和c不同,Swift允许你对浮点数进行浮点运算,同时还提供C种没有的两数字区间的运算符(a..b 和a...b),以方便我们表达区间内的数值。 +Swift supports most standard C operators and improves several capabilities to eliminate common coding errors. The assignment operator (=) does not return a value, to prevent it from being mistakenly used when the equal to operator (==) is intended. Arithmetic operators (+, -, *, /, % and so forth) detect and disallow value overflow, to avoid unexpected results when working with numbers that become larger or smaller than the allowed value range of the type that stores them. You can opt in to value overflow behavior by using Swift’s overflow operators, as described in Overflow Operators. -本章节只描述了 Swift 中的基本运算符,高级运算符包含了高级运算符,及如何自定义运算符,及如何进行自定义类型的运算符重载。 + +Swift 支持大部分标准 C 语言运算符,且改进了许多特性来避免常规编码错误。赋值操作符(=)不再返回一个值,从而避免当应该使用相等运算符(==)的地方,错写成赋值符而导致的错误。算术运算符(+,-,*,/,%等)会检测值溢出并且不允许溢出,以此来避免当保存变量时,变量大于或小于其类型所能承载的范围时所导致的异常结果。当然你可以使用 Swift 的溢出运算符来实现溢出。详情参见[溢出运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_37)。 + +Unlike C, Swift lets you perform remainder (%) calculations on floating-point numbers. Swift also provides two range operators (a..b and a...b) not found in C, as a shortcut for expressing a range of values. + +与C语言不同,Swift允许你对浮点数进行求余(%)运算,同时还提供C语言没有的两种区间运算符(a..b 和a...b),以方便我们表达一定区间内的数值。 + +This chapter describes the common operators in Swift. Advanced Operators covers Swift’s advanced operators, and describes how to define your own custom operators and implement the standard operators for your own custom types. + + +本章节只描述了 Swift 中的基本运算符,[高级运算符](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_28)包含了高级运算符相关内容,以及如何自定义运算符与通过扩充标准运算符来生成自定义运算符。 ###术语 -运算符有一元,二元,三元。 +Operators are unary, binary, or ternary: + +Unary operators operate on a single target (such as -a). Unary prefix operators appear immediately before their target (such as !b), and unary postfix operators appear immediately after their target (such as i++). +Binary operators operate on two targets (such as 2 + 3) and are infix because they appear in between their two targets. +Ternary operators operate on three targets. Like C, Swift has only one ternary operator, the ternary conditional operator (a ? b : c). +The values that operators affect are operands. In the expression 1 + 2, the + symbol is a binary operator and its two operands are the values 1 and 2. + -* 一元运算符是对单一操作对象的操作(如-a).一元运算符的前元算符出现在操作对象的前面(如!b),后运算符则出现在操作对象的后面(如i++). -* 二元运算符是对两个操作对象的操作,同时它出现在2个操作对象之间(如2+3) -* 三元运算符就是对三个对象的操作,和C一样,Swift 只有一个三元运算符,就是三元条件运算符(a ? b : c)。 -受运算符影响的值叫操作数,在表达式1 + 2中,加号+是二元运算符,它的两个操作数是值1和2。 +运算符包括一元运算符,二元运算符,三元运算符。 + +* 一元运算符是对单一操作对象的操作(如-a).一元运算符中,前置运算符出现在操作对象的前面(如!b),后置运算符则出现在操作对象的后面(如i++). +* 二元运算符是对二个操作对象的操作,位于二个操作对象之间(如2+3) +* 三元运算符就是对三个对象的操作,和C语言一样,Swift 只有一个三元运算符,即三元条件运算符(a ? b : c)。 + +受运算符影响的值叫操作数,在表达式1 + 2中,加符号`+`是二元运算符,它的两个操作数是两个值1和2。 ###赋值运算符 -赋值运算符(a = b),表示通过b来初始化或更新a; + +The assignment operator (a = b) initializes or updates the value of a with the value of b: + +赋值运算符(a = b),表示通过b来初始化或更新a的值; let b = 10 var a = 5 a = b // a 现在等于 10 -如果赋值的右边是一个多元组,它的元素可以马上被分解多个变量或变量: +If the right side of the assignment is a tuple with multiple values, its elements can be decomposed into multiple constants or variables at once: + +如果赋值运算符右边是一个多元组,它的元素可以马上被拆分为多个常量或值: let (x, y) = (1, 2) // 此时 x 等于 1, y 等于 2 - -与 C 语言和 Objective-C 不同,Swift 的赋值操作并不返回任何值。所以以下代码是错误的: + +Unlike the assignment operator in C and Objective-C, the assignment operator in Swift does not itself return a value. The following statement is not valid: + +与 C 语言和 Objective-C 不同,Swift 的赋值操作符并不返回任何值。所以以下代码是错误的: if x = y { // 这里是错误的, 因为 x = y 并不返回任何值 } -这个特性使你无法把(==)错写成(=),由于if x = y是错误代码,Swift 从底层帮你避免了这些错误代码。 +This feature prevents the assignment operator (=) from being used by accident when the equal to operator (==) is actually intended. By making if x = y invalid, Swift helps you to avoid these kinds of errors in your code. + + +这个特性使你无法把(==)错写成(=),由于if x = y是错误代码,Swift 从代码层面帮你避免了这些错误的产生。 + +Arithmetic Operators +Swift supports the four standard arithmetic operators for all number types: -###数值运算 +Addition (+) +Subtraction (-) +Multiplication (*) +Division (/) -Swift 支持基本的四则运算: +###算术运算符 + +Swift 支持所有number类型间的标准四则运算: * 加法(+) * 减法(-) * 乘法(*) @@ -52,14 +89,18 @@ Swift 支持基本的四则运算: 5 - 3 // 等于 2 2 * 3 // 等于 6 10.0 / 2.5 // 等于 4.0 + +Unlike the arithmetic operators in C and Objective-C, the Swift arithmetic operators do not allow values to overflow by default. You can opt in to value overflow behavior by using Swift’s overflow operators (such as a &+ b). See Overflow Operators. + +The addition operator is also supported for String concatenation: -和C、Object-C不同的是,Swift 默认不允许在数值运算中出现溢出情况。但你可以使用 Swift 的溢出运算符来达到你有目的的溢出(如a &+ b)。详情参见溢出运算符。 +和C、Object-C不同的是,Swift 默认不允许在数值运算中出现溢出情况。但你可以使用 Swift 的溢出运算符来达到有目的的溢出(如a &+ b)。详情参见溢出运算符。 -加法运算符也可用于String的拼接: +加运算符也可用于String的拼接: "hello, " + "world" // 等于 "hello, world" -两个Character值或一个String和一个Character值,相加会生成一个新的String值: +两个`Character`类型的值或一个`String`类型和一个`Character`类型的值,相加会生成一个新的`String`类型的值: let dog: Character = "d" let cow: Character = "c" @@ -70,27 +111,55 @@ Swift 支持基本的四则运算: 详情参见字符,字符串的拼接。 -###求余运算 -求余运算(a % b)是计算b的多少倍刚刚好可以容入a,返回多出来的那部分(余数)。 +###求余运算符 + +The remainder operator (a % b) works out how many multiples of b will fit inside a and returns the value that is left over (known as the remainder). + +求余运算(a % b)来计算b的多少倍刚刚好可以容入a,之后返回多出来的那部分(余数)。 + +>NOTE + +>The remainder operator (%) is also known as a modulo operator in other languages. However, its behavior in +>Swift for negative numbers means that it is, strictly speaking, a remainder rather than a modulo operation. + + >注意: -求余运算(%)在其他语言也叫取模运算。然而严格说来,我们看该运算符对负数的操作结果,"求余"比"取模"更合适些。 -我们来谈谈取余是怎么回事,计算9 % 4,你先计算出4的多少倍会刚好可以容入9中: -<图> -2倍,非常好,那余数是1(用橙色标出) +求余运算(%)在其他语言也叫取模运算。然而严格说来,Swift对于该运算符对负数的操作结果,"求余"比"取模"更合适些。 + +Here’s how the remainder operator works. To calculate 9 % 4, you first work out how many 4s will fit inside 9: + +这里展示了求余运算符是怎样计算的。若计算9 % 4,你首先要计算出4的多少倍刚好可以融入9中: + +![求余](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/remainderInteger_2x.png) + +You can fit two 4s inside 9, and the remainder is 1 (shown in orange). + +两个4正好装到9里,余数是1(用橙色标出) 在 Swift 中这么来表达: 9 % 4 // 等于 1 +To determine the answer for a % b, the % operator calculates the following equation and returns remainder as its output: + 为了得到a % b的结果,%计算了以下等式,并输出余数作为结果: a = (b × 倍数) + 余数 +where some multiplier is the largest number of multiples of b that will fit inside a. + +Inserting 9 and 4 into this equation yields: + 当倍数取最大值的时候,就会刚好可以容入a中。 +The same method is applied when calculating the remainder for a negative value of a: + 把9和4代入等式中,我们得1: 9 = (4 × 2) + 1 + +Inserting -9 and 4 into the equation yields: + 同样的方法,我来们计算 -9 % 4: -9 % 4 // 等于 -1 @@ -100,26 +169,50 @@ a = (b × 倍数) + 余数 余数是-1。 +The sign of b is ignored for negative values of b. This means that a % b and a % -b always give the same answer. + + 在对负数b求余时,b的符号会被忽略。这意味着 a % b 和 a % -b的结果是相同的。 -###浮点数求余计算 -与 C 语言和 Objective-C不同,Swift中可以对浮点数进行求余。 + + +###浮点数求余 + +Unlike the remainder operator in C and Objective-C, Swift’s remainder operator can also operate on floating-point numbers: + +与 C 语言和 Objective-C不同,Swift中可以对浮点数进行求余运算。 8 % 2.5 // 等于 0.5 + +In this example, 8 divided by 2.5 equals 3, with a remainder of 0.5, so the remainder operator returns a Double value of 0.5. -这个例子中,8除于2.5等于3余0.5,所以结果是一个Double值0.5。 -[图片]{} +这个例子中,8除于2.5等于3余0.5,所以结果是一个Double类型的值0.5。 + +![浮点数求余](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/remainderFloat_2x.png) + +Increment and Decrement Operators -###自增和自增运算 -和 C 语言一样,Swift 也提供了方便对变量本身加1或减1的自增(++)和自减(--)的运算符。其操作对象可以是整形和浮点型。 +Like C, Swift provides an increment operator (++) and a decrement operator (--) as a shortcut to increase or decrease the value of a numeric variable by 1. You can use these operators with variables of any integer or floating-point type. + +###自增和自减运算符 +和 C 语言一样,Swift 也提供了对变量本身加1或减1这类运算的缩写:自增(++)和自减(--)的运算符。其操作对象可以是整形和浮点类型的变量。 var i = 0 ++i // 现在 i = 1 + +Each time you call ++i, the value of i is increased by 1. Essentially, ++i is shorthand for saying i = i + 1. Likewise, --i can be used as shorthand for i = i - 1. 每调用一次++i,i的值就会加1。实际上,++i是i = i + 1的简写,而--i是i = i - 1的简写。 +The ++ and -- symbols can be used as prefix operators or as postfix operators. ++i and i++ are both valid ways to increase the value of i by 1. Similarly, --i and i-- are both valid ways to decrease the value of i by 1. + ++和--既是前置又是后置运算。++i,i++,--i和i--都是有效的写法。 -我们需要注意的是这些运算符修改了i后有一个返回值。如果你只想修改i的值,那你就可以忽略这个返回值。但如果你想使用返回值,你就需要留意前置和后置操作的返回值是不同的。 +Note that these operators modify i and also return a value. If you only want to increment or decrement the value stored in i, you can ignore the returned value. However, if you do use the returned value, it will be different based on whether you used the prefix or postfix version of the operator, according to the following rules: + +需要注意的是,这些运算符修改了i后有一个返回值。如果你只想修改i的值,那你就可以忽略这个返回值。但如果你想使用返回值,你需要留意前置和后置操作符的返回值是不同的。 + +If the operator is written before the variable, it increments the variable before returning its value. +If the operator is written after the variable, it increments the variable after returning its value. 当++前置的时候,先自増再返回。 当++后置的时候,先返回再自增。 @@ -128,23 +221,42 @@ a = (b × 倍数) + 余数 let b = ++a // a 和 b 现在都是 1 let c = a++ // a 现在 2, 但 c 是 a 自增前的值 1 -上述例子,let b = ++a先把a加1了再返回a的值。所以a和b都是新值1。 +In the example above, let b = ++a increments a before returning its value. This is why both a and b are equal to to the new value of 1. + +However, let c = a++ increments a after returning its value. This means that c gets the old value of 1, and a is then updated to equal 2. + +Unless you need the specific behavior of i++, it is recommended that you use ++i and --i in all cases, because they have the typical expected behavior of modifying i and returning the result. + + + +上述例子中,`let b = ++a`首先使a自增1,再返回a的值。所以a和b都是新值1。 -而let c = a++,是先返回了a的值,然后a才加1。所以c得到了a的旧值1,而a加1后变成2。 +而let c = a++,先返回了a的值,然后a才自增1。所以c得到了a的旧值1,而a加1后变成2。 除非你需要使用i++的特性,不然推荐你使用++i和--i,因为先修改后返回这样的行为更符合我们的逻辑。 +The sign of a numeric value can be toggled using a prefixed -, known as the unary minus operator: -###一元负号 -数值的正负号可以使用前缀-(即一元负号)来切换: +###一元减号运算符 + +数值的正负号可以使用前缀-(即一元减号运算符)来切换: let three = 3 let minusThree = -three // minusThree 等于 -3 let plusThree = -minusThree // plusThree 等于 3, 或 "负负3" -一元负号(-)写在操作数之前,中间没有空格。 -###一元正号 -一元正号(+)不做任何改变地返回操作数的值。 +The unary minus operator (-) is prepended directly before the value it operates on, without any white space. + + +一元减号运算符(-)写在操作数之前,中间没有空格。 + +Unary Plus Operator + +The unary plus operator (+) simply returns the value it operates on, without any change: + +###一元加号操作符 + +一元加号操作符(+)不做任何改变地返回操作数的值。 let minusSix = -6 let alsoMinusSix = +minusSix // alsoMinusSix 等于 -6 @@ -162,7 +274,7 @@ a = (b × 倍数) + 余数 在表达式章节里有复合运算符的完整列表。 ‌ -##比较运算 +##比较运算符 swift支持所有c语言中的比较运算 * 等于(a == b) @@ -172,10 +284,18 @@ swift支持所有c语言中的比较运算 * 大于等于(a >= b) * 小于等于(a <= b) + +NOTE + +Swift also provides two identity operators (=== and !==), which you use to test whether two object references both refer to the same object instance. For more information, see Classes and Structures. + + >注意: -Swift 也提供恒等===和不恒等!==这两个比较符来判断两个对象是否引用同一个对象实例。更多细节在类与结构。 +Swift 也提供身份操作符(`===`和`!==`)来判断两个对象是否是同一个对象实例的引用。更多细节可以参考类与结构体。 + +Each of the comparison operators returns a Bool value to indicate whether or not the statement is true: -每个比较运算都返回了一个标识表达式是否成立的布尔值: +每个比较运算符都返回一个布尔值,用来表示一个表达式是否成立: 1 == 1 // true, 因为 1 等于 1 2 != 1 // true, 因为 2 不等于 1 @@ -184,6 +304,8 @@ Swift 也提供恒等===和不恒等!==这两个比较符来判断两个对象 1 >= 1 // true, 因为 1 大于等于 1 2 <= 1 // false, 因为 2 并不小于等于 1 +Comparison operators are often used in conditional statements, such as the if statement: + 比较运算多用于条件语句,如if条件: let name = "world" @@ -193,10 +315,20 @@ Swift 也提供恒等===和不恒等!==这两个比较符来判断两个对象 println("I'm sorry \(name), but I don't recognize you") } // 输出 "hello, world", 因为 `name` 就是等于 "world" -关于if语句,请看控制流。 -##三元条件运算 -三元条件运算的特殊在于它是有三个操作数的运算符,它的原型是 问题 ? 答案1 : 答案2。它简洁地表达根据问题成立与否作出二选一的操作。如果问题成立,返回答案1的结果; 如果不成立,返回答案2的结果。 +For more on the if statement, see Control Flow. + + +关于if语句,请参考[控制流](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-XID_153)。 + +Ternary Conditional Operator + +The ternary conditional operator is a special operator with three parts, which takes the form question ? answer1 : answer2. It is a shortcut for evaluating one of two expressions based on whether question is true or false. If question is true, it evaluates answer1 and returns its value; otherwise, it evaluates answer2 and returns its value. + +The ternary conditional operator is shorthand for the code below: + +##三元条件运算符 +三元条件运算符的特殊之处,在于它是一个包含三个部分的运算符,它的形式是 问题 ? 答案1 :答案2。它简洁地表达了两个表达式:如果问题成立,返回答案1的结果; 如果不成立,返回答案2的结果。 使用三元条件运算简化了以下代码 @@ -207,6 +339,9 @@ Swift 也提供恒等===和不恒等!==这两个比较符来判断两个对象 answer2 } +Here’s an example, which calculates the pixel height for a table row. The row height should be 50 pixels taller than the content height if the row has a header, and 20 pixels taller if the row doesn’t have a header: + + 这里有个计算表格行高的例子。如果有表头,那行高应比内容高度要高出50像素; 如果没有表头,只需高出20像素。 let contentHeight = 40 @@ -218,6 +353,8 @@ Swift 也提供恒等===和不恒等!==这两个比较符来判断两个对象 let hasHeader = true var rowHeight = contentHeight +The preceding example is shorthand for the code below: + 这样写会比下面的代码简洁: if hasHeader { @@ -227,12 +364,24 @@ Swift 也提供恒等===和不恒等!==这两个比较符来判断两个对象 } // rowHeight 现在是 90 -第一段代码例子使用了三元条件运算,所以一行代码就能让我们得到正确答案。这比第二段代码简洁得多,无需将rowHeight定义成变量,因为它的值无需在if语句中改变。 +The first example’s use of the ternary conditional operator means that rowHeight can be set to the correct value on a single line of code. This is more concise than the second example, and removes the need for rowHeight to be a variable, because its value does not need to be modified within an if statement. -三元条件运算提供有效率且便捷的方式来表达二选一的选择。需要注意的事,过度使用三元条件运算就会由简洁的代码变成难懂的代码。我们应避免在一个组合语句使用多个三元条件运算符。 +The ternary conditional operator provides an efficient shorthand for deciding which of two expressions to consider. Use the ternary conditional operator with care, however. Its conciseness can lead to hard-to-read code if overused. Avoid combining multiple instances of the ternary conditional operator into one compound statement. + + +第一段代码中使用了三元条件运算符,所以一行代码就能让我们得到正确的值。这比第二段代码简洁得多,无需将rowHeight定义成变量,因为它的值无需在if语句中改变。 + +三元条件运算符提供高效且便捷的方式来表达二选一的选择。需要注意的是,过度使用三元条件运算符,就会使代码变的难以阅读。我们应避免在一个组合语句中使用多个三元条件运算符。 ##区间运算符 -Swift 提供了两个方便表达一个区间的值的运算符。 +Swift 提供了两个方便表达一定区间的值的运算符。 + +Closed Range Operator + +The closed range operator (a...b) defines a range that runs from a to b, and includes the values a and b. + +The closed range operator is useful when iterating over a range in which you want all of the values to be used, such as with a for-in loop: + ###闭区间运算符 闭区间运算符(a...b)定义一个包含从a到b(包括a和b)的所有值的区间。 ‌ 闭区间运算符在迭代一个区间的所有值时是非常有用的,如在for-in循环中: @@ -245,12 +394,18 @@ Swift 提供了两个方便表达一个区间的值的运算符。 // 4 * 5 = 20 // 5 * 5 = 25 -关于for-in,请看控制流。 +关于for-in,请参考[控制流](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ControlFlow.html#//apple_ref/doc/uid/TP40014097-CH9-XID_153)。 -###半闭区间 -半闭区间(a..b)定义一个从a到b但不包括b的区间。 之所以称为半闭区间,是因为该区间包含第一个值而不包括最后的值。 +Half-Closed Range Operator -半闭区间的实用性在于当你使用一个0始的列表(如数组)时,非常方便地从0数到列表的长度。 +The half-closed range operator (a..b) defines a range that runs from a to b, but does not include b. It is said to be half-closed because it contains its first value, but not its final value. + +Half-closed ranges are particularly useful when you work with zero-based lists such as arrays, where it is useful to count up to (but not including) the length of the list: + +###半闭区间运算符 +半闭区间(a..b)定义了一个从a到b但不包括b的区间。 之所以称为半闭区间,是因为该区间包含第一个值而不包含最后的值。 + +半闭区间的实用性在于,当你使用一个初始元素序号为0的列表(如数组)时,可以非常方便地从0枚举到列表的长度。 let names = ["Anna", "Alex", "Brian", "Jack"] let count = names.count @@ -262,34 +417,60 @@ Swift 提供了两个方便表达一个区间的值的运算符。 // 第 3 个人叫 Brian // 第 4 个人叫 Jack -数组有4个元素,但0..count只数到3(最后一个元素的下标),因为它是半闭区间。关于数组,请查阅数组。 +Note that the array contains four items, but 0..count only counts as far as 3 (the index of the last item in the array), because it is a half-closed range. For more on arrays, see Arrays. + +Logical Operators -##逻辑运算 -逻辑运算的操作对象是逻辑布尔值。Swift 支持基于 C 语言的三个标准逻辑运算。 +Logical operators modify or combine the Boolean logic values true and false. Swift supports the three standard logical operators found in C-based languages: + +数组有4个元素,但0..count只数到3(最后一个元素的序号),因为它是半闭区间。关于数组,请查阅[数组章节]()。 + +##逻辑运算符 +逻辑运算符的操作对象是逻辑布尔值。Swift 支持基于 C 语言的三个标准逻辑运算。 * 逻辑非(!a) * 逻辑与(a && b) * 逻辑或(a || b) +Logical NOT Operator + +The logical NOT operator (!a) inverts a Boolean value so that true becomes false, and false becomes true. -###逻辑非 -逻辑非运算(!a)对一个布尔值取反,使得true变false,false变true。 +The logical NOT operator is a prefix operator, and appears immediately before the value it operates on, without any white space. It can be read as “not a”, as seen in the following example: -它是一个前置运算符,需出现在操作数之前,且不加空格。读作非 a,然后我们看以下例子: + +###逻辑非运算符 +逻辑非运算符(!a)对一个布尔值取反,使得true变false,false变true。 + +它是一个前置运算符,需要出现在操作数之前,之间不需要加空格。可以读作非 a。我们看以下的例子: let allowedEntry = false if !allowedEntry { println("ACCESS DENIED") } // 输出 "ACCESS DENIED" + +The phrase if !allowedEntry can be read as “if not allowed entry.” The subsequent line is only executed if “not allowed entry” is true; that is, if allowedEntry is false. + +As in this example, careful choice of Boolean constant and variable names can help to keep code readable and concise, while avoiding double negatives or confusing logic statements. + -if !allowedEntry语句可以读作 "如果 非 alowed entry。",接下一行代码只有在如果 "非 allow entry" 为true,即allowEntry为false时被执行。 -在示例代码中,小心地选择布尔常量或变量有助于代码的可读性,并且避免使用双重逻辑非运算,或混乱的逻辑语句。 -###逻辑与 -逻辑与(a && b)表达了只有a和b的值都为true时,整个表达式的值才会是true。 -只要任意一个值为false,整个表达式的值就为false。事实上,如果第一个值为false,那么是不去计算第二个值的,因为它已经不可能影响整个表达式的结果了。这被称做 "短路计算(short-circuit evaluation)"。 -以下例子,只有两个Bool值都为true值的时候才允许进入: +`if !allowedEntry`语句可以读作 "如果 非 alowed entry。",下一行代码只有在如果 "非 allow entry" 为`true`,即`allowEntry`为`false`时被执行。 +在示例代码中,谨慎地选择布尔常量或变量有助于代码的可读性,并且避免使用双重逻辑非运算,或使用混乱的逻辑语句。 + +Logical AND Operator + +The logical AND operator (a && b) creates logical expressions where both values must be true for the overall expression to also be true. + +If either value is false, the overall expression will also be false. In fact, if the first value is false, the second value won’t even be evaluated, because it can’t possibly make the overall expression equate to true. This is known as short-circuit evaluation. + +This example considers two Bool values and only allows access if both values are true: + +###逻辑与运算符 +逻辑与运算符`(a && b)`表达了只有`a`和`b`的值都为`true`时,整个表达式的值才会是`true`。 +只要任意一个值为`false`,整个表达式的值就为`false`。事实上,如果第一个值为`false`,那么是不会去计算第二个值的,因为它已经不可能影响整个表达式的结果了。这被称做 "短路计算(short-circuit evaluation)"。 +以下例子,只有两个`Bool`值都为`true`值的时候才允许进入: let enteredDoorCode = true let passedRetinaScan = false @@ -300,11 +481,21 @@ if !allowedEntry语句可以读作 "如果 非 alowed entry。",接下一行 } // 输出 "ACCESS DENIED" -###逻辑或 -逻辑或(a || b)是一个由两个连续的|组成的中置运算符。它表示了两个逻辑表达式的其中一个为true,整个表达式就为true。 +Logical OR Operator + +The logical OR operator (a || b) is an infix operator made from two adjacent pipe characters. You use it to create logical expressions in which only one of the two values has to be true for the overall expression to be true. + +Like the Logical AND operator above, the Logical OR operator uses short-circuit evaluation to consider its expressions. If the left side of a Logical OR expression is true, the right side is not evaluated, because it cannot change the outcome of the overall expression. + +In the example below, the first Bool value (hasDoorKey) is false, but the second value (knowsOverridePassword) is true. Because one value is true, the overall expression also evaluates to true, and access is allowed: + -同逻辑与运算类似,逻辑或也是"短路计算"的,当左端的表达式为true时,将不计算右边的表达式了,因为它不可能改变整个表达式的值了。 -以下示例代码中,第一个布尔值(hasDoorKey)为false,但第二个值(knowsOverridePassword)为true,所以整个表达是true,于是允许进入: + +###逻辑或运算符 +逻辑或运算符(a || b)是一个由两个连续的`|`组成的中置运算符。它表示两个逻辑表达式中,其中一个为`true`,整个表达式就为`true`。 + +同逻辑与运算类似,逻辑或也是"短路计算"的,当左端的表达式为`true`时,将不计算右边的表达式了,因为它不可能改变整个表达式的值了。 +以下示例代码中,第一个布尔值(hasDoorKey)为`false`,但第二个值(knowsOverridePassword)为`true`,所以整个表达是`true`,于是允许进入: let hasDoorKey = false let knowsOverridePassword = true @@ -324,15 +515,25 @@ if !allowedEntry语句可以读作 "如果 非 alowed entry。",接下一行 println("ACCESS DENIED") } // 输出 "Welcome!" + +This example uses multiple && and || operators to create a longer compound expression. However, the && and || operators still operate on only two values, so this is actually three smaller expressions chained together. It can be read as: + +If we’ve entered the correct door code and passed the retina scan; or if we have a valid door key; or if we know the emergency override password, then allow access. + +Based on the values of enteredDoorCode, passedRetinaScan, and hasDoorKey, the first two mini-expressions are false. However, the emergency override password is known, so the overall compound expression still evaluates to true. + +Explicit Parentheses + +It is sometimes useful to include parentheses when they are not strictly needed, to make the intention of a complex expression easier to read. In the door access example above, it is useful to add parentheses around the first part of the compound expression to make its intent explicit: -这个例子使用了含多个&&和||的复合逻辑。但无论怎样,&&和||始终只能操作两个值。所以这实际是三个简单逻辑连续操作的结果。我们来解读一下: +这个例子使用了含多个&&和||运算符的复合逻辑。但无论怎样,&&和||始终只能操作两个值。所以这实际是三个子表达式连续操作的结果。我们来解读一下: -如果我们输入了正确的密码并通过了视网膜扫描; 或者我们有一把有效的钥匙; 又或者我们知道紧急情况下重置的密码,我们就能把门打开进入。 +如果我们输入了正确的密码(enteredDoorCode)并通过了视网膜扫描(passedRetinaScan); 或者我们有一把有效的钥匙(hasDoorKey); 又或者我们知道紧急情况下重置的密码(knowsOverridePassword),我们就能把门打开。 -前两种情况,我们都不满足,所以前两个简单逻辑的结果是false,但是我们是知道紧急情况下重置的密码的,所以整个复杂表达式的值还是true。 +若前两种情况,我们都不满足,所以前两个简单逻辑的结果是`false`,但是我们若知道紧急情况下重置的密码,整个复杂表达式的值还是`true`。 ###使用括号来明确优先级 -为了一个复杂表达式更容易读懂,在合适的地方使用括号来明确优先级是很有效的,虽然它并非必要的。在上个关于门的权限的例子中,我们给第一个部分加个括号,使用它看起来逻辑更明确: +为了一个复杂表达式更容易读懂,在合适的地方使用括号来明确优先级是很有效的,虽然它并非必要。在上个关于门的权限的例子中,我们给第一个部分加个括号,使它看起来逻辑更明确: if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword { println("Welcome!") @@ -341,6 +542,6 @@ if !allowedEntry语句可以读作 "如果 非 alowed entry。",接下一行 } // 输出 "Welcome!" -这括号使得前两个值被看成整个逻辑表达中独立的一个部分。虽然有括号和没括号的输出结果是一样的,但对于读代码的人来说有括号的代码更清晰。可读性比简洁性更重要,请在可以让你代码变清晰地地方加个括号吧! +这个括号使得前两个值被看成整个逻辑表达中独立的一个部分。虽然有括号和没括号的输出结果是一样的,但对于读代码的人来说,有括号的代码更清晰。可读性比简洁性更重要,请在可以让你代码变清晰地地方加个括号吧! From fc6f5569e6dd25f85949066b0926dd490ac9da9b Mon Sep 17 00:00:00 2001 From: Joanna Wu Date: Fri, 4 Jul 2014 09:30:49 +0800 Subject: [PATCH 240/261] finish merge 2_01 the basics and delete the Chinese part --- src/chapter2/01_The_Basics.md | 226 +---- src/chapter2/01_The_Basics_reviewed.md | 1140 ------------------------ src/chapter2/12_Subscripts_Chinese.md | 2 +- 3 files changed, 27 insertions(+), 1341 deletions(-) delete mode 100644 src/chapter2/01_The_Basics_reviewed.md diff --git a/src/chapter2/01_The_Basics.md b/src/chapter2/01_The_Basics.md index 91f4514..1106ab0 100644 --- a/src/chapter2/01_The_Basics.md +++ b/src/chapter2/01_The_Basics.md @@ -8,9 +8,9 @@ Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整 除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,比如可以创建和传递一组数值的元组(tuples)。元组能在函数中以一个复合值的形式返回多个值。 -Swift还有可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用`nil`,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的`nil`,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大特性的核心。 +Swift还有可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用`nil`,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的`nil`,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大特性的核心。 -可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(`String`),类型安全性会阻止你错误的给它赋一个整型(`Int`)的值。这让你在开发的过程中尽早的发现***和解决***问题。 +可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(`String`),类型安全性会阻止你错误的给它赋一个整型(`Int`)的值。这让你在开发的过程中尽早的发现和解决问题。 # 常量和变量 @@ -27,8 +27,6 @@ var currentLoginAttempt = 0 这段代码可以解读为: -“Declare a new constant called maximumNumberOfLoginAttempts, and give it a value of 10. Then, declare a new variable called currentLoginAttempt, and give it an initial value of 0.” - 声明一个新的常量,叫做`maximumNumberOfLoginAttempts`(最大尝试登陆次数),值为`10`。声明一个新的变量,叫做`currentLoginAttempt`(当前尝试登陆次数),初始值设为`0`。 在这个例子中,最大尝试登陆次数被声明为常量,因为这个最大值不会改变,当前尝试登陆次数被声明为变量,因为这个值在每次尝试登陆失败后都要增加。 @@ -83,23 +81,11 @@ let 🐶🐮 = "dogcow" 一旦你声明了常量或变量为特定类型,你不能用同样的名称重新声明,不能改变它的储值类型,也不能把常量改为变量或变量改为常量。 -> NOTE - -> If you need to give a constant or variable the same name as a reserved Swift keyword, you can do so by surrounding the keyword with back ticks (`) when using it as a name. However, you should avoid using keywords as names unless you have absolutely no choice. - > 注意 > 如果你需要给一个常量或变量一个相同的名字作为swift的关键字,你可以在使用这个名字的时候用重音符(`)把关键字包围起来。然而,除非你没有别的选择,你应该避免使用关键字的方式来命名。 -You can change the value of an existing variable to another value of a compatible type. In this example, the value of friendlyWelcome is changed from "Hello!" to "Bonjour!": - -你可以改变一个已经存在的变量的值,变成另一个适配类型的值将一个已经存在的变量的值改变成另一个适配类型的值。在下面的例子里,变量`friendlyWelcome`的值从`"Hello!"`变成了`"Bonjour!"`: - -``` -var friendlyWelcome = "Hello!" -friendlyWelcome = "Bonjour!" -// friendlyWelcome is now "Bonjour!" -``` +你可以将一个已经存在的变量的值改变成另一个适配类型的值。在下面的例子里,变量`friendlyWelcome`的值从`"Hello!"`变成了`"Bonjour!"`: ``` var friendlyWelcome = "Hello!" @@ -107,8 +93,6 @@ friendlyWelcome = "Bonjour!" // friendlyWelcome的值现在是"Bonjour!"了。 ``` -Unlike a variable, the value of a constant cannot be changed once it is set. Attempting to do so is reported as an error when your code is compiled: - 和变量不同,常量的值一旦设定就不能更改。尝试更改会导致代码编译时报错。 ``` @@ -117,66 +101,39 @@ languageName = "Swift++" // this is a compile-time error - languageName cannot be changed ``` -# Printing Constants and Variables # 输出常量和变量 -You can print the current value of a constant or variable with the println function: - 你可以用`printIn`函数输出常量和变量的当前值: -``` -println(friendlyWelcome) -// prints "Bonjour!" -``` - ``` println(friendlyWelcome) // 输出 "Bonjour!" ``` -println is a global function that prints a value, followed by a line break, to an appropriate output. If you are working in Xcode, for example, println prints its output in Xcode’s “console” pane. (A second function, print, performs the same task without appending a line break to the end of the value to be printed.) - `printIn`是一个输出值的全局函数,为了得到良好的输出结果,输出后会加上一个空行。如果你使用的是Xcode,`printIn`会将结果输出到Xcode的调试信息栏。(另一个函数,`print`,会执行几乎相同的任务,除了不会在输出结果之后加空行以外。) -The println function prints any String value you pass to it: - -`printIn`函数会输出任何你赋值的字符串传递给它的字符串(`String`)值: +`printIn`函数会输出任何你传递给它的字符串(`String`)值: ``` println("This is a string") // prints "This is a string" ``` -The println function can print more complex logging messages, in a similar manner to Cocoa’s NSLog function. These messages can include the current values of constants and variables. - `printIn`函数可以输出更复杂的记录信息,和Cocoa的`NSlog`函数类似。这些信息可以包含常量和变量的当前值。 -Swift uses string interpolation to include the name of a constant or variable as a placeholder in a longer string, and to prompt Swift to replace it with the current value of that constant or variable. Wrap the name in parentheses and escape it with a backslash before the opening parenthesis: - -Swift使用字符串内插插值(string interpolation)的方式将常量或变量名以占位符的形式加入一个长的字符串中,并且提示Swift用常量或变量的当前值取代替它替换对应占位符。书写格式是将名字包裹在括号中并在前面加上反斜扛来转义: +Swift使用字符串插值(string interpolation)的方式将常量或变量名以占位符的形式加入字符串中,并且提示Swift用常量或变量的当前值替换对应占位符。书写格式是将名字包裹在括号中并在前面加上反斜扛来转义: -``` -println("The current value of friendlyWelcome is \(friendlyWelcome)") -// prints "The current value of friendlyWelcome is Bonjour!" -``` ``` println("The current value of friendlyWelcome is \(friendlyWelcome)") // 输出 "The current value of friendlyWelcome is Bonjour!" ``` -> NOTE - -> All options you can use with string interpolation are described in String Interpolation. - > 注意 > 关于字符串插值的详细参数,参见[字符串插值](link)。 -# Comments # 注释 -Use comments to include non-executable text in your code, as a note or reminder to yourself. Comments are ignored by the Swift compiler when your code is compiled. - 将代码中不会执行的文本,笔记或者备忘用注释来表达。注释在代码编译时会被忽略。 Swift中的注释和C中的注释十分相似。单行的注释以两个正斜杠(```//```)开头: @@ -242,10 +199,6 @@ Swift也提供了无符号整数类型,`UInt`,它和当前平台的原生长 * 在32位的平台上,`UInt`和`UInt32`范围相同。 * 在64位的平台上,`UInt`和`UInt64`范围相同。 -> NOTE - -> Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference. - > 注意 > 只在你需要特别指定无符号整数与当前平台原生长度范围相同时才使用`UInt`,否则,推荐使用`Int`,即使是你知道不会存储负值的时候。使用一致的`Int`整数类型有助于代码的复用,避免了不同数字类型之间的转换,并且和整数的类型推断结果一致,详见[类型安全和类型推断](link)。 @@ -256,16 +209,9 @@ Swift也提供了无符号整数类型,`UInt`,它和当前平台的原生长 浮点类型比整数类型范围大很多,它可以储存比整数更大或者更小的数。Swift提供了两种有符号的浮点数类型: -* Double represents a 64-bit floating-point number. Use it when floating-point values must be very large or particularly precise. -* Float represents a 32-bit floating-point number. Use it when floating-point values do not require 64-bit precision. - * `Double`代表64位浮点数。当你需要特别大和特别精确的值的时候使用`Double`类型。 * `Float`代表32位浮点数。当不需要像64位那么精确的时候使用`Float`就够了。 -> NOTE - -> Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. - > 注意 > `Double`有至少15位数字的精确度,而`Float`的精确度只有至少6位数字。根据业务需要的值的范围去选择合适的浮点类型。 @@ -427,8 +373,6 @@ var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound的值是0 ``` -Here, AudioSample is defined as an alias for UInt16. Because it is an alias, the call to AudioSample.min actually calls UInt16.min, which provides an initial value of 0 for the maxAmplitudeFound variable. - 在这个例子中,`AudioSample`被定义为`UInt16`的一个别名。因为这是一个别名,调用`AudioSample.min`实际上是调用`UInt16.min`给变量`maxAmplitudeFound`赋了初始值`0`。 # 布尔值 @@ -473,8 +417,6 @@ if i == 1 { } ``` -The result of the i == 1 comparison is of type Bool, and so this second example passes the type-check. Comparisons like i == 1 are discussed in Basic Operators. - `i == 1`的比较结果是一个`Bool`类型的值,因此第二个例子通过了类型检查。类似`i == 1`的比较我们会在[Basic Operators](link)进行深入讨论。 和其他Swift的类型安全的例子一样,这种检查避免了意外的错误并且保证了特定的某块代码的意图始终是明确的。 @@ -483,8 +425,6 @@ The result of the i == 1 comparison is of type Bool, and so this second example 元组将多个数值组合成一个单独的复合值。一个元组中的值可以是任何类型,不必是同一种类型。 -In this example, (404, "Not Found") is a tuple that describes an HTTP status code. An HTTP status code is a special value returned by a web server whenever you request a web page. A status code of 404 Not Found is returned if you request a webpage that doesn’t exist. - 在这个例子里, `(404, "Not Found")` 是一个用来形容HTTP状态码的元组。HTTP状态码是当你请求一个网页的时候网页服务器的返回值。当你请求的网页不存在的时候会返回`404 Not Found`的状态码。 ``` @@ -537,70 +477,43 @@ println("The status message is \(http200Status.description)") // prints "The status message is OK" ``` -Tuples are particularly useful as the return values of functions. A function that tries to retrieve a web page might return the (Int, String) tuple type to describe the success or failure of the page retrieval. By returning a tuple with two distinct values, each of a different type, the function provides more useful information about its outcome than if it could only return a single value of a single type. For more information, see Functions with Multiple Return Values. - 作为函数的返回值元组是很有用的。一个试图获取网页的函数可能返回一个(Int, String)类型的元组来描述这个页面获取成功或失败的状态。通过返回一个含有两个不同类型值的元组,这个函数的结果相比只能返回一个单独类型值的函数提供了更多有用的信息。详见[Functions with Multiple Return Values]()。 > 注意 > 当你处理一些相关数据的临时组合,元组是很有用的。它们不适合用于一些复杂的数据类型的创建。如果你的数据结构超过了一个临时的范畴,用class或者structrue会比用元组tuple更合适。更多信息,参见[Classes and Structures](link)。 -# Optionals # 可选类型 -You use optionals in situations where a value may be absent. An optional says: - 当值可能缺失的情况下,可以用可选类型(Options)。可选类型表示: -- There is a value, and it equals x - -or - -- There isn’t a value at all - - - 那里有一个值,它等于x 或者 - 值不存在 -> NOTE - -> The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structs, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there is a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants. - > 注意 -> 可选类型在C或者Objective-C中都不存在。在Objective-C中最接近的是一个返回一个对象的方法也可以返回一个`nil`值的能力,`nil`的意思是“有效对象的缺失”。然而,它只对对象有效,对`structs`,basic C types, or enumeration values*基本的C类型、或者枚举类型*都是无效的。对这些类型,Objective-C通常会返回一个特殊值(比如`NSNotFound`)来表示值缺失。这样的方式假定我们调用方法时它必须知道有一个特殊值,并且要记得去检查它。Siwft的可选类型让你可以给任意类型的值声明这个值缺失,不需要任何其它的特殊常量。 - -Here’s an example. Swift’s String type has a method called toInt, which tries to convert a String value into an Int value. However, not every string can be converted into an integer. The string "123" can be converted into the numeric value 123, but the string "hello, world" does not have an obvious numeric value to convert to. - -下面是一个例子。Siwft的字符串类型有一个`toInt`的方法,它会尝试将一个字符串类型转换成一个整数类型。然而,不是每一个字符串都可以转换成整数。字符串“123”`"123"`可以转换为数字量`123`,但是字符串`"Hello, world"`并没有一个明显的数字量可以转换。 +> 可选类型在C或者Objective-C中都不存在。在Objective-C中最接近的是返回一个对象的方法也可以返回一个`nil`值的能力,`nil`的意思是“有效对象的缺失”。然而,它只对对象有效,对`structs`,基本的C类型、或者枚举类型都是无效的。对这些类型,Objective-C通常会返回一个特殊值(比如`NSNotFound`)来表示值缺失。这样的方式假定我们调用方法时它必须知道有一个特殊值,并且要记得去检查它。Siwft的可选类型让你可以给任意类型的值声明这个值缺失,不需要任何其它的特殊常量。 -The example below uses the toInt method to try to convert a String into an Int: +下面是一个例子。Swift的字符串类型有一个`toInt`的方法,它会尝试将一个字符串类型转换成一个整数类型。然而,不是每一个字符串都可以转换成整数。字符串`"123"`可以转换为数字量`123`,但是字符串`"Hello, world"`并没有一个明显的数字量可以转换。 下面这个例子用`toInt`方法尝试转换字符串到整数: ``` let possibleNumber = "123" let convertedNumber = possibleNumber.toInt() -// convertedNumber is inferred to be of type "Int?", or "optional Int" +// convertedNumber被推断为"Int?"类型, 或 "可选整数" ``` -Because the toInt method might fail, it returns an optional Int, rather than an Int. An optional Int is written as Int?, not Int. The question mark indicates that the value it contains is optional, meaning that it might contain some Int value, or it might contain no value at all. (It can’t contain anything else, such as a Bool value or a String value. It’s either an Int, or it’s nothing at all.) +因为`toInt`方法可能失败,它返回的是可选类型的整数,而不是一个整数。一个可选的整数表示为`Int?`,而不是`Int`。最后的问号表示这个值是可选的,意味着它可能包含整数类型的值,或者没有值。(它不能包括其它任何值,比如布尔值或者字符串。它要么是一个整数,要么就没有值。) -因为`toInt`方法可能失败,它返回的是可以可选类型的整数,而不是一个整数。一个可选的整数表示为`Int?`,而不是`Int`。最后的问号表示这个值是可选的,意味着它可能包含整数类型的值,或者没有值。(它不能包括其它任何值,比如布尔值或者字符串。它要么是一个整数,要么就没有值。) - -## If Statements and Forced Unwrapping ## If语句和强制解析 -You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to true; if it has no value at all, it evaluates to false. - 你可以使用`if`语句来判断一个可选类型是否有值。如果有值,它就等于`true`,如果没有值,就等于`false`。 -Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value: - -一旦你确定可选类型是有值的,你可以在可选类型的名字后面加一个感叹号(!)`!`来调用它的值。这个感叹号的意思是:”我知道这个可选类型的值一定存在一个值,请使用这个值。“这叫做可选值的强制解析: +一旦你确定可选类型是有值的,你可以在可选类型的名字后面加一个感叹号`!`来调用它的值。这个感叹号的意思是:”我知道这个可选类型的值存在值,请使用这个值。“这叫做可选值的强制解析: ``` if convertedNumber { @@ -611,27 +524,16 @@ if convertedNumber { // prints "123 has an integer value of 123" ``` -For more on the if statement, see Control Flow. - -更多*`if`语句的*信息,见[Control Flow](link)。 - -> NOTE - -> Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value. +更多`if`语句的信息,见[Control Flow](link)。 > 注意 -> 如果你使用`!`来调用一个不存在的可选值,会报出实时运行时错误。在使用`!`强制解析可选值之前总是请确认这个可选值包含一个非`nil`的值。 +> 如果你使用`!`来调用一个不存在的可选值,会报运行时错误。在使用`!`强制解析可选值之前请确认这个可选值包含一个非`nil`的值。 -## Optional Binding ## 可选值绑定 -You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used with if and while statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action. if and while statements are described in more detail in Control Flow. - 你可以使用可选值绑定(optional binding)来找出一个可选类型是否包含值,如果包含,则可以把这个值作为一个临时常量或变量来使用。可选值绑定可以和`if`或`while`语句一起来检查可选值里面的值,并且解析到一个常量或变量中,所有这些都在一步操作中完成。更多关于`if`和`while`语句的信息,见[Control Flow](link)。 -Write optional bindings for the if statement as follows: - 像这样给`if`语句写可选值绑定: ``` @@ -640,8 +542,6 @@ if let constantName = someOptional { } ``` -You can rewrite the possibleNumber example from above to use optional binding rather than forced unwrapping: - 你可以用可选值绑定来代替强制解析来重写之前那个`possibleNumber`的例子: ``` @@ -653,28 +553,16 @@ if let actualNumber = possibleNumber.toInt() { // prints "123 has an integer value of 123" ``` -This can be read as: - 这段代码可以解读为: -“If the optional Int returned by possibleNumber.toInt contains a value, set a new constant called actualNumber to the value contained in the optional.” - -”如果可选整数值通过`possibleNumber.toInt`返回一个值,设定一个叫`actualNumber`的新常量来储存这个可选整数中的值。“ - -If the conversion is successful, the actualNumber constant becomes available for use within the first branch of the if statement. It has already been initialized with the value contained within the optional, and so there is no need to use the ! suffix to access its value. In this example, actualNumber is simply used to print the result of the conversion. +”如果可选整数值通过`possibleNumber.toInt`返回一个值,设定一个叫`actualNumber`的新常量来储存这个可选整数中的值。“ 如果这个转换是成功的,那么常量`actualNumber`在`if`语句的第一个分支就可用了。它已经用可选量中的值初始化了,所以现在不需要用`!`后缀来调用这个值。在这个例子中,`actualNumber`只是简单的用于输出转换结果。 -You can use both constants and variables with optional binding. If you wanted to manipulate the value of actualNumber within the first branch of the if statement, you could write if var actualNumber instead, and the value contained within the optional would be made available as a variable rather than a constant. - 无论是常量还是变量你都可以使用可选值绑定。如果你希望对`if`语句第一个分支中`actualNumber`的值进行操作,你可以用`if var actualNumber`来声明,然后可选量中的值就会成为一个可用的变量而不是常量。 -## nil ## nil -You set an optional variable to a valueless state by assigning it the special value nil: - -给可选变量一个没有值的状态是通过给它赋予一个特殊值`nil`来完成的: 通过给可选变量赋予特殊值`nil`来表示没有值的状态: ``` @@ -684,51 +572,30 @@ serverResponseCode = nil // serverResponseCode now contains no value ``` -> NOTE - -> nil cannot be used with non-optional constants and variables. If a constant or variable in your code needs to be able to cope with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type. - > 注意 > `nil`不能被用于可选类型之外的常量和变量。如果你的代码中的常量或变量需要处理值缺失的情况,总是用一个可选的合适类型来声明它。 -If you define an optional constant or variable without providing a default value, the constant or variable is automatically set to nil for you: - -如果你定义一个可选的常量或变量,却没有赋初值,这个常量或变量会自动设*置*为`nil`: +如果你定义一个可选的常量或变量,却没有赋初值,这个常量或变量会自动设置为`nil`: ``` var surveyAnswer: String? // surveyAnswer is automatically set to nil ``` -> NOTE - -> Swift’s nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a non-existent object. In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types. - > 注意 -> Swift的`nil`和Objective-C中的不完全一样。Objective-C中,`nil`是指向不存在对象*的指针*。而在Swift中,`nil`不止是一个指针——它是一个特定类型的值缺失。可选的任何类型都可以设为`nil`,不只是对象类型。 +> Swift的`nil`和Objective-C中的不完全一样。Objective-C中,`nil`是指向不存在对象的指针。而在Swift中,`nil`不止是一个指针——它是一个特定类型的值缺失。可选的任何类型都可以设为`nil`,不只是对象类型。 -## Implicitly Unwrapped Optionals ## 隐式解析可选值 -As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist. - 像之前说的,可选值意味着一个常量或变量允许“没有值”。可以通过`if`语句来判断可选值中是否有值存在,如果值存在则用可选值绑定来调用可选量的值。 -Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time. - 有时候从程序的结构可以清楚的知道一个可选值在第一次值设定之后,它总是有值的。在这些情况下,把每次调用都检查并解析可选量的值去掉是很有用的,因为它们可以安全的被推断出它们总是有值的。 -These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional. +这些类型的可选值被定义为隐式解析可选值。当你创建可选值的时候,你可以通过写感叹号(String!)而不是问号(String?)的形式来表示一个隐式解析的可选值。 -这些类型的可选值被定义为隐式解析可选值。当你创建可选值的时候,你可以通过写感叹号(String!)而不是问号(String?)的形式来表示一个隐式解析的可选值。 - -Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties. - -如果可选值在第一次定义之后就肯定存在值并且之后每一刻都肯定存在,这种情况下隐式解析可选值是很有用的。Swift中的隐式解析可选值的主要用法是在类的初始化过程中,参见[Unowned References and Implicitly Unwrapped Optional Properties](link)。 - -An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it is accessed. The following example shows the difference in behavior between an optional String and an implicitly unwrapped optional String: +如果可选值在第一次定义之后就肯定存在值并且之后每一刻都肯定存在,这种情况下隐式解析可选值是很有用的。Swift中的隐式解析可选值的主要用法是在类的初始化过程中,参见[Unowned References and Implicitly Unwrapped Optional Properties](link)。 一个隐式解析可选值其实是一个普通的可选值,但它也可以像非可选的值那样使用,无须每次调用都解析可选量的值。下面的例子显示了一个普通的可选的字符串和一个隐式解析的可选字符串的区别: @@ -742,19 +609,11 @@ println(assumedString) // no exclamation mark is needed to access its value // prints "An implicitly unwrapped optional string." ``` -You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used. Rather than placing an exclamation mark after the optional’s name each time you use it, you place an exclamation mark after the optional’s type when you declare it. - 你可以把隐式解析可选值当作一个允许可选值每次都能自动解析的授权。你只需要当你声明的时候在可选量的类型后面放一个感叹号,而不用每次使用的时候都在可选值后面放感叹号。 -> NOTE - -> If you try to access an implicitly unwrapped optional when it does not contain a value, you will trigger a runtime error. The result is exactly the same as if you place an exclamation mark after a normal optional that does not contain a value. - > 注意 -> 如果你试图调用一个没有值的隐式解析可选值,你会得到一个实时的运行时错误。这和你在一个普通的不含值的可选值后面放感叹号的结果是完全一样的。 - -You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value: +> 如果你试图调用一个没有值的隐式解析可选值,你会得到一个运行时错误。这和你在一个普通的不含值的可选值后面放感叹号的结果是完全一样的。 你仍然可以把隐式解析可选值当作一个普通的可选值,来检查它是否含有值: @@ -765,8 +624,6 @@ if assumedString { // prints "An implicitly unwrapped optional string." ``` -You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement: - 你同样可以对隐式解析可选值使用可选值绑定,在一行声明中来检查和解析它的值: ``` @@ -776,35 +633,21 @@ if let definiteString = assumedString { // prints "An implicitly unwrapped optional string." ``` -> NOTE - -> Implicitly unwrapped optionals should not be used when there is a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable. - > 注意 > 当一个变量有可能是`nil`的情况下,不应当使用隐式解析可选值。如果在整个过程中检查一个变量是否有`nil`值,你应该用一个普通的可选值。 -# Assertions # 断言 -Optionals enable you to check for values that may or may not exist, and to write code that copes gracefully with the absence of a value. In some cases, however, it is simply not possible for your code to continue execution if a value does not exist, or if a provided value does not satisfy certain conditions. In these situations, you can trigger an assertion in your code to end code execution and to provide an opportunity to debug the cause of the absent or invalid value. - -可选值让你可以检查一个值是否存在,并且优雅的处理值缺失的情况。然而,在一些情况下,如果值不存在或者值不满足指定的条件,你的程序就无法继续执行。在这些情况下,你可以在代码中触发一个断言,来中断代码的执行并且提供一个来调试为什么值缺失或无效的机会。 +可选值让你可以检查一个值是否存在,并且优雅的处理值缺失的情况。然而,在一些情况下,如果值不存在或者值不满足指定的条件,你的程序就无法继续执行。在这些情况下,你可以在代码中触发一个断言,来中断代码的执行来调试为什么值缺失或无效。 -## Debugging with Assertions ## 用断言来调试 -An assertion is a runtime check that a logical condition definitely evaluates to true. Literally put, an assertion “asserts” that a condition is true. You use an assertion to make sure that an essential condition is satisfied before executing any further code. If the condition evaluates to true, code execution continues as usual; if the condition evaluates to false, code execution ends, and your app is terminated. +断言是判断一个逻辑条件是否为真的实时检查。基本上,一个断言就是“断定”(asserts)一个条件为真。你可以使用断言来确保在运行后续代码之前一个必要的条件是已经满足了的。如果这个条件为真,代码会正常执行,如果条件为否,代码会停止执行,并且你的应用会终止。 -断言是判断一个逻辑条件是否为真的实时检查。基本上,一个断言就是“断定”(asserts)一个条件为真。你可以使用断言来确保在运行后续代码之前它的一个必要的条件是已经满足了的。如果这个条件为真,代码会正常执行,如果条件为否,代码会停止执行,并且你的app应用会终止。 +如果你的代码在调试环境下触发了一个断言(比如当你在Xcode中创建并运行一个app的时候),你可以准确的看到非法语句出现的位置,也可以查询到当断言触发时app的状态。断言还允许你可以提供一个相应的调试信息。 -If your code triggers an assertion while running in a debug environment, such as when you build and run an app in Xcode, you can see exactly where the invalid state occurred and query the state of your app at the time that the assertion was triggered. An assertion also lets you provide a suitable debug message as to the nature of the assert. - -如果你的代码在调试环境下触发了一个断言(比如当你在Xcode中创建并运行一个app的时候),你可以准确的看到非法语句出现的位置,也可以查询到当断言触发时app的状态。断言还允许你可以提供一个相应的调试信息。 - -You write an assertion by calling the global assert function. You pass the assert function an expression that evaluates to true or false and a message that should be displayed if the result of the condition is false: - -通过调用全局的断言assert函数来写一个断言。你给断言函数传入一个等于true或false的表达式会被解析为`true`或者`false`的表达式,当结果是false的时候,会显示出一条信息以及在解析为`false`时的提示信息: +通过调用全局的assert函数来写一个断言。你给断言函数传入一个会被解析为`true`或者`false`的表达式,以及在解析为`false`时的提示信息: ``` let age = -3 @@ -812,41 +655,24 @@ assert(age >= 0, "A person's age cannot be less than zero") // this causes the assertion to trigger, because age is not >= 0 ``` -In this example, code execution will continue only if age >= 0 evaluates to true, that is, if the value of age is non-negative. If the value of age is negative, as in the code above, then age >= 0 evaluates to false, and the assertion is triggered, terminating the application. - -在这个例子里,只有`age >= 0`为真的时候代码才会继续执行,也就是,如果`age`的值是非负数。在上面的代码中,如果`age`的值是负数,在上面的代码中,`age >= 0`的条件判断这个表达式解析为否,这个断言被触发,终止了这个程序。 - -Assertion messages cannot use string interpolation. The assertion message can be omitted if desired, as in the following example: +在这个例子里,只有`age >= 0`为真的时候代码才会继续执行,也就是,如果`age`的值是非负数。在上面的代码中,如果`age`的值是负数,`age >= 0`这个表达式解析为否,断言被触发,终止了这个程序。 -断言信息不能使用字符串插值。如果你想,断言信息可以省略,像下面这个例子: +断言信息不能使用字符串插值。断言信息可以省略,像下面这个例子: ``` assert(age >= 0) ``` -## When to Use Assertions ## 何时使用断言 -Use an assertion whenever a condition has the potential to be false, but must definitely be true in order for your code to continue execution. Suitable scenarios for an assertion check include: - -如果在一个条件有可能为否,但只有它为真的时候代码才能继续执行,这时时,应该使用断言。适当的使用断言检查的*合适*场景包括: - -- An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high. -- A value is passed to a function, but an invalid value means that the function cannot fulfill its task. -- An optional value is currently nil, but a non-nil value is essential for subsequent code to execute successfully. +在一个条件有可能为否,但只有它为真的时候代码才能继续执行时,应该使用断言。使用断言检查的合适场景包括: - 一个整数类型的下标索引被传入一个自定义的下标实现,但是这个下标索引值太小或太大。 - 一个值传入一个函数,但是如果传入不合法的值,这个函数就无法满足需求。 - 一个可选值当前的值是`nil`,但是后续代码成功执行需要一个非`nil`值。 -See also Subscripts and Functions. - 参见[Subscripts and Functions](link)。 -> NOTE - -> Assertions cause your app to terminate and are not a substitute for designing your code in such a way that invalid conditions are unlikely to arise. Nonetheless, in situations where invalid conditions are possible, an assertion is an effective way to ensure that such conditions are highlighted and noticed during development, before your app is published. - > 注意 -> 断言会造成你的app终止,它并不能代替你设计代码来保证不合法情况不出现。尽管如此,当不合法的情况可能出现时,断言可以有效的保证在你的app正式发布之前,在的开发过程中这种不合法的情况就会被高亮并被注意到。 \ No newline at end of file +> 断言会造成你的app终止,它并不能代替你设计代码来保证不合法情况不出现。尽管如此,当不合法的情况可能出现时,断言可以有效的保证在你的app在正式发布之前的开发过程中这种不合法的情况就会被高亮并被注意到。 \ No newline at end of file diff --git a/src/chapter2/01_The_Basics_reviewed.md b/src/chapter2/01_The_Basics_reviewed.md deleted file mode 100644 index af57fc6..0000000 --- a/src/chapter2/01_The_Basics_reviewed.md +++ /dev/null @@ -1,1140 +0,0 @@ -- ***加了删除线跟着后面的文本是我建议翻译的内容,加粗的文本是我建议应该有的文本,你可以看着merge。*** -- ***我对所有语法关键字、代码都加了markdown的代码标记*** - -# The Basics -# 基础部分 - -Swift is a new programming language for iOS and OS X app development. Nonetheless, many parts of Swift will be familiar from your experience of developing in C and Objective-C. - -Swift是一个用于iOS和OS X平台开发的新的编程语言。尽管如此,Swift在很多地方都会和你以往用C语言和Objective-C开发的经验类似。 - -Swift provides its own versions of all fundamental C and Objective-C types, including Int for integers; Double and Float for floating-point values; Bool for Boolean values; and String for textual data. Swift also provides powerful versions of the two primary collection types, Array and Dictionary, as described in Collection Types. - -***建议对语法关键字加上代码标记。*** - -Swift为所有C和Objective-C的基础类型提供了自己的版本,包括整数值`Int`,浮点值`Double`和`Float`,布尔值`Bool`,以及文本值`String`。Swift还提供了两个强大的常见集合类型,数组和字典数组`Array`和字典`Dictionary`,见[集合类型](link)。 - -Like C, Swift uses variables to store and refer to values by an identifying name. Swift also makes extensive use of variables whose values cannot be changed. These are known as constants, and are much more powerful than constants in C. Constants are used throughout Swift to make code safer and clearer in intent when you work with values that do not need to change. - -***感觉括号就统一用中文的,会不会好点= =*** - -和C一样,Swift使用具有唯一名称的变量(variables)来储存和指向特定值。Swift还对那些值不能改变的变量进行了扩展,他们也被称为常量(Constants),Swift中的常量比C中的常量更加强大。在Swift中当你需要处理一些恒定不变的值的时候,使用常量(Constants)可以让代码更加安全和整洁。 - -In addition to familiar types, Swift introduces advanced types not found in Objective-C. These include tuples, which enable you to create and pass around groupings of values. Tuples can return multiple values from a function as a single compound value. - -除了这些我们熟知的类型以外,Swift还有一些在Objective-C中没有的高级类型,包括:元组(tuples),你可以创建和传递一组数值。元组(tuples)可以在函数中以一个复合值的形式返回多个数值。比如可以创建和传递一组数值的元组(tuples)。元组能在函数中以一个复合值的形式返回多个值。 - -Swift also introduces optional types, which handle the absence of a value. Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”. Optionals are similar to using nil with pointers in Objective-C, but they work for any type, not just classes. Optionals are safer and more expressive than nil pointers in Objective-C and are at the heart of many of Swift’s most powerful features. - -Swift还有可选(Optionals)类型,来处理值缺失的情况。可选类型表示“值是x”或者“没有值”。可选类型类似于在Objective-C的指针中使用`nil`,但是可选类型可以用在任意类型上,而不只是类。相比于Objective-C中的`nil`,可选类型(Optionals)更加安全和高效,可选类型也是Swift的众多强大特性的核心。 - -Optionals are an example of the fact that Swift is a type safe language. Swift helps you to be clear about the types of values your code can work with. If part of your code expects a String, type safety prevents you from passing it an Int by mistake. This enables you to catch and fix errors as early as possible in the development process. - -可选类型说明了Swift是一个类型安全的语言。Swift让你清楚的知道你的代码中可用的值的类型。如果你期望这部分代码是字符串(`String`),类型安全性会阻止你错误的给它赋一个整型(`Int`)的值。这让你在开发的过程中尽早的发现***和解决***问题。 - -# Constants and Variables -# 常量和变量 - -Constants and variables associate a name (such as maximumNumberOfLoginAttempts or welcomeMessage) with a value of a particular type (such as the number 10 or the string "Hello"). The value of a constant cannot be changed once it is set, whereas a variable can be set to a different value in the future. - -常量和变量对应一个变量名(如`maximumNumberOfLoginAttempts`或`welcomeMessage`)以及对应类型的值(如数字`10`或字符串`"Hello"`)将一个变量名(如`maximumNumberOfLoginAttempts`或`welcomeMessage`)和对应类型的值(如数字`10`或字符串`"Hello"`)进行关联。常量的值一旦设定就不能改变,变量的值可以改变。 - -# Declaring Constants and Variables -# 声明常量和变量 - -Constants and variables must be declared before they are used. You declare constants with the let keyword and variables with the var keyword. Here’s an example of how constants and variables can be used to track the number of login attempts a user has made: - -常量和变量必须在使用前声明。用`let`来声明常量,用`var`来声明变量。下面是一个用常量和变量来记录用户尝试登录次数的例子: - -``` -let maximumNumberOfLoginAttempts = 10 -var currentLoginAttempt = 0 ``` - -This code can be read as: - -这段代码可以解读为: - -“Declare a new constant called maximumNumberOfLoginAttempts, and give it a value of 10. Then, declare a new variable called currentLoginAttempt, and give it an initial value of 0.” - -声明一个新的常量,叫做“登录尝试次数的最大值”`maximumNumberOfLoginAttempts`(最大尝试登陆次数),值为`10`。声明一个新的变量,叫“当前尝试次数”做`currentLoginAttempt`(当前尝试登陆次数),初始值设为`0`。 - -In this example, the maximum number of allowed login attempts is declared as a constant, because the maximum value never changes. The current login attempt counter is declared as a variable, because this value must be incremented after each failed login attempt. - -在这个例子中,登录尝试次数的最大值最大尝试登陆次数被声明为常量,因为这个最大值不会改变,当前尝试次数当前尝试登陆次数被声明为变量,因为这个值在每次失败的登录尝试尝试登陆失败后都要增加。 - -You can declare multiple constants or multiple variables on a single line, separated by commas: - -你可以在同一行内声明多个常量或变量,用逗号分割: - -``` -var x = 0.0, y = 0.0, z = 0.0 -``` - -> NOTE - -> If a stored value in your code is not going to change, always declare it as a constant with the let keyword. Use variables only for storing values that need to be able to change. - -> 注意 - -> 当值不会改变时,永远用`let`声明常量。只在值需要改变的时候用变量。 - -# Type Annotations -# 类型批注 - -You can provide a type annotation when you declare a constant or variable, to be clear about the kind of values the constant or variable can store. Write a type annotation by placing a colon after the constant or variable name, followed by a space, followed by the name of the type to use. - -在声明常量和变量时,你可以提供一个类型批注,来表明这个常量或变量可以储存的值的类型。类型批注的格式是在常量或变量名后加一个冒号,接着是一个空格,接着是要***使***用的类型的名称。 - -This example provides a type annotation for a variable called welcomeMessage, to indicate that the variable can store String values: - -下面是一个叫`welcomeMessage`的变量的类型批注的例子,来说明这个变量可以储存字符串`String`(字符串)类型的值: - -``` -var welcomeMessage: String -``` - -The colon in the declaration means “…of type…,” so the code above can be read as: - -这个表达式声明中***的***冒号表示“类型是”,所以这段代码可以解读为: - -“Declare a variable called welcomeMessage that is of type String.” - -“声明一个叫`welcomeMessage`的变量,类型是`String`(字符串)。” - -The phrase “of type String” means “can store any String value.” Think of it as meaning “the type of thing” (or “the kind of thing”) that can be stored. - -“类型是`String`(字符串)”表示“可以储存任意的`String`(字符串)类型的值”。可以把它想作是它可以储存的“一个事物的类型”。 - -The welcomeMessage variable can now be set to any string value without error: - -变量`welcomeMessage`可以被赋值为任意`String`(字符串)类型的值,而不会报错: - -``` -welcomeMessage = "Hello" -``` - -> NOTE - -> It is rare that you need to write type annotations in practice. If you provide an initial value for a constant or variable at the point that it is defined, Swift can almost always infer the type to be used for that constant or variable, as described in Type Safety and Type Inference. In the welcomeMessage example above, no initial value is provided, and so the type of the welcomeMessage variable is specified with a type annotation rather than being inferred from an initial value. - -> 注意 - -> 在实践中你需要写类型批注的很少见很少需要写类型批注。如果你在定义一个常量或变量的时候时给了它一个初始值,Swift几乎总是可以推断出这个常量或变量使用的类型,参见[类型安全和类型推断](link)。在上面这个welcomeMessage的例子里,没有提供初始值,所以`welcomeMessage`这个变量的类型通过类型批注的形式指定,而不是通过从初始值推断而来。 - -# Naming Constants and Variables -# 命名常量和变量 - -You can use almost any character you like for constant and variable names, including Unicode characters: - -你可以使用几乎所有你喜欢的符号来命名常量和变量,包括unicode字符: - -``` -let π = 3.14159 -let 你好 = "你好世界" -let 🐶🐮 = "dogcow" -``` - -Constant and variable names cannot contain mathematical symbols, arrows, private-use (or invalid) Unicode code points, or line- and box-drawing characters. Nor can they begin with a number, although numbers may be included elsewhere within the name. - -常量和变量的命名不能包括数学运算符,箭头, 私有(或无效)的unicode码位, 或者线条(line-),以及制表符(box-drawing)字符。也不能以数字开头,尽管数字可以出现在变量名的其他位置。 - -Once you’ve declared a constant or variable of a certain type, you can’t redeclare it again with the same name, or change it to store values of a different type. Nor can you change a constant into a variable or a variable into a constant. - -一旦你声明了常量或变量为特定类型,你不能用同样的名称重新声明,不能改变它的储值类型,也不能把常量改为变量或变量改为常量。 - -> NOTE - -> If you need to give a constant or variable the same name as a reserved Swift keyword, you can do so by surrounding the keyword with back ticks (`) when using it as a name. However, you should avoid using keywords as names unless you have absolutely no choice. - -> 注意 - -> 如果你需要给一个常量或变量一个相同的名字作为swift的关键字,你可以在使用这个名字的时候用重音符(`)把关键字包围起来。然而,除非你没有别的选择,你应该避免使用关键字的方式来命名。 - -You can change the value of an existing variable to another value of a compatible type. In this example, the value of friendlyWelcome is changed from "Hello!" to "Bonjour!": - -你可以改变一个已经存在的变量的值,变成另一个适配类型的值将一个已经存在的变量的值改变成另一个适配类型的值。在下面的例子里,变量`friendlyWelcome`的值从`"Hello!"`变成了`"Bonjour!"`: - -``` -var friendlyWelcome = "Hello!" -friendlyWelcome = "Bonjour!" -// friendlyWelcome is now "Bonjour!" -``` - -``` -var friendlyWelcome = "Hello!" -friendlyWelcome = "Bonjour!" -// friendlyWelcome的值现在是"Bonjour!"了。 -``` - -Unlike a variable, the value of a constant cannot be changed once it is set. Attempting to do so is reported as an error when your code is compiled: - -和变量不同,常量的值一旦设定就不能更改。尝试更改会导致代码编译时报错。 - -``` -let languageName = "Swift" -languageName = "Swift++" -// this is a compile-time error - languageName cannot be changed -``` - -# Printing Constants and Variables -# 输出常量和变量 - -You can print the current value of a constant or variable with the println function: - -你可以用`printIn`函数输出常量和变量的当前值: - -``` -println(friendlyWelcome) -// prints "Bonjour!" -``` - -``` -println(friendlyWelcome) -// 输出 "Bonjour!" -``` - -println is a global function that prints a value, followed by a line break, to an appropriate output. If you are working in Xcode, for example, println prints its output in Xcode’s “console” pane. (A second function, print, performs the same task without appending a line break to the end of the value to be printed.) - -`printIn`是一个输出值的全局函数,为了得到良好的输出结果,输出后会加上一个空行。如果你使用的是Xcode,`printIn`会将结果输出到Xcode的调试信息栏。(另一个函数,`print`,会执行几乎相同的任务,除了不会在输出结果之后加空行以外。) - -The println function prints any String value you pass to it: - -`printIn`函数会输出任何你赋值的字符串传递给它的字符串(`String`)值: - -``` -println("This is a string") -// prints "This is a string" -``` - -The println function can print more complex logging messages, in a similar manner to Cocoa’s NSLog function. These messages can include the current values of constants and variables. - -`printIn`函数可以输出更复杂的记录信息,和Cocoa的`NSlog`函数类似。这些信息可以包含常量和变量的当前值。 - -Swift uses string interpolation to include the name of a constant or variable as a placeholder in a longer string, and to prompt Swift to replace it with the current value of that constant or variable. Wrap the name in parentheses and escape it with a backslash before the opening parenthesis: - -Swift使用字符串内插插值(string interpolation)的方式将常量或变量名以占位符的形式加入一个长的字符串中,并且提示Swift用常量或变量的当前值取代替它替换对应占位符。书写格式是将名字包裹在括号中并在前面加上反斜扛来转义: - -``` -println("The current value of friendlyWelcome is \(friendlyWelcome)") -// prints "The current value of friendlyWelcome is Bonjour!" -``` -``` -println("The current value of friendlyWelcome is \(friendlyWelcome)") -// 输出 "The current value of friendlyWelcome is Bonjour!" -``` - -> NOTE - -> All options you can use with string interpolation are described in String Interpolation. - -> 注意 - -> 关于字符串插值的详细参数,参见[字符串插值](link)。 - -# Comments -# 注释 - -Use comments to include non-executable text in your code, as a note or reminder to yourself. Comments are ignored by the Swift compiler when your code is compiled. - -将代码中不会执行的文本,笔记或者备忘用注释来表达。注释在***代码***编译时会被忽略。 - -Comments in Swift are very similar to comments in C. Single-line comments begin with two forward-slashes (//): - -Swift中的注释和C中的注释十分相似。单行的注释以两个正斜杠(```//```)开头: - -``` -// this is a comment -``` - -``` -// 这是一个注释 -``` - -You can also write multiline comments, which start with a forward-slash followed by an asterisk (/*) and end with an asterisk followed by a forward-slash (*/): - -你也可以写多行的注释,用一个正斜杠跟着一个星号开头(`/*`),用一个星号跟着一个正斜杠结束(`*/`): - -``` -/* this is also a comment, -but written over multiple lines */ -``` - -``` -/* 这还是一个注释, -但是是多行的 */ -``` - -Unlike multiline comments in C, multiline comments in Swift can be nested inside other multiline comments. You write nested comments by starting a multiline comment block and then starting a second multiline comment within the first block. The second block is then closed, followed by the first block: - -和C中的多行注释不同,Swift的多行注释可以嵌套在另一个多行注释内部。你可以这样写嵌套的注释:开始一个多行注释块,在第一块多行注释内部跟着开始第二个多行注释。第二个多行注释块结束,然后第一个多行注释块结束。 - -``` -/* this is the start of the first multiline comment -/* this is the second, nested multiline comment */ -this is the end of the first multiline comment */ -``` - -``` -/* 这是第一个多行注释开始 -/* 这是第二个,嵌套的多行注释 */ -这是第一个多行注释的结束 */ -``` - -Nested multiline comments enable you to comment out large blocks of code quickly and easily, even if the code already contains multiline comments. - -嵌套的多行注释让你可以简单快捷的注释一大段代码,即使这段代码之前已经有多行注释块。 - -# Semicolons -# 分号 - -Unlike many other languages, Swift does not require you to write a semicolon (;) after each statement in your code, although you can do so if you wish. Semicolons are required, however, if you want to write multiple separate statements on a single line: - -和其他很多语言不同,Swift并不要求你在代码的每一个语句之后写一个分号(`;`),尽管如果你愿意你可以这么做。然而,如果你想在一行里写多个独立的语句,分号是必要的。 - - let cat = "🐱"; println(cat) - // prints "🐱" - -# Integers -# 整数 - -Integers are whole numbers with no fractional component, such as 42 and -23. Integers are either signed (positive, zero, or negative) or unsigned (positive or zero). - -整数就是没有小数部分的完整数字,如`42`和`-23`。整数可以有符号(正数,0,或负数),也可以没有符号(正数或0)。 - -Swift provides signed and unsigned integers in 8, 16, 32, and 64 bit forms. These integers follow a naming convention similar to C, in that an 8-bit unsigned integer is of type UInt8, and a 32-bit signed integer is of type Int32. Like all types in Swift, these integer types have capitalized names. - -Swift提供8,16,32和64进制位的带符号和不带符号的整数类型。这些整数遵从和C类似的命名约定,在这个约定中,8进制位的无符号整数的类型为`UInt8`,而一个32进制位的有符号整数的类型是`Int32`。和Swift的所有类型一样,这些整数的类型是首字母大写的。 - -## Integer Bounds -## 整数边界 - -You can access the minimum and maximum values of each integer type with its min and max properties: - -你可以通过整数类型的`max`和`min`属性来访问它的最大值和最小值: - -``` -let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8 -let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8 -``` - -``` -let minValue = UInt8.min // 最小值是 0, 类型是 UInt8 -let maxValue = UInt8.max // 最大值是 255, 类型是 UInt8 -``` - -The values of these properties are of the appropriate-sized number type (such as UInt8 in the example above) and can therefore be used in expressions alongside other values of the same type. - -这些属性值是相应数字类型的合适范围(比如上面例子里的`UInt8`),因此它们可以在其他拥有相同类型值的表达式中沿用。 - -## Int -## 整数 - -In most cases, you don’t need to pick a specific size of integer to use in your code. Swift provides an additional integer type, Int, which has the same size as the current platform’s native word size: - -在大多数情况下,你不需要在代码中指定整数的范围。Swift提供了一个专门的整数类型`Int`,它和当前平台的原生长度范围相同。 - -* On a 32-bit platform, Int is the same size as Int32. -* On a 64-bit platform, Int is the same size as Int64. - -* 在32位的平台上,`Int`和`Int32`范围相同。 -* 在64位的平台上,`Int`和`Int64`范围相同。 - -Unless you need to work with a specific size of integer, always use Int for integer values in your code. This aids code consistency and interoperability. Even on 32-bit platforms, Int can store any value between -2,147,483,648 and 2,147,483,647, and is large enough for many integer ranges. - -如果你不需要处理特定的整数范围,请在代码中的整数值始终使用`Int`类型。这有助于代码的一致性和可复用性。即使在32位的平台上,`Int`类型可以储存从`-2,147,483,648`到`2,147,483,647`的整数,大多数情况下这足够用了。 - -## UInt -## 无符号整数 - -Swift also provides an unsigned integer type, UInt, which has the same size as the current platform’s native word size: - -Swift也提供了无符号整数类型,`UInt`,它和当前平台的原生长度范围相同。 - -* On a 32-bit platform, UInt is the same size as UInt32. -* On a 64-bit platform, UInt is the same size as UInt64. - -* 在32位的平台上,`UInt`和`UInt32`范围相同。 -* 在64位的平台上,`UInt`和`UInt64`范围相同。 - -> NOTE - -> Use UInt only when you specifically need an unsigned integer type with the same size as the platform’s native word size. If this is not the case, Int is preferred, even when the values to be stored are known to be non-negative. A consistent use of Int for integer values aids code interoperability, avoids the need to convert between different number types, and matches integer type inference, as described in Type Safety and Type Inference. - -> 注意 - -> 只在你需要特别指定无符号整数与当前平台原生长度范围相同时才使用`UInt`,否则,推荐使用`Int`,即使是你知道不会存储负值的时候。使用一致的`Int`整数类型有助于代码的复用,避免了不同数字类型之间的转换,并且匹配整数的类型推断和类型推断,详见[类型安全和类型推断](link)。 - -# Floating-Point Numbers -# 浮点型数字 - -Floating-point numbers are numbers with a fractional component, such as 3.14159, 0.1, and -273.15. - -浮点型数字是指有小数部分的数字,比如`3.14159`,`0.1`和`-273.15`。 - -Floating-point types can represent a much wider range of values than integer types, and can store numbers that are much larger or smaller than can be stored in an Int. Swift provides two signed floating-point number types: - -浮点类型比整数类型范围大很多,它可以储存比整数更大或者更小的数。Swift提供了两种有符号的浮点数类型: - -* Double represents a 64-bit floating-point number. Use it when floating-point values must be very large or particularly precise. -* Float represents a 32-bit floating-point number. Use it when floating-point values do not require 64-bit precision. - -* `Double`代表64位浮点数。当你需要特别大和特别精确的值的时候使用`Double`类型。 -* `Float`代表32位浮点数。当不需要像64位那么精确的时候使用`Float`就够了。 - -> NOTE - -> Double has a precision of at least 15 decimal digits, whereas the precision of Float can be as little as 6 decimal digits. The appropriate floating-point type to use depends on the nature and range of values you need to work with in your code. - -> 注意 - -> `Double`有至少15位数字的精确度,而`Float`的精确度最少只有6位数字。根据业务需要的值的范围去选择合适的浮点类型。 - -# Type Safety and Type Inference -# 类型安全和类型推断 - -Swift is a type safe language. A type safe language encourages you to be clear about the types of values your code can work with. If part of your code expects a String, you can’t pass it an Int by mistake. - -Swift是一个类型安全的语言。一个类型安全的语言鼓励你声明代码中使用的值的类型。如果你期望这部分代码是`String`(字符串),你就不能错误的给它赋一个`Int`(整型)的值。 - -Because Swift is type safe, it performs type checks when compiling your code and flags any mismatched types as errors. This enables you to catch and fix errors as early as possible in the development process. - -因为Swift是类型安全的,它会在编译时运行类型检查,并且将所有不匹配的类型标记为错误。这让你可以在开发过程中今早的发现和修复问题。 - -Type-checking helps you avoid errors when you’re working with different types of values. However, this doesn’t mean that you have to specify the type of every constant and variable that you declare. If you don’t specify the type of value you need, Swift uses type inference to work out the appropriate type. Type inference enables a compiler to deduce the type of a particular expression automatically when it compiles your code, simply by examining the values you provide. - -当你处理不同类型的值的时候,类型检查帮助你避免错误。然而,这并不意味着你需要给每一个声明的常量和变量指定特定的类型。如果你没有指定特定的类型,Swift会使用类型推断来推断出合适的类型。当编译代码时,类型推断特性使得编译器可以简单的通过检查你提供的值来自动推断出特定表达式的类型。 - -Because of type inference, Swift requires far fewer type declarations than languages such as C or Objective-C. Constants and variables are still explicitly typed, but much of the work of specifying their type is done for you. - -因为有了类型推断,Swift与类似C和Objective-C的语言相比需要更少的类型声明。常量和变量同样会有准确的类型,但是大部分关于指定类型的工作Swift已经帮你做好了。 - -Type inference is particularly useful when you declare a constant or variable with an initial value. This is often done by assigning a literal value (or literal) to the constant or variable at the point that you declare it. (A literal value is a value that appears directly in your source code, such as 42 and 3.14159 in the examples below.) - -当你声明一个有初始值的常量或变量的时候时类型推断特别实用。通常是当你声明一个常量和变量的时候你就给它赋一个字面量(literal value)。(字面量是会直接出现在源码里的值,比如下面例子里的`42`和`3.14159`。) - -For example, if you assign a literal value of 42 to a new constant without saying what type it is, Swift infers that you want the constant to be an Int, because you have initialized it with a number that looks like an integer: - -举个例子,如果你给一个新的常量赋了一个字面量`42`,但没有指定它的类型,Swift会推断你希望这个常量是一个整数类型(Int)`Int`(整数)类型,因为你用了一个像是整数的数字来初始化***变量***: - -``` -let meaningOfLife = 42 -// meaningOfLife is inferred to be of type Int -``` - -``` -let meaningOfLife = 42 -// meaningOfLife被推断为整数类型(Int) -``` - -Likewise, if you don’t specify a type for a floating-point literal, Swift infers that you want to create a Double: - -类似的,如果你没有特别指定一个浮点型的字面量,Swift会推断你需要一个`Double`类型的浮点数: - -``` -let pi = 3.14159 -// pi is inferred to be of type Double -``` - -``` -let pi = 3.14159 -// pi被推断为Double类型 -``` - -Swift always chooses Double (rather than Float) when inferring the type of floating-point numbers. - -在推断浮点型的数字时,Swift总是会选择`Double`*类*型而不是`Float`*类型*。 - -If you combine integer and floating-point literals in an expression, a type of Double will be inferred from the context: - -如果你将整数型和浮点型的字面量相加,这种情况下会推断为`Double`类型: - -``` -let anotherPi = 3 + 0.14159 -// anotherPi is also inferred to be of type Double -``` - -``` -let anotherPi = 3 + 0.14159 -// anotherPi也被推断为Double类型 -``` - -The literal value of 3 has no explicit type in and of itself, and so an appropriate output type of Double is inferred from the presence of a floating-point literal as part of the addition. - -字面量`3`本身并没有准确的类型,因此是通过相加的元素中有一个浮点型的字面量推断出合适的输出类型为`Double`。 - -# Numeric Literals -# 数字字面量 - -Integer literals can be written as: - -整数字面量可以写成: - -* A decimal number, with no prefix -* A binary number, with a 0b prefix -* An octal number, with a 0o prefix -* A hexadecimal number, with a 0x prefix - -* 十进制的数字,不需要任何前缀 -* 二进制的数字,前缀是`0b` -* 八进制的数字,前缀是`0o` -* 十六进制的数字,前缀是`0x` - -All of these integer literals have a decimal value of 17: - -下面所有的整数字面量在十进制下的值都是`17`: - -``` -let decimalInteger = 17 -let binaryInteger = 0b10001 // 17 in binary notation -let octalInteger = 0o21 // 17 in octal notation -let hexadecimalInteger = 0x11 // 17 in hexadecimal notation -``` - -``` -let decimalInteger = 17 -let binaryInteger = 0b10001 // 二进制声明中的17 -let octalInteger = 0o21 // 八进制声明中的17 -let hexadecimalInteger = 0x11 // 十六进制声明中的17 -``` - -Floating-point literals can be decimal (with no prefix), or hexadecimal (with a 0x prefix). They must always have a number (or hexadecimal number) on both sides of the decimal point. They can also have an optional exponent, indicated by an uppercase or lowercase e for decimal floats, or an uppercase or lowercase p for hexadecimal floats. - -浮点型的字面量可以是十进制的(没有前缀),或者十六进制(前缀是`0x`)。在小数点两边都必须有数字(或十六进制数字符号)。它们也可以有一个可选的指数,在十进制中用大写或小写的`e`来表示,或者在十六进制中用大写或小写的`p`来表示。 - -For decimal numbers with an exponent of exp, the base number is multiplied by 10exp: - -在十进制数字中有一个的指数`exp`表示基数乘以10exp: - -* ```1.25e2``` means 1.25 × 102, or `125.0`. -* ```1.25e-2``` means 1.25 × 10-2, or `0.0125`. - -* ```1.25e2``` 表示 1.25 × 102,或者`125.0`. -* ```1.25e-2``` 表示 1.25 × 10-2,或者`0.0125` - -For hexadecimal numbers with an exponent of exp, the base number is multiplied by 2exp: - -在十六进制的数字中有一个的指数`exp`表示基数乘以2exp - -* 0xFp2 means 15 × 22, or 60.0. -* 0xFp-2 means 15 × 2-2, or 3.75. - -* 0xFp2 表示 15 × 22,或者 60.0. -* 0xFp-2 表示 15 × 2-2,或者 3.75. - -All of these floating-point literals have a decimal value of 12.1875: - -以下这些浮点字面量在十进制下的值都是`12.1875`: - -``` -let decimalDouble = 12.1875 -let exponentDouble = 1.21875e1 -let hexadecimalDouble = 0xC.3p0 -``` - -Numeric literals can contain extra formatting to make them easier to read. Both integers and floats can be padded with extra zeroes and can contain underscores to help with readability. Neither type of formatting affects the underlying value of the literal: - -数字字面量可以使用额外的格式让它们更易读。不论整数还是浮点数都可以添加额外的0,也可以增加下划线来增加可读性。这些格式都不会影响到这些字面量原本的值: - -``` -let paddedDouble = 000123.456 -let oneMillion = 1_000_000 -let justOverOneMillion = 1_000_000.000_000_1 -``` - -# Numeric Type Conversion -# 数字类型转换 - -Use the Int type for all general-purpose integer constants and variables in your code, even if they are known to be non-negative. Using the default integer type in everyday situations means that integer constants and variables are immediately interoperable in your code and will match the inferred type for integer literal values. - -在一般情况下对整数的常量或变量使用`Int`类型,即使是你知道不会存储负值的时候。总是使用默认的整数类型意味着你的代码中整数的常量和变量可以很好的协作,并且可以和整数字面量推断出的类型一致。 - -Use other integer types only when they are are specifically needed for the task at hand, because of explicitly-sized data from an external source, or for performance, memory usage, or other necessary optimization. Using explicitly-sized types in these situations helps to catch any accidental value overflows and implicitly documents the nature of the data being used. - -只在当前工作中有特殊需要的时候,才使用其他的整数类型,比如是从外部来源的需要指定精确度的数据,或者为了性能,内存使用量,或者其他必要的优化。在这些情况下使用指定精确度的数字类型可以帮助我们发现溢出值和暗示这个数据的特性。 - -## Integer Conversion -## 整数类型转换 - -The range of numbers that can be stored in an integer constant or variable is different for each numeric type. An Int8 constant or variable can store numbers between -128 and 127, whereas a UInt8 constant or variable can store numbers between 0 and 255. A number that will not fit into a constant or variable of a sized integer type is reported as an error when your code is compiled: - -不同整数类型的常量或变量可以储存不同范围的数字。一个`Int8`的常量或变量可以储存`-128`到`127`之间的数字,然而一个`UInt8`型的常量或变量可以储存从`0`到`255`之间的数字。如果一个数字不符合常量或变量的储值范围,编译的时候会报错: - -``` -let cannotBeNegative: UInt8 = -1 -// UInt8 cannot store negative numbers, and so this will report an error -// UInt8不能储存负数,所以这里会报错 -let tooBig: Int8 = Int8.max + 1 -// Int8 cannot store a number larger than its maximum value, -// and so this will also report an error -// Int8不能储存一个大于其最大值的数字 -// 所以这里同样会报错 -``` - -Because each numeric type can store a different range of values, you must opt in to numeric type conversion on a case-by-case basis. This opt-in approach prevents hidden conversion errors and helps make type conversion intentions explicit in your code. - -因为每一种数字类型可以储存不同范围的值,你必须根据具体的案例选择合适的数字类型转换。这种选择方式组织阻止了隐式的转换报错,并且让你的代码中的类型转换意图更明确。 - -To convert one specific number type to another, you initialize a new number of the desired type with the existing value. In the example below, the constant twoThousand is of type UInt16, whereas the constant one is of type UInt8. They cannot be added together directly, because they are not of the same type. Instead, this example calls UInt16(one) to create a new UInt16 initialized with the value of one, and uses this value in place of the original: - -要将一种特定类型转换成另一种,你需要用一个你想要的类型的新数字*值*来重新初始化。在下面的例子里,常量`twoThousand`是`UInt16`类型的,然而常量`one`是`UInt8`类型的。它们不能直接相加,因为它们类型不同。因此,这个例子调用了`UInt16(one)`来对常量`one`创建一个新的`UInt16`*类型的*初始值,然后用这个值来代替原来的值: - -``` -let twoThousand: UInt16 = 2_000 -let one: UInt8 = 1 -let twoThousandAndOne = twoThousand + UInt16(one) -``` - -Because both sides of the addition are now of type UInt16, the addition is allowed. The output constant (twoThousandAndOne) is inferred to be of type UInt16, because it is the sum of two UInt16 values. - -因为相加的两个数现在都是`UInt16`类型了,这样相加是允许的。输出结果的常量`twoThousandAndOne`被推断为`UInt16`类型,因为它是两个`UInt16`类型的值的和。 - -`SomeType(ofInitialValue)` is the default way to call the initializer of a Swift type and pass in an initial value. Behind the scenes, UInt16 has an initializer that accepts a UInt8 value, and so this initializer is used to make a new UInt16 from an existing UInt8. You can’t pass in any type here, however—it has to be a type for which UInt16 provides an initializer. Extending existing types to provide initializers that accept new types (including your own type definitions) is covered in Extensions. - -`SomeType(ofInitialValue)`是Swift初始化并赋予一个初值的默认方法。在语言内部,`UInt16`类型有一个初始值设定项会接受一个`UInt8`的值,然后这个初始值设定项是用来从已知的`UInt8`中创建一个新的`UInt16`的值。你不能传递任意类型,只能传入`UInt16`提供初始化的类型。扩展已有的类型来提供更多的初始化选项,来接受新的类型(包括自定义类型),见[扩展](link)。 - -## Integer and Floating-Point Conversion -## 整数和浮点数转换 - -Conversions between integer and floating-point numeric types must be made explicit: -整数和浮点数之间的类型转换必须是显性的: - -``` -let three = 3 -let pointOneFourOneFiveNine = 0.14159 -let pi = Double(three) + pointOneFourOneFiveNine -// pi equals 3.14159, and is inferred to be of type Double -// pi等于3.14159,它被推断为Double类型 -``` -Here, the value of the constant three is used to create a new value of type Double, so that both sides of the addition are of the same type. Without this conversion in place, the addition would not be allowed. - -在这里,常量`three`的值被用来创建一个新的`Double`型的值,所以相加的两个数都是同样的类型了,无须转换,这个加法是允许的。 - -The reverse is also true for floating-point to integer conversion, in that an integer type can be initialized with a Double or Float value: - -相对的,由浮点数到证书整数的转换也是可行的,也就是说一个整数类型可以被初始化为一个`Double`或者`Float`型的值: - -``` -let integerPi = Int(pi) -// integerPi equals 3, and is inferred to be of type Int -// integerPi等于3,它被推断为整数(Int)类型 -``` - -Floating-point values are always truncated when used to initialize a new integer value in this way. This means that 4.75 becomes 4, and -3.9 becomes -3. - -当浮点型的值初始化为一个新的整数型的值时,它的数值总是被截断的。这意味着`4.75`会成为`4`,而`-3.9`会成为`-3`。 - -> NOTE - -> The rules for combining numeric constants and variables are different from the rules for numeric literals. The literal value 3 can be added directly to the literal value 0.14159, because number literals do not have an explicit type in and of themselves. Their type is inferred only at the point that they are evaluated by the compiler. - -> 注意 - -> 数字的常量和变量相加的规则和数字字面量的规则是不一样的。字面量`3`可以和字面量`0.14159`直接相加,因为数字字面量本身并没有一个显式的类型声明。他们的类型是在编译器运行时被推断的。 - -# Type Aliases -# 类型别名 - -Type aliases define an alternative name for an existing type. You define type aliases with the typealias keyword. - -类型别名给已经存在的类型定义另一个名字。你用关键字`typealias`来定义类型别名。 - -Type aliases are useful when you want to refer to an existing type by a name that is contextually more appropriate, such as when working with data of a specific size from an external source: - -当你想用一个更合适的名字来命名一个已有类型的时候,类型别名是很有用的。比如当你处理一个外部来源的需要指定精确度的需要指定精确度的外部来源数据时: - -``` -typealias AudioSample = UInt16 -``` - -Once you define a type alias, you can use the alias anywhere you might use the original name: - -一旦你定义了类型别名,你就可以在任何你可以使用原始名字的地方使用这个别名: - -``` -var maxAmplitudeFound = AudioSample.min -// maxAmplitudeFound is now 0 -``` - -Here, AudioSample is defined as an alias for UInt16. Because it is an alias, the call to AudioSample.min actually calls UInt16.min, which provides an initial value of 0 for the maxAmplitudeFound variable. - -在这里这个例子中,`AudioSample`***被***定义为`UInt16`的一个别名。因为这是一个别名,调用`AudioSample.min`实际上是调用`UInt16.min`给变量`maxAmplitudeFound`赋了一个0的初始值初始值`0`。 - -# Booleans -# 布尔值 - -Swift has a basic Boolean type, called Bool. Boolean values are referred to as logical, because they can only ever be true or false. Swift provides two Boolean constant values, true and false: - -Swift有一个基本的布尔值类型,叫做`Bool`。布尔值可以用作逻辑判断,因为它们只有true和false“真”和“假”两个值。Swift提供两种布尔值常量,`true`和`false`: - -``` -let orangesAreOrange = true -let turnipsAreDelicious = false -``` - -The types of orangesAreOrange and turnipsAreDelicious have been inferred as Bool from the fact that they were initialized with Boolean literal values. As with Int and Double above, you don’t need to declare constants or variables as Bool if you set them to true or false as soon as you create them. Type inference helps make Swift code more concise and readable when it initializes constants or variables with other values whose type is already known. - -因为`orangesAreOrange`和`turnipsAreDelicious`有一个布尔的字面量作为初*使*值,它们的类型被推断为`Bool`。如果你在创建常量或变量的时候就把它们的值设为`true`或者`false`,你不需要声明它们的类型是`Bool`。当你赋予常量或变量一个类型已知的初值时,类型推断让Swift的代码更加准确和可读。 - -Boolean values are particularly useful when you work with conditional statements such as the if statement: - -在条件声明比如if语句中,布尔值布尔值在条件声明(比如:`if`语句)中特别有用: - -``` -if turnipsAreDelicious { - println("Mmm, tasty turnips!") -} else { - println("Eww, turnips are horrible.") -} -// prints "Eww, turnips are horrible." -``` - -Conditional statements such as the if statement are covered in more detail in Control Flow. - -关于条件声明(比如`if`语句)的更多细节会在Control Flow这一章节中详细讲解。 - -Swift’s type safety prevents non-Boolean values from being be substituted for Bool. The following example reports a compile-time error: - -Swift的类型安全会阻止一个非布尔值替换`Bool`值。下面的例子会在编译时报错: - -``` -let i = 1 -if i { - // this example will not compile, and will report an error - // 这个例子不会顺利编译,会报错 -} -``` - -However, the alternative example below is valid: - -然而,下面这个例子是有效的: - -``` -let i = 1 -if i == 1 { - // this example will compile successfully - // 这个例子会成功编译 -} -``` - -The result of the i == 1 comparison is of type Bool, and so this second example passes the type-check. Comparisons like i == 1 are discussed in Basic Operators. - -`i == 1`**的**比较结果是一个`Bool`类型的值,因此第二个例子通过了类型检查。类似`i == 1`的比较我们会在[Basic Operators](link)进行深入讨论。 - -As with other examples of type safety in Swift, this approach avoids accidental errors and ensures that the intention of a particular section of code is always clear. - -和其他Swift的类型安全的例子一样,这个例子这种检查避免了意外的错误并且保证了特定的某块代码的意图始终是明确的。 - -# Tuples -# 元组 - -Tuples group multiple values into a single compound value. The values within a tuple can be of any type and do not have to be of the same type as each other. - -元组将多个数值组合成一个单独的复合值。一个元组中的值可以是任何类型,不必是同一种类型。 - -In this example, (404, "Not Found") is a tuple that describes an HTTP status code. An HTTP status code is a special value returned by a web server whenever you request a web page. A status code of 404 Not Found is returned if you request a webpage that doesn’t exist. - -在这个例子里, `(404, "Not Found")` 是一个用来形容HttpHTTP状态码的元组。一个HttpHTTP状态码是当你请求一个网页的时候网页服务器的返回值。当你请求的网页不存在的时候会返回`404找不到网页``404 Not Found`的状态码。 - -``` -let http404Error = (404, "Not Found") -// http404Error is of type (Int, String), and equals (404, "Not Found") -``` - -``` -let http404Error = (404, "Not Found") -// http404Error的类型是(Int, String),值等于(404, "Not Found") -``` - -The (404, "Not Found") tuple groups together an Int and a String to give the HTTP status code two separate values: a number and a human-readable description. It can be described as “a tuple of type (Int, String)”. - -元组`(404, "Not Found")`将一个整数值`Int`和一个字符字符串`String`组合起来,给httpHTTP状态码赋予两个独立的值:一个机器语言的数字和一句人类语言的描述。它可以描述为”一个类型为 `(Int, String)`的元组“。 - -You can create tuples from any permutation of types, and they can contain as many different types as you like. There’s nothing stopping you from having a tuple of type (Int, Int, Int), or (String, Bool), or indeed any other permutation you require. - -你可以创建一个含任意类型组合的元组,它们可以包含任意多的类型。谁也不能阻止你创建一个`(Int, Int, Int)`类型或者`(String, Bool)`类型,又或者任意你想要的类型组合的元组。 - -You can decompose a tuple’s contents into separate constants or variables, which you then access as usual: - -你可以把一个元组的内容分解成独立的常量或变量,然后你就可以像平常一样调用引用它们: - -``` -let (statusCode, statusMessage) = http404Error -println("The status code is \(statusCode)") -// prints "The status code is 404" -println("状态码是 \(statusCode)") -// 输出”状态码是404“ -println("The status message is \(statusMessage)") -// prints "The status message is Not Found" -``` - -``` -let (statusCode, statusMessage) = http404Error -println("状态码是 \(statusCode)") -// 输出”状态码是404“ -println("状态信息是 \(statusMessage)") -// prints "状态信息是 Not Found" -``` - -If you only need some of the tuple’s values, ignore parts of the tuple with an underscore (_) when you decompose the tuple: - -如果你只需要元组的一部分值,当你分解元组的时候当你在分解元组时,只需要元祖的一部分值,可以使用下划线(`_`)来忽略元组的一部分值: - -``` -let (justTheStatusCode, _) = http404Error -println("The status code is \(justTheStatusCode)") -// prints "The status code is 404" -``` - -``` -let (justTheStatusCode, _) = http404Error -println("状态码是 \(justTheStatusCode)") -// prints "状态码是 404" -``` - -Alternatively, access the individual element values in a tuple using index numbers starting at zero: - -同样的,使用从`0`开始的序列可以调用引用元组中的一个单独元素的值。 - -``` -println("The status code is \(http404Error.0)") -// prints "The status code is 404" -println("The status message is \(http404Error.1)") -// prints "The status message is Not Found" -``` - -You can name the individual elements in a tuple when the tuple is defined: - -定义元组的时候,你可以给元素单独命名: - -``` -let http200Status = (statusCode: 200, description: "OK") -``` - -If you name the elements in a tuple, you can use the element names to access the values of those elements: - -如果你给元组中的元素命名了,你可以用这个名字来调用引用它们的值: - -``` -println("The status code is \(http200Status.statusCode)") -// prints "The status code is 200" -println("The status message is \(http200Status.description)") -// prints "The status message is OK" -``` - -Tuples are particularly useful as the return values of functions. A function that tries to retrieve a web page might return the (Int, String) tuple type to describe the success or failure of the page retrieval. By returning a tuple with two distinct values, each of a different type, the function provides more useful information about its outcome than if it could only return a single value of a single type. For more information, see Functions with Multiple Return Values. - -作为函数的返回值元组是很有用的。*这还没有翻译完哦~* - -> NOTE - -> Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple. For more information, see Classes and Structures. - -> 注意 - -> 当你处理一些相关数据的临时组合,元组是很有用的。如果你的数据结构超过了一个临时的范畴,用class或者structrue会比用元组tuple更合适。更多信息,参见[Classes and Structures](link)。 - -# Optionals -# 可选类型 - -You use optionals in situations where a value may be absent. An optional says: - -当值可能缺失的情况下,可以用可选类型(Options)。可选类型表示: - -- There is a value, and it equals x - -or - -- There isn’t a value at all - - -- 那里有一个值,它等于x - -或者 - -- 值不存在 - -> NOTE - -> The concept of optionals doesn’t exist in C or Objective-C. The nearest thing in Objective-C is the ability to return nil from a method that would otherwise return an object, with nil meaning “the absence of a valid object.” However, this only works for objects—it doesn’t work for structs, basic C types, or enumeration values. For these types, Objective-C methods typically return a special value (such as NSNotFound) to indicate the absence of a value. This approach assumes that the method’s caller knows there is a special value to test against and remembers to check for it. Swift’s optionals let you indicate the absence of a value for any type at all, without the need for special constants. - -> 注意 - -> 可选类型在C或者Objective-C中都不存在。在Objective-C中最接近的是一个返回一个对象的方法也可以返回一个`nil`值的能力,`nil`的意思是“有效对象的缺失”。然而,它只对对象有效,对`structs`,basic C types, or enumeration values*基本的C类型、或者枚举类型*都是无效的。对这些类型,Objective-C通常会返回一个特殊值(比如`NSNotFound`)来表示值缺失。这样的方式假定我们调用方法时它必须知道有一个特殊值,并且要记得去检查它。Siwft的可选类型让你可以给任意类型的值声明这个值缺失,不需要任何其它的特殊常量。 - -Here’s an example. Swift’s String type has a method called toInt, which tries to convert a String value into an Int value. However, not every string can be converted into an integer. The string "123" can be converted into the numeric value 123, but the string "hello, world" does not have an obvious numeric value to convert to. - -下面是一个例子。Siwft的字符串类型有一个`toInt`的方法,它会尝试将一个字符串类型转换成一个整数类型。然而,不是每一个字符串都可以转换成整数。字符串“123”`"123"`可以转换为数字量`123`,但是字符串`"Hello, world"`并没有一个明显的数字量可以转换。 - -The example below uses the toInt method to try to convert a String into an Int: - -下面这个例子用`toInt`方法尝试转换字符串到整数: - -``` -let possibleNumber = "123" -let convertedNumber = possibleNumber.toInt() -// convertedNumber is inferred to be of type "Int?", or "optional Int" -``` - -Because the toInt method might fail, it returns an optional Int, rather than an Int. An optional Int is written as Int?, not Int. The question mark indicates that the value it contains is optional, meaning that it might contain some Int value, or it might contain no value at all. (It can’t contain anything else, such as a Bool value or a String value. It’s either an Int, or it’s nothing at all.) - -因为`toInt`方法可能失败,它返回的是可以可选类型的整数,而不是一个整数。一个可选的整数表示为`Int?`,而不是`Int`。最后的问号表示这个值是可选的,意味着它可能包含整数类型的值,或者没有值。(它不能包括其它任何值,比如布尔值或者字符串。它要么是一个整数,要么就没有值。) - -## If Statements and Forced Unwrapping -## If语句和强制解析 - -You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to true; if it has no value at all, it evaluates to false. - -你可以使用`if`语句来判断一个可选类型是否有值。如果有值,它就等于`true`,如果没有值,就等于`false`。 - -Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation mark (!) to the end of the optional’s name. The exclamation mark effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value: - -一旦你确定可选类型是有值的,你可以在可选类型的名字后面加一个感叹号(!)`!`来调用它的值。这个感叹号的意思是:”我知道这个可选类型的值一定存在一个值,请使用这个值。“这叫做可选值的强制解析: - -``` -if convertedNumber { - println("\(possibleNumber) has an integer value of \(convertedNumber!)") -} else { - println("\(possibleNumber) could not be converted to an integer") -} -// prints "123 has an integer value of 123" -``` - -For more on the if statement, see Control Flow. - -更多*`if`语句的*信息,见[Control Flow](link)。 - -> NOTE - -> Trying to use ! to access a non-existent optional value triggers a runtime error. Always make sure that an optional contains a non-nil value before using ! to force-unwrap its value. - -> 注意 - -> 如果你使用`!`来调用一个不存在的可选值,会报出实时运行时错误。在使用`!`强制解析可选值之前总是请确认这个可选值包含一个非`nil`的值。 - -## Optional Binding -## 可选值绑定 - -You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used with if and while statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action. if and while statements are described in more detail in Control Flow. - -你可以使用可选值绑定(optional binding)来找出一个可选类型是否包含值,如果包含,则可以把这个值作为一个临时常量或变量来使用。可选值绑定可以和`if`或`while`语句一起来检查可选值里面的值,并且解析到一个常量或变量中,所有这些都在一步操作中完成。更多关于`if`和`while`语句的信息,见[Control Flow](link)。 - -Write optional bindings for the if statement as follows: - -像这样给`if`语句写可选值绑定: - -``` -if let constantName = someOptional { - statements -} -``` - -You can rewrite the possibleNumber example from above to use optional binding rather than forced unwrapping: - -你可以用可选值绑定来代替强制解析来重写之前那个`possibleNumber`的例子: - -``` -if let actualNumber = possibleNumber.toInt() { - println("\(possibleNumber) has an integer value of \(actualNumber)") -} else { - println("\(possibleNumber) could not be converted to an integer") -} -// prints "123 has an integer value of 123" -``` - -This can be read as: - -这段代码可以解读为: - -“If the optional Int returned by possibleNumber.toInt contains a value, set a new constant called actualNumber to the value contained in the optional.” - -”如果可选整数值通过`possibleNumber.toInt`返回一个值,设定一个叫`actualNumber`的新常量来储存这个可选整数中的值。“ - -If the conversion is successful, the actualNumber constant becomes available for use within the first branch of the if statement. It has already been initialized with the value contained within the optional, and so there is no need to use the ! suffix to access its value. In this example, actualNumber is simply used to print the result of the conversion. - -如果这个转换是成功的,那么常量`actualNumber`在`if`语句的第一个分支就可用了。它已经用可选量中的值初始化了,所以现在不需要用`!`后缀来调用这个值。在这个例子中,`actualNumber`只是简单的用于输出转换结果。 - -You can use both constants and variables with optional binding. If you wanted to manipulate the value of actualNumber within the first branch of the if statement, you could write if var actualNumber instead, and the value contained within the optional would be made available as a variable rather than a constant. - -无论是常量还是变量你都可以使用可选值绑定。如果你希望对`if`语句第一个分支中`actualNumber`的值进行操作,你可以用`if var actualNumber`来声明,然后可选量中的值就会成为一个可用的变量而不是常量。 - -## nil -## nil - -You set an optional variable to a valueless state by assigning it the special value nil: - -给可选变量一个没有值的状态是通过给它赋予一个特殊值`nil`来完成的: -通过给可选变量赋予特殊值`nil`来表示没有值的状态: - -``` -var serverResponseCode: Int? = 404 -// serverResponseCode contains an actual Int value of 404 -serverResponseCode = nil -// serverResponseCode now contains no value -``` - -> NOTE - -> nil cannot be used with non-optional constants and variables. If a constant or variable in your code needs to be able to cope with the absence of a value under certain conditions, always declare it as an optional value of the appropriate type. - -> 注意 - -> `nil`不能被用于可选类型之外的常量和变量。如果你的代码中的常量或变量需要处理值缺失的情况,总是用一个可选的合适类型来声明它。 - -If you define an optional constant or variable without providing a default value, the constant or variable is automatically set to nil for you: - -如果你定义一个可选的常量或变量,却没有赋初值,这个常量或变量会自动设*置*为`nil`: - -``` -var surveyAnswer: String? -// surveyAnswer is automatically set to nil -``` - -> NOTE - -> Swift’s nil is not the same as nil in Objective-C. In Objective-C, nil is a pointer to a non-existent object. In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types. - -> 注意 - -> Swift的`nil`和Objective-C中的不完全一样。Objective-C中,`nil`是指向不存在对象*的指针*。而在Swift中,`nil`不止是一个指针——它是一个特定类型的值缺失。可选的任何类型都可以设为`nil`,不只是对象类型。 - -## Implicitly Unwrapped Optionals -## 隐式解析可选值 - -As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist. - -像之前说的,可选值意味着一个常量或变量允许“没有值”。可以通过`if`语句来判断可选值中是否有值存在,如果值存在则用可选值绑定来调用可选量的值。 - -Sometimes it is clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time. - -有时候从程序的结构可以清楚的知道一个可选值在第一次值设定之后,它总是有值的。在这些情况下,把每次调用都检查并解析可选量的值去掉是很有用的,因为它们可以安全的被推断出它们总是有值的。 - -These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional. - -这些类型的可选值被定义为隐式解析可选值。当你创建可选值的时候,你可以通过写感叹号(String!)而不是问号(String?)的形式来表示一个隐式解析的可选值。 - -Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties. - -如果可选值在第一次定义之后就肯定存在值并且之后每一刻都肯定存在,这种情况下隐式解析可选值是很有用的。Swift中的隐式解析可选值的主要用法是在类的初始化过程中,参见[Unowned References and Implicitly Unwrapped Optional Properties](link)。 - -An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it is accessed. The following example shows the difference in behavior between an optional String and an implicitly unwrapped optional String: - -一个隐式解析可选值其实是一个普通的可选值,但它也可以像非可选的值那样使用,无须每次调用都解析可选量的值。下面的例子显示了一个普通的可选的字符串和一个隐式解析的可选字符串的区别: - -``` -let possibleString: String? = "An optional string." -println(possibleString!) // requires an exclamation mark to access its value -// prints "An optional string." - -let assumedString: String! = "An implicitly unwrapped optional string." -println(assumedString) // no exclamation mark is needed to access its value -// prints "An implicitly unwrapped optional string." -``` - -You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used. Rather than placing an exclamation mark after the optional’s name each time you use it, you place an exclamation mark after the optional’s type when you declare it. - -你可以把隐式解析可选值当作一个允许可选值每次都能自动解析的授权。你只需要当你声明的时候在可选量的类型后面放一个感叹号,而不用每次使用的时候都在可选值后面放感叹号。 - -> NOTE - -> If you try to access an implicitly unwrapped optional when it does not contain a value, you will trigger a runtime error. The result is exactly the same as if you place an exclamation mark after a normal optional that does not contain a value. - -> 注意 - -> 如果你试图调用一个没有值的隐式解析可选值,你会得到一个实时的运行时错误。这和你在一个普通的不含值的可选值后面放感叹号的结果是完全一样的。 - -You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value: - -你仍然可以把隐式解析可选值当作一个普通的可选值,来检查它是否含有值: - -``` -if assumedString { - println(assumedString) -} -// prints "An implicitly unwrapped optional string." -``` - -You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement: - -你同样可以对隐式解析可选值使用可选值绑定,在一行声明中来检查和解析它的值: - -``` -if let definiteString = assumedString { - println(definiteString) -} -// prints "An implicitly unwrapped optional string." -``` - -> NOTE - -> Implicitly unwrapped optionals should not be used when there is a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable. - -> 注意 - -> 当一个变量有可能是`nil`的情况下,不应当使用隐式解析可选值。如果在整个过程中检查一个变量是否有`nil`值,你应该用一个普通的可选值。 - -# Assertions -# 断言 - -Optionals enable you to check for values that may or may not exist, and to write code that copes gracefully with the absence of a value. In some cases, however, it is simply not possible for your code to continue execution if a value does not exist, or if a provided value does not satisfy certain conditions. In these situations, you can trigger an assertion in your code to end code execution and to provide an opportunity to debug the cause of the absent or invalid value. - -可选值让你可以检查一个值是否存在,并且优雅的处理值缺失的情况。然而,在一些情况下,如果值不存在或者值不满足指定的条件,你的程序就无法继续执行。在这些情况下,你可以在代码中触发一个断言,来中断代码的执行并且提供一个来调试为什么值缺失或无效的机会。 - -## Debugging with Assertions -## 用断言来调试 - -An assertion is a runtime check that a logical condition definitely evaluates to true. Literally put, an assertion “asserts” that a condition is true. You use an assertion to make sure that an essential condition is satisfied before executing any further code. If the condition evaluates to true, code execution continues as usual; if the condition evaluates to false, code execution ends, and your app is terminated. - -断言是判断一个逻辑条件是否为真的实时检查。基本上,一个断言就是“断定”(asserts)一个条件为真。你可以使用断言来确保在运行后续代码之前它的一个必要的条件是已经满足了的。如果这个条件为真,代码会正常执行,如果条件为否,代码会停止执行,并且你的app应用会终止。 - -If your code triggers an assertion while running in a debug environment, such as when you build and run an app in Xcode, you can see exactly where the invalid state occurred and query the state of your app at the time that the assertion was triggered. An assertion also lets you provide a suitable debug message as to the nature of the assert. - -如果你的代码在调试环境下触发了一个断言(比如当你在Xcode中创建并运行一个app的时候),你可以准确的看到非法语句出现的位置,也可以查询到当断言触发时app的状态。断言还允许你可以提供一个相应的调试信息。 - -You write an assertion by calling the global assert function. You pass the assert function an expression that evaluates to true or false and a message that should be displayed if the result of the condition is false: - -通过调用全局的断言assert函数来写一个断言。你给断言函数传入一个等于true或false的表达式会被解析为`true`或者`false`的表达式,当结果是false的时候,会显示出一条信息以及在解析为`false`时的提示信息: - -``` -let age = -3 -assert(age >= 0, "A person's age cannot be less than zero") -// this causes the assertion to trigger, because age is not >= 0 -``` - -In this example, code execution will continue only if age >= 0 evaluates to true, that is, if the value of age is non-negative. If the value of age is negative, as in the code above, then age >= 0 evaluates to false, and the assertion is triggered, terminating the application. - -在这个例子里,只有`age >= 0`为真的时候代码才会继续执行,也就是,如果`age`的值是非负数。在上面的代码中,如果`age`的值是负数,在上面的代码中,`age >= 0`的条件判断这个表达式解析为否,这个断言被触发,终止了这个程序。 - -Assertion messages cannot use string interpolation. The assertion message can be omitted if desired, as in the following example: - -断言信息不能使用字符串插值。如果你想,断言信息可以省略,像下面这个例子: - -``` -assert(age >= 0) -``` - -## When to Use Assertions -## 何时使用断言 - -Use an assertion whenever a condition has the potential to be false, but must definitely be true in order for your code to continue execution. Suitable scenarios for an assertion check include: - -如果在一个条件有可能为否,但只有它为真的时候代码才能继续执行,这时时,应该使用断言。适当的使用断言检查的*合适*场景包括: - -- An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high. -- A value is passed to a function, but an invalid value means that the function cannot fulfill its task. -- An optional value is currently nil, but a non-nil value is essential for subsequent code to execute successfully. - -- 一个整数类型的下标索引被传入一个自定义的下标实现,但是这个下标索引值太小或太大。 -- 一个值传入一个函数,但是如果传入不合法的值,这个函数就无法满足需求。 -- 一个可选值当前的值是`nil`,但是后续代码成功执行需要一个非`nil`值。 - -See also Subscripts and Functions. - -参见[Subscripts and Functions](link)。 - -> NOTE - -> Assertions cause your app to terminate and are not a substitute for designing your code in such a way that invalid conditions are unlikely to arise. Nonetheless, in situations where invalid conditions are possible, an assertion is an effective way to ensure that such conditions are highlighted and noticed during development, before your app is published. - -> 注意 - -> 断言会造成你的app终止,它并不能代替你设计代码来保证不合法情况不出现。尽管如此,当不合法的情况可能出现时,断言可以有效的保证在你的app正式发布之前,在的开发过程中这种不合法的情况就会被高亮并被注意到。 \ No newline at end of file diff --git a/src/chapter2/12_Subscripts_Chinese.md b/src/chapter2/12_Subscripts_Chinese.md index bb3d5c3..414c34f 100644 --- a/src/chapter2/12_Subscripts_Chinese.md +++ b/src/chapter2/12_Subscripts_Chinese.md @@ -54,7 +54,7 @@ println("3的6倍是\(threeTimesTable[6])") > 提示 > -> TimesTable例子是基于一个固定的数学公式。它并不适合开放写权限来对threeTimesTable[someIndex]进行赋值操作,这也是为什么下标只定义为只读的原因。 +> TimesTable例子是基于一个固定的数学公式。它并不适合开放写权限来对`threeTimesTable[someIndex]`进行赋值操作,这也是为什么下标只定义为只读的原因。 ## 下标用法 From 4d9687955f6fda91025b2fee4c96be1f9ead9f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Fri, 4 Jul 2014 13:03:07 +0800 Subject: [PATCH 241/261] add review about the language reference and lexical structure and types --- .../01_About_the_Language_Reference.md | 45 +-- src/chapter3/02_Lexical_Structure.md | 337 ++++++----------- src/chapter3/03_Types.md | 344 ++++-------------- 3 files changed, 185 insertions(+), 541 deletions(-) diff --git a/src/chapter3/01_About_the_Language_Reference.md b/src/chapter3/01_About_the_Language_Reference.md index a95d021..7779aa3 100644 --- a/src/chapter3/01_About_the_Language_Reference.md +++ b/src/chapter3/01_About_the_Language_Reference.md @@ -1,61 +1,36 @@ -# Language Reference +# 语言参考 -## About the Language Reference ## 关于语言参考 -This part of the book describes the formal grammar of the Swift programming language.The grammar described here is intended to help you understand the language in more detail, rather than to allow you to directly implement a parser or compiler. - - 本书的该部分描述了Swift编程语言的正式语法。在此描述语法的目的是为了帮助你更详细的理解该语言,而不是让你直接实现一个解析器或编译器。 -The Swift language is relatively small, because many common types, functions, and operators that appear virtually everywhere in Swift code are actually defined in the Swift standard library. Although these types, functions, and operators are not part of the Swift language itself, they are used extensively in the discussions and code examples in this -part of the book. - -Swift语言相对较小,因为那些无处不在出现在Swift代码中的很多常见的类型,函数,和运算符实际上已经定义在了Swift的标准库中。虽然这些类型,函数,和运算符本身不是Swift语言的一部分,但它们被广泛应用于该书本部分的探讨和代码示例中。 +Swift语言相对较小,因为那些无处不在出现在Swift代码中的很多常见的类型,函数,和运算符实际上已经定义在了Swift的标准库中。虽然这些类型,函数,和运算符不是Swift语言本身的一部分,但它们被广泛应用于该书本部分的探讨和代码示例中。 -## How to Read the Grammar ## 如何阅读语法 -The notation used to describe the formal grammar of the Swift programming language follows a few conventions: 用于描述Swift编程语言正规语法的标记有如下几个约定: - * An arrow (→) is used to mark grammar productions and can be read as “can consist of.“ - -* 箭头(→)用于标记语法生产和可以理解为“可包括” - -* Syntactic categories are indicated by italic text and appear on both sides of a grammar production rule. +* 箭头(→)用于标记文法和可以理解为“可包括” * 语法范围以斜体文字表示,显示在语法规范的两侧。 -* Literal words and punctuation are indicated by boldface constant width text and appear only on the right-hand side of a grammar production rule. +* 文字和标点由固定宽度的粗体文字显示,并只出现在一个标记文法的右侧. -* 文字和标点由固定宽度的粗体文字显示,并只出现在一个语法生产规范的右侧. -* Alternative grammar productions are separated by vertical bars (|). When alternative productions are too long to read easily, they are broken into multiple grammar production rules on new lines. +* 替代标记文法式由竖线(|)分隔。当替代文法过长而不易阅读时,它们将在新行中变换为多个标记文法规范。 -* 替代语法产生式由竖线(|)分隔。当替代产生式过长而不易阅读时,它们将在新行中变换为多个语法产生式规范。 +* 在一些案例中,常规字体文本将用于描述右侧的标记文法规则。 -* In a few cases, regular font text is used to describe the right-hand side of a grammar production rule. - -* 在一些案例中,常规字体文本将用于描述右侧的语法产生式规则。 - -* Optional syntactic categories and literals are marked by a trailing subscript, opt. - -* 可选的句法范围和文字为在尾部以opt标识描述。 - -As an example, the grammar of a getter-setter block is defined as follows: +* 可选的句法范围和字面量则以尾部下标opt作为标识。 比如,getter-setter 区的语法定义如下: -> G R A M M A R O F A G E T T E R- S E T T E R B L O C K - -> getter-setter-block → { getter-clause setter-clause opt } |{ setter-clause getter clause -} +> GETTER-SETTER区语法 -This definition indicates that a getter-setter block can consist of a getter clause followed by an optional setter clause, enclosed in braces, or a setter clause followed by a getter clause, enclosed in braces. The grammar production above is equivalent to the following two productions, where the alternatives are spelled out explicitly: +> getter-setter-block → { getter-clause setter-clause opt } |{ setter-clause getter clause} 该定义表示,一个getter-setter方法块可由一个getter子句后跟一个可选的setter语句,括在大括号中。或者一个setter子句后跟一个getter子句,括在大括号中。上述语法产生式等价于下面的两个替代处已经明确拼写出的产生式。 -> G R A M M A R O F A G E T T E R S E T T E R B L O C K +> GETTER-SETTER区语法 > getter-setter-block → { getter-clause setter-clause opt } diff --git a/src/chapter3/02_Lexical_Structure.md b/src/chapter3/02_Lexical_Structure.md index 4d6f61f..9f53437 100644 --- a/src/chapter3/02_Lexical_Structure.md +++ b/src/chapter3/02_Lexical_Structure.md @@ -1,422 +1,289 @@ -# Lexical Structure # 词法结构 -The lexical structure of Swift describes what sequence of characters form valid tokens of the language. These valid tokens form the lowest-level building blocks of the language and are used to describe the rest of the language in subsequent chapters. - Swift的词法结构描述了如何在该语言中用字符序列构建合法标记。这些合法标识构成了该语言最底层的基石,并将会被用于描述后续章节的剩余部分。 -In most cases, tokens are generated from the characters of a Swift source file by considering the longest possible substring from the input text, within the constraints of the grammar that are specified below. This behavior is referred to as longest match or maximal munch. - -通常,标识将从Swift源文件的输入文本中提取可能的最长子字符串生成。这种方法称为“最长匹配项(longest match)”,或者“最大适合”(maximal munch)。 +在大多数情况下,在后续指定的语法约束内,标识将从Swift源文件的输入文本中提取尽可能长的子字符串生成。这种方法称为“最长匹配项”,或者“最大适合”。 -## Whitespace and Comments ## 空白与注释 -Whitespace has two uses: to separate tokens in the source file and to help determine whether an operator is a prefix or postfix (see Operators), but is otherwise ignored. The following characters are considered whitespace: space (U+0020), line feed (U+000A),carriage return (U+000D), horizontal tab (U+0009), vertical tab (U+000B), form feed (U+000C) and null (U+0000). - -空白(whitespace)有两个用途:区分源文件中的标识符和帮助确定一个操作符是前缀还是后缀(参见:运算符),否则忽略。以下字符会被认为是空白:s空格(space)(U+0020)、换行符(line feed)(U+000A)、回车符(carriage return)(U+000D)、水平 tab(horizontal tab)(U+0009)、垂直 tab(vertical tab)(U+000B)、换页符(form feed)(U+000C)以及空(null)(U+0000)。 - -Comments are treated as whitespace by the compiler. Single line comments begin with // and continue until the end of the line. Multiline comments begin with /* and end with */.Nesting is allowed, but the comment markers must be balanced. +空白有两个用途:区分源文件中的标识符和帮助确定一个操作符是前缀还是后缀(参见:运算符),否则忽略。以下字符会被认为是空白:空格(U+0020)、换行符(U+000A)、回车符(U+000D)、水平制表符(U+0009)、垂直制表符(U+000B)、换页符(U+000C)以及空(U+0000)。 -注释(comments)被编译器当作空白处理。单行注释以//开始直到该行结束。多行注释由/\*开始,以*/结束。注释允许嵌套,但注释标记必须相匹配。 +注释会被编译器当作空白处理。单行注释以 // 开始直到该行结束。多行注释由 /\* 开始,以 */ 结束。注释允许嵌套,但注释标记必须相匹配。 -## Identifiers ## 标识符 -Identifiers begin with an upper case or lower case letter A through Z, an underscore (_), a noncombining alphanumeric Unicode character in the Basic Multilingual Plane, or a character outside the Basic Multilingual Plan that isn’t in a Private Use Area. After the first character, digits and combining Unicode characters are also allowed. - -标识符以大写或小写字母A到Z,下划线(_),基本多语言面(Basic Multilingual Plane)中的非组合Unicode字符或者基本多语言面(Basic Multilingual Plane)以外的非专用区(Private Use Area)的字符开始。首字符之后,可以使用数字和 Unicode 字符组合。 - -To use a reserved word as an identifier, put a backtick (\`) before and after it. For example, class is not a valid identifier, but \`class\` is valid. The backticks are not considered part of the identifier; \`x\` and x have the same meaning. +标识符以大写或小写字母A到Z,下划线(_),基本多语言文种平面 中的非组合Unicode字符或者基本多语言文种平面以外的私有使用区的字符开始。在首字符之后,数字和 Unicode 字符组合也是可以允许的。 要使用保留字作为标识符,需要在其前后增加一个反引号(\`)。例如:类不是一个有效的标识符,但`class`是有效的。反引号不会被当做标识符的一部分;`x` 和 x 意义相同。 -Inside a closure with no explicit parameter names, the parameters are implicitly named $0, $1, $2, and so on. These names are valid identifiers within the scope of the closure. +闭包中如果没有明确的参数名称,参数将被隐式命名为 $0、$1、$2... 这些命名在闭包作用域内是有效的标识符。 -闭包(closure)中如果没有明确指定参数名称,参数将被隐式命名为 $0、$1、$2... 这些命名在闭包作用域内是合法的标识符。 -> G R A M M A R O F A N I D E N T I F I E R > 标识符语法 -> identifier → identifier-head identifier-characters[opt] - -> 标识符 → 标识符头(Head) 标识符字符列表 可选 +> 标识符 → 标识符头 标识符字符 [可选] -> identifier → \` identifier-head > identifier-characters[opt] ` +> 标识符 → ` 标识符头 标识符字符 [可选] ` -> 标识符 → ` 标识符头(Head) 标识符字符列表 可选 ` -> - -> identifier → implicit-parameter-name > 标识符 → 隐式参数名 -> identifier-list → identifier identifier , identifier-list - -> 标识符列表 → 标识符 | 标识符 , 标识符列表 - -> identifier-head → Upper- or lowercase letter A through Z - -> 标识符头(Head) → Upper- or lowercase letter A through Z - -> identifier-head → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or -U+00B7–U+00BA - -> 标识符头(Head) → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA - -> identifier-head → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or -U+00F8–U+00FF - -> 标识符头(Head) → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF - - -> identifier-head → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F– -U+1DBF - -> 标识符头(Head) → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF - -> identifier-head → U+1E00–U+1FFF - ->标识符头(Head) → U+1E00–U+1FFF - -> identifier-head → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or -U+2060–U+206F - -> 标识符头(Head) → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F - - -> identifier-head → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776– -U+2793 - ->标识符头(Head) → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793 +> 标识符列表 → 标识符 标识符 , 标识符列表 -> identifier-head → U+2C00–U+2DFF or U+2E80–U+2FFF +> 标识符头 → 大写或小写字母A到Z -> 标识符头(Head) → U+2C00–U+2DFF or U+2E80–U+2FFF +> 标识符头 → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, 或 U+00B7–U+00BA -> identifier-head → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040– -U+D7FF +> 标识符头 → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, 或 U+00F8–U+00FF -> 标识符头(Head) → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF +> 标识符头 → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, 或 U+180F–U+1DBF -> identifier-head → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or -U+FE30–U+FE44 +> 标识符头 → U+1E00–U+1FFF -> 标识符头(Head) → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44 +> 标识符头 → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, 或 U+2060–U+206F -> identifier-head → U+FE47–U+FFFD -> 标识符头(Head) → U+FE47–U+FFFD +> 标识符头 → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, 或 U+2776–U+2793 +> 标识符头 → U+2C00–U+2DFF 或 U+2E80–U+2FFF -> identifier-head → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or -U+40000–U+4FFFD +> 标识符头 → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, 或 U+3040–U+D7FF -> 标识符头(Head) → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD +> 标识符头 → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, 或 U+FE30–U+FE44 -> identifier-head → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or -U+80000–U+8FFFD +> 标识符头 → U+FE47–U+FFFD -> 标识符头(Head) → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD +> 标识符头 → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, 或 U+40000–U+4FFFD -> identifier-head → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or -U+C0000–U+CFFFD +> 标识符头 → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, 或 U+80000–U+8FFFD -> 标识符头(Head) → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD +> 标识符头 → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, 或 U+C0000–U+CFFFD -> identifier-head → U+D0000–U+DFFFD or U+E0000–U+EFFFD -> 标识符头(Head) → U+D0000–U+DFFFD or U+E0000–U+EFFFD +> 标识符头 → U+D0000–U+DFFFD 或 U+E0000–U+EFFFD -> identifier-character → Digit 0 through 9 +> 标识符字符 → 数字 0 到 9 -> 标识符字符 → 数值 0 到 9 +> 标识符字符 → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, 或 U+FE20–U+FE2F -> identifier-character → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or -U+FE20–U+FE2F +> 标识符字符 → 标识符头 -> 标识符字符 → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F +> 标识符字符 → 标识符字符 标识符字符列表 [可选] -> identifier-character → identifier-head -> 标识符字符 → 标识符头(Head) +> 隐式参数名 → $十进制数字 -> identifier-characters → identifier-character identifier-characters[opt] -> 标识符字符列表 → 标识符字符 标识符字符列表 可选 -> implicit-parameter-name → $ decimal- -> 隐式参数名 → $ 十进制数字列表 - - -## Keywords ## 关键字 -The following keywords are reserved and may not be used as identifiers, unless they’re escaped with backticks, as described above in Identifiers. - -下述被保留的关键字不允许用作标识符,除非它们被反引号转义,参见标识符。 -* Keywords used in declarations: class, deinit, enum, extension, func, import, init, let, protocol,static, struct, subscript, typealias, and var. -* 用作声明的关键字:class、deinit、enum、extension、func、import、init、let、protocol、static、struct、subscript、typealias、var +下述被保留的关键字不允许用作标识符,除非它们被反引号转义,参见上面的标识符。 -* Keywords used in statements: break, case, continue, default, do, else, fallthrough, if, in, for,return, switch, where, and while. +* 用作声明的关键字:class、deinit、enum、extension、func、imp或 t、init、let、protocol、static、struct、subscript、typealias、var -* 用作语句的关键字:break、case、continue、default、do、else、fallthrough、if、in、for、return、switch、where、while - -* Keywords used in expressions and types: as, dynamicType, is, new, super, self, Self, Type,__COLUMN__, __FILE__, __FUNCTION__, and __LINE__. +* 用作语句的关键字:break、case、continue、default、do、else、fallthrough、if、in、f或 、return、switch、where、while * 用作表达和类型的关键字:as、dynamicType、is、new、super、self、Self、Type、__COLUMN__、__FILE__、__FUNCTION__、__LINE__ -* Keywords reserved in particular contexts: associativity, didSet, get, infix, inout, left, mutating,none, nonmutating, operator, override, postfix, precedence, prefix, right, set, unowned, unowned(safe),unowned(unsafe), weak and willSet. Outside the context in which they appear in the grammar, they can be used as identifiers. - -* 特定上下文中被保留的关键字:associativity、didSet、get、infix、inout、left、mutating、none、nonmutating、operator、override、postfix、precedence、prefix、right、set、unowned、unowned(safe)、unowned(unsafe)、weak、willSet,这些关键字在特定上下文之外可以被用于标识符。 +* 特定上下文中被保留的关键字:associativity、didSet、get、infix、inout、left、mutating、none、nonmutating、operat或 、override、postfix、precedence、prefix、right、set、unowned、unowned(safe)、unowned(unsafe)、weak、willSet,这些关键字在特定上下文之外可以被用于标识符。 -## Literals ## 字面量 -A literal is the source code representation of a value of an integer, floating-point number, or string type. The following are examples of literals: 字面量在源代码中表示一个整数,浮点数或字符串类型的值。以下是示例: -> 42 // Integer literal +> 42 //整形字面量 -> 3.14159 // Floating-point literal +> 3.14159 //浮点型字面量 -> "Hello, world!" // String literal +> "Hello, w或 ld!" //字符串型字面量 -> G R A M M A R O F A L I T E R A L -> literal → integer-literal floating-point-literal string-literal +> 字面量语法 > 字面量 → 整型字面量 | 浮点数字面量 | 字符串字面量 -## Integer Literals ## 整型字面量 -Integer literals represent integer values of unspecified precision. By default, integer literals are expressed in decimal; you can specify an alternate base using a prefix. Binary literals begin with 0b, octal literals begin with 0o, and hexadecimal literals begin with 0x. - -整型字面量(integer literals)表示未指定精度整型数的值。整型字面量默认为十进制;你可以通过加前缀来改变其数。二进制字面量以 0b 开始,八进制字面量以 0o 开始,十六进制字面量以 0x 开始。 +整型字面量表示未指定精度的整型值。整型字面量默认为十进制;你可以通过加前缀来改变基数。二进制字面量以 0b 开始,八进制字面量以 0o 开始,十六进制字面量以 0x 开始。 -Decimal literals contain the digits 0 through 9. Binary literals contain 0 and 1, octal literalscontain 0 through 7, and hexadecimal literals contain 0 through 9 as well as A through F in upper- or lowercase. - -十进制字面量包含数字 0 至 9。二进制字面量只包含 0 或 1,八进制字面量包含数字 0 至 7,十六进制字面量包含数字 0 至 9 以及大写或小写的字母 A 至 F。 - -Negative integers literals are expressed by prepending a minus sign (-) to an integer literal, as in -42. +十进制字面量包含数字 0 到 9。二进制字面量只包含 0 和 1,八进制字面量包含数字 0 到 7,十六进制字面量包含数字 0 到 9 以及大写或小写的字母 A 到 F。 负整型字面量的字面量需要在整型字量面前加减号 -,比如 -42。 -Underscores (_) are allowed between digits for readability, but are ignored and therefore don’t affect the value of the literal. Integer literals can begin with leading zeros (0), but are likewise ignored and don’t affect the base or value of the literal. +数字间允许使用下划线 _ 来增加可读性,但下划线会被忽略而不会影响字面量的值。整型字面量可以以0开始,但同样会被忽略而不会影响其基数或字面量的值。 -数字间允许使用下划线 _ 来增加可读性,但下划线会被忽略而不会影响字面量的值。整型字面量也可以以0开始,但同样会被忽略而不会影响其基数及字面量的值。 +除非另有指定,整型字面量的默认类型为 Swift 标准库类型中的 Int。Swift 标准库还定义了各种不同长度的有符号和无符号的整数类型,请参见 整型。 -Unless otherwise specified, the default type of an integer literal is the Swift standard library type Int. The Swift standard library also defines types for various sizes of signed and unsigned integers, as described in Integers. +> 整型字面量语法 -除非特殊指定,整型字面量的默认类型为 Swift 标准库类型中的 Int。Swift 标准库还定义了各种不同长度的是否带符号的整数类型,请参考 整数类型。 -> 整型字面量语法 > 整型字面量 → 二进制字面量 + > 整型字面量 → 八进制字面量 + > 整型字面量 → 十进制字面量 + > 整型字面量 → 十六进制字面量 + > 二进制字面量 → 0b 二进制数字 二进制字面量字符列表 可选 -> 二进制数字 → 数值 0 到 1 + +> 二进制数字 → 数字 0 到 1 + > 二进制字面量字符 → 二进制数字 | _ + > 二进制字面量字符列表 → 二进制字面量字符 二进制字面量字符列表 可选 + > 八进制字面量 → 0o 八进字数字 八进制字符列表 可选 + > 八进字数字 → 数值 0 到 7 + > 八进制字符 → 八进字数字 | _ + > 八进制字符列表 → 八进制字符 八进制字符列表 可选 + > 十进制字面量 → 十进制数字 十进制字符列表 可选 + > 十进制数字 → 数值 0 到 9 + > 十进制数字列表 → 十进制数字 十进制数字列表 可选 + > 十进制字符 → 十进制数字 | _ + > 十进制字符列表 → 十进制字符 十进制字符列表 可选 + > 十六进制字面量 → 0x 十六进制数字 十六进制字面量字符列表 可选 -> 十六进制数字 → 数值 0 到 9, a through f, or A through F + +> 十六进制数字 → 数值 0 到 9, a 到 f,或 A 到 F + > 十六进制字符 → 十六进制数字 | _ + > 十六进制字面量字符列表 → 十六进制字符 十六进制字面量字符列表 可选 -## Floating-Point Literals ## 浮点型字面量 -Floating-point literals represent floating-point values of unspecified precision. - -浮点型字面量(floating-point literals)表示未指定精度浮点数的值。 - -By default, floating-point literals are expressed in decimal (with no prefix), but they can also be expressed in hexadecimal (with a 0x prefix). +浮点型字面量表示未指定精度浮点数的值。 浮点型字面量默认用十进制表示(无前缀),但也可以用十六进制表示(加前缀 0x)。 -Decimal floating-point literals consist of a sequence of decimal digits followed by either a decimal fraction, a decimal exponent, or both. The decimal fraction consists of a decimal point (.) followed by a sequence of decimal digits. The exponent consists of an upper- or lowercase e prefix followed by sequence of decimal digits that indicates what power of 10 the value preceding the e is multiplied by. For example, 1.25e2 represents 1.25 ⨉ 102, which evaluates to 125.0. Similarly, 1.25e-2 represents 1.25 ⨉ 10-2, which evaluates to 0.0125. - -十进制浮点型字面量(decimal floating-point literals)由十进制数字后跟小数部分或指数部分(或两者皆有)组成。十进制小数部分由小数点 . 后跟十进制数字组成。指数部分由大写或小写字母的前缀e 后跟十进制数字组成,这串数字表示 e 之前的数量乘以 10 的几次方。例如:1.25e2 表示 1.25 ⨉ 10^2,也就是 125.0;同样,1.25e-2 表示 1.25 ⨉ 10^-2,也就是 0.0125。 - -Hexadecimal floating-point literals consist of a 0x prefix, followed by an optional hexadecimal fraction, followed by a hexadecimal exponent. The hexadecimal fraction consists of a decimal point followed by a sequence of hexadecimal digits. The exponent consists of an upper- or lowercase p prefix followed by sequence of decimal digits that indicates what power of 2 the value preceding the p is multiplied by. For example, 0xFp2 represents 15 ⨉ 22, which evaluates to 60. Similarly, 0xFp-2 represents 15 ⨉ 2-2, which evaluates to 3.75. -十六进制浮点型字面量(hexadecimal floating-point literals)由前缀 0x 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字组成。指数部分由大写或小写字母的前缀p 后跟十进制数字串组成,这串数字表示 p 之前的数量乘以 2 的几次方。例如:0xFp2 表示15 ⨉ 2^2,也就是 60;同样,0xFp-2 表示 15 ⨉ 2^-2,也就是 3.75。 +十进制浮点型字面量由十进制数字后跟小数部分或指数部分组成,或两者都有。十进制小数部分由小数点 . 后跟十进制数字组成。指数部分由大写或小写字母的前缀e 后跟十进制数字组成,这串数字表示 e 之前的数量乘以 10 的几次方。例如:1.25e2 表示 1.25 * 10^2,也就是 125.0;同样,1.25e-2 表示 1.25 * 10^-2,也就是 0.0125。 -Unlike with integer literals, negative floating-point numbers are expressed by applying the unary minus operator (-) to a floating-point literal, as in -42.0. The result is an expression, not a floating-point integer literal. +十六进制浮点型字面量由前缀 0x 后跟可选的十六进制小数部分以及十六进制指数部分组成。十六进制小数部分由小数点后跟十六进制数字组成。指数部分由大写或小写字母的前缀p 后跟十进制数字串组成,这串数字表示 p 之前的数量乘以 2 的几次方。例如:0xFp2 表示15 * 2^2,也就是 60;同样,0xFp-2 表示 15 * 2^-2,也就是 3.75。 与整型字面量不同,负的浮点型字面量由一元运算符减号 - 和浮点型字面量组成,例如 -42.0。这代表一个表达式,而不是一个浮点整型字面量。 -Underscores (_) are allowed between digits for readability, but are ignored and therefore don’t affect the value of the literal. Floating-point literals can begin with leading zeros (0),but are likewise ignored and don’t affect the base or value of the literal. - 下划线 _ 允许被用于增强可读性,但会被忽略而不影响字面量的值。浮点型字面量也可以在数字前加 0,但同样会被忽略而不影响字面量的值。 -Unless otherwise specified, the default type of a floating-point literal is the Swift standard library type Double, which represents a 64-bit floating-point number. The Swift standard library also defines a Float type, which represents a 32-bit floating-point number. - -除非特殊指定,浮点型字面量的默认类型为 Swift 标准库类型中的 Double,表示64位浮点数。Swift 标准库也定义 Float 类型,表示32位浮点数。 +除非另外指定,浮点型字面量的默认类型为 Swift 标准库类型中的 Double,表示64位浮点数。Swift 标准库也定义 Float 类型,表示32位浮点数。 > 浮点型字面量语法 + > 浮点数字面量 → 十进制字面量 十进制分数 可选 十进制指数 可选 + > 浮点数字面量 → 十六进制字面量 十六进制分数 可选 十六进制指数 + > 十进制分数 → . 十进制字面量 + > 十进制指数 → 浮点数e 正负号 可选 十进制字面量 + > 十六进制分数 → . 十六进制字面量 可选 + > 十六进制指数 → 浮点数p 正负号 可选 十六进制字面量 + > 浮点数e → e | E + > 浮点数p → p | P + > 正负号 → + | - -## String Literals ## 字符串型字面量 -A string literal is a sequence of characters surrounded by double quotes, with the following form: 字符串型字面量是双引号括起来的一个字符序列,形式如下: " characters " -String literals cannot contain an unescaped double quote ("), an unescaped backslash (\), a carriage return, or a line feed. - 字符串型字面量中不能包含未转义的双引号 "、未转义的反斜线\、回车符(carriage return)或换行符(line feed)。 -Special characters can be included in string literals using the following escape sequences: -* Null Character (\0) -* Backslash (\\) -* Horizontal Tab (\t) -* Line Feed (\n) -* Carriage Return (\r) -* Double Quote (\") -* Single Quote (\') - -特殊符号可以经如下转义后在字符串型字面量中使用: +特殊符号经如下转义后可在字符串型字面量中使用: -* 空字符(Null Character)\0 -* 反斜线(Backslash)\\ -* 水平Tab (Horizontal Tab)\t -* 换行符(Line Feed)\n -* 回车符(Carriage Return)\r -* 双引号(Double Quote)\" -* 单引号(Single Quote)\' +* 空字符 \0 +* 反斜线 \\ +* 水平制表符 \t +* 换行符 \n +* 回车符 \r +* 双引号 \" +* 单引号 \' -Characters can also be expressed by \x followed by two hexadecimal digits, \u followed by four hexadecimal digits, or \U followed by eight hexadecimal digits. The digits in these escape sequences identify a Unicode codepoint. - -字符也可以用以下方式表示:\x 后跟两位十六进制数字,\u 后跟四位十六进制数字,\U 后跟八位十六进制数字。在这些转义序列后跟的数字表示一个Unicode码。 - -The value of an expression can be inserted into a string literal by placing the expression in parentheses after a backslash (\). The interpolated expression must not contain an unescaped double quote ("), an unescaped backslash (\), a carriage return, or a line feed. +字符也可以用以下方式表示:\x 后跟两位十六进制数字,\u 后跟四位十六进制数字,或 \U 后跟八位十六进制数字。在这些转义序列后跟的数字表示一个Unicode码。 字符串字面量可以在反斜线后面的小括号中插入表达式\()。插入的表达式必须不能包含未的双引号(”),反斜线(\),回车符或换行符。 -The expression must evaluate to a value of a type that the String class has an initializer for. - 表达式的计算结果必须是String类的一个有初始化的类型的值。 -For example, all the following string literals have the same value: -1. “1 2 3" -2. "1 2 \(3)" -3. "1 2 \(1 + 2)" -4. “var x = 3; "1 2 \(x)” +比如,下面所有的字符串型字面量拥有同样的值: -摘录来自: Apple Inc. “The Swift Programming Language”。 iBooks. https://itun.es/cn/jEUH0.l +> "1 2 3" -比如,下面所有的字符串型字面量拥有同样的值: +> "1 2 \(3)" -"1 2 3" -"1 2 \(3)" -"1 2 \(1 + 2)" -var x = 3; "1 2 \(x)" +> "1 2 \(1 + 2)" + +> var x = 3; "1 2 \(x)" -The default type of a string literal is String. The characters that make up a string are of type Character. For more information about the String and Character types, see Strings and Characters. 字符串型字面量的默认类型为 String。组成字符串的字符的类型为 Character,更多关于String和Character类型,请参考 字符串和字符。 > 字符型字面量语法 + > 字符串型字面量 → " 引用文本 " + > 引用文本 → 引用文本条目 引用文本 可选 + > 引用文本条目 → 转义字符 + > 引用文本条目 → ( 表达式 ) -> 引用文本条目 → 除了"¬, \¬, U+000A, or U+000D的所有Unicode的字符 + +> 引用文本条目 → 除了"¬, \¬, U+000A, 或 U+000D的所有Unicode的字符 + > 转义字符 → \0 | \ | \t | \n | \r | \" | \' + > 转义字符 → \x 十六进制数字 十六进制数字 + > 转义字符 → \u 十六进制数字 十六进制数字 十六进制数字 十六进制数字 + > 转义字符 → \U 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 十六进制数字 -## Operators ## 运算符 -The Swift standard library defines a number of operators for your use, many of which are discussed in Basic Operators and Advanced Operators. The present section describes which characters can be used as operators. - Swift标准库定义了许多供你使用的运算符,其中大部分将在 基础运算符 和 高级运算符 中进行阐述。本章节将描述了哪些字符可被用作运算符。 -Operators are made up of one or more of the following characters: /, =, -, +, !, *, %, <, >,&, |, ^, ~, and .. That said, the tokens =, ->, //, /*, */, ., and the unary prefix operator & are reserved. These tokens can’t be overloaded, nor can they be used to define custom operators. - 运算符由一个或多个如下字符组成:/、=、-、+、!、*、%、<、>、&、|、^、~、.。也就是说,标记 =,->、//、/*、*/、. 以及一元前缀运算符 & 属于保留字,这些标记不能被重写或用于定义自定义的运算符。 -The whitespace around an operator is used to determine whether an operator is used as a prefix operator, a postfix operator, or a binary operator. This behavior is summarized in the following rules: - -运算符两侧的空白被用来区分一个运算符是否被用为前缀运算符(prefix operator)、后缀运算符(postfix operator)或二元运算符(binary operator)。规则总结如下: - -* If an operator has whitespace around both sides or around neither side, it is -treated as a binary operator. As an example, the + operator in a+b and a + b is -treated as a binary operator. +运算符两侧的空白被用来区分一个运算符是否被用为前缀运算符(prefix operat或 )、后缀运算符(postfix operat或 )或二元运算符(binary operat或 )。规则总结如下: * 如果运算符两侧都有空白或两侧都无空白,将被看作二元运算符。例如:a+b 和 a + b 中的运算符+ 被看作二元运算符。 -* If an operator has whitespace on the left side only, it is treated as a prefix unary operator. As an example, the ++ operator in a ++b is treated as a prefix unary operator. * 如果运算符只有左侧空白,将被看作前缀一元运算符。例如 a ++b 中的 ++ 被看作前缀一元运算符。 -* If an operator has whitespace on the right side only, it is treated as a postfix -unary operator. As an example, the ++ operator in a++ b is treated as a postfix unary operator. * 如果运算符只有右侧空白,将被看作后缀一元运算符。例如 a++ b 中的 ++ 被看作后缀一元运算符。 - -* If an operator has no whitespace on the left but is followed immediately by a dot (.), it is treated as a postfix unary operator. As an example, the ++ operator in a++.b is treated as a postfix unary operator (a++ . b rather than a ++ .b). - * 如果运算符左侧没有空白并紧跟 .,将被看作后缀一元运算符。例如 a++.b 中的 ++ 被看作后缀一元运算符(同理, a++ . b 中的 ++ 是后缀一元运算符而 a ++ .b 中的 ++ 不是). - -For the purposes of these rules, the characters (, [, and { before an operator, the -characters ), ], and } after an operator, and the characters ,, ;, and : are also considered whitespace. - 鉴于这些规则的目的,运算符前的字符 (、[ 和 { ;运算符后的字符 )、] 和 } 以及字符 ,、; 和: 同样被认为空白。 -There is one caveat to the rules above. If the ! or ? operator has no whitespace on the left, it is treated as a postfix operator, regardless of whether it has whitespace on the right. To use the ? operator as syntactic sugar for the Optional type, it must not have whitespace on the left. To use it in the conditional (? :) operator, it must have whitespace around both sides. - 以上规则有一点需要注意。如果运算符 ! 或 ? 左侧没有空白,则不管右侧是否有空白都将被看作后缀运算符。如果将 ? 用作修饰可选类型(optional type),左侧必须无空白。如果用于条件运算符 ? :,必须两侧都有空白。 -In certain constructs, operators with a leading < or > may be split into two or more tokens. The remainder is treated the same way and may be split again. As a result, there is no need to use whitespace to disambiguate between the closing > characters in constructs like Dictionary>. In this example, the closing > characters are not treated as a single token that may then be misinterpreted as a bit shift >> operator. - 在特定构成中 ,以 < 或 > 开头的运算符会被分离成两个或多个标记,剩余部分以同样的方式会被再次分离。因此,在 Dictionary> 中没有必要添加空白来消除闭合字符 > 的歧义。在这个例子中, 闭合字符 > 被看作单字符标记,而不会被误解为移位运算符 >>。 -To learn how to define new, custom operators, see Custom Operators and Operator Declaration.To learn how to overload existing operators, see Operator Functions. - 要学习如何自定义新的,自定义的运算符,请参考 自定义操作符 和 运算符声明。学习如何重写现有运算符,请参考 运算符方法。 -> GRAMMAR OF OPERATORS > 运算符语法语法 -> -> operator → operator-characteroperatoropt > 运算符 → 运算符字符 运算符 可选 -> operator-character → / = - + ! * % < > & | ^ ~ . - > 运算符字符 → / | = | - | + | ! | * | % | < | > | & | | | ^ | ~ | . -> binary-operator → operator - > 二元运算符 → 运算符 -> prefix-operator → operator - > 前置运算符 → 运算符 -> postfix-operator → operator > 后置运算符 → 运算符 diff --git a/src/chapter3/03_Types.md b/src/chapter3/03_Types.md index 6b95612..87295de 100644 --- a/src/chapter3/03_Types.md +++ b/src/chapter3/03_Types.md @@ -1,421 +1,273 @@ -# Types # 类型 - -In Swift, there are two kinds of types: named types and compound types. A named type is a type that can be given a particular name when it is defined. Named types include classes, structures, enumerations, and protocols. For example, instances of a user-defined class named MyClass have the type MyClass. In addition to user-defined named types, the Swift standard library defines many commonly used named types, including those that represent arrays, dictionaries, and optional values. - -在swift里,有两种类型:命名类型和复合类型。命名类型是指在定义的时候时候能够给一个指定名字的类型。命名类型包含类、结构、枚举和协议。例如,用户定义的类的实例MyClass,其类型就是MyClass。除了用户定义的命名类型,swift标准库还定义了很多常用命名类型,如一些数组,字典,可选值。 - - -Data types that are normally considered basic or primitive in other languages—such as types that represent numbers, characters, and strings—are actually named types, defined and implemented in the Swift standard library using structures. Because they are named types, you can extend their behavior to suit the needs of your program, using an extension declaration, discussed in Extensions and Extension Declaration. - +在swift里,有两种类型:命名类型和复合类型。命名类型是指在定义的时候能够给一个指定名字的类型。命名类型包含类、结构、枚举和协议。例如,一个用户自定义的名为MyClass的类的实例,其类型就是MyClass。除了用户定义的命名类型,swift标准库还定义了很多常用命名类型,如一些数组,字典,可选值。 一些被其它语言视为是最基础或最原始的数据类型,例如数字、字符、字符串,实际上都是命名类型,swift标准库使用结构去定义和实现他们。由于他们是命名类型的,你可以用扩展声明来扩展他们的功能,来满足你的程序需求,具体请参考‘扩展和扩展声明’。 - -A compound type is a type without a name, defined in the Swift language itself. There are two compound types: function types and tuple types. A compound type may contain named types and other compound types. For instance, the tuple type (Int, (Int, Int)) contains two elements: The first is the named type Int, and the second is another compound type (Int, Int). - -复合类型是一个没有名字的类型,由swift内部自己定义。swift有两种复合类型:函数类型和元组类型。一个复合数据类型可以包含命名类型和其他复合类型。例如,一个元组类型(Int, (Int, Int))包含两个元素:第一个是命名类型Int,第二个是复合类型(Int, Int)。 - -This chapter discusses the types defined in the Swift language itself and describes the type inference behavior of Swift. +复合类型是一个没有名字的类型,由swift内部自己定义。swift有两种复合类型:函数类型和元组类型。一个复合数据类型可以包含命名类型和其他复合类型。例如,一个元组类型(Int, (Int, Int))包含两个元素:第一个是命名类型Int,第二个是另外一个复合类型(Int, Int)。 本章讨论swift语言本身定义的类型,并描述在swift中类型推断的方式。 -> GRAMMAR OF A TYPE -> > 类型的语法 -> type → array-type function-type type-identifier tuple-type optional-type implicitly-unwrapped-optional-type protocol-composition-type metatype-type - -> type -> 数组类型|函数类型|类型标识|元组类型|可选类型|隐式去包装可选类型|协议构成类型|元型类型 - - -## Type Annotation - -## 类型注释 -A type annotation explicitly specifies the type of a variable or expression. Type annotations begin with a colon (:) and end with a type, as the following examples show: +> 类型 -> 数组类型|函数类型|类型标识|元组类型|可选类型|隐式去包装可选类型|协议构成类型|元型类型 -类型标注明确的指定一个变量或者表达式的类型。类型注释以冒号(:)开始,类型结束,如下面的例子: +## 类型注解 - 1. let someTuple:(Double, Double) = (3.14159, 2.71828) - - 2. func someFunction(a:Int) { /**/} -In the first example, the expression someTuple is specified to “have the tuple type (Double, Double). In the second example, the parameter a to the function someFunction is specified to have the type Int. +类型注解明确的指定一个变量或者表达式的类型。类型注解以冒号(:)开始,以类型结束,如下面的例子: + + 1. let someTuple:(Double, Double) = (3.14159, 2.71828) + 2. func someFunction(a:Int) { /**/} + 在第一个例子中,表达式someTuple是被定义为元组类型(Double, Double)。在第二个例子中,函数someFuncion中的参数a被定义为Int类型。 -Type annotations can contain an optional list of type attributes before the type. -类型注释可以在类型前面添加一个类型属性的可选列表。 +类型注解可以在类型前面包含一个可选的类型属性的列表。 -> GRAMMAR OF A TYPE ANNOTATION +> 类型注解的语法 -> 类型注释的语法 +> 类型注解 -> :属性[可选]类型 -> type-annotation → :attributes[opt]type -> -> type-annotation -> :属性[可选]类型 - -## Type Identifier ## 类型标识符 -A type identifier refers to either a named type or a type alias of a named or compound type. 类型标识符是指一个命名类型或者说命名类型/复合类型的别名。 -Most of the time, a type identifier directly refers to a named type with the same name as the identifier. For example, Int is a type identifier that directly refers to the named type Int, and the type identifier Dictionary directly refers to the named type Dictionary. - -大多数情况下,类型标识符直接指向和标示符命名相同的命名类型。例如,类型标识符Int指向命名类型Int,类型标识符Dictionary指向命名类型Dictionary。 -There are two cases in which a type identifier does not refer to a type with the same name. In the first case, a type identifier refers to a type alias of a named or compound type. For instance, in the example below, the use of Point in the “type annotation refers to the tuple type (Int, Int). +大多数情况下,类型标识符直接指向和标示符命名相同的命名类型。例如,类型标识符Int指向命名类型Int,类型标识符Dictionary指向命名类型Dictionary。 -命名标识符和类型不同名有以下两种情况。第一种情况,命名标识符指向命名类型或者复合类型的别名。例如下面的例子,类型标识符使用Point指向元组类型(Int, Int)。 - typealias Point = (Int, Int); - let origin: Point = (0, 0); - +命名标识符和类型标识符不同名有两种情况。第一种情况,命名标识符指向命名类型或者复合类型的别名。例如,在下面的例子中,类型标识符使用Point指向元组类型(Int, Int)。 -In the second case, a type identifier uses dot (.) syntax to refer to named types declared in other modules or nested within other types. For example, the type identifier in the following code references the named type MyType that is declared in the ExampleModule module. + typealias Point = (Int, Int); + let origin: Point = (0, 0); 第二种情况,类型标识符用点(.)指向在其它模块中声明或嵌套在其它类型中的命名类型。例如,在下面的代码中,类型标识符引用在模块ExampleModule中声明的命名类型MyType。 - - var someValue: ExampleModule.MyType - -> GRAMMAR OF A TYPE IDENTIFIER + var someValue: ExampleModule.MyType + > 命名标识符的语法 -> type-identifier → type-namegeneric-argument-clauseopt type-namegeneric-argument-clauseopt.type-identifier - > 命名标识符 -> 类型名称 泛型参数子句[可选]|类型名称 泛型参数子句[可选].类型标识符 -> type-name → identifier - > 类型标识符 -> 标识符 -## Tuple Type ## 元组类型 -A tuple type is a comma-separated list of zero or more types, enclosed in parentheses. - 元组类型是指在括号中,用逗号分隔的零到多个类型的列表。 -You can use a tuple type as the return type of a function to enable the function to return a single tuple containing “multiple values. You can also name the elements of a tuple type and use those names to refer to the values of the individual elements. An element name consists of an identifier followed immediately by a colon (:). For an example that demonstrates both of these features, see Functions with Multiple Return Values. 你可以用元组类型作为函数的返回值类型,这样函数就能返回包含多个值的单元组。你也可以给元组类型中的元素命名,用这些名字来指代单个元素的值。元素的名字由标识符和紧跟着的冒号(:)组成。关于这两种特性的具体用法,请看 ‘多个返回值的函数’。 - -Void is a typealias for the the empty tuple type, (). If there is only one element inside the parentheses, the type is simply the type of that element. For example, the type of (Int) is Int, not (Int). As a result, you can label a tuple element only when the tuple type has two or more elements. +Void是空元组类型的别名,表示为()。如果在括号里面只有一个元素,那么这个类型就是这个元素的类型。例如,(Int)的类型是Int,不是(Int)。因此,你可以认为仅当元组类型包含两个或者更多元素的时候才是元组元素。 -Void是空元组类型的别名,表示为()。如果在括号里面只有一个元素,那么这个类型就是元素的类型。例如,(Int)的类型是Int,不是(Int)。因此,你可以认为仅当元组类型包含两个或者更多元素的时候才是元组元素。 - - -> GRAMMAR OF A TUPLE TYPE -> > 元组类型的语法 -> -> tuple-type → (tuple-type-bodyopt) + > 元组类型 -> (元组类型体[可选]) -> tuple-type-body → tuple-type-element-list...opt > 元组类型体 -> 元组类型元素列表...[可选] -> tuple-type-element-list → tuple-type-element tuple-type-element,tuple-type-element-list > 元组类型元素列表 -> 元组类型元素|元组类型元素,元组类型元素列表 -> tuple-type-element → attributesoptinoutopttype inoutoptelement-nametype-annotation -> 元组类型元素 -> 属性[可选]inout[可选]类型|inout[可选]元素名称 类型注释 +> 元组类型元素 -> 属性[可选]inout[可选]类型|inout[可选]元素名称 类型注解 -> element-name → identifier > 元素名称 -> 标识符 - -## Function Type + ## 函数类型 -A function type represents the type of a function, method, or closure and consists of a parameter and return type separated by an arrow (->): 函数类型表示一个函数,方法或者闭包的类型,它由参数和返回类型组成,中间通过箭头(->)分隔: - - parameter type -> return type - -Because the parameter type and the return type can be a tuple type, function types support functions and methods that take multiple paramaters and return multiple values. - + 由于参数类型和返回类型都可以为元组类型,所以函数类型支持含有多个参数和多个返回值的函数和方法。 -You can apply the auto_closure attribute to a function type that has a parameter type of () and that returns the type of an expression (see Type Attributes). An autoclosure function captures an implicit closure over the specified expression, instead of the expression itself. The following example uses the auto_closure attribute in defining a very simple assert function: - - -你可以把自动闭包(auto_closure)的属性归为有一个参数类型为(),返回值为表达的函数类型(请看 ‘类型属性’)。一个自动闭包函数捕获的是指定表达式上的隐式闭包而不是表达式本身。下面的例子用auto_closure属性来定义一个简单的assert函数: - - func simpleAssert(condition: @auto_closure () -> Bool, message: String){ - if !condition(){ - println(message) - } +你可以把自动闭包(auto_closure)的属性归为有一个参数类型为(),返回值为表达式类型(请看 ‘类型属性’)。一个自动闭包函数捕获的是指定表达式上的隐式闭包而不是表达式本身。下面的例子用auto_closure属性来定义一个简单的assert函数: + + func simpleAssert(condition: @auto_closure () -> Bool, message: String){ + if !condition(){ + println(message) } - let testNumber = 5 - simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.") - // prints "testNumber isn't an even number." - + } + let testNumber = 5 + simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.") + // prints "testNumber isn't an even number." + -A function type can have a variadic parameter as the last parameter in its parameter type. Syntactically, a variadic parameter consists of a base type name followed immediately by three dots (...), as in Int.... A variadic parameter is treated as an array that contains elements of the base type name. For instance, the variadic parameter Int... is treated as Int[]. For an example that uses a variadic parameter, see Variadic Parameters. 一个函数类型在参数类型中可以让一个可变参数作为其最后一个参数。从语法上来说,可变参数可以由一个基础类型名称和紧跟着的三个点(...)组成,例如Int...。可变参数被认为是一个包含基础类型名称的数组。例如,可变参数Int... 被认为是Int[]。使用可变参数的例子,请参考 ‘可变参数’。 -To specify an in-out parameter, prefix the parameter type with the inout keyword. You can’t mark a variadic parameter or a return type with the inout keyword. In-out parameters are discussed in In-Out Parameters. 指定一个in-out参数,需要给参数类型加上inout的前缀。可变参数和返回类型不能使用inout标记。in-out参数在’In-Out参数‘中有讨论。 -The type of a curried function is equivalent to a nested function type. For example, the type of the curried function addTwoNumbers()() below is Int -> Int -> Int: 柯里化函数(curried function)类型相当于嵌套函数类型。例如,下面的柯里化函数addTwoNumbers()()的类型是Int -> Int -> Int: + func addTwoNumbers(a: Int)(b: Int) -> Int{ + return a + b + } - func addTwoNumbers(a: Int)(b: Int) -> Int{ - return a + b - } - - addTwoNumbers(4)(5) // returns 9 - - -The function types of a curried function are grouped from right to left. For instance, the function type Int -> Int -> Int is understood as Int -> (Int -> Int)—that is, a function that takes an Int and returns another function that takes and return an Int. For example, you can rewrite the curried function addTwoNumbers()() as the following nested function: + addTwoNumbers(4)(5) // returns 9 -柯里化函数的函数类型从右到左形成一组。例如,函数类型Int -> Int -> Int被理解为Int -> (Int -> Int) -- 指函数传入一个Int,然后返回另外一个输入输出都是Int的函数。例如,你可以把柯里化函数addTwoNumbers()()写成如下的嵌套函数形式: - func addTwoNumbers(a: Int) -> (Int -> Int){ - func addTheSecondNumber(b: Int) -> Int{ - return a + b - } - return addTheSecondNumber +柯里化函数的函数类型从右到左形成一组。例如,函数类型Int -> Int -> Int被理解为Int -> (Int -> Int) -- 指函数传入一个Int,然后返回另外一个输入输出都是Int的函数。例如,你可以把柯里化函数addTwoNumbers()()写成如下的嵌套函数形式: + + func addTwoNumbers(a: Int) -> (Int -> Int){ + func addTheSecondNumber(b: Int) -> Int{ + return a + b } - - addTwoNumbers(4)(5) // Returns 9 - + return addTheSecondNumber + } -> GRAMMAR OF A FUNCTION TYPE + addTwoNumbers(4)(5) // Returns 9 -> 函数类型的语法 -> function-type → type->type +> 函数类型的语法 > 函数类型 → 类型 -> 类型 - - -## Array Type + + ## 数组类型 -The Swift language uses square brackets ([]) immediately after the name of a type as syntactic sugar for the named type Array, which is defined in the Swift standard library. In other words, the following two declarations are equivalent: -在swift中类型紧跟着[]作为标准库定义的命名类型Array的简写。换句话说,下面两个声明是相等的: +在swift中类型紧跟着可括号[]作为标准库定义的命名类型Array的简写。换句话说,下面两个声明是相等的: let someArray: String[] = ["Alex", "Brian", "Dave"] let someArray: Array = ["Alex", "Brian", "Dave"] -In both cases, the constant someArray is declared as an array of strings. The elements of an array can be accessed using square brackets as well: someArray[0] refers to the element at index 0, "Alex". 在这两种情况下,常量someArray被定义为字符串数组。数组元素也可以用中括号访问:someArray[0] 指向index为0的元素,即‘Alex’。 -As the above example also shows, you can use square brackets to create an array using an array literal. Empty array literals are written using an empty pair of square brackets and can be used to create an empty array of a specified type. - -如上所示,你可以用数组自变量和[]创建一个数组。空数组自变量用[]表示,也可以创建特定类型的空数组。 +如上所示,你可以用数组自变量字面量?和[]创建一个数组。空数组自变量用[]表示,也可以创建特定类型的空数组。 var emptyArray: Double[] = [] - -You can create multidimensional arrays by chaining multiple sets of square brackets to the name of the base type of the elements. For example, you can create a three-dimensional array of integers using three sets of square brackets: -你可以用多组中括号相连来创建多维数组。例如,你可以用三组中括号来创建一个三维整数数组 +你可以用多组中括号相连来创建多维数组。例如,你可以用三组中括号来创建一个三维整数数组: var array3D: Int[][][] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] -When accessing the elements in a multidimensional array, the left-most subscript index refers to the element at that index in the outermost array. The next subscript index to the right refers to the element at that index in the array that’s nested one level in. And so on. This means that in the example above, array3D[0] refers to [[1, 2], [3, 4]], array3D[0][1] refers to [3, 4], and array3D[0][1][1] refers to the value 4. - -当访问多维数组里面的元素时,最左边的下标指向数组最外层对应位置的元素,接下来往右的下标指向第一层嵌套的数组相应位置的元素。依此类推。根据上面的定义,则array3D[0]指向[[1, 2], [3, 4]],array3D[0][1]指向[3, 4],array3D[0][1][1]的值是4。 - -For a detailed discussion of the Swift standard library Array type, see Arrays. -swift标准库中关于数组类型的详细讨论,请看“数组“ +当访问多维数组里面的元素时,最左边的下标指向数组最外层对应位置的元素,接下来往右的下标指向第一层嵌套的数组相应位置的元素。依此类推。根据上面的定义,则array3D[0]指向[[1, 2], [3, 4]],array3D[0][1]指向[3, 4],array3D[0][1][1]的值是4。 -> GRAMMAR OF AN ARRAY TYPE +想要更多了解swift标准库中关于数组类型的详细讨论,请看“数组“ > 数组类型的语法 +> 数组类型 → 类型[] 数组类型[] -> array-type → type[] array-type[] -> 数组类型 → 类型[] 数组类型[] - - -## Optional Type ## 可选类型 -The Swift language defines the postfix ? as syntactic sugar for the named type Optional, which is defined in the Swift standard library. In other words, the following two declarations are equivalent: -在swift中定义后缀?是标准库定义的命名类型Optional的简写。换句话说,以下两种声明是相等的: - +Swfit语言定义后缀?作为命名类型Optional的简写,换句话说,以下两种声明是相等的: var optionalInteger: Int? var optionalInteger: Optional - -In both cases, the variable optionalInteger is declared to have the type of an optional integer. Note that no whitespace may appear between the type and the ?. - 在这两种情况下,变量optionalInteger都是可选整数类型。注意,在类型和?之间没有空格。 -The type Optional is an enumeration with two cases, None and Some(T), which are used to represent values that may or may not be present. Any type can be explicitly declared to be (or implicitly converted to) an optional type. When declaring an optional type, be sure to use parentheses to properly scope the ? operator. As an example, to declare an optional array of integers, write the type annotation as (Int[])?; writing Int[]? produces an error. -Optional 是一个含有两种情况的枚举,None和Some(T),用来表示可能有也可能没有值。任何类型都可以声明为(或者隐式转换)可选类型。当声明一个可选类型的时候,要确保用括号给?操作符提供确定的范围。例如,声明可选整数数组,应该写成(Int[])?;写成Int[]?会报错。 +Optional 是一个含有两种情况的枚举,None和Some(T),用来表示可能有或可能没有值。任何类型都可以明确声明为(或者隐式转换)可选类型。当声明一个可选类型的时候,要确保用括号给?操作符一个合适的范围。例如,声明可选整数数组,应该写成(Int[])?;写成Int[]?会报错。 -If you don’t provide an initial value when you declare an optional variable or property, its value automatically defaults to nil. 当你声明一个可选变量或者可选属性的时候没有提供初始值,它的值会默认为nil。 -Optionals conform to the LogicValue protocol and therefore may occur in a Boolean context. In that context, if an instance of an optional type T? contains any value of type T (that is, it’s value is Optional.Some(T)), the optional type evaluates to true. Otherwise, it evaluates to false. -可选遵照LogicValue协议,因此可以出现在布尔环境中。在这种情况下,可选类型T?包含类型为T的任何值(也就是说它的值是Optional.Some(T)),这个可选类型等于true,反之为false。 +可选项遵照LogicValue协议,因此可以出现在布尔环境中。在这种情况下,如果可选类型T?包含类型为T的任何值(也就是说它的值是Optional.Some(T)),这个可选类型等于true,反之为false。 -If an instance of an optional type contains a value, you can access that value using the postfix operator !, as shown below: -如果可选类型包含一个值,你可以用后缀!访问,如下所示: +如果一个可选类型的实例包含一个值,你可以用后缀操作符!来访问这个值,如下所示: optionalInteger = 42 optionalInteger! // 42 -Using the ! operator to unwrap an optional that has a value of nil results in a runtime error. +使用操作符!去获取值为nil的可选变量会有运行时错误。 -用操作符!去获取值为nil的可选变量会有运行错误。 - - -You can also use optional chaining and optional binding to conditionally perform an operation on an optional expression. If the value is nil, no operation is performed and therefore no runtime error is produced. 你可以用可选链接和可选绑定选择性执行可选表达式上的操作。如果值为nil,任何操作都不会执行,也不会有运行报错。 -For more information and to see examples that show how to use optional types, see Optionals. - - 更过关于可选类型的信息和例子,请看“可选“。 -> GRAMMAR OF AN OPTIONAL TYPE > 可选类型语法 - -> optional-type → type? + > 可选类型 → 类型 ? -## Implicitly Unwrapped Optional Type ## 隐式解析可选类型 -The Swift language defines the postfix ! as syntactic sugar for the named type ImplicitlyUnwrappedOptional, which is defined in the Swift standard library. In other words, the following two declarations are equivalent: - - -在swift中定义后缀!为标准库定义的名类型ImplicitlyUnwrappedOptional的简写。换句话说,以下两种声明是相等的: +在swift中定义后缀!为标准库定义的名类型ImplicitlyUnwrappedOptional的简写。换句话说,以下两种声明是相等的: var implicitlyUnwrappedString: String! var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional -In both cases, the variable implicitlyUnwrappedString is declared to have the type of an implicitly unwrapped optional string. Note that no whitespace may appear between the type and the !. 在这两种情况下,变量implicitlyUnwrappedString被声明为隐式可选类型字符串。注意,在类型和!之间没有空格。 -You can use implicitly unwrapped optionals in all the same places in your code that you can use optionals. For instance, you can assign values of implicitly unwrapped optionals to variables, constants, and properties of optionals, and vice versa. 你代码中用到可选的地方都可以用隐式解析可选。例如,你可以设置隐式可选类型的值为变量、常量、可选属性,反之亦然。 -As with optionals, if you don’t provide an initial value when you declare an implicitly unwrapped optional variable or property, it’s value automatically defaults to nil. 有了可选,当你声明一个隐式解析可选变量或者属性的时候没有赋初始值,它的值默认为nil。 -Because the value of an implicitly unwrapped optional is automatically unwrapped when you use it, there’s no need to use the ! operator to unwrap it. That said, if you try to use an implicitly unwrapped optional that has a value of nil, you’ll get a runtime error. - -隐式解析可选的值会在使用的时候自动解析,所以不需要用!去解析它。也就是说,如果你用值为nil的隐式解析可选,那么会会导致运行错误。 +隐式解析可选的值会在使用的时候自动解析,所以不需要用!去解析它。也就是说,如果你用值为nil的隐式解析可选,那么将会导致运行错误。 -Use optional chaining to conditionally perform an operation on an implicitly unwrapped optional expression. If the value is nil, no operation is performed and therefore no runtime error is produced. 使用可选链能够选择性的执行隐式解析可选表达式上的操作。用可选链接在隐式解析可选的表达式上做一定的操作。如果值是nil,没有操作会被执行,也不会有运行错误。 -For more information about implicitly unwrapped optional types, see Implicitly Unwrapped Optionals. - 更多关于隐式解析可选类型,请看 “隐式解析可选”。 -> GRAMMAR OF AN IMPLICITLY UNWRAPPED OPTIONAL TYPE > 隐式解析可选类型语法 -> implicitly-unwrapped-optional-type → type! - > 隐式解析可选类型 -> 类型! - -## Protocol Composition Type ## 协议组合类型 -A protocol composition type describes a type that conforms to each protocol in a list of specified protocols. Protocol composition types may be used in type annotations and in generic parameters. - -协议组合类型是指符合指定协议列表里每个协议的类型。协议组合类型可以用在类型注释和泛型参数中。 - - -Protocol composition types have the following form: +协议组合类型是指符合指定协议列表里每个协议的类型。协议组合类型可以用在类型注解和泛型参数中。 协议组合类型的格式如下: protocol -A protocol composition type allows you to specify a value whose type conforms to the requirements of multiple protocols without having to explicitly define a new, named protocol that inherits from each protocol you want the type to conform to. For example, specifying a protocol composition type protocol is effectively the same as defining a new protocol ProtocolD that inherits from ProtocolA, ProtocolB, and ProtocolC, but without having to introduce a new name. - -一个协议组合类型的类型符合多个协议的要求,不需定义新的命名协议,它继承了从每个协议符合的类型。例如,指定一个协议组合类型protocol相当于定义一个新的协议ProtocolD,它继承了ProtocolA, ProtocolB和 ProtocolC,但是没有引入一个新的名字。 - -Each item in a protocol composition list must be either the name of protocol or a type alias of a protocol composition type. If the list is empty, it specifies the empty protocol composition type, which every type conforms to. +一个协议组合类型的类型符合多个协议的要求,不需定义新的命名协议,它继承了从每个协议符合的类型。例如,指定一个协议组合类型protocol相当于定义一个新的协议ProtocolD,它继承了ProtocolA, ProtocolB和 ProtocolC,但是没有引入一个新的名字。 协议组合列表中的每一项必须是协议名或者是协议组合类型的别名。如果列表是空的,它会指定一个空的协议组合类型,任何类型都可以匹配。 -> GRAMMAR OF A PROTOCOL COMPOSITION TYPE -> > 协议组合类型语法 -> protocol-composition-type → protocol -> > 协议组合类型 -> 协议<协议标示符列表[可选]> -> protocol-identifier-list → protocol-identifier | protocol-identifier,protocol-identifier-list - > 协议标示符列表 -> 协议标示符 | 协议标示符,协议标示符列表 -> -> protocol-identifier → type-identifier > 协议标示符 -> 类型标示符 -## Metatype Type ## 元类型 -A metatype type refers to the type of any type, including class types, structure types, enumeration types, and protocol types. 元类型是指所有类型的类型,包括类、结构、枚举、协议。 -The metatype of a class, structure, or enumeration type is the name of that type followed by .Type. The metatype of a protocol type—not the concrete type that conforms to the protocol at runtime—is the name of that protocol followed by .Protocol. For example, the metatype of the class type SomeClass is SomeClass.Type and the metatype of the protocol SomeProtocol is SomeProtocol.Protocol. - 类、结构、枚举的元类型是相应的类型名称后面跟着的名字.Type。协议类型的元类型 -- 不是具体的类型,而是根据协议运行时来适配 -- 是该协议后面跟着的名字.Protocol。例如,类SomeClass的元类型是SomeClass.Type,协议SomeProtocol的元类型是SomeProtocol.Protocol。 -You can use the postfix self expression to access a type as a value. For example, SomeClass.self returns SomeClass itself, not an instance of SomeClass. And SomeProtocol.self returns SomeProtocol itself, not an instance of a type that conforms to SomeProtocol at runtime. You can use a dynamicType expression with an instance of a type to access that instance’s runtime type as a value, as the following example shows: - 你可以用后缀self的方式获取类型。例如,SomeClass.self返回 SomeClass本身,不是SomeClass的实例。SomeProtocol.self返回SomeProtocol本身, 不是运行时SomeProtocol的实例。你可以用dynamicType表达式类获取实例运行时的类型,如下面的例子所示: @@ -432,104 +284,54 @@ You can use the postfix self expression to access a type as a value. For example let someInstance: SomeBaseClass = SomeSubClass() // someInstance is of type SomeBaseClass at compile time, but // someInstance is of type SomeSubClass at runtime - + someInstance.dynamicType.printClassName() - + // prints "SomeSubClass" - -> GRAMMAR OF A METATYPE TYPE > 元类型语法 -> metatype-type → type.Type | type.Protocol - > 元类型 → 类型.Type | 类型.Protocol -> -## Type Inheritance Clause + + ## 类型继承子句 -A type inheritance clause is used to specify which class a named type inherits from and which protocols a named type conforms to. A type inheritance clause begins with a colon (:), followed by a comma-separated list of type identifiers. 类型继承子句被用来指定一个命名类型继承哪个类,适配哪些协议。类型继承子句以冒号(:)开始,紧跟着以逗号分割的类型标示符列表。 -Class types may inherit from a single superclass and conform to any number of protocols. When defining a class, the name of the superclass must appear first in the list of type identifiers, followed by any number of protocols the class must conform to. If the class does not inherit from another class, the list may begin with a protocol instead. For an extended discussion and several examples of class inheritance, see Inheritance. - 类类型可能继承单个超类,适配多个协议。当定义一个类的时候,超类的名称必须出现在类型标示符列表首位,接着是类必须适配的一些协议。如果类不继承其他类,那么列表就是以协议开头。类机继承的扩展讨论和例子,请看 “继承”。 -Other named types may only inherit from or conform to a list of protocols. Protocol types may inherit from any number of other protocols. When a protocol type inherits from other protocols, the set of requirements from those other protocols are aggregated together, and any type that inherits from the current protocol must conform to all of those requirements. - 其他命名协议可能仅继承或适配一个协议列表。协议类型可能继承多个其它协议。当一个协议类型继承其它协议的时候,其它协议的条件会被集合在一起,任何继承当前协议的类型必须适配所有的这些条件。 -A type inheritance clause in an enumeration definition may be either a list of protocols, or in the case of an enumeration that assigns raw values to its cases, a single, named type that specifies the type of those raw values. For an example of an enumeration definition that uses a type inheritance clause to specify the type of its raw values, see Raw Values. - 在枚举类型里面定义的类型继承子句可以是一个协议列表,或者指定原始值的枚举实例,或一个单独的指定原始值类型的命名型类型。在枚举定义中用类型继承子句来指定原始值类型的例子,请看 “原始类型”。 -> GRAMMAR OF A TYPE INHERITANCE CLAUSE > 类型继承子句语法 - -> type-inheritance-clause → :type-inheritance-list -> + > 类型继承子句 → : 类型继承列表 -> -> type-inheritance-list → type-identifier | type-identifier,type-inheritance-list > 类型继承列表 → 类型标示符 | 类型表示符,类型继承列表 -## Type Inference -## 类型推断 - -Swift uses type inference extensively, allowing you to omit the type or part of the type of many variables and expressions in your code. For example, instead of writing var x: Int = 0, you can omit the type completely and simply write var x = 0—the compiler correctly infers that x names a value of type Int. Similarly, you can omit part of a type when the full type can be inferred from context. For instance, if you write let dict: Dictionary = ["A": 1], the compiler infers that dict has the type Dictionary. +## 类型推断 -swift广泛使用类型推断,允许你在代码里忽略很多变量和表达式的类型或者部分类型。例如,var x: Int = 0可以完全忽略类型,简写成 var x = 0 -- 编译器能够正确的推测出x的类型名称是Int。同样,当完整的类型能够通过上下文推断出来的时候,你可以忽略部分类型。例如, -dict: Dictionary = ["A": 1],编译器推断出dict的类型是Dictionary。 -In both of the examples above, the type information is passed up from the leaves of the expression tree to its root. That is, the type of x in var x: Int = 0 is inferred by first checking the type of 0 and then passing this type information up to the root (the variable x). +swift广泛使用类型推断,它允许你在代码里忽略很多变量和表达式的类型或者部分类型。例如,var x: Int = 0可以完全忽略类型,简写成 var x = 0 -- 编译器能够正确的推测出x的类型名称是Int。同样,当完整的类型能够通过上下文推断出来的时候,你可以忽略部分类型。例如, dict: Dictionary = ["A": 1],编译器推断出dict的类型是Dictionary。 在上面的两个例子中,类型信息从表达树的叶子传向根。也就是说,x在var x: Int = 0的类型通过首先判断0的类型,然后再传递类型信息到根(即变量x)。 -In Swift, type information can also flow in the opposite direction—from the root down to the leaves. In the following example, for instance, the explicit type annotation (: Float) on the constant eFloat causes the numeric literal 2.71828 to have type Float instead of type Double. - -在swift里面,类型推断可以反方向推断 -- 从根传递到叶子。下面这个例子就是这种情况,常量eFloat显示类型注释(:Float)导致数字2.71828的类型是Float而不是Double。 +在swift里面,类型推断可以反方向推断 -- 从根传递到叶子。下面这个例子就是这种情况,常量eFloat显示类型注解(:Float)导致数字2.71828的类型是Float而不是Double。 let e = 2.71828 // The type of e is inferred to be Double. let eFloat: Float = 2.71828 // The type of eFloat is Float. - - -Type inference in Swift operates at the level of a single expression or statement. This means that all of the information needed to infer an omitted type or part of a type in an expression must be accessible from type-checking the expression or one of its subexpressions. - + swift中的类型推断在单个表达式或者语句上操作。这意味着推测忽略类型或者部分类型信息必须从表达式或者其子表达式类型检测中获取。 - - - - - - - - - - - - - - - - - - - - - - - - From a1b61456c8fcd54e78468872fb64e0a7b7cd0551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Fri, 4 Jul 2014 13:05:29 +0800 Subject: [PATCH 242/261] modify lexical structure --- src/chapter3/02_Lexical_Structure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chapter3/02_Lexical_Structure.md b/src/chapter3/02_Lexical_Structure.md index 9f53437..dea3c6f 100644 --- a/src/chapter3/02_Lexical_Structure.md +++ b/src/chapter3/02_Lexical_Structure.md @@ -24,7 +24,7 @@ Swift的词法结构描述了如何在该语言中用字符序列构建合法标 > 标识符 → 标识符头 标识符字符 [可选] -> 标识符 → ` 标识符头 标识符字符 [可选] ` +> 标识符 → \` 标识符头 标识符字符 [可选] \` > 标识符 → 隐式参数名 From b205d59ed64bad516d3468c0b3071ede9e68262f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Fri, 4 Jul 2014 13:16:03 +0800 Subject: [PATCH 243/261] modify types --- src/chapter3/03_Types.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/chapter3/03_Types.md b/src/chapter3/03_Types.md index 87295de..8f18f50 100644 --- a/src/chapter3/03_Types.md +++ b/src/chapter3/03_Types.md @@ -1,9 +1,9 @@ # 类型 在swift里,有两种类型:命名类型和复合类型。命名类型是指在定义的时候能够给一个指定名字的类型。命名类型包含类、结构、枚举和协议。例如,一个用户自定义的名为MyClass的类的实例,其类型就是MyClass。除了用户定义的命名类型,swift标准库还定义了很多常用命名类型,如一些数组,字典,可选值。 -一些被其它语言视为是最基础或最原始的数据类型,例如数字、字符、字符串,实际上都是命名类型,swift标准库使用结构去定义和实现他们。由于他们是命名类型的,你可以用扩展声明来扩展他们的功能,来满足你的程序需求,具体请参考‘扩展和扩展声明’。 +一些被其它语言视为是最基础或最原始的数据类型,例如数字、字符、字符串,实际上都是命名类型,swift标准库使用结构去定义和实现他们。由于他们是命名类型的,你可以用扩展声明来扩展他们的功能,来满足你的程序需求,具体请参考 “扩展和扩展声明“。 -复合类型是一个没有名字的类型,由swift内部自己定义。swift有两种复合类型:函数类型和元组类型。一个复合数据类型可以包含命名类型和其他复合类型。例如,一个元组类型(Int, (Int, Int))包含两个元素:第一个是命名类型Int,第二个是另外一个复合类型(Int, Int)。 +复合类型是一个没有名字的类型,由swift内部自己定义。swift有两种复合类型:函数类型和元组类型。一个复合数据类型可以包含命名类型和其他复合类型。例如,一个元组类型(Int, (Int, Int))包含两个元素:第一个的命名类型是Int,第二个是其他复合类型(Int, Int)。 本章讨论swift语言本身定义的类型,并描述在swift中类型推断的方式。 @@ -34,10 +34,10 @@ ## 类型标识符 -类型标识符是指一个命名类型或者说命名类型/复合类型的别名。 +类型标识符是指一个命名类型或者命名类型/复合类型的别名。 -大多数情况下,类型标识符直接指向和标示符命名相同的命名类型。例如,类型标识符Int指向命名类型Int,类型标识符Dictionary指向命名类型Dictionary。 +大多数情况下,类型标识符直接指向和标示符命名相同的命名类型。例如,类型标识符Int指向命名类型Int,类型标识符Dictionary指向命名类型Dictionary。 命名标识符和类型标识符不同名有两种情况。第一种情况,命名标识符指向命名类型或者复合类型的别名。例如,在下面的例子中,类型标识符使用Point指向元组类型(Int, Int)。 @@ -62,9 +62,9 @@ 元组类型是指在括号中,用逗号分隔的零到多个类型的列表。 -你可以用元组类型作为函数的返回值类型,这样函数就能返回包含多个值的单元组。你也可以给元组类型中的元素命名,用这些名字来指代单个元素的值。元素的名字由标识符和紧跟着的冒号(:)组成。关于这两种特性的具体用法,请看 ‘多个返回值的函数’。 +你可以用元组类型作为函数的返回值类型,这样函数就能返回包含多个值的单元组。你也可以给元组类型中的元素命名,用这些名字来指代单个元素的值。元素的名字由标识符和紧跟着的冒号(:)组成。关于这两种特性的具体用法,请看 “多个返回值的函数“。 -Void是空元组类型的别名,表示为()。如果在括号里面只有一个元素,那么这个类型就是这个元素的类型。例如,(Int)的类型是Int,不是(Int)。因此,你可以认为仅当元组类型包含两个或者更多元素的时候才是元组元素。 +Void是空元组类型的别名,表示为()。如果在括号里面只有一个元素,那么这个类型就是这个元素的类型。例如,(Int)的类型是Int,不是(Int)。因此,你可以认为仅当元组类型包含两个或者更多元素的时候才是元组元素。 > 元组类型的语法 @@ -92,7 +92,7 @@ Void是空元组类型的别名,表示为()。如果在括号里面只有一 由于参数类型和返回类型都可以为元组类型,所以函数类型支持含有多个参数和多个返回值的函数和方法。 -你可以把自动闭包(auto_closure)的属性归为有一个参数类型为(),返回值为表达式类型(请看 ‘类型属性’)。一个自动闭包函数捕获的是指定表达式上的隐式闭包而不是表达式本身。下面的例子用auto_closure属性来定义一个简单的assert函数: +你可以把自动闭包(auto_closure)的属性归为有一个参数类型为(),返回值为表达式类型(请看 “类型属性“)的函数类型。一个自动闭包函数捕获的是指定表达式上的隐式闭包而不是表达式本身。下面的例子用auto_closure属性来定义一个简单的assert函数: func simpleAssert(condition: @auto_closure () -> Bool, message: String){ if !condition(){ @@ -105,7 +105,7 @@ Void是空元组类型的别名,表示为()。如果在括号里面只有一 -一个函数类型在参数类型中可以让一个可变参数作为其最后一个参数。从语法上来说,可变参数可以由一个基础类型名称和紧跟着的三个点(...)组成,例如Int...。可变参数被认为是一个包含基础类型名称的数组。例如,可变参数Int... 被认为是Int[]。使用可变参数的例子,请参考 ‘可变参数’。 +一个函数类型在参数类型中可以让一个可变参数作为其最后一个参数。从语法上来说,可变参数可以由一个基础类型名称和紧跟着的三个点(...)组成,例如Int...。可变参数被认为是一个包含基础类型名称的数组。例如,可变参数Int... 被认为是Int[]。使用可变参数的例子,请参考 “可变参数“。 指定一个in-out参数,需要给参数类型加上inout的前缀。可变参数和返回类型不能使用inout标记。in-out参数在’In-Out参数‘中有讨论。 @@ -161,7 +161,7 @@ Void是空元组类型的别名,表示为()。如果在括号里面只有一 当访问多维数组里面的元素时,最左边的下标指向数组最外层对应位置的元素,接下来往右的下标指向第一层嵌套的数组相应位置的元素。依此类推。根据上面的定义,则array3D[0]指向[[1, 2], [3, 4]],array3D[0][1]指向[3, 4],array3D[0][1][1]的值是4。 -想要更多了解swift标准库中关于数组类型的详细讨论,请看“数组“ +想要更多了解swift标准库中关于数组类型的详细讨论,请看 “数组“。 > 数组类型的语法 @@ -198,7 +198,7 @@ Optional 是一个含有两种情况的枚举,None和Some(T),用来表示可 你可以用可选链接和可选绑定选择性执行可选表达式上的操作。如果值为nil,任何操作都不会执行,也不会有运行报错。 -更过关于可选类型的信息和例子,请看“可选“。 +更过关于可选类型的信息和例子,请看 “可选“。 > 可选类型语法 @@ -246,7 +246,7 @@ Optional 是一个含有两种情况的枚举,None和Some(T),用来表示可 protocol -一个协议组合类型的类型符合多个协议的要求,不需定义新的命名协议,它继承了从每个协议符合的类型。例如,指定一个协议组合类型protocol相当于定义一个新的协议ProtocolD,它继承了ProtocolA, ProtocolB和 ProtocolC,但是没有引入一个新的名字。 +一个协议组合类型的类型符合多个协议的要求,不需定义新的命名协议,它继承了从每个协议符合的类型。例如,指定一个协议组合类型protocol相当于定义一个新的协议ProtocolD,它继承了ProtocolA,ProtocolB和 ProtocolC,但是没有引入一个新的名字。 协议组合列表中的每一项必须是协议名或者是协议组合类型的别名。如果列表是空的,它会指定一个空的协议组合类型,任何类型都可以匹配。 @@ -299,7 +299,7 @@ Optional 是一个含有两种情况的枚举,None和Some(T),用来表示可 ## 类型继承子句 -类型继承子句被用来指定一个命名类型继承哪个类,适配哪些协议。类型继承子句以冒号(:)开始,紧跟着以逗号分割的类型标示符列表。 +类型继承子句被用来指定一个命名类型继承哪个类,适配哪些协议。类型继承子句以冒号(:)开始,紧跟着以逗号分割的类型标示符列表。 类类型可能继承单个超类,适配多个协议。当定义一个类的时候,超类的名称必须出现在类型标示符列表首位,接着是类必须适配的一些协议。如果类不继承其他类,那么列表就是以协议开头。类机继承的扩展讨论和例子,请看 “继承”。 @@ -322,7 +322,7 @@ Optional 是一个含有两种情况的枚举,None和Some(T),用来表示可 ## 类型推断 -swift广泛使用类型推断,它允许你在代码里忽略很多变量和表达式的类型或者部分类型。例如,var x: Int = 0可以完全忽略类型,简写成 var x = 0 -- 编译器能够正确的推测出x的类型名称是Int。同样,当完整的类型能够通过上下文推断出来的时候,你可以忽略部分类型。例如, dict: Dictionary = ["A": 1],编译器推断出dict的类型是Dictionary。 +swift广泛使用类型推断,它允许你在代码里忽略很多变量和表达式的类型或者部分类型。例如,var x: Int = 0可以完全忽略类型,简写成 var x = 0 -- 编译器能够正确的推测出x的类型名称是Int。同样,当完整的类型能够通过上下文推断出来的时候,你可以忽略部分类型。例如, dict: Dictionary = ["A": 1],编译器推断出dict的类型是Dictionary。 在上面的两个例子中,类型信息从表达树的叶子传向根。也就是说,x在var x: Int = 0的类型通过首先判断0的类型,然后再传递类型信息到根(即变量x)。 From 8c7bf5fb19ab54b2305ddcefefe8b75994289e1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Fri, 4 Jul 2014 13:17:59 +0800 Subject: [PATCH 244/261] modify types --- src/chapter3/03_Types.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chapter3/03_Types.md b/src/chapter3/03_Types.md index 8f18f50..4581ed3 100644 --- a/src/chapter3/03_Types.md +++ b/src/chapter3/03_Types.md @@ -172,6 +172,7 @@ Void是空元组类型的别名,表示为()。如果在括号里面只有一 Swfit语言定义后缀?作为命名类型Optional的简写,换句话说,以下两种声明是相等的: + var optionalInteger: Int? var optionalInteger: Optional From 265492d5348b9198484aeb908f8e8f3fa3b43542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Fri, 4 Jul 2014 13:54:22 +0800 Subject: [PATCH 245/261] add expressions review --- src/chapter3/04_Expressions.md | 590 +++++++++------------------------ 1 file changed, 150 insertions(+), 440 deletions(-) diff --git a/src/chapter3/04_Expressions.md b/src/chapter3/04_Expressions.md index 67367ed..39f13d4 100644 --- a/src/chapter3/04_Expressions.md +++ b/src/chapter3/04_Expressions.md @@ -1,37 +1,20 @@ -# Expressions -# 表达式 -In Swift, there are four kinds of expressions: prefix expressions, binary expressions, primary expressions, and postfix expressions. Evaluating an expression returns a value, causes a side effect, or both. +# 表达式 在swift中有四种表达式:前缀表达式,二元表达式,主表达式和后缀表达式。对表达式求值可以得到一个返回值、或完成某些逻辑运算,或同时完成这两件事。 -Prefix and binary expressions let you apply operators to smaller expressions. Primary expressions are conceptually the simplest kind of expression, and they provide a way to access values. Postfix expressions, like prefix and binary expressions, let you build up more complex expressions using postfixes such as function calls and member access. Each kind of expression is described in detail in the sections below. +前缀和二元表达式可以让你在更短小的表达式中使用运算符。主表达式从概念上来看是最简单的表达式,并提供了一种求值的方式。后缀表达式,与前缀表达式和二元表达式相似,都可以让你建立更为复杂的表达方式,比如函数调用和成员访问。我们将在本节中详细解释每种表达式。 -前缀和二元表达式可以让我们在更短小的表达式中运算符。主表达式从概念上来看是最简单短小的表达式,同时又提供了一种求值的途径。后缀表达式,与前缀表达式和二元表达式相似,都可以让你建立更为复杂的表达方式,比如函数调用和成员访问。我们将在本节中详细解释每种表达式。 +> 表达式语法 -> GRAMMAR OF AN EXPRESSION +> 表达式 → 前置表达式 二元表达式列表 可选 -> expression → prefix-expressionbinary-expressionsopt +> 表达式列表 → 表达式 | 表达式 **,** 表达式列表 -> expression-list → expression expression,expression-list - -## Prefix Expressions ## 前缀表达式 -Prefix expressions combine an optional prefix operator with an expression. Prefix operators take one argument, the expression that follows them. - -前缀表达式由一个任意前缀运算符接表达式构成。前缀表达式只接受一个参数。 - -The Swift standard library provides the following prefix operators: - -* ++ Increment -* -- Decrement -* ! Logical NOT -* ~ Bitwise NOT -* \+ Unary plus -* \- Unary minus - +前缀表达式由一个任意前缀运算符和表达式构成。前缀表达式只接受一个参数。 Swift标准库提供了如下前缀运算符: @@ -43,60 +26,32 @@ Swift标准库提供了如下前缀运算符: * \- 一元负 -For information about the behavior of these operators, see Basic Operators and Advanced Operators. - -关于这些运算符的信息,请参见:“Basic Operators and Advanced Operators.”两节。 - - -In addition to the standard library operators listed above, you use & immediately before the name of a variable that’s being passed as an in-out argument to a function call expression. For more information and to see an example, see In-Out Parameters. +关于这些运算符的信息,请参见:“Basic Operators and Advanced Operators.”。 -作为对上述运算符的补充,你可以在作为某个函数参数的变量名前使用‘&’运算符。更多信息和实例,参见:In-Out Parameters一节。 - -> “GRAMMAR OF A PREFIX EXPRESSION +除了上面标准库的运算符列表,你可以在调用函数的参数变量名前使用‘&’。?? +除了上述标准库运算符外,你可以在作为某个函数参数的变量名前使用‘&’运算符。更多信息和例子,请见:In-Out Parameters。 > 前缀表达式语法 -> prefix-expression → prefix-operatoroptpostfix-expression +> 前置表达式 → 前置运算符 可选 后置表达式 -> prefix-expression → in-out-expression -‌ in-out-expression → &identifier +> 前置表达式 → 写入写出表达式 +> 写入写出表达式 → **&** 标识符 -## Binary Expressions ## 二元表达式 - -Binary expressions combine an infix binary operator with the expression that it takes as its left-hand and right-hand arguments. It has the following form: - -二元表达式由中缀二元运算符和“左边参数”与“右边参数”组成。形式如下: +二元表达式由‘左边表参数’+‘中缀二元操作符’+‘右边参数’组成。形式如下: left-hand argument operator right-hand argument - -The Swift standard library provides the following binary operators: - -Swift标准库提供了如下的二元运算符: - - -* Exponentiative (No associativity, precedence level 160) - * << Bitwise left shift - * \>> Bitwise right shift +Swift标准库提供了以下的二元运算符: * 指数(无结合性,优先级160) * << 按位左移 * \>> 按位右移 - - -* Multiplicative (Left associative, precedence level 150) - * Multiply - * / Divide - * % Remainder - * &* Multiply, ignoring overflow - * &/ Divide, ignoring overflow - * &% Remainder, ignoring overflow - * & Bitwise AND * 乘法(左结合,优先级150) * \* 乘 @@ -107,15 +62,6 @@ Swift标准库提供了如下的二元运算符: * &% 求余,ignoring overflow * & 按位与 - -* Additive (Left associative, precedence level 140) - * \+ Add - * \- Subtract - * &+ Add with overflow - * &- Subtract with overflow - * | Bitwise OR - * ^ Bitwise XOR - * 加法(左结合,优先级140) * \+ 加 * \- 减 @@ -123,33 +69,15 @@ Swift标准库提供了如下的二元运算符: * &- 减,with overflow * | 按位或 * ^ 按位异或 - -* Range (No associativity, precedence level 135) - * .. Half-closed range - * ... Closed range * 值域(无结合性,优先级135) * .. 半闭值域 * ... 闭值域 -* Cast (No associativity, precedence level 132) - * is Type check - * as Type cast * 类型转换(无结合性,优先级132) * is 类型检查 * as 类型转换 - -* Comparative (No associativity, precedence level 130) - * < Less than - * <= Less than or equal - * \> Greater than - * \>= Greater than or equal - * == Equal - * != Not equal - * === Identical - * !== Not identical - * ~= Pattern match * 比较(无结合性,优先级130) * < 小于 @@ -162,41 +90,15 @@ Swift标准库提供了如下的二元运算符: * !== 不恒等 * ~= 模式匹配 -* Conjunctive (Left associative, precedence level 120) - * && Logical AND - * 合取性(conjunctive)(左结合,优先级120) * && 逻辑与 -* Disjunctive (Left associative, precedence level 110) - * || Logical OR - * 析取性(disjunction)(左结合,优先级110) * || 逻辑或 - - -* Ternary Conditional (Right associative, precedence level 100) - * ?: Ternary conditional * 三元条件(右结合,优先级100) * ?: 三元条件 -* Assignment (Right associative, precedence level 90) - * = Assign - * *= Multiply and assign - * /= Divide and assign - * %= Remainder and assign - * += Add and assign - * -= Subtract and assign - * <<= Left bit shift and assign - * \>>= Right bit shift and assign - * &= Bitwise AND and assign - * ^= Bitwise XOR and assign - * |= Bitwise OR and assign - * &&= Logical AND and assign - * ||= Logical OR and assign - - * 赋值(右结合,优先级90) * = 赋值 * *= 乘等 @@ -212,98 +114,66 @@ Swift标准库提供了如下的二元运算符: * &&= 逻辑与等 * ||= 逻辑或等 -For information about the behavior of these operators, see Basic Operators and Advanced Operators. - - -关于这些运算符的信息,请参见:Basic Operators and Advanced Operators两节。 +关于这些运算符的使用信息,请参见:Basic Operators and Advanced Operators。 -> NOTE > 注解 -> At parse time, an expression made up of binary operators is represented as a flat list. This list is transformed into a tree by applying operator precedence For example, the expression 2 + 3 * 5 is initially understood as a flat list of five items, 2, +, `` 3``, *, and 5. This process transforms it into the tree (2 + (3 * 5)). - -> 在解析时,由二元操作符构成的表达式被表达为一个简单列表。这个列表按照运算符的优先级被转换成树(tree),比如“2 + 3 * 5”首先被认为是'2'、'+'、'3'、'+'、'5'这5个元素,随后被转换成树(2 + (3 * 5))。 +> 在解析时,由二元操作符构成的表达式被视为一个简单列表。这个列表按照运算符的优先级被转换成树(tree),比如“2 + 3 * 5”首先被理解为一个5个元素的列表:'2'、'+'、'3'、'+'、'5',随后被转换成树(2 + (3 * 5))。 > 二元表达式语法 -> GRAMMAR OF A BINARY EXPRESSION - -‌> binary-expression → binary-operatorprefix-expression +> 二元表达式 → 二元运算符 前置表达式 -‌> binary-expression → assignment-operatorprefix-expression +> 二元表达式 → 赋值运算符 前置表达式 -‌> binary-expression → conditional-operatorprefix-expression +> 二元表达式 → 条件运算符 前置表达式 -‌> binary-expression → type-casting-operator +> 二元表达式 → 类型转换运算符 -‌> binary-expressions → binary-expressionbinary-expressionsopt +> 二元表达式列表 → 二元表达式 二元表达式列表 可选 -## Assignment Operator ## 赋值运算符 -The assigment operator sets a new value for a given expression.It has the following form: - -赋值运算符会给某个给定的表达式赋值。如下面的例子: +赋值运算符会给某个给定的表达式赋值。形式如下: expression = value -The value of the expression is set to the value obtained by evaluating the value. If the expression is a tuple, the value must be a tuple with the same number of elements. (Nested tuples are allowed.) Assignment is performed from each part of the value to the corresponding part of the expression. For example: - - -上面语句的意思就是计算`value`的值并赋给`expression`。如果`expression`是个元组,那么`value`必须是含有同等数量元素的元祖。(嵌套元祖也是可以直接赋值滴。)元祖赋值会把`value`中相对应的部分分别赋给`expression`。例如: +表达式的意思就是计算`value`的值并赋给`expression`。如果`expression`是个元组,那么`value`必须是含有同等数量元素的元祖。(嵌套元祖亦可。)元祖赋值会把`value`中相对应的部分分别赋给`expression`。例如: > (a, _, (b, c)) = ("test", 9.45, (12, 3)) > // a is "test", b is 12, c is 3, and 9.45 is ignored -The assignment operator does not return any value. - 赋值运算符不返回任何值。 -> GRAMMAR OF AN ASSIGNMENT OPERATOR - > 赋值运算符的语法 -> assignment-operator → = +> 赋值运算符 → **=** -## Ternary Conditional Operator - ## 三元条件运算符 -The ternary conditional operator evaluates to one of two given values based on the value of a condition. It has the following form: - - 三元条件运算符是根据一个条件判断来求值。形式如下: condition ? expression used if true : expression used if false - -If the condition evaluates to true, the conditional operator evaluates the first expression and returns its value. Otherwise, it evaluates the second expression and returns its value. The unused expression is not evaluated. - -上面例子中,当condition的值为true时,那么将对第一个表达式求值并返回。否则将对第二个表达式求值并返回。期间没有用到的那个表达式将不会被调用。 - -For an example that uses the ternary conditional operator, see Ternary Conditional Operator. +如果condition的值为true时,那么就对第一个表达式求值并返回。否则就对第二个表达式求值并返回。没有用到的表达式将不会被调用。 更多三元条件运算符的例子,请参见Ternary Conditional Operator。 -> GRAMMAR OF A CONDITIONAL OPERATOR > 条件运算符语法: -> conditional-operator → ?expression: +> 三元条件运算符 → **?** 表达式 **:** -## Type-Casting Operators ## 类型转换运算符 -There are two type-casting operators, the as operator and the is operator. They have the following form: - -类型转换运算符有两种:as运算符合is运算符。形式如下: +类型转换运算符有两种:as运算符和is运算符。形式如下: expression as type @@ -313,21 +183,16 @@ There are two type-casting operators, the as operator and the is operator. They expression is type -The as operator performs a cast of the expression to the specified type. It behaves as follows: +as 运算符会把目标表达式`expression`转换成指定的类型`type`。方式如下: -上面例子中,as 运算符会把目标表达式`expression`转换成指定的类型`type`。过程如下: -* If conversion to the specified type is guaranteed to succeed, the value of the expression is returned as an instance of the specified type. An example is casting from a subclass to a superclass. +* 如果能够保证成功转换为指定类型,那么目标表达式`expression`就会返回指定类型的实例。典型的例子就是子类转换为超类。 -* 如果转换为`type`类型保证能够成功,那么目标表达式`expression`就会返回指定类型的实例。一个显而易见的例子就是子类类型转换成父类类型。 +* 如果转换到指定类型肯定失败,则抛出编译错误。 -* If conversion to the specified type is guaranteed to fail, a compile-time error is raised. -* 如果转换失败,则抛出编译错误。 - -* Otherwise, if it’s not known at compile time whether the conversion will succeed, the type of the cast expresion is an optional of the specified type. At runtime, if the cast succeeds, the value of expression is wrapped in an optional and returned; otherwise, the value returned is nil. An example is casting from a superclass to a subclass. - -* 如果不是以上两种情况,那么目标表达式`expression`就会被转换成指定类型的optional。在运行时,如果转换成功,那么`expression`会返回一个optional的包装类型;否则返回nil。举个例子: +如果在编译的时候不知道转换是否成功,那么转换表达式的类型是指定类型的可选类型。在运行时,如果转换成功,表达式会被包装成一个可选类型并返回。 +否则,返回nil。对应的例子就是子类转换为超类: > class SomeSuperType {} @@ -344,63 +209,49 @@ The as operator performs a cast of the expression to the specified type. It beha > let z = s as SomeChildType // might fail at runtime; type is SomeChildType? -Specifying a type with as provides the same information to the compiler as a type annotation, as shown in the following example: - -使用as指定类型与使用类型注释效果相同,看下面这个例子: +使用as指定类型与使用类型注释对编译器来说是一样的,看下面这个例子: > let y1 = x as SomeType // Type information from 'as' > let y2: SomeType = x // Type information from an annotation -The is operator checks at runtime to see whether the expression is of the specified type. If so, it returns true; otherwise, it returns false. +is运算符会在运行时检查`expression`是否指定了类型。如果是,则返回true, 否则 返回false。 - -is运算符会在运行时检查`expression`是否指定了类型。成功会返回true, 否则 false。上述检查在编译时不可用,下面例子就是无效的: + +在编译时编译器不检查它们是true还是false,下面例子是无效的: > "hello" is String > "hello" is Int -For more information about type casting and to see more examples that use the type-casting operators, see Type Casting. - -关于类型转换的更多内容和例子,请参见: Type Casting. - -> GRAMMAR OF A TYPE-CASTING OPERATOR +更多关于类型转换和使用类型转换操作符的例子,请参见: Type Casting. > 类型转换的语法 -> type-casting-operator → is­ type­| as­?(opt)­ type +> 类型转换运算符 → **is** 类型 | **as ?** 可选 类型 -## Primary Expressions ## 主表达式 -Primary expressions are the most basic kind of expression. They can be used as expressions on their own, and they can be combined with other tokens to make prefix expressions, binary expressions, and postfix expressions. - -主表达式是种最基本的表达式。它可以单独使用,也可以和其他表达式组合使用。 - -> GRAMMAR OF A PRIMARY EXPRESSION +主表达式是种最基础的表达式。它可以单独作为表达式使用,也可以和其他符号一起使用组合成前缀表达式、二元表达式和后缀表达式。 > 主表达式的语法 -> primary-expression → identifiergeneric-argument-clauseopt -> primary-expression → literal-expression -> primary-expression → self-expression -> primary-expression → superclass-expression -> primary-expression → closure-expression -> primary-expression → parenthesized-expression -> primary-expression → implicit-member-expression -> primary-expression → wildcard-expression +> 主表达式 → 标识符 泛型参数子句 可选 +> 主表达式 → 字面量表达式 +> 主表达式 → self表达式 +> 主表达式 → 超类表达式 +> 主表达式 → 闭包表达式 +> 主表达式 → 圆括号表达式 +> 主表达式 → 隐式成员表达式 +> 主表达式 → 通配符表达式 -## Literal Expression ## 字面量表达式 -A literal expression consists of either an ordinary literal (such as a string or a number), an array or dictionary literal, or one of the following special literals: - -一个字面量表达式可以由普通文本(比如一个字符串或者一个数字)、一个数组或字典字面量或以下指定的文本组成: +一个字面量表达式可以由普通文本(比如一个字符串或一个数字)、数组或字典字面量,或以下指定字面量组成: Literal | Type | Value @@ -418,63 +269,44 @@ Literal | Type | Value \__FUNCTION__| String | 当前声明的名字 -Inside a function, the value of __FUNCTION__ is the name of that function, inside a method it is the name of that method, inside a property getter or setter it is the name of that property, inside special members like init or subscript it is the name of that keyword, and at the top level of a file it is the name of the current module. +在函数中,__FUNCTION__的值是当前函数的名字。在方法中,它的值是当前方法的名字。在内部getter/setter属性中,它就是属性的名字。在init和subscript这样特殊成员中,它的值是关键字的名字。在文件顶层(at the top level of a file),它是前模块的名字。 -在函数中,__FUNCTION__的值为当前函数的名字。在方法中,它的值为当前方法的名字。在某个属性的getter/setter中为这个属性的名字。在像init和subscript这样的特殊成员中,它的值为那个关键字的名字。在文件顶层(at the top level of a file)则是当前模块的名字。 - - -An array literal is an ordered collection of values. It has the following form: - - -数组字面量是有序的值的集合。形式如下: +数组字面量是一个有序的值的集合。形式如下: [value 1, value 2, ...] -The last expression in the array can be followed by an optional comma. An empty array literal is written as an empty pair of brackets ([]). The value of an array literal has type T[], where T is the type of the expressions inside it. If there are expressions of multiple types, T is their closest common supertype. +数组中的、最后一个表达式后面可以后跟一个逗号。一个空数组可以写成[].。数组字面量的类型是T[],这个T就是数组中表达式的类型。如果数组含多个类型的表达式,T则是他们的最近公共超类型(closest common supertype)。 -数组中的最后一个表达式后面可以接一个逗号。一对空的中括号([])组成了一个空的数组字面量。数组字面量的类型是T[],这个T就是数组中表达式的类型。如果数组含多个类型的表达式,T则是他们的最近公共父类型(closest common supertype)。 - -A dictionary literal is an unordered collection of key-value pairs. It has the following form: 字典字面量是无序键值对的集合。形式如下: [key 1: value 1, key 2: value 2, ...] -The last expression in the dictionary can be followed by an optional comma. An empty dictionary literal is written as a colon inside a pair of brackets ([:]) to distinguish it from an empty array literal. The value of a dictionary literal has type Dictionary, where KeyType is the type of its key expressions and ValueType is the type of its value expressions. If there are expressions of multiple types, KeyType and ValueType are the closest common supertype for their respective values. - -字典中的最后一个表达式后面也可以接一个逗号。一对空的中括号包含一个冒号([:])组成了一个空的字典字面量。字典字面量的类型是Dictionary,这里KeyType、ValueType就是key和value的类型。如果包含多个类型,则分别取他们相应的最近的公共父类型(closest common supertype)。 - -> GRAMMAR OF A LITERAL EXPRESSION +字典中的最后一个表达式后面也可以跟一个逗号。 [:]组成了一个空的字典字面量。字典字面量的类型是Dictionary,这里KeyType、ValueType就是key和value的类型。如果包含多个类型的表达式,KeyType 和ValueType分别取他们相应的最近的公共超类型(closest common supertype)。 > 字面量表达式的语法 -> literal-expression → literal - -> literal-expression → array-literal | dictionary-literal +> 字面量表达式 → 字面量 -> literal-expression → __FILE__ | __LINE__ __COLUMN__ | __FUNCTION__ +> 字面量表达式 → 数组字面量 | 字典字面量 -> array-literal → [array-literal-itemsopt] +> 字面量表达式 → \_\_FILE\_\_ | \_\_LINE\_\_ | \_\_COLUMN\_\_ | \_\_FUNCTION\_\_ -> array-literal-items → array-literal-item,opt | array-literal-item,array-literal-items +> 数组字面量 → [ 数组字面量项列表 可选 ] -> array-literal-item → expression +> 数组字面量项列表 → 数组字面量项 , 可选 | 数组字面量项 , 数组字面量项列表 -> dictionary-literal → [dictionary-literal-items] | [:] | dictionary-literal-items → dictionary-literal-item,opt dictionary-literal-item,dictionary-literal-items - -> dictionary-literal-item → expression:expression - - -## Self Expression +> 数组字面量项 → 表达式 +> 字典字面量 → [ 字典字面量项列表 ] | [ : ] +> 字典字面量项列表 → 字典字面量项 , 可选 | 字典字面量项 , 字典字面量项列表 +> 字典字面量项 → 表达式 : 表达式 ## self表达式 -The self expression is an explicit reference to the current type or instance of the type in which it occurs. It has the following forms: - self表达式是对当前类型或当前实例的直接引用。形式如下: self @@ -488,15 +320,11 @@ self表达式是对当前类型或当前实例的直接引用。形式如下: self.init(initializer arguments) -In an initializer, subscript, or instance method, self refers to the current instance of the type in which it occurs. In a static or class method, self refers to the current type in which it occurs. +如果在初始设定式、子脚本、实例方法中,self指向当前类型实例的引用。在静态方法和类方法中,self指向前类型的引用。 -如果在初始设定式、子脚本、实例方法中,self为当前类型实例的引用。在静态方法和类方法中,self为当前类型的引用。 - -The self expression is used to specify scope when accessing members, providing disambiguation when there is another variable of the same name in scope, such as a function parameter. For example: - -self表达式被用于在访问成员变量时指定作用域,当作用域中有重名变量时,它还用来消除歧义(例如函数的参数)。例如: +self表达式用于在访问成员变量时指定作用域,消除作用域中有重名变量的冲突,例如函数的参数。例如: class SomeClass { var greeting: String @@ -506,8 +334,6 @@ self表达式被用于在访问成员变量时指定作用域,当作用域中 } -In a mutating method of value type, you can assign a new instance of that value type to self. For example: - 在派生方法中,你可以把一个那个类型的新实例赋值给self。例如: @@ -519,27 +345,21 @@ In a mutating method of value type, you can assign a new instance of that value } -> GRAMMAR OF A SELF EXPRESSION - > self表达式的语法 -> self-expression → self +> self表达式 → **self** -> self-expression → self.identifier +> self表达式 → **self** **.** 标识符 -> self-expression → self[expression] +> self表达式 → **self** [ 表达式 ] -> self-expression → self.init +> self表达式 → **self . init** -## Superclass Expression ## 超类表达式 -A superclass expression lets a class interact with its superclass. It has one of the following forms: - - -超类表达式可以让我们在某个class中访问它的超类,形式如下: +超类表达式可以让子类和超类相互访问,形式如下: super.`member name` @@ -548,65 +368,48 @@ A superclass expression lets a class interact with its superclass. It has one of super.init(`initializer arguments`) -The first form is used to access a member of the superclass. The second form is used to access the superclass’s subscript implementation. The third form is used to access an initializer of the superclass. 第一种形式用来访问超类的某个成员。第二种形式用来访问超类的子脚本实现(subscript implementation)。第三种用来访问该超类的初始设定式。 -Subclasses can use a superclass expression in their implementation of members, subscripting, and initializers to make use of the implementation in their superclass. - - -子类可以利用超类的实现,并通过使用超类表达式来实现它们的成员、子脚本和初始值。 - -> GRAMMAR OF A SUPERCLASS EXPRESSION +子类可以利用超类的实现,并通过使用超类表达式来实现它们的成员、下标和初始值。 > 超类表达式的语法 -> superclass-expression → superclass-method-expression | superclass-subscript-expression | superclass-initializer-expression - -> superclass-method-expression → super.identifier +> 超类表达式 → 超类方法表达式 | 超类下标表达式 | 超类构造器表达式 -> superclass-subscript-expression → super[expression] +> 超类方法表达式 → **super . **标识符 -> superclass-initializer-expression → super.init +> 超类下标表达式 → **super [** 表达式 **]** +> 超类构造器表达式 → **super . init** -## Closure Expression ## 闭包表达式 -A closure expression creates a closure, also known as a lambda or an anonymous function in other programming languages. Like function declarations, closures contain statements which they execute, and they capture values from their enclosing scope. It has the following form: -闭包表达式可以创建一个闭包,就好像其他语言中的lambda或者匿名函数。与函数声明相同,闭包包含了要执行的语句,接收作用域中的变量。形式如下: +闭包表达式可以创建一个闭包,就好像其他语言中的lambda或者匿名函数。跟函数声明一样,闭包包含了要执行的语句,接收作用域中的变量。形式如下: { (parameters) -> return type in statements } -The parameters have the same form as the parameters in a function declaration, as described in Function Declaration. -闭包的参数声明跟函数的参数一样,具体参见Function Declaration。 +闭包的参数声明跟函数的参数一样,具体请参见Function Declaration。 -There are several special forms that allow closures to be written more concisely: +有好几种特殊形式,让闭包写起来更加简洁: -为了写起来更加简洁,闭包还有几种特殊形式: -* A closure can omit the types of its parameters, its return type, or both. If you omit the parameter names and both types, omit the in keyword before the statements. If the omitted types can’t be inferred, a compile-time error is raised. +* 闭包可以省略参数和返回值的类型。如果省略了参数和参数类型,语句前的in也要省略。如果省略的类型不能被推断出来,那么就会抛出编译错误。 -* 闭包可以省略参数和返回值的类型。如果省略了参数和参数类型,语句前面的in也要省略。如果省略的类型不能被自动甄别,那么就会抛出编译错误。 +* 闭包可以省略参数名。如果省略参数名,它们会隐式地命名为:`$0`,`$1`,`$2`,以此类推。 -* A closure may omit names for its parameters. Its parameters are then implicitly named $ followed by their position: $0, $1, $2, and so on. -* 闭包可以省略参数名。如果省略了它们则会隐式地命名为“$+它们的顺序号”:`$0`,`$1`,`$2`等。 +如果闭包中只包含一个表达式,那么默认返回表达式的值。同时表达式的内容在进行类型推断的时候也会参考周围的表达式。 -* A closure that consists of only a single expression is understood to return the value of that expression. The contents of this expression is also considered when performing type inference on the surrounding expression. -* 如果闭包中只包含一个表达式,那么该表达式就会自动成为该闭包的返回值。同时表达式的内容在进行类型推断的时候也会参考周围的表达式。 - -The following closure expressions are equivalent: - -以下几个表达式是等价的: +以下几个闭包表达式是等价的: myFunction { (x: Int, y: Int) -> Int in @@ -622,15 +425,12 @@ The following closure expressions are equivalent: myFunction { $0 + $1 } -For information about passing a closure as an argument to a function, see Function Call Expression. 关于将闭包作为函数参数的更多内容,请参见:Function Call Expression。 -A closure expression can explicitly specify the values that it captures from the surrounding scope using a capture list. A capture list is written as a comma separated list surrounded by square brackets, before the list of parameters. If you use a capture list, you must also use the in keyword, even if you omit the parameter names, parameter types, and return type. -可以通过使用捕获列表从周围作用域中捕获值来显式指定给闭包表达式。捕获列表是以在参数列表前使用中括号加逗号分隔的形式组成的。一旦使用了参数列表,即使省略了参数名,参数类型和返回值类型,也要使用in关键字。 +闭包表达式可以明确指定从作用域中通过捕获列表来指定值。捕获列表是在参数列表前使用中括号加逗号分隔的形式组成的。一旦使用了捕获列表,即使省略了参数名,参数类型和返回值类型,也要使用in关键字。 -Each entry in the capture list can be marked as weak or unowned to capture a weak or unowned reference to the value. 捕获列表中的每一项都要标记为weak或unowned来捕获弱引用和无主引用。 @@ -641,174 +441,136 @@ Each entry in the capture list can be marked as weak or unowned to capture a wea myFunction { [unowned self] in print(self.title) } // unowned capture -在捕获列表中,你能绑定任意表达式给一个命名值。表达式在闭包形成时被根据指定强度计算并捕获。 + + +在捕获列表中,你能给命名值绑定任意表达式。在闭包执行的时候表达式被计算并捕获。例如: // Weak capture of "self.parent" as "parent" myFunction { [weak parent = self.parent] in print(parent!.title) } -For more information and examples of closure expressions, see Closure Expressions. -关于闭包表达式更多信息和例子,请参见 Closure Expressions。 - -> GRAMMAR OF A CLOSURE EXPRESSION +更多关于闭包表达式信息和例子,请参见 Closure Expressions。 > 闭包表达式的语法 -> closure-expression → {closure-signatureoptstatements} -> -> closure-signature → parameter-clausefunction-resultoptin -> -> closure-signature → identifier-listfunction-resultoptin +> 闭包表达式 → **{** 闭包签名 可选 多条语句 **}** +> 闭包签名 → 参数子句 函数结果 可选 **in** +> 闭包签名 → 标识符列表 函数结果 可选 **in** +> 闭包签名 → 捕获列表 参数子句 函数结果 可选 **in** > -> closure-signature → capture-listparameter-clausefunction-resultoptin -> -> closure-signature → capture-listidentifier-listfunction-resultoptin -> -> closure-signature → capture-listin -> -> capture-list → [capture-specifierexpression] -> -> capture-specifier → weak | unowned | unowned(safe)| unowned(unsafe) +> 闭包签名 → 捕获列表 标识符列表 函数结果 可选 **in** +> 闭包签名 → 捕获列表 **in** +> 捕获列表 → **[** 捕获说明符 表达式 **]** +> 捕获说明符 → **weak** |**unowned** | **unowned(safe)** | **unowned(unsafe)** -# Implicit Member Expression # 隐式成员表达式 -An implicit member expression is an abbreviated way to access a member of a type, such as an enumeration case or a class method, in a context where type inference can determine the implied type. It has the following form: - - -在可以判断隐藏类型的上下文中,隐式成员表达式是访问某个类型的成员的简便写法,例如在枚举或类方法中。形式如下: - +隐式成员表达式是一个访问类型成员变量的简写,例如枚举、类,通过上下文能够推断出隐式类型。形式如下: .member name -For example: 例子: var x = MyEnumeration.SomeValue x = .AnotherValue -> GRAMMAR OF A IMPLICIT MEMBER EXPRESSION > 隐式成员表达式的语法: -> implicit-member-expression → .identifier - - -## Parenthesized Expression +> 隐式成员表达式 → **.** 标识符 ## 圆括号表达式 -A parenthesized expression consists of a comma-separated list of expressions surrounded by parentheses. Each expression can have an optional identifier before it, separated by a colon (:). It has the following form: - -圆括号表达式由中括号包裹的一组逗号分隔的子表达式列表组成。每个子表达式前面可以有一个可选标识符,由`:`隔开。形式如下: +圆括号表达式由圆括号包裹、逗号分隔的子表达式列表组成。每个子表达式前面可以有一个可选标识符,由`:`分隔。形式如下: (identifier 1: expression 1, identifier 2: expression 2, ...) -Use parenthesized expressions to create tuples and to pass arguments to a function call. If there is only one value inside the parenthesized expression, the type of the parenthesized expression is the type of that value. For example, the type of the parenthesized expression (1) is Int, not (Int). - -圆括号表达式可以用来创建元祖或给函数传参。如果圆括号表达式中只有一个值,那么这个表达式的类型则与此值相同,例如表达式`(1)`的类型为`Int`而不是`(Int)`。 -> GRAMMAR OF A PARENTHESIZED EXPRESSION +圆括号表达式可以用来创建元祖,然后传递参数给函数。如果圆括号表达式中只有一个值,那么这个表达式的类型就是值的类型,例如表达式`(1)`的类型为`Int`不是`(Int)`。 > 圆括号表达式的语法 -> parenthesized-expression → (expression-element-listopt) +> 圆括号表达式 → **(**表达式元素列表 可选 **)** > -> expression-element-list → expression-element expression-element,expression-element-list +> 表达式元素列表 → 表达式元素 | 表达式元素 , 表达式元素列表 > -> expression-element → expression identifier:expression +> 表达式元素 → 表达式 | 标识符 **:** 表达式 - -## Wildcard Expression ## 通配符表达式 -A wildcard expression is used to explicitly ignore a value during an assignment. For example, in the following assignment 10 is assigned to x and 20 is ignored: -通配符表达式用来在赋值的时候显式地忽略某个值。比如下面的赋值语句中,`10`被传递给`x`,`20`则被忽略。 +通配符表达式用来在赋值的时候显式地忽略某个值。比如下面的赋值语句中,`10`传递给`x`,`20`则被忽略。 (x, _) = (10, 20) // x is 10, 20 is ignored -> GRAMMAR OF A WILDCARD EXPRESSIO > 通配符表达式的语法 -> wildcard-expression → _ +> 通配符表达式 → _ -## Postfix Expressions ## 后缀表达式 -Postfix expressions are formed by applying a postfix operator or other postfix syntax to an expression. Syntactically, every primary expression is also a postfix expression. 后缀表达式由一个表达式后面加上一个后缀操作符或其他后缀语法组成。单纯从语法上讲,每个主表达式也是一个后缀表达式。 -The Swift standard library provides the following postfix operators: * ++ Increment * -- Decrement -swift标准库提供了如下后缀操作符: +swift标准库提供了以下后缀操作符: * ++ 自增 * -- 自减 -For information about the behavior of these operators, see Basic Operators and Advanced Operators. -关于这些表达式行为的更多信息,请参见“Basic Operators and Advanced Operators.” +更多关于这些操作符的使用信息,请参见“Basic Operators and Advanced Operators.” -> GRAMMAR OF A POSTFIX EXPRESSION > 后缀表达式的语法 > -> postfix-expression → primary-expression +> 后置表达式 → 主表达式 > -> postfix-expression → postfix-expressionpostfix-operator +> 后置表达式 → 后置表达式 后置运算符 > -> postfix-expression → function-call-expression +> 后置表达式 → 函数调用表达式 > -> postfix-expression → initializer-expression +> 后置表达式 → 构造器表达式 > -> postfix-expression → explicit-member-expression +> 后置表达式 → 显示成员表达式 > -> postfix-expression → postfix-self-expression +> 后置表达式 → 后置self表达式 > -> postfix-expression → dynamic-type-expression +> 后置表达式 → 动态类型表达式 > -> postfix-expression → subscript-expression +> 后置表达式 → 下标表达式 > -> postfix-expression → forced-value-expression +> 后置表达式 → 强制取值表达式 > -> postfix-expression → optional-chaining-expression - +> 后置表达式 → 可选表达式 -## Function Call Expression ## 函数调用表达式 -A function call expression consists of a function name followed by a comma-separated list of the function’s arguments in parentheses. Function call expressions have the following form: - 函数调用表达式由函数名后加圆括号组成,圆括号里面为逗号分隔的函数参数列表。形式如下: function name(argument value 1, argument value 2) -The function name can be any expression whose value is of a function type. -上面的`function name`可以是任何返回值为函数类型的表达式。 +函数名称可以是任何返回值为函数类型的表达式。 -If the function definition includes names for its parameters, the function call must include names before its argument values separated by a colon (:). This kind of function call expression has the following form: -如果函数声明中包含了参数名,那么函数调用时必须在参数值前加上参数名,并用分号隔开。这种函数调用表达式形式如下: +如果函数声明中包含了参数名,那么函数调用时必须在参数值前加上参数名,并以分号分隔。这种函数调用表达式形式如下: function name(argument name 1: argument value 1, argument name 2: argument value 2) -A function call expression can include a trailing closure in the form of a closure expression immediately after the closing parenthesis. The trailing closure is understood as an argument to the function, added after the last parenthesized argument. The following function calls are equivalent: -函数调用表达式可以包含一个由紧跟在圆括号后面由一个闭包表达式组成的尾随闭包(`trailing closure`)。追加在圆括号后面的尾随闭包会被当做函数的参数。下面两种写法均可: +函数调用表达式在括号后面可以包含闭包表达式的后缀闭包。后缀闭包会被当做函数的最后一个参数。下面两种写法相同: // someFunction takes an integer and a closure as its arguments @@ -816,7 +578,6 @@ A function call expression can include a trailing closure in the form of a closu someFunction(x) {$0 == 13} -If the trailing closure is the function’s only argument, the parentheses can be omitted. 如果这个闭包是函数的唯一参数,那么圆括号可以省略。 @@ -826,39 +587,32 @@ If the trailing closure is the function’s only argument, the parentheses can b myData.someMethod {$0 == 13} -> GRAMMAR OF A FUNCTION CALL EXPRESSION > 函数调用表达式语法 -> function-call-expression → postfix-expressionparenthesized-expression +> 函数调用表达式 → 后置表达式 圆括号表达式 -> function-call-expression → postfix-expressionparenthesized-expressionopttrailing-closure +> 函数调用表达式 → 后置表达式 圆括号表达式 可选 后置闭包 > -> trailing-closure → closure-expression +> 后置闭包 → 闭包表达式 -## Initializer Expression +## 构造器表达式 -## 初始化函数表达式 - -An initializer expression provides access to a type’s initializer. It has the following form: - -初始化函数表达式用来给类型初始化。形式如下: +构造器表达式提供类型初始化。形式如下: expression.init(initializer arguments) -You use the initializer expression in a function call expression to initialize a new instance of a type. Unlike functions, an initializer can’t be used as a value. For example: -你可以在函数调用表达式中使用初始化函数表达式来初始化一个类型的实例。初始化函数不像函数,它不能有返回值,例如: +你可以在函数调用表达式中使用构造器表达式来初始化一个类型的实例。构造器函数不像函数,它不能有返回值,例如: var x = SomeClass.someClassFunction // ok var y = SomeClass.init // error -You also use an initializer expression to delegate to the initializer of a superclass. -初始化函数表达式还可以用来完成对父类初始化函数的代理。 +构造器表达式还可以用作对超类初始化函数的代理。 class SomeSubClass: SomeSuperClass { init() { @@ -867,25 +621,20 @@ You also use an initializer expression to delegate to the initializer of a super } } -> GRAMMAR OF AN INITIALIZER EXPRESSION -> 初始化函数表达式的语法 +> 构造器表达式的语法 -> initializer-expression → postfix-expression.init +> 构造器表达式 → 后置表达式 **. init** -## Explicit Member Expression ## 显式成员表达式 -A explicit member expression allows access to the members of a named type, a tuple, or a module. It consists of a period (.) between the item and the identifier of its member. -显示成员表达式允许我们访问已命名类型、元祖或模块的成员。它由元素和成员的标识符以及二者之间的点(`.`)组成。 +显示成员表达式允许我们访问命名类型、元祖或模块的成员。它由元素、点(`.`)、成员的标识符三者组成。 expression.member name -The members of a named type are named as part of the type’s declaration or extension. For example: - -对于已命名类型,成员是类型定义或扩展的一部分。例如: +对于命名类型可作为类型定义或扩展的一部分。例如: class SomeClass { var someProperty = 42 @@ -893,66 +642,51 @@ The members of a named type are named as part of the type’s declaration or ext let c = SomeClass() let y = c.someProperty // Member access -The members of a tuple are implicitly named using integers in the order they appear, starting from zero. For example: -对于元祖,成员通过从零开始的它们出现的顺序整数来访问。例如: +元祖成员通过从零开始的有序整数隐式命名。例如: var t = (10, 20, 30) t.0 = t.1 // Now t is (20, 20, 30) -The members of a module access the top-level declarations of that module. -对于模块,成员访问的是模块的顶级(top-level)声明。 +模块成员可以访问模块的顶级(top-level)声明。 -> GRAMMAR OF AN EXPLICIT MEMBER EXPRESSION > 显示成员表达式的语法 +> 显示成员表达式 → 后置表达式 . 十进制数字 +> 显示成员表达式 → 后置表达式 . 标识符 泛型参数子句 可选 -> explicit-member-expression → postfix-expression.decimal-digit -> -> explicit-member-expression → postfix-expression.identifiergeneric-argument-clauseopt - -## Postfix Self Expression ## 后缀self表达式 -A postfix self expression consists of an expression or the name of a type, immediately followed by .self. It has the following forms: -后缀self表达式由表达式或类名接一个`.self`组成。形式如下: +后缀self表达式由表达式或类型名,紧跟着`.self`组成。形式如下: expression.self type.self -The first form evaluates to the value of the expression. For example, x.self evaluates to x. 第一种形式计算出表达式(`expression`)的值。例如`x.self`就等于`x`。 -The second form evaluates to the value of the type. Use this form to access a type as a value. For example, because SomeClass.self evaluates to the SomeClass type itself, you can pass it to a function or method that accepts a type-level argument. -第二种形式计算出对应类型(`type`)的值。这种形式可以将某类型作为一个值来访问。例如,由于`SomeClass.self`等于`SomeClass`本身,所以你可以将其传给一个函数或方法。 +第二种形式计算出对应类型(`type`)的值。这种形式可以将某类型作为一个值来访问。例如,由于`SomeClass.self`等于`SomeClass`本身,所以你可以将其传给接受这种类型参数的函数或方法。 -> GRAMMAR OF A SELF EXPRESSION > 后缀self表达式的语法 -> postfix-self-expression → postfix-expression.self - - +> 后缀self表达式 → 后缀表达式 **. self** -## Dynamic Type Expression ## 动态类型表达式 -A dynamicType expression consists of an expression, immediately followed by .dynamicType. It has the following form: -动态类型(`dynamicType`)表达式由表达式接`.dynamicType`组成。形式如下: +动态类型(`dynamicType`)表达式由表达式和`.dynamicType`组成。形式如下: expression.dynamicType -The expression can’t be the name of a type. The entire dynamicType expression evaluates to the value of the runtime type of the expression, as the following example shows: -表达式不能是类型的名字。整个动态类型表达式计算出表达式运行时的值,参见下例: +表达式不能是类型的名字。整个动态类型表达式计算出表达式运行时的值,如下面的例子: class SomeBaseClass { class func printClassName() { @@ -970,82 +704,60 @@ The expression can’t be the name of a type. The entire dynamicType expression someInstance.dynamicType.printClassName() // prints "SomeSubClass -> GRAMMAR OF A DYNAMIC TYPE EXPRESSION > 动态类型表达式的语法 -> dynamic-type-expression → postfix-expression.dynamicType - - -## Subscript Expression +> 动态类型表达式 → 后置表达式 **. dynamicType** ## 下标表达式 -A subscript expression provides subscript access using the getter and setter of the corresponding subscript declaration. It has the following form: -下标表达式提供了通过响应的下标声明来访问getter/setter方法。形式如下: +下标表达式提供用getter/setter方法访问下标声明。形式如下: expression[index expressions] -To evaluate the value of a subscript expression, the subscript getter for the expression’s type is called with the index expressions passed as the subscript parameters. To set its value, the subscript setter is called in the same way. -下标表达式可以通过传递下标参数(`index expressions`)计算getter的值,setter亦同理。 +下标表达式可以通过传递下标参数(`index expressions`)计算getter的值,setter也可以通过同样的方式。 -For information about subscript declarations, see Protocol Subscript Declaration. 更多关于下标声明的信息,参见Protocol Subscript Declaration。 -> GRAMMAR OF A SUBSCRIPT EXPRESSION - > 下标表达式语法: > -> subscript-expression → postfix-expression[expression-list] - +> 下标表达式 → 后置表达式 **[** 表达式列表 **]** -## Forced-Value Expression -## 强取值表达式 +## 强制取值表达式 -A forced-value expression unwraps an optional value that you are certain is not nil. It has the following form: -强取值表达式用于对非空(not `nil`)的可选值进行拆包。形式如下: +强制取值表达式用于对非空(not `nil`)的可选值进行强行拆包装。形式如下: expression! -If the value of the expression is not nil, the optional value is unwrapped and returned with the corresponding nonoptional type. Otherwise, a runtime error is raised. -上式中,如果一个`expression`的值不是`nil`,那么该可选值会被拆包并返回响应的类型。否则抛出运行时错误。 +上式中,如果一个`expression`的值不是`nil`,那么该可选值会被拆包装并返回相应的类型。否则抛出运行时错误。 -> GRAMMAR OF A FORCED-VALUE EXPRESSION +> 强制取值表达式的语法: > -> 强取值表达式的语法: -> -> forced-value-expression → postfix-expression! - +> 强制取值表达式 → 后置表达式 **!** -## Optional-Chaining Expression ## 可选链式表达式 -An optional-chaining expression provides a simplified syntax for using optional values in postfix expressions. It has the following form: 可选链式表达式提供一种在后缀表达式中使用可选值的简化的语法。形式如下: expression? -On its own, the postfix ? operator simply returns the value of its argument as an optional. 后缀`?`表达式就是简单的将所传参数作为可选值返回。 -Postfix expressions that contain an optional-chaining expression are evaluated in a special way. If the optional-chaining expression is nil, all of the other operations in the postfix expression are ignored and the entire postfix expression evaluates to nil. If the optional-chaining expression is not nil, the value of the optional-chaining expression is unwrapped and used to evaluate the rest of the postfix expression. In either case, the value of the postfix expression is still of an optional type. -包含可选链式表达式的后缀表达式计算起来比较特殊。如果可选链式表达式为`nil`,所有在此后缀表达式中的操作符都将被忽略,然后整个后缀表达式返回`nil`。如果不为`nil`,则可选链式表达式被拆包然后应用于后续的计算。在这两种情况下,该后缀表达式仍然是一个可选值。 +包含可选链式表达式的后缀表达式通过特殊的方式计算。如果可选链式表达式为nil,所有在此后缀表达式中的操作符都将被忽略,整个后缀表达式返回nil。如果不为nil,则可选链式表达式被拆包装,然后用于其他的后最表达式的计算。在这两种情况下,该后缀表达式仍然是一个可选类型。 -If a postfix expression that contains an optional-chaining expression is nested inside other postfix expressions, only the outermost expression returns an optional type. In the example below, when c is not nil, its value is unwrapped and used to evaluate both .property and .performAction(), and the entire expression c?.property.performAction() has a value of an optional type. -如果一个包含可选链式表达式的后缀表达式嵌套在其他后缀表达式中,只有最外层的返回一个可选类型。下面例子中,当`c`不为`nil`,时,它将被拆包然后用于`.property`和`.performAction()`的计算,整个表达式`c?.property.performAction() `拥有一个可选类型的值。 +如果一个包含可选链式表达式的后缀表达式嵌套在其他后缀表达式中,只有最外层的返回一个可选类型。下面例子中,当c不为nil时,它将被拆包然后用于.property和.performAction()的计算,整个表达式`c?.property.performAction() `拥有一个可选类型的值。 var c: SomeClass? var result: Bool? = c?.property.performAction() -The following example shows the behavior of the example above without using optional chaining. 如果不使用可选链表达式,那么上面例子的代码等价于: @@ -1053,9 +765,7 @@ The following example shows the behavior of the example above without using opti result = unwrappedC.property.performAction() } -> GRAMMAR OF AN OPTIONAL-CHAINING EXPRESSION -> -> 可选链式表达式的语法 -> optional-chaining-expression → postfix-expression? +> 可选链表达式的语法 +> 可选链表达式 → 后置表达式 ? \ No newline at end of file From df62ee4fc6b9edfe71281b96ddfde97dffe74917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=B0=E6=A2=A6?= Date: Fri, 4 Jul 2014 13:57:22 +0800 Subject: [PATCH 246/261] modify expression --- src/chapter3/04_Expressions.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/chapter3/04_Expressions.md b/src/chapter3/04_Expressions.md index 39f13d4..6dc7fb3 100644 --- a/src/chapter3/04_Expressions.md +++ b/src/chapter3/04_Expressions.md @@ -479,6 +479,8 @@ self表达式用于在访问成员变量时指定作用域,消除作用域中 > 隐式成员表达式的语法: > 隐式成员表达式 → **.** 标识符 + + ## 圆括号表达式 @@ -708,6 +710,7 @@ swift标准库提供了以下后缀操作符: > 动态类型表达式的语法 > 动态类型表达式 → 后置表达式 **. dynamicType** + ## 下标表达式 From 45e146170092a415ce2d037b22494ffd86b4e286 Mon Sep 17 00:00:00 2001 From: Neekey Date: Sun, 6 Jul 2014 17:08:14 +0800 Subject: [PATCH 247/261] =?UTF-8?q?=E5=AE=8C=E6=88=90=20=E6=B3=9B=E5=9E=8B?= =?UTF-8?q?=E7=9A=84=E5=88=9D=E6=AD=A5review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/22_Generics.md | 266 +++++++++++++++++++----------------- 1 file changed, 141 insertions(+), 125 deletions(-) diff --git a/src/chapter2/22_Generics.md b/src/chapter2/22_Generics.md index ff00776..3dffdaf 100644 --- a/src/chapter2/22_Generics.md +++ b/src/chapter2/22_Generics.md @@ -318,115 +318,128 @@ You can define your own type constraints when creating custom generic types, and ##Type Constraint Syntax ##类型约束语法 - You write type constraints by placing a single class or protocol constraint after a type parameter’s name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types): + +You write type constraints by placing a single class or protocol constraint after a type parameter’s name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types): - 你可以通过在参数名称的后边以冒号分割,加上类型参数约束。基础的泛型函数的类型约束语法如下(同样的,泛型类型的语法相同) +你可以通过在类型参数名称的后边以冒号分割,加上类型参数约束。基础的泛型函数的类型约束语法如下(同样的,这个语法也适用于泛型类型) ``` func someFunction(someT: T, someU: U) { // function body goes here } - ``` +``` + The hypothetical function above has two type parameters. The first type parameter, T, has a type constraint that requires T to be a subclass of SomeClass. The second type parameter, U, has a type constraint that requires U to conform to the protocol SomeProtocol. 上边函数有两个参数。参数一类型参数为T,需要T必须是`SomeClass`子类;第二个参数类型为U,需要U必须遵循`SomeClass`协议。 ##Type Constraints in Action -##类型约束行为 +##类型约束实践 Here’s a non-generic function called findStringIndex, which is given a String value to find and an array of String values within which to find it. The findStringIndex function returns an optional Int value, which will be the index of the first matching string in the array if it is found, or nil if the string cannot be found: -这里有个名为findStringIndex的非泛型函数,该函数是去查找包含一指定String值的数组。若查找到匹配的字符串,findStringIndex函数返回该字符串在数组中的索引位置(Int),反之返回nil: - - func findStringIndex(array: String[], valueToFind: String) -> Int? { +现在有一个名为findStringIndex的非泛型函数,它接收一个字符串以及一个字符串数组作为参数,并从这个数组中对这个给定的字符串进行查找。若查找到匹配的字符串,findStringIndex函数返回该字符串在数组中的索引位置(Int),反之返回nil: +``` +func findStringIndex(array: String[], valueToFind: String) -> Int? { for (index, value) in enumerate(array) { - if value == valueToFind { - return index - } + if value == valueToFind { + return index + } } return nil - } +} +``` The findStringIndex function can be used to find a string value in an array of strings: -`findStringIndex`用于查找数组中的指定String值: +`findStringIndex`可以用于查找数组中指定的String值: +``` let strings = ["cat", "dog", "llama", "parakeet", "terrapin"] if let foundIndex = findStringIndex(strings, "llama") { println("The index of llama is \(foundIndex)") } // prints "The index of llama is 2" +``` The principle of finding the index of a value in an array isn’t useful only for strings, however. You can write the same functionality as a generic function called findIndex, by replacing any mention of strings with values of some type T instead. -如果只是查找数组中的指定字符串用处不大,但是你可以写出相同功能的泛型版本`findIndex`,用T代替字符串类型。 +如果只是查找数组中的指定字符串用处不大,但是你可以通过使用泛型类型T来代替上面的类型`String`,写出一个具有相同功能的泛型函数`findIndex`。 Here’s how you might expect a generic version of findStringIndex, called findIndex, to be written. Note that the return type of this function is still Int?, because the function returns an optional index number, not an optional value from the array. Be warned, though—this function does not compile, for reasons explained after the example: -下边是你理想中的`findStringIndex`的泛型版本`findIndex`。注意到函数的返回结果仍然是Int?,这是因为这个函数使用用于返回具体的索引值,而不是搜索值。需要提醒的是,这个函数不会编译,原因后边会说明: +下边就是`findStringIndex`的泛型版本`findIndex`。注意到函数的返回结果仍然是Int?,这是因为这个函数返回匹配到的数组索引值,而不是数组中的值。需要提醒的是,这个函数不会编译,原因后边会说明: - func findIndex(array: T[], valueToFind: T) -> Int? { +``` +func findIndex(array: T[], valueToFind: T) -> Int? { for (index, value) in enumerate(array) { - if value == valueToFind { - return index - } + if value == valueToFind { + return index + } } return nil - } +} +``` This function does not compile as written above. The problem lies with the equality check, “if value == valueToFind”. Not every type in Swift can be compared with the equal to operator (==). If you create your own class or structure to represent a complex data model, for example, then the meaning of “equal to” for that class or structure is not something that Swift can guess for you. Because of this, it is not possible to guarantee that this code will work for every possible type T, and an appropriate error is reported when you try to compile the code. -这个函数按照上边的写法不会编译。原因是因为比较这部分`“if value == valueToFind”. 不是所有的泛型类型都可以用比较操作`==`。如果你创建了自己的函数或者结构代表一个负责的数据模型,那么Swift语言没法猜出这个类或者结果等于的意思。正因为如此,不能保证这个代码可以作用于所有类型T,而且会编译出错。 +这个函数按照上边的写法不会编译。原因是等价检查部分“if value == valueToFind”. 不是所有的泛型类型都可以用`==`进行比较。如果你创建了自己的类或者结构代表一个复杂的数据模型,那么Swift语言没法猜测如何对这个类或者结构进行是否相等的比较。正因为如此,这个代码无法保证可以作用于所有可能的类型T,并且当你尝试编译这段代码时,编译器会给抛出错误指出这个问题。 All is not lost, however. The Swift standard library defines a protocol called Equatable, which requires any conforming type to implement the equal to operator (==) and the not equal to operator (!=) to compare any two values of that type. All of Swift’s standard types automatically support the Equatable protocol. -不过,有解决方法。Swift 标准库中定义了一个Equatable协议,该协议要求任何遵循的类型实现等式符(==)和不等符(!=)对任何两个该类型进行比较。所有的 Swift 标准类型自动支持Equatable协议。 +不过还是有解决方法。Swift 标准库中定义了一个Equatable协议,该协议要求任何遵循它的类型需要实现相等符(==)和不等符(!=)来对任何两个该类型的值进行比较。所有的 Swift 标准类型都自动支持Equatable协议。 Any type that is Equatable can be used safely with the findIndex function, because it is guaranteed to support the equal to operator. To express this fact, you write a type constraint of Equatable as part of the type parameter’s definition when you define the function: -任何Equatable类型都可以安全的使用在findIndex函数中,它保证可以支持等号操作。为了说明这个事实,你定义函数时,可以写一个Equatable类型约束作为类型参数定义的一部分: +任何Equatable类型都可以安全的使用在findIndex函数中,它保证可以支持相等操作。为了说明这个事实,在定义函数时,可以添加一个Equatable类型约束作为类型参数定义的一部分: - func findIndex(array: T[], valueToFind: T) -> Int? { +``` +func findIndex(array: T[], valueToFind: T) -> Int? { for (index, value) in enumerate(array) { - if value == valueToFind { - return index - } + if value == valueToFind { + return index + } } return nil - } +} +``` -The single type parameter for findIndex is written as T: Equatable, which means “any type T that conforms to the Equatable protocol. +The single type parameter for findIndex is written as T: Equatable, which means “any type T that conforms to the Equatable protocol”. -`findIndex`的类型参数可以写成`T: Equatable`,表示任意实现` Equatable`协议的类型。 +`findIndex`的类型参数写成`T: Equatable`,表示“任意实现Equatable协议的类型”。 The findIndex function now compiles successfully and can be used with any type that is Equatable, such as Double or String: -`findIndex`类型现在可以成功编译,并且可以用于任意实现了` Equatable`协议的类型,比如`Doubl`e 或者`String`: +`findIndex`类型现在可以成功编译,并且可以用于任意实现了`Equatable`协议的类型,比如`Double`e 或者`String`: - let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3) - // doubleIndex is an optional Int with no value, because 9.3 is not in the array - let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea") - // stringIndex is an optional Int containing a value of 2 +``` +let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3) +// doubleIndex is an optional Int with no value, because 9.3 is not in the array +let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea") +// stringIndex is an optional Int containing a value of 2 +``` #Associated Types #关联类型 When defining a protocol, it is sometimes useful to declare one or more associated types as part of the protocol’s definition. An associated type gives a placeholder name (or alias) to a type that is used as part of the protocol. The actual type to use for that associated type is not specified until the protocol is adopted. Associated types are specified with the typealias keyword. -当定义一个协议时,有时声明一个或多个关联类型作为协议的一部分非常有用。一个关联类型给定作用于协议部分的类型一个节点名(或别名)。作用于关联类型实际类型不需要指定,直到协议接受。关联类型被指定为typealias关键字。 +当定义一个协议时,有时声明一个或多个关联类型作为协议的一部分非常有用。一个关联类型为包含在协议中的某个类型提供了一个占位符名称(或别名)。一个关联类型代表的实际类型只有在这个协议真正被适配时才得到确定。关联类型通过typealias关键字来指定。 ##Associated Types in Action -##关联类型行为 +##关联类型实践 Here’s an example of a protocol called Container, which declares an associated type called ItemType: 下边是一个协议`Container`,定义了关联类型`ItemType`: - protocol Container { +``` +protocol Container { typealias ItemType mutating func append(item: ItemType) var count: Int { get } subscript(i: Int) -> ItemType { get } - } +} +``` The Container protocol defines three required capabilities that any container must provide: @@ -437,228 +450,231 @@ The Container protocol defines three required capabilities that any container mu 3. It must be possible to retrieve each item in the container with a subscript that takes an Int index value. 1. 必须可以通过append方法添加新的元素到容器中。 -2. 必须提供一个属性方法可以获取容器中的元素数目,并返回一个Int值。 +2. 必须提供一个count属性方法可以获取容器中的元素数目,以Int值返回。 3. 必须可以通过Int索引下标检索每个值。 This protocol doesn’t specify how the items in the container should be stored or what type they are allowed to be. The protocol only specifies the three bits of functionality that any type must provide in order to be considered a Container. A conforming type can provide additional functionality, as long as it satisfies these three requirements. -这个协议没有指定容器中items该如何存储,也没有指定数据是什么类型。协议只是指定了三个任意遵循Container类型所必须的功能点。只要满足这三个条件,遵循协议的类型也可以添加额外的功能。 +这个协议没有指定容器中成员该如何存储,也没有指定他们的数据类型。协议只是指定了任何遵循Container类型所必须具备的三个功能点。只要满足这三个条件,遵循协议的类型也可以添加额外的功能。 Any type that conforms to the Container protocol must be able to specify the type of values it stores. Specifically, it must ensure that only items of the right type are added to the container, and it must be clear about the type of the items returned by its subscript. -任意遵循Container协议的类型必须指定所存储的数据值类型。必须保证指定的数据类型可以存储到Container中,而且必须明确可以通过其下标返回结果值。 +任何遵循Container协议的类型必须能指定所存储的数据值类型。必须保证只有正确数据类型可以存储到Container中,而且对于通过其下标返回结果值的数据类型也必须是明确的。 To define these requirements, the Container protocol needs a way to refer to the type of the elements that a container will hold, without knowing what that type is for a specific container. The Container protocol needs to specify that any value passed to the append method must have the same type as the container’s element type, and that the value returned by the container’s subscript will be of the same type as the container’s element type. -为了定义这些条件,Container协议需要一个方法指定容器里的元素将会保留,不需要知道特定容器的类型。Container协议需要定义任何append方法添加至容器中的值和容器中的元素是相同类型,并且通过容器下标返回的容器元素值的类型是相同的。 +为了能定义这些要求,需要有一种方式,能在Container协议不知道某个具体的容器实际会存储的数据类型的前提下,还能引用到那个数据类型。Container协议需要能指明,任何通过append方法添加至容器的值的数据类型和容器中的元素的数据类型相同,并且通过容器下标返回的值的类型和容器中的元素的类型也是是相同的。 To achieve this, the Container protocol declares an associated type called ItemType, written as typealias ItemType. The protocol does not define what ItemType is an alias for—that information is left for any conforming type to provide. Nonetheless, the ItemType alias provides a way to refer to the type of the items in a Container, and to define a type for use with the append method and subscript, to ensure that the expected behavior of any Container is enforced. -为了达到这个目的,container协议声明了一个相关类型ItemType,记为`typealias ItemType`。该协议不会定义ItemType是谁的别名,这个信息留给任何遵循协议的类型来提供。尽管如此,ItemType别名支持一种方法识别在一个容器里的items类型,并定义一种使用在append方法和下标中的类型,保证任何期望的Container行为是强制性的。 +为了达到这个目的,container协议声明了一个相关类型ItemType,记为`typealias ItemType`。该协议不会定义ItemType是谁的别名,这个信息留给任何遵循协议的类型来提供。尽管如此,ItemType别名提供了一种方法来引用容器中的元素类型,并定义一种使用在append方法和下标中的类型,从而保证任何Container期望的行为都能得到强制实施。 Here’s a version of the non-generic IntStack type from earlier, adapted to conform to the Container protocol: 下边是之前的IntStack结构的非泛型版本,适用于遵循Container协议: - struct IntStack: Container { +``` +struct IntStack: Container { // original IntStack implementation var items = Int[]() mutating func push(item: Int) { - items.append(item) + items.append(item) } mutating func pop() -> Int { - return items.removeLast() + return items.removeLast() } // conformance to the Container protocol typealias ItemType = Int mutating func append(item: Int) { - self.push(item) + self.push(item) } var count: Int { - return items.count + return items.count } subscript(i: Int) -> Int { - return items[i] - } + return items[i] } +} +``` The IntStack type implements all three of the Container protocol’s requirements, and in each case wraps part of the IntStack type’s existing functionality to satisfy these requirements. -`IntStack`类型实现了`Container`协议的所有需求,每个包含部分的功能都满足这些要求。 +`IntStack`类型实现了`Container`协议的所有需求,在每一个要求中,都通过包装IntStack类型现有的功能来满足。 Moreover, IntStack specifies that for this implementation of Container, the appropriate ItemType to use is a type of Int. The definition of typealias ItemType = Int turns the abstract type of ItemType into a concrete type of Int for this implementation of the Container protocol. -此外, `IntStack`指定了`Container`的实现,合适的`ItemType`被用作Int类型。对于Container协议实现来说,定义 `typealias ItemType = Int`,将抽象的`ItemType`类型转换为具体的Int类型。 +此外, 在`IntStack`对于协议`Container`的实现中,对应的`ItemType`类型是Int。在这次对于Container协议实现中,通过 `typealias ItemType = Int`的定义,将抽象的`ItemType`类型转换为具体的Int类型。 Thanks to Swift’s type inference, you don’t actually need to declare a concrete ItemType of Int as part of the definition of IntStack. Because IntStack conforms to all of the requirements of the Container protocol, Swift can infer the appropriate ItemType to use, simply by looking at the type of the append method’s item parameter and the return type of the subscript. Indeed, if you delete the typealias ItemType = Int line from the code above, everything still works, because it is clear what type should be used for ItemType. -感谢Swift类型参考,你实际上不用在IntStack定义部分声明具体的Int的ItemType。由于IntStack满足Container协议的所有要求,只需通过简单的查找append方法中的item参数类型和下标返回的类型,Swift就可以推断出合适的ItemType来使用。实际上,如果你删除了上述代码中的 typealias ItemType = Int,仍可以正常运行,因为它清楚的知道ItemType使用的是何种类型。 +感谢Swift的类型推理机制,你实际上不用在IntStack定义部分声明具体的Int类型的ItemType。由于IntStack满足Container协议的所有要求,只需通过简单的查找append方法中的item参数类型和下标返回的类型,Swift就可以推断出合适的ItemType来使用。实际上,如果你删除了上述代码中的 typealias ItemType = Int,仍可以正常运行,因为它清楚的知道ItemType使用的是何种类型。 You can also make the generic Stack type conform to the Container protocol: -你同样可以生成遵循Containner协议的泛型Stack类型: +你同样可以编写遵循Containner协议的泛型Stack类型: - struct Stack: Container { +``` +struct Stack: Container { // original Stack implementation var items = T[]() mutating func push(item: T) { - items.append(item) + items.append(item) } mutating func pop() -> T { - return items.removeLast() + return items.removeLast() } // conformance to the Container protocol mutating func append(item: T) { - self.push(item) + self.push(item) } var count: Int { - return items.count + return items.count } subscript(i: Int) -> T { - return items[i] - } + return items[i] } +} +``` This time, the placeholder type parameter T is used as the type of the append method’s item parameter and the return type of the subscript. Swift can therefore infer that T is the appropriate type to use as the ItemType for this particular container. -这个时候,占位符T被用作append方法的item参数类型和下标的返回类型。Swift因此也就可以推断出用作ItemType的T的合适类型。 +这个时候,占位符T被用作append方法的item参数类型和下标的返回类型。Swift因此也就可以推断出ItemType的合适类型就是T。 #Extending an Existing Type to Specify an Associated Type -#扩展一个存在的类型为一指定关联类型 +#通过扩展已经存在的类型来指定关联类型 You can extend an existing type to add conformance to a protocol, as described in Adding Protocol Conformance with an Extension. This includes a protocol with an associated type. -你可以用[使用扩展来添加协议兼容性](../chapter2/21_Protocols.html)的方法,扩展一个已存在的类型遵循指定协议。这包含一个关联类型的协议。 +你可以用[使用扩展来添加协议兼容性](../chapter2/21_Protocols.html)的方法,通过增加对协议的遵循来扩展一个已存在的类型。这些协议也可以包含关联类型。 Swift’s Array type already provides an append method, a count property, and a subscript with an Int index to retrieve its elements. These three capabilities match the requirements of the Container protocol. This means that you can extend Array to conform to the Container protocol simply by declaring that Array adopts the protocol. You do this with an empty extension, as described in Declaring Protocol Adoption with an Extension: -Swift中的数据类型已经提供了`append`方法、`count`属性方法和下标索引方法。这三个功能满足`Container`协议。也就是说你可以扩展数组方法遵循Container协议,只需简单声明Array适用于该协议。你用一个空的扩展来这么做,就像[通过扩展补充协议声明](../chapter2/21_Protocols.html)中描述的一样。 +Swift中的数据类型已经提供了`append`方法、`count`属性方法和下标索引方法。这三个功能满足`Container`协议。也就是说你只需简单声明Array适配Container协议即可。你用一个空的扩展实现了这个目的,就像[通过扩展补充协议声明](../chapter2/21_Protocols.html)中描述的一样。 - extension Array: Container {} +``` +extension Array: Container {} +``` Array’s existing append method and subscript enable Swift to infer the appropriate type to use for ItemType, just as for the generic Stack type above. After defining this extension, you can use any Array as a Container. -数组存在的append方法和下标索引方法使Swift可以推断出ItemType的实际类型,像上边的泛型版`Stack`一样。当定义了这个扩展之后,你可以用这个数组作为容器。 +数组中存在的append方法和下标索引方法使Swift可以推断出ItemType的实际类型,像上边的泛型版`Stack`一样。当定义了这个扩展之后,你可以用任何数组作为容器。 #Where Clauses -#Where语句 +#Where从句 Type constraints, as described in Type Constraints, enable you to define requirements on the type parameters associated with a generic function or type. -类型约束确保相关的泛型函数和类型的指定参数满足需求。 +类型约束能让你为泛型函数或者类型中相关的类型参数添加要求。 It can also be useful to define requirements for associated types. You do this by defining where clauses as part of a type parameter list. A where clause enables you to require that an associated type conforms to a certain protocol, and/or that certain type parameters and associated types be the same. You write a where clause by placing the where keyword immediately after the list of type parameters, followed by one or more constraints for associated types, and/or one or more equality relationships between types and associated types. -定义关联类型的满足条件也是非常有用的。你可以通过定义where语句作为类型参数的一部分。通过where语句指定一个关联类型遵循一个特定的协议,以及(或)那个特定的类型参数和关联类型可以是相同的。可以在类型参数后,紧跟着where语句,where语句中跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型的等于关系。 +而为关联类型添加满足条件也是非常有用的。你可以通过定义where从句作为类型参数的一部分来添加要求。通过where语句能要求一个关联类型遵循一个特定的协议,以及(或)指定某个特定的类型参数和关联类型必须相同。where从句通过在类型参数后面添加where关键词开始,其后跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型的等于关系。 The example below defines a generic function called allItemsMatch, which checks to see if two Container instances contain the same items in the same order. The function returns a Boolean value of true if all items match and a value of false if they do not. -下边的例子定义了泛型函数`allItemsMatch`,用于判断两个`Container`实例是否包含相同的元素并具有相同的顺序。如果所有元素满足条件,函数返回true,否则返回false。 +下边的例子定义了一个泛型函数`allItemsMatch`,用于判断两个`Container`实例是否包含相同的元素并具有相同的顺序。如果所有元素满足条件,函数返回true,否则返回false。 The two containers to be checked do not have to be the same type of container (although they can be), but they do have to hold the same type of items. This requirement is expressed through a combination of type constraints and where clauses: -需要检查的两个`containers`,不需要是相同类型的`container`(当然也可以是相同的),但是他们的元素必须相同。这个需求通过一个类型约束和where语句相结合来表示: +需要检查的两个容器,不需要是相同类型的容器(当然也可以是相同的),但是他们的元素必须相同。这个需求通过一个类型约束和where从句相结合来表示: - func allItemsMatch< - C1: Container, C2: Container - where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> +``` +func allItemsMatch (someContainer: C1, anotherContainer: C2) -> Bool { // check that both containers contain the same number of items if someContainer.count != anotherContainer.count { - return false + return false } // check each pair of items to see if they are equivalent for i in 0..someContainer.count { - if someContainer[i] != anotherContainer[i] { - return false - } + if someContainer[i] != anotherContainer[i] { + return false + } } // all items match, so return true return true - } +} +``` This function takes two arguments called `someContainer` and `anotherContainer`. The `someContainer` argument is of type `C1`, and the `anotherContainer` argument is of type `C2`. Both `C1` and `C2` are placeholder type parameters for two container types to be determined when the function is called. -这个函数有两个参数`someContainer`和`anotherContainer`。`someContainer`参数是`C1`类型,`anotherContainer`参数是`C2`类型。`C1`和`C2`都是占位符,真正的参数类型等函数运行时决定。 +这个函数有两个参数`someContainer`和`anotherContainer`。`someContainer`参数是`C1`类型,`anotherContainer`参数是`C2`类型。`C1`和`C2`都是占位符,真正的参数类型在函数被调用时确定。 The function’s type parameter list places the following requirements on the two type parameters: 这个函数的类型参数列紧随在两个类型参数需求的后面: - C1 must conform to the Container protocol (written as C1: Container). - - C2 must also conform to the Container protocol (written as C2: Container). - - The ItemType for C1 must be the same as the ItemType for C2 (written as C1.ItemType == C2.ItemType). +- C1 must conform to the Container protocol (written as C1: Container). +- C2 must also conform to the Container protocol (written as C2: Container). +- The ItemType for C1 must be the same as the ItemType for C2 (written as C1.ItemType == C2.ItemType). +- The ItemType for C1 must conform to the Equatable protocol (written as C1.ItemType: Equatable). - The ItemType for C1 must conform to the Equatable protocol (written as C1.ItemType: Equatable). - -``` - C1必须遵循`Container`协议(写法`C1: Container`) - C2必须遵循`Container`协议(写法`C2: Container`) - C1的ItemType必须和C2的ItemType相等(写法C1.ItemType == C2.ItemType) - C1的ItemType必须遵循`Equatable`协议 -``` +- C1必须遵循`Container`协议(写法`C1: Container`) +- C2必须遵循`Container`协议(写法`C2: Container`) +- C1的ItemType必须和C2的ItemType相等(写法C1.ItemType == C2.ItemType) +- C1的ItemType必须遵循`Equatable`协议 + The third and fourth requirements are defined as part of a where clause, and are written after the where keyword as part of the function’s type parameter list. -第三四个要求在where语句中定义,并作为参数类型值部分内容放到where语句后。 +第三四个要求在where语句中定义,并作为参数类型列表的一部分放到where关键词后。 These requirements mean: 这几个要求意义是: - someContainer is a container of type C1. - - anotherContainer is a container of type C2. - - someContainer and anotherContainer contain the same type of items. - - The items in someContainer can be checked with the not equal operator (!=) to see if they are different from each other. +- someContainer is a container of type C1. +- anotherContainer is a container of type C2. +- someContainer and anotherContainer contain the same type of items. +- The items in someContainer can be checked with the not equal operator (!=) to see if they are different from each other. -``` -someContainer是C1类型的anotherContainer -anotherContainer是C2类型的anotherContainer -someContainer和anotherContainer包含相同类型的元素 -someContainer中的元素可以通过调用不等于操作(!=)判断他们是否不同 -``` +- someContainer是C1类型的容器 +- anotherContainer是C2类型的容器 +- someContainer和anotherContainer包含相同类型的元素 +- someContainer中的元素可以通过调用不等于操作(!=)判断他们是否不同 The third and fourth requirements combine to mean that the items in anotherContainer can also be checked with the != operator, because they are exactly the same type as the items in someContainer. -第三四个需求结合起来标示`anotherContainer`的元素同样可以调用`!=`操作,因为他们和`someContainer`中的类型是一样的。 +第三四个需求结合起来表明`anotherContainer`的元素同样可以调用`!=`操作,因为他们和`someContainer`中的类型是一样的。 These requirements enable the allItemsMatch function to compare the two containers, even if they are of a different container type. -这些要求使得`allItemsMatch`函数可以比较两个`containers`,即便他们具有不同的`containers`类型。 +这些要求使得`allItemsMatch`函数可以比较两个容器,即便他们是不同的容器类型。 The allItemsMatch function starts by checking that both containers contain the same number of items. If they contain a different number of items, there is no way that they can match, and the function returns false. -`allItemsMatch`函数会先检查`containers`是否包含相同数目的元素。如果包含内容不相同,他们互相也就不相等,结果返回`false`。 +`allItemsMatch`函数会先检查`containers`是否包含相同数目的元素。如果元素数目不同,他们互相也就不相等,结果返回`false`。 After making this check, the function iterates over all of the items in someContainer with a for-in loop and the half-closed range operator (..). For each item, the function checks whether the item from someContainer is not equal to the corresponding item in anotherContainer. If the two items are not equal, then the two containers do not match, and the function returns false. -如果具有相同的元素个数,函数通过`for-in`循环和半闭区间操作(..)来迭代`someContainer`中的所有元素。循环中,`someContainer`中的元素是否和`anotherContainer`中的对应元素相同。如果有不相同的,函数返回`false`。 +如果具有相同的元素个数,函数通过`for-in`循环和半闭区间操作(..)来迭代`someContainer`中的所有元素。循环中,检查`someContainer`中的元素是否和`anotherContainer`中的对应元素相同。如果有不相同的,函数返回`false`。 -If the loop finishes without finding a mismatch, the two match, and the function returns true. +If the loop finishes without finding a mismatch, the two match, and the function returns true. -如果循环过程中没有一个不相同的,则`containers`相等,结果返回`true`。 +如果循环过程中没有一个不匹配的,则这两个容器相等,结果返回`true`。 Here’s how the `allItemsMatch` function looks in action: -这里演示了`allItemsMatch`函数运算的过程: +下面展示`allItemsMatch`函数的实际使用: - var stackOfStrings = Stack() - stackOfStrings.push("uno") - stackOfStrings.push("dos") - stackOfStrings.push("tres") - var arrayOfStrings = ["uno", "dos", "tres"] - if allItemsMatch(stackOfStrings, arrayOfStrings) { +``` +var stackOfStrings = Stack() +stackOfStrings.push("uno") +stackOfStrings.push("dos") +stackOfStrings.push("tres") + +var arrayOfStrings = ["uno", "dos", "tres"] + +if allItemsMatch(stackOfStrings, arrayOfStrings) { println("All items match.") - } else { +} else { println("Not all items match.") - } - // prints "All items match." +} + +// prints "All items match." + +``` The example above creates a Stack instance to store String values, and pushes three strings onto the stack. The example also creates an Array instance initialized with an array literal containing the same three strings as the stack. Even though the stack and the array are of a different type, they both conform to the Container protocol, and both contain the same type of values. You can therefore call the allItemsMatch function with these two containers as its arguments. In the example above, the allItemsMatch function correctly reports that all of the items in the two containers match. -上边的例子中创建一个`Stack`实例存储字符串值,然后`push`三个字符串到堆栈中。同样创建一个数组实例初始化为包含三个字符串,和堆栈元素相同。尽管堆栈和数组是不同的数据类型,但是他们遵循相同的协议,并且包含相同的数据类型,相同的数据值。所以你可以调用`allItemsMatch`去比较两者。在上边的例子中,`allItemsMatch`函数会返回两者包含的所有元素相匹配。 +上边的例子中创建了一个`Stack`实例存储字符串值,然后`push`三个字符串到堆栈中。同样创建一个数组,并在初始化时加入了三个和堆栈中的元素相同的字符串。尽管堆栈和数组是不同的数据类型,但是他们都遵循Container协议,并且包含相同数据类型,相同的数据值。所以你可以调用`allItemsMatch`去比较两者。在上边的例子中,`allItemsMatch`函数正确地报告了两者包含的所有元素相匹配。 From 5931d3c571cd3538e811ce4d8e7154840639f5eb Mon Sep 17 00:00:00 2001 From: Neekey Date: Sun, 6 Jul 2014 17:40:30 +0800 Subject: [PATCH 248/261] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20=E6=B3=9B=E5=9E=8B?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=BB=86=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/22_Generics.md | 189 +++++++++++++++++++----------------- 1 file changed, 98 insertions(+), 91 deletions(-) diff --git a/src/chapter2/22_Generics.md b/src/chapter2/22_Generics.md index 3dffdaf..f2ca75e 100644 --- a/src/chapter2/22_Generics.md +++ b/src/chapter2/22_Generics.md @@ -14,7 +14,7 @@ Generics are one of the most powerful features of Swift, and much of the Swift s Here’s a standard, non-generic function called `swapTwoInts`, which swaps two Int values: -下面的代码是一个标准的、非泛型函数`swapTwoInts`, 用于交换两个int值: +下面的代码是一个标准的、非泛型函数`swapTwoInts`,用于交换两个int值: ``` func swapTwoInts(inout a: Int, inout b: Int) { @@ -26,11 +26,11 @@ func swapTwoInts(inout a: Int, inout b: Int) { This function makes use of in-out parameters to swap the values of a and b, as described in [In-Out Parameters](). -这个函数使用in-out参数交换a,b值,具体的可以参考[In-Out Parameters](). +这个函数使用in-out参数交换a,b值,具体的可以参考[In-Out Parameters]()。 The `swapTwoInts` function swaps the original value of b into a, and the original value of a into b. You can call this function to swap the values in two Int variables: -`swapTwoInts`函数把b的原始值赋值给a, a的原始值给b.你可以调用这个函数去交换两个整形值: +`swapTwoInts`函数把b的原始值赋值给a,a的原始值给b。你可以调用这个函数去交换两个整形值: ``` var someInt = 3 @@ -42,7 +42,7 @@ println("someInt is now \(someInt), and anotherInt is now \(anotherInt)") The `swapTwoInts` function is useful, but it can only be used with Int values. If you want to swap two String values, or two Double values, you have to write more functions, such as the `swapTwoStrings` and `swapTwoDoubles `functions shown below: -`swapTwoInts`函数非常有用,但是它只能交换int值。如果想交换两个String、或者是两个Double类型的值,你不得不再写几个函数,比如`swapTwoStrings`,`swapTwoDoublesfunctions`,如下所示: +`swapTwoInts`函数非常有用,但是它只能交换int值。如果想交换两个String、或者是两个Double类型的值,你不得不再写几个函数,比如`swapTwoStrings`,`swapTwoDoublesfunctions`,如下所示: ``` func swapTwoStrings(inout a: String, inout b: String) { @@ -63,16 +63,17 @@ You may have noticed that the bodies of the `swapTwoInts`, `swapTwoStrings`, and It would be much more useful, and considerably more flexible, to write a single function that could swap two values of any type. This is the kind of problem that generic code can solve. (A generic version of these functions is defined below.) -如果可以只编写一个函数就能提供交换两个任意类型的值的功能的话,这种方式将更加有用和灵活。而这正是泛型所要解决的问题。(下面是使用泛型重新编写的函数)。 +如果可以只编写一个函数就能提供交换两个任意类型的值的功能的话,这种方式将更加有用和灵活。而这正是泛型所要解决的问题。(下面是使用泛型重新编写的函数)。 -``` -NOTE -In all three functions, it is important that the types of a and b are defined to be the same as each other. If a and b were not of the same type, it would not be possible to swap their values. Swift is a type-safe language, and does not allow (for example) a variable of type String and a variable of type Double to swap values with each other. Attempting to do so would be reported as a compile-time error. -``` -``` -注意 -上面的三个函数中,a和b的类型必须是一样的。如果不一样,就不能交换两者的值。Swift是类型安全的语言,不允许一个`String`和`Double`类型变量互相交换值。如果试图进行这样的操作,会出现编译错误。 -``` + +> NOTE + +> In all three functions, it is important that the types of a and b are defined to be the same as each other. If a and b were not of the same type, it would not be possible to swap their values. Swift is a type-safe language, and does not allow (for example) a variable of type String and a variable of type Double to swap values with each other. Attempting to do so would be reported as a compile-time error. + + +> 注意 + +> 上面的三个函数中,a和b的类型必须是一样的。如果不一样,就不能交换两者的值。Swift是类型安全的语言,不允许一个`String`和`Double`类型变量互相交换值。如果试图进行这样的操作,会出现编译错误。 #Generic Functions #泛型函数 @@ -107,11 +108,11 @@ The other difference is that the generic function’s name (swapTwoValues) is fo The `swapTwoValues` function can now be called in the same way as `swapTwoInts`, except that it can be passed two values of any type, as long as both of those values are of the same type as each other. Each time `swapTwoValues` is called, the type to use for T is inferred from the types of values passed to the function. -`swapTwoValues`函数现在可以和`swapTwoInts`一样被调用。除此之外,`swapTwoValues`可以接收两个任意类型的参数,只要这两个参数的类型相同。每次`swapTwoValues`被调用,T所代表类型会根据实际传入的参数来确定。 +`swapTwoValues`函数现在可以和`swapTwoInts`一样被调用。除此之外,`swapTwoValues`可以接收两个任意类型的参数,只要这两个参数的类型相同。每次`swapTwoValues`被调用,T所代表的类型会根据实际传入的参数来确定。 In the two examples below, T is inferred to be Int and String respectively: -在下边的例子中,T分别代表Int和String类型。 +在下面的例子中,T分别代表Int和String类型。 ``` var someInt = 3 @@ -125,48 +126,52 @@ swapTwoValues(&someString, &anotherString) // someString is now "world", and anotherString is now "hello" ``` -``` -NOTE -The swapTwoValues function defined above is inspired by a generic function called swap, which is part of the Swift standard library, and is automatically made available for you to use in your apps. If you need the behavior of the swapTwoValues function in your own code, you can use Swift’s existing swap function rather than providing your own implementation. -``` -``` -注意 -上边定义的`swapTwoValues`函数是受到一个泛型函数`swap`的启发而实现的,这个函数被包含在Swift的标准库中,你可以直接在你的应用中使用它。如果在你的代码中需要一个和`swapTwoValues`类似的功能,可以直接使用Swift中已存在的`swap`方法,而不需要自己再实现一遍。 -``` +> NOTE + +> The swapTwoValues function defined above is inspired by a generic function called swap, which is part of the Swift standard library, and is automatically made available for you to use in your apps. If you need the behavior of the swapTwoValues function in your own code, you can use Swift’s existing swap function rather than providing your own implementation. + +> 注意 + +> 上面定义的`swapTwoValues`函数是受到一个泛型函数`swap`的启发而实现的,这个函数被包含在Swift的标准库中,你可以直接在你的应用中使用它。如果在你的代码中需要一个和`swapTwoValues`类似的功能,可以直接使用Swift中已存在的`swap`方法,而不需要自己再实现一遍。 + + #Type Parameters #类型参数 + In the swapTwoValues example above, the placeholder type T is an example of a type parameter. Type parameters specify and name a placeholder type, and are written immediately after the function’s name, between a pair of matching angle brackets (such as ). -在上边的`swapTwoValues`例子中,占位符T是一个关于使用类型参数的例子。类型参数通过给定一个占位符类型的方式,放置于紧跟在函数名称之后的尖括号内(例如)。 +在上面的`swapTwoValues`例子中,占位符T是一个关于使用类型参数的例子。类型参数通过给定一个占位符类型的方式,放置于紧跟在函数名称之后的尖括号内(例如)。 Once specified, a type parameter can be used to define the type of a function’s parameters (such as the a and b parameters of the swapTwoValues function); or as the function’s return type; or as a type annotation within the body of the function. In each case, the placeholder type represented by the type parameter is replaced with an actual type whenever the function is called. (In the swapTwoValues example above, T was replaced with Int the first time the function was called, and was replaced with String the second time it was called.) -一旦被指定,参数类型可以用来定义函数接收的参数(例如`swapTwoValues`函数中的a和b参数);或者也可以作为函数的返回值类型。这每个例子中,被类型参数代表的占位符类型,在函数被调用时,会被真实的参数类型所代替。(在`swapTwoValues`的例子中,当函数被第一次调用时,T会被Int代替,第二次调用中T会被String代替。) +一旦被指定,参数类型可以用来定义函数接收的参数(例如`swapTwoValues`函数中的a和b参数);或者作为函数的返回值类型;或者在函数体中作为类型注释。在每一种场景子中,被类型参数代表的占位符类型,在函数被调用时,会被真实的参数类型所代替。(在`swapTwoValues`的例子中,当函数被第一次调用时,T会被Int代替,第二次调用中T会被String代替。) You can provide more than one type parameter by writing multiple type parameter names within the angle brackets, separated by commas. -你可以在尖括号中通过逗号分隔的方式指定多个类型参数名称,来为函数提供多个类型参数。 +你可以在尖括号中通过逗号分隔的方式指定多个类型参数名称,为函数提供多个类型参数。 ‌ #Naming Type Parameters #类型参数命名 + In simple cases where a generic function or generic type needs to refer to a single placeholder type (such as the swapTwoValues generic function above, or a generic collection that stores a single type, such as Array), it is traditional to use the single-character name T for the type parameter. However, you are can use any valid identifier as the type parameter name. -在一般的情况下,如果泛型函数或者泛型类型需要指定一个占位符(像上边的`swapTwoValues`泛型函数或者只包含单个类型的泛型集合,比如数组),通常会用一个字符T来代表参数类型。不过,你也可以用任意有效的标识符来表示参数类型。 +在一般的情况下,如果泛型函数或者泛型类型需要指定一个占位符(像上面的`swapTwoValues`泛型函数或者只包含单个类型的泛型集合,比如数组),通常会用一个字符T来代表参数类型。不过,你也可以用任意有效的标识符来表示参数类型。 If you are defining more complex generic functions, or generic types with multiple parameters, it can be useful to provide more descriptive type parameter names. For example, Swift’s Dictionary type has two type parameters—one for its keys and one for its values. If you were writing Dictionary yourself, you might name these two type parameters KeyType and ValueType to remind you of their purpose as you use them within your generic code. -如果你正在定义更加复杂的泛型函数或者泛型类型,并需要多个参数,那么使用更具有描述性的类型参数名称就很有必要了。比如Swift中的字典类型就有两个参数,其中一个作为键,一个作为值。如果你实现来字典类型,你可以为这两个类型取名为`KeyType`和`ValueType`,从而提醒你这两个参数在泛型代码中的作用。 +如果你正在定义更加复杂的泛型函数或者泛型类型,并需要多个参数,那么使用更具有描述性的类型参数名称就很有必要了。比如Swift中的字典类型就有两个参数,其中一个作为键,一个作为值。如果由你来实现字典类型,你可以为这两个类型分别取名为`KeyType`和`ValueType`,从而提醒你这两个参数在泛型代码中的作用。 + +> NOTE + +> Always give type parameters UpperCamelCase names (such as T and KeyType) to indicate that they are a placeholder for a type, not a value. + +> 注意 + +> 请始终使用大写字母开头的驼峰命名法(例如T和KeyType)来给类型参数命名,以表明它们是类型的占位符,而非类型值。 -``` -NOTE -Always give type parameters UpperCamelCase names (such as T and KeyType) to indicate that they are a placeholder for a type, not a value. -``` -``` -注意 -请始终使用大写字母开头的驼峰式命名法(例如T和KeyType)来给类型参数命名,以表明它们是类型的占位符,而非类型值。 -``` #Generic Types #泛型类型 + In addition to generic functions, Swift enables you to define your own generic types. These are custom classes, structures, and enumerations that can work with any type, in a similar way to Array and Dictionary. 除了泛型函数,Swift可以让你定义自己的泛型类型。这些类型可以是自定义的类、结构和枚举,他们和数组以及字典一样,可以和其他任意类型一起工作。 @@ -175,36 +180,35 @@ This section shows you how to write a generic collection type called Stack. A st 本节将展示如何编写堆栈这样的泛型集合类型。堆栈是一个具有特定顺序的数值的集合,和数组类似,但是和数组相比,堆栈在操作上有更多的限制。数组允许元素可以从任何位置插入或者删除。而堆栈只允许添加新元素到集合的顶部(叫做push一个新值到堆栈)。同样的,堆栈只允许从集合的顶部删除一个元素(叫做从堆栈pop出一个值)。 -``` -NOTE -The concept of a stack is used by the UINavigationController class to model the view controllers in its navigation hierarchy. You call the UINavigationController class pushViewController:animated: method to add (or push) a view controller on to the navigation stack, and its popViewControllerAnimated: method to remove (or pop) a view controller from the navigation stack. A stack is a useful collection model whenever you need a strict “last in, first out” approach to managing a collection. -``` +> NOTE + +> The concept of a stack is used by the UINavigationController class to model the view controllers in its navigation hierarchy. You call the UINavigationController class pushViewController:animated: method to add (or push) a view controller on to the navigation stack, and its popViewControllerAnimated: method to remove (or pop) a view controller from the navigation stack. A stack is a useful collection model whenever you need a strict “last in, first out” approach to managing a collection. + +> 注意 + +> 堆栈的概念被用在`UINavigationController`类中作为视图控制器的导航结构的数据模型。你可以通过调用`UINavigationController`的`pushViewController:animated: `方法来添加一个视图到堆栈中,调用` popViewControllerAnimated:`方法从堆栈中删除一个试图。当你需要一个严格的“先进先出”方式来管理集合时,堆栈是非常有用的。 -``` -注意 -堆栈的概念被用在`UINavigationController`类中,作为视图控制器的导航结构的数据模型。你调用`UINavigationController`的`pushViewController:animated: `方法添加一个视图到堆栈中,调用` popViewControllerAnimated:`方法从堆栈中删除一个试图。当你需要一个严格的“先进先出”方式来管理集合时,堆栈是非常有用的。 -``` The illustration below shows the push / pop behavior for a stack: -下面的图表展示了堆栈的进入、退出操作: +下面的图表展示了堆栈的进入、推出操作: ![stack](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPushPop_2x.png) -1. There are currently three values on the stack. -2. A fourth value is “pushed” on to the top of the stack. -3. The stack now holds four values, with the most recent one at the top. -4. The top item in the stack is removed, or “popped”. -5. After popping a value, the stack once again holds three values. + 1. There are currently three values on the stack. + 2. A fourth value is “pushed” on to the top of the stack. + 3. The stack now holds four values, with the most recent one at the top. + 4. The top item in the stack is removed, or “popped”. + 5. After popping a value, the stack once again holds three values. -1.当前堆栈里有3个值 -2.第四个值从堆栈的顶部被“push”进去 -3.现在堆栈中有4个值,其中最新的值在最顶部 -4.堆栈最顶部的值被移除,或者叫“popped” -5.当推出一个值后,堆栈重新变成了三个值 + 1. 当前堆栈里有3个值。 + 2. 第四个值从堆栈的顶部被“push”进去。 + 3. 现在堆栈中有4个值,其中最新的值在最顶部。 + 4. 堆栈最顶部的值被移除,或者叫“popped”。 + 5. 当推出一个值后,堆栈重新变成了三个值。 -Here’s how to write a non-generic version of a “stack, in this case for a stack of Int values +Here’s how to write a non-generic version of a “stack”, in this case for a stack of Int values 下面展示如何编写一个非泛型版本的堆栈,这个例子中的堆栈是Int类型: @@ -226,7 +230,7 @@ This structure uses an Array property called items to store the values in the st The IntStack type shown above can only be “used with Int values, however. It would be much more useful to define a generic Stack class, that can manage a stack of any type of value. -上边的这个`IntStack`类型只能用于Int值。如果定义一个可以管理任何数据类型的泛型类型的堆栈类型,可以管理堆栈中得任意类型,是非常有用的。 +上面的这个`IntStack`类型只能用于Int值。如果定义一个可以管理任何数据类型的泛型类型的堆栈类型,可以管理堆栈中的任意类型,那将非常有用。 Here’s a generic version of the same code: @@ -245,19 +249,19 @@ struct Stack { ``` Note how the generic version of Stack is essentially the same as the non-generic version, but with a placeholder type parameter called T instead of an actual type of Int. This “type parameter is written within a pair of angle brackets () immediately after the structure’s name. -可以注意到,除了使用T作为占位符类型参数来代替真实int类型之外,泛型版本的堆栈结构和上边非泛型版本基本上是一样的。这个类型参数直接跟在结构的名称后并被一对尖括号包裹(). +可以注意到,除了使用T作为占位符类型参数来代替真实int类型之外,泛型版本的堆栈结构和上面非泛型版本基本上是一样的。这个类型参数直接跟在结构的名称后并被一对尖括号包裹(). T defines a placeholder name for “some type T” to be provided later on. This future type can be referred to as “T” anywhere within the structure’s definition. In this case, T is used as a placeholder in three places: -T作为一个占位符名称来代替后续实际会给定的“某种类型T”。这种将来类型可以在结构体定义中的任何地方使用`T`来表示。在这个例子中,`T`在如下三个位置作为占位符: +其中T作为一个占位符名称来代替后续实际会给定的“某种类型T”。这种将来类型可以在结构体定义中的任何地方使用`T`来表示。在这个例子中,`T`在如下三个位置作为占位符: -1. To create a property called items, which is initialized with an empty array of values of type T -2. To specify that the push method has a single parameter called item, which must be of type T -3. To specify that the value returned by the pop method will be a value of type T + 1. To create a property called items, which is initialized with an empty array of values of type T + 2. To specify that the push method has a single parameter called item, which must be of type T + 3. To specify that the value returned by the pop method will be a value of type T -1.创建成员变量`items`,并将它初始化为包含类型T的空数组 -2.指定`push`方法有一个参数item,类型为T类型 -3.指定`pop`方法返回结果类型为T + 1. 创建成员变量`items`,并将它初始化为包含类型T的空数组 + 2. 指定`push`方法有一个参数item,类型为T类型 + 3. 指定`pop`方法返回结果类型为T You create instances of Stack in a similar way to Array and Dictionary, by writing the actual type to be used for this specific stack within angle brackets after the type name when creating a new instance with initializer syntax: @@ -274,27 +278,28 @@ stackOfStrings.push("cuatro") Here’s how stackOfStrings looks after pushing these four values on to the stack: -下边展示`stackOfStrings`如何把四个值push进栈: +下面展示`stackOfStrings`如何把四个值push进栈: ![进栈](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPushedFourStrings_2x.png) - Popping a value from the stack returns and removes the top value, "cuatro": +Popping a value from the stack returns and removes the top value, "cuatro": - 下图是如何从栈中pop一个值的过程,移除栈最顶上结果,“cuatro”,并返回其值: +下图是如何从栈中pop一个值的过程,移除栈最顶上结果,“cuatro”,并返回其值: ``` - let fromTheTop = stackOfStrings.pop() - // fromTheTop is equal to "cuatro", and the stack now contains 3 strings +let fromTheTop = stackOfStrings.pop() +// fromTheTop is equal to "cuatro", and the stack now contains 3 strings ``` + Here’s how the stack looks after popping its top value: -下边是推出最顶层数据之后的堆栈效果: +下面是推出最顶层数据之后的堆栈效果: ![移除堆栈效果](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Art/stackPoppedOneString_2x.png) - Because it is a generic type, Stack can be used to create a stack of any valid type in Swift, in a similar manner to Array and Dictionary. +Because it is a generic type, Stack can be used to create a stack of any valid type in Swift, in a similar manner to Array and Dictionary. - 由于`Stack`是泛型类型,所以在Swift中可以用于创建任何合法类型的栈,方式同`Array`和`Dictionary`。 +由于`Stack`是泛型类型,所以在Swift中可以用于创建任何合法类型的栈,方式同`Array`和`Dictionary`。 #Type Constraints #类型约束 @@ -321,17 +326,17 @@ You can define your own type constraints when creating custom generic types, and You write type constraints by placing a single class or protocol constraint after a type parameter’s name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types): -你可以通过在类型参数名称的后边以冒号分割,加上类型参数约束。基础的泛型函数的类型约束语法如下(同样的,这个语法也适用于泛型类型) +你可以通过在类型参数名称的后边以冒号分割,加上类型参数约束。基础的泛型函数的类型约束语法如下(同样的,这个语法也适用于泛型类型): ``` - func someFunction(someT: T, someU: U) { +func someFunction(someT: T, someU: U) { // function body goes here - } +} ``` The hypothetical function above has two type parameters. The first type parameter, T, has a type constraint that requires T to be a subclass of SomeClass. The second type parameter, U, has a type constraint that requires U to conform to the protocol SomeProtocol. -上边函数有两个参数。参数一类型参数为T,需要T必须是`SomeClass`子类;第二个参数类型为U,需要U必须遵循`SomeClass`协议。 +上面函数有两个参数。参数一类型参数为T,需要T必须是`SomeClass`子类;第二个参数类型为U,需要U必须遵循`SomeClass`协议。 ##Type Constraints in Action ##类型约束实践 @@ -339,6 +344,7 @@ The hypothetical function above has two type parameters. The first type paramete Here’s a non-generic function called findStringIndex, which is given a String value to find and an array of String values within which to find it. The findStringIndex function returns an optional Int value, which will be the index of the first matching string in the array if it is found, or nil if the string cannot be found: 现在有一个名为findStringIndex的非泛型函数,它接收一个字符串以及一个字符串数组作为参数,并从这个数组中对这个给定的字符串进行查找。若查找到匹配的字符串,findStringIndex函数返回该字符串在数组中的索引位置(Int),反之返回nil: + ``` func findStringIndex(array: String[], valueToFind: String) -> Int? { for (index, value) in enumerate(array) { @@ -355,11 +361,11 @@ The findStringIndex function can be used to find a string value in an array of s `findStringIndex`可以用于查找数组中指定的String值: ``` - let strings = ["cat", "dog", "llama", "parakeet", "terrapin"] - if let foundIndex = findStringIndex(strings, "llama") { +let strings = ["cat", "dog", "llama", "parakeet", "terrapin"] +if let foundIndex = findStringIndex(strings, "llama") { println("The index of llama is \(foundIndex)") - } - // prints "The index of llama is 2" +} +// prints "The index of llama is 2" ``` The principle of finding the index of a value in an array isn’t useful only for strings, however. You can write the same functionality as a generic function called findIndex, by replacing any mention of strings with values of some type T instead. @@ -368,7 +374,7 @@ The principle of finding the index of a value in an array isn’t useful only fo Here’s how you might expect a generic version of findStringIndex, called findIndex, to be written. Note that the return type of this function is still Int?, because the function returns an optional index number, not an optional value from the array. Be warned, though—this function does not compile, for reasons explained after the example: -下边就是`findStringIndex`的泛型版本`findIndex`。注意到函数的返回结果仍然是Int?,这是因为这个函数返回匹配到的数组索引值,而不是数组中的值。需要提醒的是,这个函数不会编译,原因后边会说明: +下面就是`findStringIndex`的泛型版本`findIndex`。注意到函数的返回结果仍然是Int?,这是因为这个函数返回匹配到的数组索引值,而不是数组中的值。需要提醒的是,这个函数不会编译,原因后边会说明: ``` func findIndex(array: T[], valueToFind: T) -> Int? { @@ -383,7 +389,7 @@ func findIndex(array: T[], valueToFind: T) -> Int? { This function does not compile as written above. The problem lies with the equality check, “if value == valueToFind”. Not every type in Swift can be compared with the equal to operator (==). If you create your own class or structure to represent a complex data model, for example, then the meaning of “equal to” for that class or structure is not something that Swift can guess for you. Because of this, it is not possible to guarantee that this code will work for every possible type T, and an appropriate error is reported when you try to compile the code. -这个函数按照上边的写法不会编译。原因是等价检查部分“if value == valueToFind”. 不是所有的泛型类型都可以用`==`进行比较。如果你创建了自己的类或者结构代表一个复杂的数据模型,那么Swift语言没法猜测如何对这个类或者结构进行是否相等的比较。正因为如此,这个代码无法保证可以作用于所有可能的类型T,并且当你尝试编译这段代码时,编译器会给抛出错误指出这个问题。 +这个函数按照上面的写法不会编译。原因是等价检查部分“if value == valueToFind”。 不是所有的泛型类型都可以用`==`进行比较。如果你创建了自己的类或者结构代表一个复杂的数据模型,那么Swift语言没法猜测如何对这个类或者结构进行是否相等的比较。正因为如此,这个代码无法保证可以作用于所有可能的类型T,并且当你尝试编译这段代码时,编译器会给抛出错误指出这个问题。 All is not lost, however. The Swift standard library defines a protocol called Equatable, which requires any conforming type to implement the equal to operator (==) and the not equal to operator (!=) to compare any two values of that type. All of Swift’s standard types automatically support the Equatable protocol. @@ -406,7 +412,7 @@ func findIndex(array: T[], valueToFind: T) -> Int? { The single type parameter for findIndex is written as T: Equatable, which means “any type T that conforms to the Equatable protocol”. -`findIndex`的类型参数写成`T: Equatable`,表示“任意实现Equatable协议的类型”。 +`findIndex`的类型参数写成`T: Equatable`,表示“任意实现Equatable协议的类型”。 The findIndex function now compiles successfully and can be used with any type that is Equatable, such as Double or String: @@ -421,6 +427,7 @@ let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea") #Associated Types #关联类型 + When defining a protocol, it is sometimes useful to declare one or more associated types as part of the protocol’s definition. An associated type gives a placeholder name (or alias) to a type that is used as part of the protocol. The actual type to use for that associated type is not specified until the protocol is adopted. Associated types are specified with the typealias keyword. 当定义一个协议时,有时声明一个或多个关联类型作为协议的一部分非常有用。一个关联类型为包含在协议中的某个类型提供了一个占位符名称(或别名)。一个关联类型代表的实际类型只有在这个协议真正被适配时才得到确定。关联类型通过typealias关键字来指定。 @@ -430,7 +437,7 @@ When defining a protocol, it is sometimes useful to declare one or more associat Here’s an example of a protocol called Container, which declares an associated type called ItemType: -下边是一个协议`Container`,定义了关联类型`ItemType`: +下面是一个协议`Container`,定义了关联类型`ItemType`: ``` protocol Container { @@ -467,11 +474,11 @@ To define these requirements, the Container protocol needs a way to refer to the To achieve this, the Container protocol declares an associated type called ItemType, written as typealias ItemType. The protocol does not define what ItemType is an alias for—that information is left for any conforming type to provide. Nonetheless, the ItemType alias provides a way to refer to the type of the items in a Container, and to define a type for use with the append method and subscript, to ensure that the expected behavior of any Container is enforced. -为了达到这个目的,container协议声明了一个相关类型ItemType,记为`typealias ItemType`。该协议不会定义ItemType是谁的别名,这个信息留给任何遵循协议的类型来提供。尽管如此,ItemType别名提供了一种方法来引用容器中的元素类型,并定义一种使用在append方法和下标中的类型,从而保证任何Container期望的行为都能得到强制实施。 +为了达到这个目的,container协议声明了一个相关类型ItemType,记为`typealias ItemType`。该协议不会定义ItemType是谁的别名,这个信息留给任何遵循协议的类型来提供。尽管如此,ItemType别名提供了一种方法来引用容器中的元素类型,并定义一种使用在append方法和下标中的类型,从而保证任何Container期望的行为都能得到强制实施。 Here’s a version of the non-generic IntStack type from earlier, adapted to conform to the Container protocol: -下边是之前的IntStack结构的非泛型版本,适用于遵循Container协议: +下面是之前的IntStack结构的非泛型版本,适用于遵循Container协议: ``` struct IntStack: Container { @@ -545,7 +552,7 @@ This time, the placeholder type parameter T is used as the type of the append me You can extend an existing type to add conformance to a protocol, as described in Adding Protocol Conformance with an Extension. This includes a protocol with an associated type. -你可以用[使用扩展来添加协议兼容性](../chapter2/21_Protocols.html)的方法,通过增加对协议的遵循来扩展一个已存在的类型。这些协议也可以包含关联类型。 +你可以用[使用扩展来添加协议兼容性](../chapter2/21_Protocols.html)的方法,通过增加对协议的遵循来扩展一个已存在的类型。这些协议也可以包含关联类型。 Swift’s Array type already provides an append method, a count property, and a subscript with an Int index to retrieve its elements. These three capabilities match the requirements of the Container protocol. This means that you can extend Array to conform to the Container protocol simply by declaring that Array adopts the protocol. You do this with an empty extension, as described in Declaring Protocol Adoption with an Extension: @@ -557,7 +564,7 @@ extension Array: Container {} Array’s existing append method and subscript enable Swift to infer the appropriate type to use for ItemType, just as for the generic Stack type above. After defining this extension, you can use any Array as a Container. -数组中存在的append方法和下标索引方法使Swift可以推断出ItemType的实际类型,像上边的泛型版`Stack`一样。当定义了这个扩展之后,你可以用任何数组作为容器。 +数组中存在的append方法和下标索引方法使Swift可以推断出ItemType的实际类型,像上面的泛型版`Stack`一样。当定义了这个扩展之后,你可以用任何数组作为容器。 #Where Clauses #Where从句 @@ -572,7 +579,7 @@ It can also be useful to define requirements for associated types. You do this b The example below defines a generic function called allItemsMatch, which checks to see if two Container instances contain the same items in the same order. The function returns a Boolean value of true if all items match and a value of false if they do not. -下边的例子定义了一个泛型函数`allItemsMatch`,用于判断两个`Container`实例是否包含相同的元素并具有相同的顺序。如果所有元素满足条件,函数返回true,否则返回false。 +下面的例子定义了一个泛型函数`allItemsMatch`,用于判断两个`Container`实例是否包含相同的元素并具有相同的顺序。如果所有元素满足条件,函数返回true,否则返回false。 The two containers to be checked do not have to be the same type of container (although they can be), but they do have to hold the same type of items. This requirement is expressed through a combination of type constraints and where clauses: @@ -677,4 +684,4 @@ if allItemsMatch(stackOfStrings, arrayOfStrings) { The example above creates a Stack instance to store String values, and pushes three strings onto the stack. The example also creates an Array instance initialized with an array literal containing the same three strings as the stack. Even though the stack and the array are of a different type, they both conform to the Container protocol, and both contain the same type of values. You can therefore call the allItemsMatch function with these two containers as its arguments. In the example above, the allItemsMatch function correctly reports that all of the items in the two containers match. -上边的例子中创建了一个`Stack`实例存储字符串值,然后`push`三个字符串到堆栈中。同样创建一个数组,并在初始化时加入了三个和堆栈中的元素相同的字符串。尽管堆栈和数组是不同的数据类型,但是他们都遵循Container协议,并且包含相同数据类型,相同的数据值。所以你可以调用`allItemsMatch`去比较两者。在上边的例子中,`allItemsMatch`函数正确地报告了两者包含的所有元素相匹配。 +上面的例子中创建了一个`Stack`实例存储字符串值,然后`push`三个字符串到堆栈中。同样创建一个数组,并在初始化时加入了三个和堆栈中的元素相同的字符串。尽管堆栈和数组是不同的数据类型,但是他们都遵循Container协议,并且包含相同数据类型,相同的数据值。所以你可以调用`allItemsMatch`去比较两者。在上面的例子中,`allItemsMatch`函数正确地报告了两者包含的所有元素相匹配。 From 2cab212a1fa155f62d448da17ffc7e072384931c Mon Sep 17 00:00:00 2001 From: Neekey Date: Sun, 6 Jul 2014 18:10:41 +0800 Subject: [PATCH 249/261] =?UTF-8?q?=E4=BC=98=E5=8C=96=20=E6=B3=9B=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/22_Generics.md | 44 ++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/chapter2/22_Generics.md b/src/chapter2/22_Generics.md index f2ca75e..66e1a86 100644 --- a/src/chapter2/22_Generics.md +++ b/src/chapter2/22_Generics.md @@ -284,7 +284,7 @@ Here’s how stackOfStrings looks after pushing these four values on to the stac Popping a value from the stack returns and removes the top value, "cuatro": -下图是如何从栈中pop一个值的过程,移除栈最顶上结果,“cuatro”,并返回其值: +下图是如何从栈中pop一个值的过程,移除栈最顶上结果,“cuatro”,并返回其值: ``` let fromTheTop = stackOfStrings.pop() @@ -326,7 +326,7 @@ You can define your own type constraints when creating custom generic types, and You write type constraints by placing a single class or protocol constraint after a type parameter’s name, separated by a colon, as part of the type parameter list. The basic syntax for type constraints on a generic function is shown below (although the syntax is the same for generic types): -你可以通过在类型参数名称的后边以冒号分割,加上类型参数约束。基础的泛型函数的类型约束语法如下(同样的,这个语法也适用于泛型类型): +你可以通过在类型参数名称的后边以冒号分割,加上类型参数约束。基本的泛型函数的类型约束语法如下(同样的,这个语法也适用于泛型类型): ``` func someFunction(someT: T, someU: U) { @@ -336,7 +336,7 @@ func someFunction(someT: T, someU: U) { The hypothetical function above has two type parameters. The first type parameter, T, has a type constraint that requires T to be a subclass of SomeClass. The second type parameter, U, has a type constraint that requires U to conform to the protocol SomeProtocol. -上面函数有两个参数。参数一类型参数为T,需要T必须是`SomeClass`子类;第二个参数类型为U,需要U必须遵循`SomeClass`协议。 +上面的函数有两个参数。第一个参数为类型参数为T,并要求T必须是`SomeClass`的子类;第二个参数为参数类型U,且它必须遵循`SomeClass`协议。 ##Type Constraints in Action ##类型约束实践 @@ -374,7 +374,7 @@ The principle of finding the index of a value in an array isn’t useful only fo Here’s how you might expect a generic version of findStringIndex, called findIndex, to be written. Note that the return type of this function is still Int?, because the function returns an optional index number, not an optional value from the array. Be warned, though—this function does not compile, for reasons explained after the example: -下面就是`findStringIndex`的泛型版本`findIndex`。注意到函数的返回结果仍然是Int?,这是因为这个函数返回匹配到的数组索引值,而不是数组中的值。需要提醒的是,这个函数不会编译,原因后边会说明: +下面就是`findStringIndex`的泛型版本`findIndex`。注意到函数的返回结果仍然是Int?,这是因为这个函数返回匹配到的数组索引值,而不是数组中的值。需要提醒的是,这个函数无法通过编译,原因后边会说明: ``` func findIndex(array: T[], valueToFind: T) -> Int? { @@ -389,15 +389,15 @@ func findIndex(array: T[], valueToFind: T) -> Int? { This function does not compile as written above. The problem lies with the equality check, “if value == valueToFind”. Not every type in Swift can be compared with the equal to operator (==). If you create your own class or structure to represent a complex data model, for example, then the meaning of “equal to” for that class or structure is not something that Swift can guess for you. Because of this, it is not possible to guarantee that this code will work for every possible type T, and an appropriate error is reported when you try to compile the code. -这个函数按照上面的写法不会编译。原因是等价检查部分“if value == valueToFind”。 不是所有的泛型类型都可以用`==`进行比较。如果你创建了自己的类或者结构代表一个复杂的数据模型,那么Swift语言没法猜测如何对这个类或者结构进行是否相等的比较。正因为如此,这个代码无法保证可以作用于所有可能的类型T,并且当你尝试编译这段代码时,编译器会给抛出错误指出这个问题。 +这个函数按照上面的写法无法编译。原因是等价检查部分“if value == valueToFind”。 因为不是所有的泛型类型都可以用操作符(==)进行比较。如果你创建了自己的类或者结构来表示一个复杂的数据模型,那么Swift语言没法猜测如何对这个类或者结构进行是否相等的比较。正因为如此,这个代码无法保证可以用于所有的类型T,当你尝试编译这段代码时,编译器会抛出错误指出这个问题。 All is not lost, however. The Swift standard library defines a protocol called Equatable, which requires any conforming type to implement the equal to operator (==) and the not equal to operator (!=) to compare any two values of that type. All of Swift’s standard types automatically support the Equatable protocol. -不过还是有解决方法。Swift 标准库中定义了一个Equatable协议,该协议要求任何遵循它的类型需要实现相等符(==)和不等符(!=)来对任何两个该类型的值进行比较。所有的 Swift 标准类型都自动支持Equatable协议。 +当然,还是有解决方案。Swift 标准库中定义了一个Equatable协议,该协议要求任何遵循它的类型需要都实现相等符(==)和不等符(!=)来对任何两个该类型的值进行比较。所有的 Swift 标准类型都自动支持Equatable协议。 Any type that is Equatable can be used safely with the findIndex function, because it is guaranteed to support the equal to operator. To express this fact, you write a type constraint of Equatable as part of the type parameter’s definition when you define the function: -任何Equatable类型都可以安全的使用在findIndex函数中,它保证可以支持相等操作。为了说明这个事实,在定义函数时,可以添加一个Equatable类型约束作为类型参数定义的一部分: +任何Equatable类型都可以安全地使用在findIndex函数中,它保证可以支持相等操作。为了说明这个事实,在定义函数时,可以添加一个Equatable类型约束作为类型参数定义的一部分: ``` func findIndex(array: T[], valueToFind: T) -> Int? { @@ -416,7 +416,7 @@ The single type parameter for findIndex is written as T: Equatable, which means The findIndex function now compiles successfully and can be used with any type that is Equatable, such as Double or String: -`findIndex`类型现在可以成功编译,并且可以用于任意实现了`Equatable`协议的类型,比如`Double`e 或者`String`: +`findIndex`类型现在可以成功通过编译,并且可以适用于任何实现了`Equatable`协议的类型,比如`Double`e 或者`String`: ``` let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3) @@ -462,19 +462,19 @@ The Container protocol defines three required capabilities that any container mu This protocol doesn’t specify how the items in the container should be stored or what type they are allowed to be. The protocol only specifies the three bits of functionality that any type must provide in order to be considered a Container. A conforming type can provide additional functionality, as long as it satisfies these three requirements. -这个协议没有指定容器中成员该如何存储,也没有指定他们的数据类型。协议只是指定了任何遵循Container类型所必须具备的三个功能点。只要满足这三个条件,遵循协议的类型也可以添加额外的功能。 +这个协议没有指定容器中成员该如何存储,也没有指定他们的数据类型。协议只是指定了任何遵循Container协议的类型必须具备的三个功能点。只要满足这三个条件,遵循协议的类型也可以添加额外的功能。 Any type that conforms to the Container protocol must be able to specify the type of values it stores. Specifically, it must ensure that only items of the right type are added to the container, and it must be clear about the type of the items returned by its subscript. -任何遵循Container协议的类型必须能指定所存储的数据值类型。必须保证只有正确数据类型可以存储到Container中,而且对于通过其下标返回结果值的数据类型也必须是明确的。 +任何遵循Container协议的类型必须能指定所存储的数据值类型。必须保证只有正确数据类型可以被存储到Container中,而且通过其下标返回的结果值的数据类型也必须是明确的。 To define these requirements, the Container protocol needs a way to refer to the type of the elements that a container will hold, without knowing what that type is for a specific container. The Container protocol needs to specify that any value passed to the append method must have the same type as the container’s element type, and that the value returned by the container’s subscript will be of the same type as the container’s element type. -为了能定义这些要求,需要有一种方式,能在Container协议不知道某个具体的容器实际会存储的数据类型的前提下,还能引用到那个数据类型。Container协议需要能指明,任何通过append方法添加至容器的值的数据类型和容器中的元素的数据类型相同,并且通过容器下标返回的值的类型和容器中的元素的类型也是是相同的。 +为了能定义这些要求,需要有一种方式,能在Container协议不知道某个具体的容器实际会存储的数据类型的前提下,还能引用到那个数据类型。Container协议需要能指明,任何通过append方法添加至容器的值的数据类型和容器中的元素的数据类型相同,并且通过容器下标返回的值的类型和容器中的元素的类型也是相同的。 To achieve this, the Container protocol declares an associated type called ItemType, written as typealias ItemType. The protocol does not define what ItemType is an alias for—that information is left for any conforming type to provide. Nonetheless, the ItemType alias provides a way to refer to the type of the items in a Container, and to define a type for use with the append method and subscript, to ensure that the expected behavior of any Container is enforced. -为了达到这个目的,container协议声明了一个相关类型ItemType,记为`typealias ItemType`。该协议不会定义ItemType是谁的别名,这个信息留给任何遵循协议的类型来提供。尽管如此,ItemType别名提供了一种方法来引用容器中的元素类型,并定义一种使用在append方法和下标中的类型,从而保证任何Container期望的行为都能得到强制实施。 +为了达到这个目的,container协议声明了一个相关类型ItemType,记为`typealias ItemType`。该协议不会定义ItemType是谁的别名,这个信息留给任何遵循协议的类型来提供。尽管如此,ItemType别名提供了一种方法来引用容器中的元素类型,并定义一种使用在append方法和下标中的类型,从而保证任何Container期望的行为都能得到贯彻。 Here’s a version of the non-generic IntStack type from earlier, adapted to conform to the Container protocol: @@ -506,7 +506,7 @@ struct IntStack: Container { The IntStack type implements all three of the Container protocol’s requirements, and in each case wraps part of the IntStack type’s existing functionality to satisfy these requirements. -`IntStack`类型实现了`Container`协议的所有需求,在每一个要求中,都通过包装IntStack类型现有的功能来满足。 +`IntStack`类型实现了`Container`协议的所有要求,对于每一个要求,IntStack类型都通过包装现有的功能来满足。 Moreover, IntStack specifies that for this implementation of Container, the appropriate ItemType to use is a type of Int. The definition of typealias ItemType = Int turns the abstract type of ItemType into a concrete type of Int for this implementation of the Container protocol. @@ -514,7 +514,7 @@ Moreover, IntStack specifies that for this implementation of Container, the appr Thanks to Swift’s type inference, you don’t actually need to declare a concrete ItemType of Int as part of the definition of IntStack. Because IntStack conforms to all of the requirements of the Container protocol, Swift can infer the appropriate ItemType to use, simply by looking at the type of the append method’s item parameter and the return type of the subscript. Indeed, if you delete the typealias ItemType = Int line from the code above, everything still works, because it is clear what type should be used for ItemType. -感谢Swift的类型推理机制,你实际上不用在IntStack定义部分声明具体的Int类型的ItemType。由于IntStack满足Container协议的所有要求,只需通过简单的查找append方法中的item参数类型和下标返回的类型,Swift就可以推断出合适的ItemType来使用。实际上,如果你删除了上述代码中的 typealias ItemType = Int,仍可以正常运行,因为它清楚的知道ItemType使用的是何种类型。 +实际上,借助于Swift的类型推理机制,你不用在IntStack定义部分声明具体的Int类型的ItemType。由于IntStack满足Container协议的所有要求,只需通过简单的查找append方法中的item参数类型和下标返回的类型,Swift就可以推断出合适的ItemType来使用。实际上,如果你删除了上述代码中的 typealias ItemType = Int,这段代码仍可以正常运行,因为它清楚的知道ItemType使用的是何种类型。 You can also make the generic Stack type conform to the Container protocol: @@ -552,7 +552,7 @@ This time, the placeholder type parameter T is used as the type of the append me You can extend an existing type to add conformance to a protocol, as described in Adding Protocol Conformance with an Extension. This includes a protocol with an associated type. -你可以用[使用扩展来添加协议兼容性](../chapter2/21_Protocols.html)的方法,通过增加对协议的遵循来扩展一个已存在的类型。这些协议也可以包含关联类型。 +你可以用[使用扩展来添加协议兼容性](../chapter2/21_Protocols.html)的方法,通过增加遵循的对协议来扩展一个已存在的类型。这些协议也可以包含关联类型。 Swift’s Array type already provides an append method, a count property, and a subscript with an Int index to retrieve its elements. These three capabilities match the requirements of the Container protocol. This means that you can extend Array to conform to the Container protocol simply by declaring that Array adopts the protocol. You do this with an empty extension, as described in Declaring Protocol Adoption with an Extension: @@ -575,7 +575,7 @@ Type constraints, as described in Type Constraints, enable you to define require It can also be useful to define requirements for associated types. You do this by defining where clauses as part of a type parameter list. A where clause enables you to require that an associated type conforms to a certain protocol, and/or that certain type parameters and associated types be the same. You write a where clause by placing the where keyword immediately after the list of type parameters, followed by one or more constraints for associated types, and/or one or more equality relationships between types and associated types. -而为关联类型添加满足条件也是非常有用的。你可以通过定义where从句作为类型参数的一部分来添加要求。通过where语句能要求一个关联类型遵循一个特定的协议,以及(或)指定某个特定的类型参数和关联类型必须相同。where从句通过在类型参数后面添加where关键词开始,其后跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型的等于关系。 +而为关联类型添加要求也是非常有用的。你可以通过定义where从句作为类型参数的一部分来添加要求。通过where从句能要求一个关联类型遵循一个特定的协议,以及(或)指定某个特定的类型参数和关联类型必须相同。where从句以在类型参数后面添加where关键词开始,其后跟着一个或者多个针对关联类型的约束,以及(或)一个或多个类型和关联类型的等于关系而结束。 The example below defines a generic function called allItemsMatch, which checks to see if two Container instances contain the same items in the same order. The function returns a Boolean value of true if all items match and a value of false if they do not. @@ -583,7 +583,7 @@ The example below defines a generic function called allItemsMatch, which checks The two containers to be checked do not have to be the same type of container (although they can be), but they do have to hold the same type of items. This requirement is expressed through a combination of type constraints and where clauses: -需要检查的两个容器,不需要是相同类型的容器(当然也可以是相同的),但是他们的元素必须相同。这个需求通过一个类型约束和where从句相结合来表示: +需要检查的两个容器,不需要是相同类型的容器(当然也可以是相同的),但是他们的元素必须相同。这个要求通过一个类型约束和where从句相结合来表达: ``` func allItemsMatch @@ -605,7 +605,7 @@ func allItemsMatch Date: Sun, 6 Jul 2014 23:33:00 +0800 Subject: [PATCH 250/261] 23_Advanced_Operators reviewed 23_Advanced_Operators reviewed --- src/chapter2/23_Advanced_Operators.md | 44 +++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index a5cf5f9..e57aaf6 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -2,12 +2,27 @@ 除了《基础操作符》里讲到的操作符,Swift还提供了一些高级操作符,用以完成更复杂的数值运算。比如位运算和移位操作符,其语法同C和Objective-C类似。 +> From 周源: +移位: 我读的时候, 感觉位移更顺口一点 + 和C语言的算术操作符不同,Swift默认不支持溢出运算。数值溢出会被捕获并报错。但是,Swift提供了另一套支持溢出运算的操作符,比如可溢出加操作符(&+),可溢出操作符都以&作为前缀。 +> From 周源: +&+ -> (&+) +So +& -> (&)? + 在自定义结构体、类或者枚举类型中,可以重载Swift操作符。通过操作符重载,可以简单地实现操作符的重定义。 +> From 周源: +我理解的 "简单的实现" 有二义性, 可表示 实现简单 和 简单实现, +这里作者的意思应该是实现简单, 我觉得 方便的实现 也可以表达作者的意思, 你怎么看? + Swift允许用户自定义操作符,并且可定制这些操作符的优先级和结合性。 +> From 周源: +这一段原文较长, 省略了部分翻译, 按照会长的意思...... + ## 位操作符 @@ -87,6 +102,8 @@ let outputBits = firstBits ^ otherBits // 等于 00010001 #### 无符号移位操作 +> From 周源: +移位 -> 位移? 无符号移位的规则如下: 1. 已有的位向左或向右移动指定的位数。 @@ -149,12 +166,19 @@ let blueComponent = pink & 0x0000FF // blueComponent是0x99, 即153 负数的编码方式称为二进制补码表示。这种表示方式看起来很奇怪,但它有几个优点。 +> From 周源: +The encoding for negative numbers is known as a two’s complement representation. +负数的编码方式称为二进制补码表示 -> 负数的编码方式用二进制补码表示? + 首先,对全部8个比特位(包括符号位)做标准的二进制加法就可以完成-1 加 -4 的操作,加法过程中丢弃超出的比特位。 ![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSignedAddition_2x.png) 第二,使用二进制补码表示方式,我们可以和正数一样对负数进行按位左移或右移,同样也是左移1位时乘于2,右移1位时除于2。但是,对有符号整型的右移有一个特别的要求: +> From 周源: +使用二进制补码表示方式 -> 使用二进制补码? + + 有符号和无符号整型按位右移时规则相同,但有符号整型移位后出现的空位使用符号位来填充,而不是0。 ![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSigned_2x.png) @@ -294,7 +318,7 @@ let y = x &/ 0 Swift操作符的优先级和结合性的完整规则,请看表达式。 -> 注意: +> 注意: > > Swift操作符的优先级和结合性的规则跟C系语言不太一样,相对于C语言和Objective-C更加简单且保守。所以在移植已有代码到Swift时,注意确认操作数的计算顺序。 @@ -370,6 +394,9 @@ let alsoPositive = -negative 加法运算之前定义过了,这里无需重新定义。加赋操作符函数使用已有的加法运算将左值加上右值: +> From 周源 +> 加赋操作符函数使用已有的加法运算将左值加上右值: -> 加法操作符... ? + ``` var original = Vector2D(x: 1.0, y: 2.0) let vectorToAdd = Vector2D(x: 3.0, y: 4.0) @@ -388,6 +415,9 @@ original += vectorToAdd 这个自加操作符函数使用了前面定义过的加赋运算,将自己加上一个值为 (1.0,1.0) 的对象然后将返回值赋给自己。 +> From 周源 +> 加赋运算 -> 加法运算... ? + ``` var toIncrement = Vector2D(x: 3.0, y: 4.0) let afterIncrement = ++toIncrement @@ -395,7 +425,7 @@ let afterIncrement = ++toIncrement // afterIncrement 也等于 (4.0, 5.0) ``` -> 注意: +> 注意: > > 默认的赋值符(=)是不可重载的。只有复合赋值符可以重载。条件操作符 a?b:c 也是不可重载的。 @@ -431,6 +461,9 @@ println("这两个向量相等") 除了标准的操作符,你还可以声明一些个性的操作符,但自定义操作符只能使用这些字符`/ = - + * % < >!& | ^ . ~` +> From 周源: +> 个性的操作符 -> 自定义的操作符 ? + 新的操作符需要在全局域使用`operator`关键字声明,可以声明为前置,中置或后置的。 ``` @@ -439,6 +472,10 @@ operator prefix +++ {} 这段代码定义了一个新的前置操作符+++,此前Swift并不存在这个操作符,此处针对`Vector2D` 对象的这个操作符具有个性化的含义。+++被定义为双自增操作符,它使用之前定义的加赋运算将自已加上自己然后返回。 +> From 周源: +> 个性化的含义 ? + + ``` @prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D { vector += vector @@ -476,6 +513,9 @@ let plusMinusVector = firstVector +- secondVector // plusMinusVector 是 Vector2D实例,等于 (4.0, -2.0) ``` +> From 周源: +> plusMinusVector 是 Vector2D实例 -> plusMinusVector 是 Vector2D的实例 ? + 这个操作符把两个向量的x相加, y相减。因为它实际上属于加减运算,所以让它保持了和加减法一样的结合性和优先级(左结合,优先级为140)。查阅完整的Swift默认优先级和结合性的设置,请移步[表达式](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-XID_655). From 4afd1c3b69991c09797bddf25f69fa8b0ddd1c10 Mon Sep 17 00:00:00 2001 From: "siemen.liuxm" Date: Tue, 8 Jul 2014 18:31:03 +0800 Subject: [PATCH 251/261] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=BF=BB=E8=AF=91?= =?UTF-8?q?=E8=BF=9B=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 04465d2..c7f366a 100644 --- a/README.md +++ b/README.md @@ -9,42 +9,42 @@ The Swift Programming Language 中文化项目 * 欢迎使用 Swift * Swift 介绍 [已完成 by 飞长] [review by 容隽] - * Swift 初见 [认领 by 容隽] [review by 闻西] + * Swift 初见 [已完成 by 容隽] [review by 闻西] * Swift 教程 * 基础部分 [已完成 by 琼雪] [review by 栖邀] - * 基本操作符 [认领 by 冰浠] [review by 姜天意] + * 基本操作符 [已完成 by 冰浠] [review by 姜天意] * 字符串和字符 [已完成 by 筱谷] [review by 尘境] * 集合类型 [已完成 by 尘境] - * 控制流 [认领 by 墨昕] + * 控制流 [已完成 by 墨昕] * 函数 [已完成 by 紫溪] [review by 飞长] - * 闭包 [认领 by 闻西] [review by 米尔] + * 闭包 [已完成 by 闻西] [review by 米尔] * 枚举 [已完成 by 灵吾] [review by 筱谷] * 类和结构体 [已完成 by 晓毒] - * 属性 [认领 by 周源] [review by 林晚] + * 属性 [已完成 by 周源] [review by 林晚] * 方法 [已完成 by 米尔] [review by 灵吾] * 下标 [已完成 by 递归] [review by 琼雪] * 继承 [已完成 by 晗光] [review by 递归] - * 构造过程 [认领 by 刘康] [review by 晓毒] - * 析构过程 [认领 by 许诺] [review by 祁涛] - * 自动引用计数 [认领 by 韩国兴/MK] [review by 孟志昂] - * 可选链 [认领 by 重鱼] [review by 玩家] - * 类型转换 [认领 by 孟志昂] [review by 耿霄] - * 嵌套类型 [认领 by 祁涛] [review by 袁鹏] + * 构造过程 [已完成 by 刘康] [review by 晓毒] + * 析构过程 [已完成 by 许诺] [review by 祁涛] + * 自动引用计数 [已完成 by 韩国兴/MK] [review by 孟志昂] + * 可选链 [已完成 by 重鱼] [review by 玩家] + * 类型转换 [已完成 by 孟志昂] [review by 耿霄] + * 嵌套类型 [已完成 by 祁涛] [review by 袁鹏] * 扩展 [已完成 by 袁鹏] [review by 姜天意] - * 协议 [认领 by 姜天意] [review by 重鱼] + * 协议 [已完成 by 姜天意] [review by 重鱼] * 泛型 [已完成 by 晴时] [review by 隐若] * 高级操作符 [认领 by 林晚] [review by 周源] * 语言参考 - * 关于语言参考 [认领 by 筱强] [review by 懂象] - * 词法结构 [认领 by 筱强] [review by 懂象] - * 类型 [认领 by 兰梦] [review by 筱强] - * 表达式 [认领 by 懂象] [review by 兰梦] - * 语句 [认领 by 玩家] - * 声明 [认领 by 墨峰] [review by 龙刚] - * 属性 [认领 by 隐若] [review by 姜天意] + * 关于语言参考 [已完成 by 筱强] [review by 懂象] + * 词法结构 [已完成 by 筱强] [review by 懂象] + * 类型 [已完成 by 兰梦] [review by 筱强] + * 表达式 [已完成 by 懂象] [review by 兰梦] + * 语句 [已完成 by 玩家] + * 声明 [已完成 by 墨峰] [review by 龙刚] + * 属性 [已完成 by 隐若] [review by 姜天意] * 模式 [已完成 by 栖邀] [review by 紫溪] - * 泛型参数 [认领 by 龙刚] [review by 墨峰] - * 语法总结 [认领 by 无独] [review by 晗光] + * 泛型参数 [已完成 by 龙刚] [review by 墨峰] + * 语法总结 [已完成 by 无独] [review by 晗光] # 分工 * 西溪分会 10人 第一部分1-2章 第二部分1-8章 From aa6b407527ab87898dd84483f8a64b3f6535b305 Mon Sep 17 00:00:00 2001 From: tjyuanpeng Date: Thu, 10 Jul 2014 20:45:46 +0800 Subject: [PATCH 252/261] Update 20_Extensions.md --- src/chapter2/20_Extensions.md | 114 ---------------------------------- 1 file changed, 114 deletions(-) diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md index fe6a95a..dcca041 100644 --- a/src/chapter2/20_Extensions.md +++ b/src/chapter2/20_Extensions.md @@ -1,20 +1,7 @@ -# Extensions - # 扩展(Extensions) - -Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) - 扩展为已有的类,结构,枚举添加新的功能。其中包括扩展没有代码访问权限的类型(即追溯建模,retroactive modeling)。扩展和 Objective-C 当中的分类(category)很相似。(与 Objective-C 中的分类不同的是,Swift 的扩展没有名字) -Extensions in Swift can: -- Add computed properties and computed static properties -- Define instance methods and type methods -- Provide new initializers -- Define subscripts -- Define and use new nested types -- Make an existing type conform to a protocol - Swift 中的扩展可以: - 增加计算属性和静态计算属性 - 定义实例方法和类型方法 @@ -23,21 +10,11 @@ Swift 中的扩展可以: - 定义和使用新的嵌套类型 - 将已有的类型转换为符合某一个协议 -> Note -> -> If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined. - - > 提示 > > 如果定义一个扩展用来在已有的类型上增加新的功能,那么新功能会应用在所有已经存在的实例上,即使是在扩展被定义之前实例化的。 - -## Extension Syntax - ## 扩展的语法 -Declare extensions with the extension keyword: - 使用 ``extension`` 关键字来声明扩展: ``` @@ -46,8 +23,6 @@ extension SomeType { } ``` -An extension can extend an existing type to make it adopt one or more protocols. Where this is the case, the protocol names are written in exactly the same way as for a class or structure: - 一个扩展可以扩展一个已有的类型,使它能适配一个或多个的协议(protocol)。如果是这种情况的话,协议的命名方式应该与类和结构体的命名方式完全一致。 ``` @@ -56,17 +31,10 @@ extension SomeType: SomeProtocol, AnotherProtocol { } ``` -Adding protocol conformance in this way is described in Adding Protocol Conformance with an Extension. - 这种增加协议一致性(protocol conformance)的方式在 [通过扩展增加协议一致性](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_355) 一文中有记述。 - -## Computed Properties - ## 计算属性(Computed Properties) -Extensions can add computed instance properties and computed type properties to existing types. This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units: - 扩展可以为已有的类型增加实例计算属性和类型计算属性。这个例子向 Swift 内建类型 ``Double`` 添加五个实例计算类型,用来提供转换为距离单位的基本功能: ``` @@ -85,20 +53,12 @@ println("Three feet is \(threeFeet) meters") // prints "Three feet is 0.914399970739201 meters" ``` -These computed properties express that a Double value should be considered as a certain unit of length. Although they are implemented as computed properties, the names of these properties can be appended to a floating-point literal value with dot syntax, as a way to use that literal value to perform distance conversions. - 这些计算属性表达的是一个 ``Double`` 类型的值是某种长度单位下的值。尽管是计算属性,但他们仍然可以接在一个带有 dot 语法的字面值的后面,用来将字面值转换成距离。 -In this example, a Double value of 1.0 is considered to represent “one meter”. This is why the m computed property returns self—the expression 1.m is considered to calculate a Double value of 1.0. - 在上述的例子中,``Double`` 类型的 ``1.0`` 代表 “一米” 。这是为什么计算属性 ``m`` 仅仅返回 ``self`` ——表达式 ``1.m`` 最终结果是 ``Double`` 类型的值 ``1.0`` 。 -Other units require some conversion to be expressed as a value measured in meters. One kilometer is the same as 1,000 meters, so the km computed property multiplies the value by 1_000.00 to convert into a number expressed in meters. Similarly, there are 3.28024 feet in a meter, and so the ft computed property divides the underlying Double value by 3.28024, to convert it from feet to meters. - 其他单位转换为以米为单位的数值需要进行一些转换。1千米等于1,000米,所以计算属性 ``km`` 要把数值转换成以米为单位,需要把值乘以 ''1_000.00''。同样,1英尺等于 ''3.28084'' 米,所以计算属性 ''ft'' 需要把值除以 ''3.28024'' 才能把英尺转换成米。 -These properties are read-only computed properties, and so they are expressed without the get keyword, for brevity. Their return value is of type Double, and can be used within mathematical calculations wherever a Double is accepted: - 因为这些都是只读的计算属性,所以为了简便起见,不需要关键字 ''keyword'' 进行表示。他们的返回值都是 ``Double`` 类型的,所以可以用在所有可以接受 ``Double`` 类型的数学计算中: ``` @@ -107,42 +67,21 @@ println("A marathon is \(aMarathon) meters long") // prints "A marathon is 42195.0 meters long" ``` -> Note -> -> Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties. - - > 提示 > > 扩展可以添加新的计算属性,但是不能添加存储属性,也不能向已有属性添加属性观察器(property observer)。 - -## Initializers - ## 构造器(Initializers) -Extensions can add new initializers to existing types. This enables you to extend other types to accept your own custom types as initializer parameters, or to provide additional initialization options that were not included as part of the type’s original implementation. - 扩展能向已有类型添加新的构造器。这允许你用自己定义的类型作为构造器参数扩展其他的类型,或者提供原始实现没有提供的额外的初始化选项 -Extensions can add new convenience initializers to a class, but they cannot add new designated initializers or deinitializers to a class. Designated initializers and deinitializers must always be provided by the original class implementation. - 扩展能向类添加新的简便构造器,但是不能添加新的指定构造器或者析构器。指定构造器和析构器必须在类的原始实现中提供。 - -> Note -> -> If you use an extension to add an initializer to a value type that provides default values for all of its stored properties and does not define any custom initializers, you can call the default initializer and memberwise initializer for that value type from within your extension’s initializer. -> This would not be the case if you had written the initializer as part of the value type’s original implementation, as described in Initializer Delegation for Value Types. - - > 提示 > > 如果使用扩展向一个值类型添加构造器,该构造器向所有存储属性提供默认值并且未定义任何其他的自定义构造器,你可以调用默认的构造和成员构造器来为你扩展的构造器当中的值类型赋值。 > 正如 [构造器对值类型的构造委托](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_281) 一文所说的那样,如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 -The example below defines a custom Rect structure to represent a geometric rectangle. The example also defines two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties: - 在下面的例子里,定义了一个用于描述几何矩形的结构体 ``Rect`` 。同时定义了两个辅助性结构体 ``Size``,``Point``,两个结构体当中的属性默认值都为 ``0.0``: ``` @@ -158,8 +97,6 @@ struct Rect { } ``` -Because the Rect structure provides default values for all of its properties, it receives a default initializer and a memberwise initializer automatically, as described in Default Initializers. These initializers can be used to create new Rect instances: - 因为 结构体 ``Rect`` 为所有的属性都提供了默认值,正如默认构造器一节所说的,它可以自动接受默认构造器和成员构造器。这些构造器可以用来创建新的 ``Rect`` 实例: ``` @@ -168,8 +105,6 @@ let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0)) ``` -You can extend the Rect structure to provide an additional initializer that takes a specific center point and size: - 你可以使用扩展来为结构体 ``Rect`` 额外提供一个以中心点和大小作为参数的构造器: ``` @@ -182,8 +117,6 @@ extension Rect { } ``` -This new initializer starts by calculating an appropriate origin point based on the provided center point and size value. The initializer then calls the structure’s automatic memberwise initializer init(origin:size:), which stores the new origin and size values in the appropriate properties: - 新构造器通过中心点和大小两个参数计算出合适的原点值,然后调用结构体的自动成员构造器 ``init(origin:size:)`` ,把计算出的值存储到合适的属性上: ``` @@ -192,22 +125,14 @@ let centerRect = Rect(center: Point(x: 4.0, y: 4.0), // centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0) ``` -> Note -> -> If you provide a new initializer with an extension, you are still responsible for making sure that each instance is fully initialized once the initializer completes. - > 提示 > > 如果使用扩展来提供新的构造器,那么你仍要确保构造过程中,每一个实例都被完全初始化了。 -## Methods - ## 方法(Methods) -Extensions can add new instance methods and type methods to existing types. The following example adds a new instance method called repetitions to the Int type: - 扩展可以向已有类型添加新的实例方法和类型方法。下面的例子中,向 类型 ``Int`` 中添加了新的实例方法 ``repetitions``: ``` @@ -220,12 +145,8 @@ extension Int { } ``` -The repetitions method takes a single argument of type () -> (), which indicates a function that has no parameters and does not return a value. - ``repetitions`` 方法的参数是 ``() -> ()``,说明参数是一个无参数无返回值的函数 -After defining this extension, you can call the repetitions method on any integer number to perform a task that many number of times: - 扩展被定义之后,你就可以在任何整数上调用 ``repetitions`` 方法,来多次执行某个任务: ``` @@ -237,8 +158,6 @@ After defining this extension, you can call the repetitions method on any intege // Hello! ``` -Use trailing closure syntax to make the call more succinct: - 使用尾随闭包(trailing closure)语法可以使调用更简洁: ``` @@ -250,17 +169,10 @@ Use trailing closure syntax to make the call more succinct: // Goodbye! ``` - -## Mutating Instance Methods - ## 可变实例方法(Mutating Instance Methods) -Instance methods added with an extension can also modify (or mutate) the instance itself. Structure and enumeration methods that modify self or its properties must mark the instance method as mutating, just like mutating methods from an original implementation. - 通过扩展添加的实例方法也可以修改实例本身。结构体和枚举类型的方法中改变 ``self`` 或者其中的属性,必须标记实例的方法为 ``mutating`` ,就像原始实现中的声明变异方法(mutating method)一样。 -The example below adds a new mutating method called square to Swift’s Int type, which squares the original value: - 下面的例子为 Swift 中的 ``Int`` 类型添加了一个新的变异方法 ``square``,用来计算原始值的平方: ``` @@ -274,20 +186,13 @@ someInt.square() // someInt is now 9 ``` - -## Subscripts - ## 下标(Subscripts) -Extensions can add new subscripts to an existing type. This example adds an integer subscript to Swift’s built-in Int type. This subscript [n] returns the decimal digit n places in from the right of the number: - 扩展可以为已有类型添加新的下标。下面的例子为 Swift 中的内建类型 ``Int`` 添加一个整型下标。下标 ``[n]`` 返回 十进制数从右往左第 n 位上的数字: - 123456789[0] returns 9 - 123456789[1] returns 8 -…and so on: - ……以此类推: ``` @@ -310,8 +215,6 @@ extension Int { // returns 7 ``` -If the Int value does not have enough digits for the requested index, the subscript implementation returns 0, as if the number had been padded with zeroes to the left: - 如果该 ``Int`` 值没有足够的位数与请求对应,即下标越界,则下标会返回 ``0`` ,就好像它自动在数字左边补0一样: ``` @@ -321,12 +224,8 @@ If the Int value does not have enough digits for the requested index, the subscr ``` -## Nested Types - ## 嵌套类型(Nested Types) -Extensions can add new nested types to existing classes, structures and enumerations: - 扩展可以向已有的类,结构体和枚举类型添加新的嵌套类型: ``` @@ -348,16 +247,10 @@ extension Character { } ``` -This example adds a new nested enumeration to Character. This enumeration, called Kind, expresses the kind of letter that a particular character represents. Specifically, it expresses whether the character is a vowel or a consonant in a standard Latin script (without taking into account accents or regional variations), or whether it is another kind of character. - 上面的例子为 ``Character`` 添加了新的嵌套枚举。枚举类型的 ``Kind`` 表示一个字符所属的种类。具体来说就是一个字符是拉丁字母的元音,辅音,还是其他种类的字符(不考虑口语和地方变种的情况下)。 -This example also adds a new computed instance property to Character, called kind, which returns the appropriate Kind enumeration member for that character. - 这个例子中同时也为 ``Character`` 添加了一个新的实例计算属性 ``kind``,用来返回字符对应的枚举成员 ``Kind`` -The nested enumeration can now be used with Character values: - 现在嵌套枚举可以在 ``Character`` 上面使用了: ``` @@ -380,16 +273,9 @@ printLetterKinds("Hello") // consonant vowel consonant consonant vowel ``` -This function, printLetterKinds, takes an input String value and iterates over its characters. For each character, it considers the kind computed property for that character, and prints an appropriate description of that kind. The printLetterKinds function can then be called to print the kinds of letters in an entire word, as shown here for the word "Hello". - ``printLetterKinds`` 函数迭代 ``String`` 类型的参数的每一个字母。每次迭代都根据当前字母包含的计算属性 ``kind`` 输出对应的类型描述。这样,``printLetterKinds`` 函数就输出了一个单词内所有字母的类型,正如上面例子中的单词 "word" 一样。 -> Note -> -> character.kind is already known to be of type Character.Kind. Because of this, all of the Character.Kind member values can be written in shorthand form inside the switch statement, such as .Vowel rather than Character.Kind.Vowel. - - > 提示 > > 因为已知 ``character.kind`` 的类型是 ``Character.Kind``,所以所有 ``Character.Kind`` 的成员值都可以在 ``switch`` 语句中使用简写形式,比如使用 ``.Vowel`` 来代替 ``Character.Kind.Vowel``。 From 62b6d7e2b3cfed60b4646a486aa7af720b42a3fa Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Fri, 11 Jul 2014 21:52:52 +0800 Subject: [PATCH 253/261] Update 04_Collection_Types.md --- src/chapter2/04_Collection_Types.md | 167 ++++++++++++++++++---------- 1 file changed, 109 insertions(+), 58 deletions(-) diff --git a/src/chapter2/04_Collection_Types.md b/src/chapter2/04_Collection_Types.md index 3179d1f..c416241 100644 --- a/src/chapter2/04_Collection_Types.md +++ b/src/chapter2/04_Collection_Types.md @@ -3,11 +3,11 @@ Swift provides two *collection types*, known as arrays and dictionaries, for storing collections of values. Arrays store ordered lists of values of the same type. Dictionaries store unordered collections of values of the same type, which can be referenced and looked up through a unique identifier (also known as a *key*). -Swift提供了两种*集合类型* 来存储数据集合,分别是数组(arrays)和词典(dictionaries)。数组用来存储有序的相同类型数据的列表。字典用来存储无序的相同类型的数据的集合,这些数据可以通过一个唯一的标识符(称为*键*)来引用和查找。 +Swift提供了两种*集合类型* 来存储数据集合,分别是数组(arrays)和字典(dictionaries)。数组用来存储有序的相同类型数据的列表。字典用来存储无序的相同类型数据的集合,这些数据可以通过唯一的标识符(称为*键*)引用和查找。 Arrays and dictionaries in Swift are always clear about the types of values and keys that they can store. This means that you cannot insert a value of the wrong type into an array or dictionary by mistake. It also means you can be confident about the types of values you will retrieve from an array or dictionary. Swift’s use of explicitly typed collections ensures that your code is always clear about the types of values it can work with and enables you to catch any type mismatches early in your code’s development. -在Swift中,数组和词典能够存储的键值类型一直是很明确的。这意味着我们不能错误地把类型不正确的数据插入到一个数组或词典中。这也意味着我们能够清楚的知道从一个数组或词典中获取到的数据的类型。Swift的显式类型的集合使得我们清楚代码中能够处理哪种类型的数据,并使得我们可以更早的在代码开发过程中发现任何类型错误。 +在Swift中,数组和字典可以存储的键值类型一直是很明确的【todo:总是明确的】。这意味着我们不能错误地把类型不正确的数据插入到一个数组或字典中【todo:这意味着不会把错误类型的值意外地插入到数组或字典中】。这也意味着我们可以清楚的知道从数组或字典中获取的数据类型。Swift的显式类型的集合使得我们清楚代码中可以处理哪种类型的数据,并使得我们可以更早的在代码开发过程中发现任何类型错误【todo:Swift 使用显示类型集合,这确保了代码中可以处理的数据类型是明确的,并让我们可以提前发现开发中得任何类型错误】。 >NOTE @@ -15,7 +15,7 @@ Arrays and dictionaries in Swift are always clear about the types of values and >注意 ->Swift的`Array`类型在赋值给常量和变量,还有传入函数和方法时与其他类型有所不同。获取更多信息请参见[Mutability of Collections](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/04_Collection_Types.md#mutability-of-collections)and[AssignmentCopy Behavior for Collection Types]()这两个章节。 +>Swift的`Array`类型在赋值给常量、变量或传入函数和方法时与其他类型的行为稍有不同。获取更多信息请参见[Mutability of Collections](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/04_Collection_Types.md#mutability-of-collections)and[AssignmentCopy Behavior for Collection Types]()这两个章节。 ## Arrays @@ -26,20 +26,20 @@ An *array* stores multiple values of the same type in an ordered list. The same Swift arrays are specific about the kinds of values they can store. They differ from Objective-C’s `NSArray` and `NSMutableArray` classes, which can store any kind of object and do not provide any information about the nature of the objects they return. In Swift, the type of values that a particular array can store is always made clear, either through an explicit type annotation, or through type inference, and does not have to be a class type. If you create an array of `Int` values, for example, you can’t insert any value other than `Int` values into that array. Swift arrays are type safe, and are always clear about what they may contain. -Swift数组能够存储的数据类型是确定的。这与Objective-C的类`NSArray`和`NSMutableArray`是不同的,这两个类能够存储任何一种类型的对象,并且不会提供它们返回的对象的任何信息。在Swift中,某个数组能够存储的数据类型是确定的,不是通过显式的类型声明,就是通过类型推断,不需要为class类型。假我们你创建了一个`Int`型的数组,那么就不能插入其他任何非`Int`型的值到这个数组中。Swift数组是类型安全的,并且它们能够包含的值也是明确的。 +Swift数组可以存储的数据类型是确定的。这与Objective-C的类`NSArray`和`NSMutableArray`不同,这两个类可以存储任何类型的对象,并且不会提供它们返回的对象的任何信息。在Swift中,某个数组可以存储的数据类型是确定的,不是通过显式的类型声明,就是通过类型推断,不需要为class类型【todo:可以使用显式的类型声明,也可以使用类型推断,且不必一定是class类型】。假如你创建了一个`Int`型的数组,那么就不能插入其他任何非`Int`型的值到这个数组中【todo:那么就不能在这个数组中插入其他任何非`Int`型的值】。Swift数组是类型安全的,并且它们可以包含的类型是明确的。 ‌ ### Array Type Shorthand Syntax -### 数组类型缩写语法 +### 数组类型简写语法 The type of a Swift array is written in full as `Array`, where `SomeType` is the type that the array is allowed to store. You can also write the type of an array in shorthand form as `SomeType[]`. Although the two forms are functionally identical, the shorthand form is preferred, and is used throughout this guide when referring to the type of an array. -Swift数组的类型的完整写法是`Array`, 这里的`SomeType`指的是数组能够存储的类型。我们也可以把它缩写为`SomeType[]`。这两种形式的数组在功能上完全相同,不过建议使用缩写的形式,本书中提到数组类型时都会以这种形式表示。 +Swift数组类型的完整写法是`Array`, 这里的`SomeType`指的是数组可以存储的类型。我们也可以把它简写为`SomeType[]`。这两种形式的数组在功能上完全相同,不过建议使用缩写的形式,本书中提到数组类型时都会以这种形式表示【todo:尽管这两种形式在功能上完全相同,但更推荐简写形式,且本书中提到数组类型时都会使用这种形式】。 ‌ ### Array Literals ### 数组字面量 You can initialize an array with an *array literal*, which is a shorthand way to write one or more values as an array collection. An array literal is written as a list of values, separated by commas, surrounded by a pair of square brackets: -你可以用*数组字面量*来初始化数组,这是把一个或多个值作为数组集合的缩写方式。数组字面量被写作一个数值列表,由逗号分隔开来,被一对方括号括起来: +你可以用*数组字面量*来初始化数组,这是一个或多个值作为数组集合的简写方式。数组字面量写作一个数值列表,由逗号分隔,被一对方括号括起来: ``` [value 1, value 2, value 3] @@ -47,16 +47,17 @@ You can initialize an array with an *array literal*, which is a shorthand way to The example below creates an array called `shoppingList` to store `String` values: -下面这个例子创建了一个命名为`shoppingList`的数组来存储`String`类型的数据。 +下面这个例子创建了一个名为`shoppingList`的数组来存储`String`类型的数据。 ``` var shoppingList: String[] = ["Eggs", "Milk"] // shoppingList has been initialized with two initial items +// 使用两个初始化项,初始化了shoppingList ``` The `shoppingList` variable is declared as “an array of `String` values”, written as `String[]`. Because this particular array has specified a value type of `String`, it is *only* allowed to store `String` values. Here, the `shoppingList` array is initialized with two `String` values (`"Eggs" `and `"Milk"`), written within an array literal. -变量shoppingList被声明为“一个`String`类型的数组”,写为`String[]`。这个特定数组的类型确定为`String`,因此它*只能*存储`String`类型的数据。这里的`shoppingList`数组被写在一个数组字面量中的两个`String`值(`“Egg”`和`"Milk"`)初始化。 +变量shoppingList声明为“`String`类型的数组”,写为`String[]`。由于这个特定数组指定了`String`的数据类型,因此它*只能*存储`String`类型的数据。这里的`shoppingList`数组被写在一个数组字面量中的两个`String`值(`“Egg”`和`"Milk"`)初始化【todo:这里的`shoppingList`数组由两个`String`值(`"Eggs" `和 `"Milk"`)以数组字面量来初始化】。 >NOTE @@ -64,15 +65,15 @@ The `shoppingList` variable is declared as “an array of `String` values”, wr >注意 ->数组`shoppingList`被声明为变量(通过关键字`var`)而不是常量(通过关键字`let`),因为在下面的例子中,更多的数组项被添加到这个购物列表中。 +>数组`shoppingList`声明为变量(通过关键字`var`)而不是常量(通过关键字`let`),因为在下面的例子中,会有更多的数组项添加到这个购物列表中。 In this case, the array literal contains two `String `values and nothing else. This matches the type of the `shoppingList` variable’s declaration (an array that can only contain `String` values), and so the assignment of the array literal is permitted as a way to initialize `shoppingList` with two initial items. -在这个例子中,该数组字面量只包含了两个`String`值。这和shoppingList变量的声明(只能包含`String`值的数组)是一致的,因此数组字面量的赋值被用来作为一种用两个初始项来初始化shopplingList的方式。 +在这个例子中,该数组字面量只包含了两个`String`值。这和shoppingList变量的声明(只能包含`String`值的数组)是一致的,因此数组字面量的赋值被用来作为一种用两个初始项来初始化shopplingList的方式【todo:因此数组字面量的赋值作为一种方式,可以使用两个初始项初始化`shoppingList`】。 Thanks to Swift’s type inference, you don’t have to write the type of the array if you’re initializing it with an array literal containing values of the same type. The initialization of `shoppingList` could have been written in a shorter form instead: -感谢Swift的类型推断,通过包含相同类型数据的数组字面量,我们不需要去写正在初始化的数组的类型。`shopplingList`的初始化可以缩写为: +感谢Swift的类型推断,通过包含相同类型数据的数组字面量,我们不需要去写正在初始化的数组的类型【todo:多亏了Swift的类型推断,如果使用包含相同类型数据的数组字面量,我们不需要写出数组的类型】。`shopplingList`的初始化可以简写为: ``` var shoppingList = ["Eggs", "Milk"] @@ -80,26 +81,27 @@ var shoppingList = ["Eggs", "Milk"] Because all values in the array literal are of the same type, Swift can infer that `String[]` is the correct type to use for the `shoppingList` variable. -因为数组字面量中所有的值的类型是相同的,Swift能够推断出`String[]`是`shoppingList`变量使用的正确类型。 +因为数组字面量中所有的值的类型是相同的,Swift可以推断出`String[]`是`shoppingList`变量使用的正确类型。 ‌ ### Accessing and Modifying an Array -### 获取和修改数组 +### 访问和修改数组 You access and modify an array through its methods and properties, or by using subscript syntax. -我们可以通过数组的方法、属性或下标语法来访问和修改数组。 +我们可以通过数组的方法、属性或使用下标语法来访问和修改数组。 To find out the number of items in an array, check its read-only `count` property: -可以通过数组的只读属性`count`来获得数组包含的数组项个数,。 +可以通过数组的只读属性`count`来获得数组包含的数组项个数。 ``` println("The shopping list contains \(shoppingList.count) items.") // prints "The shopping list contains 2 items." + ``` Use the Boolean `isEmpty` property as a shortcut for checking whether the `count` property is equal to `0`: -用布尔值`isEmpty`属性来作为查看`count`属性是否等于`0`的快捷方式。 +用布尔值`isEmpty`属性来作为检查`count`属性是否等于`0`的快捷方式。 ``` if shoppingList.isEmpty { @@ -108,42 +110,47 @@ if shoppingList.isEmpty { println("The shopping list is not empty.") } // prints "The shopping list is not empty.” + ``` You can add a new item to the end of an array by calling the array’s `append` method: -我们可以通过调用数组的`append`方法来插入一个新的数组项到数组的末尾。 +我们可以通过调用数组的`append`方法来插入一个新的数组项到数组的末尾【todo:可以通过调用数组的`append`方法,在数组的末尾插入一个新的数据项】。 ``` shoppingList.append("Flour") // shoppingList now contains 3 items, and someone is making pancakes +// shoppingList 现在包含3项 ``` Alternatively, add a new item to the end of an array with the addition assignment operator (`+=`): -或者,可以通过加法赋值运算符(`+=`)来添加新的数组项到数组的末尾。 +或者,可以通过加法赋值运算符(`+=`)来添加新的数组项到数组的末尾【todo:在数组的末尾添加新的数据项】。 ``` shoppingList += "Baking Powder" // shoppingList now contains 4 items +// shoppingList 现在包含4项 ``` You can also append an array of compatible items with the addition assignment operator (`+=`): -你还可以通过加法赋值运算符(`+=`)来插入一个同类型的数组。 +你还可以通过加法赋值运算符(`+=`)插入一个同类型的数组。 ``` shoppingList += ["Chocolate Spread", "Cheese", "Butter"] // shoppingList now contains 7 items +// shoppingList 现在包含7项 ``` Retrieve a value from the array by using *subscript syntax*, passing the index of the value you want to retrieve within square brackets immediately after the name of the array: -通过*下标语法*从数组中获取某个值,即在数组名之后紧跟由方括号括起来的想要获取的值的索引: +通过*下标语法*从数组中获取某个值,即在数组名之后紧跟由方括号括起来的想要获取的值的索引【todo:即在数组名后紧跟的方括号中传入想要获取的值的索引】: ``` var firstItem = shoppingList[0] // firstItem is equal to "Eggs" +// firstItem 等于 "Eggs" ``` Note that the first item in the array has an index of `0`, not `1`. Arrays in Swift are always zero-indexed. @@ -152,20 +159,22 @@ Note that the first item in the array has an index of `0`, not `1`. Arrays in Sw You can use subscript syntax to change an existing value at a given index: -通过指定的索引,我们可以使用下标语法来修改一个已经存在的值: +通过指定的索引,我们可以使用下标语法来修改一个已经存在的值:【todo:使用下标语法可以在给定的索引处改变已存在的值】 ``` shoppingList[0] = "Six eggs" // the first item in the list is now equal to "Six eggs" rather than "Eggs" +// 列表中第一项现在等于 "Six eggs" ,而不是"Eggs" ``` You can also use subscript syntax to change a range of values at once, even if the replacement set of values has a different length than the range you are replacing. The following example replaces `"Chocolate Spread"`, `"Cheese"`, and `"Butter"` with `"Bananas"` and `"Apples"`: -我们还可以通过下标语法一次改变一个范围内的值,即使要替换的值的长度和被替换的值的长度不一致。下面的例子用`"Bananas"` and `"Apples"`替换了`"Chocolate Spread"`, `"Cheese"`, and `"Butter"`: +我们还可以通过下标语法一次改变一个范围内的值,即使要替换的值的长度和被替换的值的长度不一致【todo:即使替换的值的集合与被替换的范围的长度不一致】。下面的例子用`"Bananas"` and `"Apples"`替换了`"Chocolate Spread"`, `"Cheese"`, and `"Butter"`: ``` shoppingList[4...6] = ["Bananas", "Apples"] // shoppingList now contains 6 items +// shoppingList现在包含6项 ``` >NOTE @@ -174,51 +183,63 @@ shoppingList[4...6] = ["Bananas", "Apples"] >注意 ->我们不能使用下标语法插入一个新的数组项到数组的末尾。如果我们试图用一个超过数组边界的下标访问或设置某个数值时,会导致运行时错误。不过,我们可以通过比较索引和数组的`count`属性来判断该索引是否有效。数组中最大的有效索引为`count-1`,除了count为`0`时(意味着这个数组是空的),因为数组的索引是从0开始的。 +>我们不能使用下标语法插入一个新的数组项到数组的末尾【todo:不能使用下标语法在数组的末尾添加新的数据项】。如果我们试图用一个超过数组边界的下标访问或设置某个数值时,会导致运行时错误。不过,我们可以通过比较索引和数组的`count`属性来判断该索引是否有效。除了count为`0`时(意味着这个数组是空的),数组中最大的有效索引为`count-1`,因为数组的索引是从0开始的。 To insert an item into the array at a specified index, call the array’s `insert(atIndex:)` method: -要给数组的指定索引处插入一个数组项,可以调用数组的`insert(atIndex:)`方法: +要在数组的指定索引处插入一个数组项,可以调用数组的`insert(atIndex:)`方法: ``` shoppingList.insert("Maple Syrup", atIndex: 0) // shoppingList now contains 7 items // "Maple Syrup" is now the first item in the list +// shoppingList 现在包含7项 +// "Maple Syrup" 现在是列表的第一项 ``` This call to the `insert` method inserts a new item with a value of `"Maple Syrup"` at the very beginning of the shopping list, indicated by an index of `0`. -上面的例子中,调用了`insert`方法插入了一个值为`“Maple Syrup”`的新数组项到数组的开头,用索引`0`来表示。 +上面的例子中,调用了`insert`方法插入了一个值为`“Maple Syrup”`的新数组项到数组的开头,用索引`0`来表示【todo:这个例子调用`insert`方法指定索引为 `0`,在shoppingList的最前面插入了值为`“Maple Syrup”`的新数据项】。 Similarly, you remove an item from the array with the `removeAtIndex` method. This method removes the item at the specified index and returns the removed item (although you can ignore the returned value if you do not need it): -相同地,`removeAtIndex`方法可以从数组中移除一个数组项。该方法移除指定索引的数组项,并返回被移除的数组项(如果不需要,我们可以忽略返回的值): +类似地,`removeAtIndex`方法可以从数组中移除一个数组项。该方法移除指定索引处的数组项,并返回被移除的数组项(如果不需要,我们可以忽略返回值): ``` let mapleSyrup = shoppingList.removeAtIndex(0) // the item that was at index 0 has just been removed // shoppingList now contains 6 items, and no Maple Syrup // the mapleSyrup constant is now equal to the removed" Maple Syrup" string + +// 索引为0的数据项被移除 +// shoppingList 现在包含6项, 不包括 Maple Syrup +// mapleSyrup 现在等于被移除的 " Maple Syrup" 字符串 ``` Any gaps in an array are closed when an item is removed, and so the value at index `0` is once again equal to `"Six eggs"`: -当一个数组项被移除后数组中的空出项会被自动填补,因此索引`0`对应的值再次等于`“Six eggs”`: +当一个数组项被移除后数组中的空缺项会被自动填补,因此索引`0`对应的值再次等于`“Six eggs”`: ``` firstItem = shoppingList[0] // firstItem is now equal to "Six eggs" + +// firstItem 现在等于"Six eggs" ``` If you want to remove the final item from an array, use the `removeLast` method rather than the `removeAtIndex `method to avoid the need to query the array’s `count` property. Like the `removeAtIndex` method, `removeLast` returns the removed item: -如果我们想要从数组中移除最后一个数组项,最好使用`removeLast`方法,而不是`removeAtIndex`方法,这样能够避免去查询数组的`count`属性。像`removeAtIndex`方法那样,`removeLast`方法也会返回被移除的数组项: +如果我们想要从数组中移除最后一个数组项,最好使用`removeLast`方法,而不是`removeAtIndex`方法,这样可以避免查询数组的`count`属性。像`removeAtIndex`方法那样,`removeLast`方法也会返回被移除的数组项: ``` let apples = shoppingList.removeLast() // the last item in the array has just been removed // shoppingList now contains 5 items, and no cheese // the apples constant is now equal to the removed "Apples" string + +// 数组中最后一项被移除 +// shoppingList 现在包含5项, 不包括cheese +// apples 现在等于被移除的"Apples" 字符串 ``` ### Iterating Over an Array @@ -239,7 +260,7 @@ for item in shoppingList { ``` If you need the integer index of each item as well as its value, use the global `enumerate` function to iterate over the array instead. The `enumerate` function returns a tuple for each item in the array composed of the index and the value for that item. You can decompose the tuple into temporary constants or variables as part of the iteration: -如果我们除了需要每个数组项的值之外,还需要每个数组项的索引,那么可以使用全局函数`enumerate`来遍历数组。函数`enumerate`返回由每个数组项的索引和对应的值组成的元组。我们可以把元组分解为临时的常量或者变量来进行遍历。 +如果我们除了需要每个数组项的值之外,还需要每个数组项的索引【todo:如果需要每一项的整型索引及对应的值】,那么可以使用全局函数`enumerate`来遍历数组。函数`enumerate`返回由每个数组项的索引和对应的值组成的元组。我们可以把元组分解为临时的常量或者变量来进行遍历。 ``` for (index, value) in enumerate(shoppingList) { @@ -269,7 +290,7 @@ println("someInts is of type Int[] with \(someInts.count) items.") ``` Note that the type of the `someInts` variable is inferred to be `Int[]`, because it is set to the output of an `Int[]` initializer. -注意,变量`someInts`的类型被认为是`Int[]`,因为它的设置自于`Int[]`初始化的输出。 +注意,变量`someInts`的类型被认为是`Int[]`,因为它的设置自于`Int[]`初始化的输出【todo:因为它设置为`Int[]`初始化器的输出结果】。 Alternatively, if the context already provides type information, such as a function argument or an already-typed variable or constant, you can create an empty array with an empty array literal, which is written as `[]` (an empty pair of square brackets): @@ -278,24 +299,34 @@ Alternatively, if the context already provides type information, such as a funct ``` someInts.append(3) // someInts now contains 1 value of type Int + +// someInts 现在包含 1 个 Int 值 + someInts = [] // someInts is now an empty array, but is still of type Int[] + +// someInts 现在是一个空数组, 但仍然是Int[]类型 ``` Swift’s `Array` type also provides an initializer for creating an array of a certain size with all of its values set to a provided default value. You pass this initializer the number of items to be added to the new array (called `count`) and a default value of the appropriate type (called `repeatedValue`): -Swift`数组`类型还提供了一个构造器来创建指定大小的数组,该数组的数组项的值是默认的。我们传递给构造器新加的数组项的大小(称为`count`),以及适合类型的默认值(称为`repeatedValue`)。 +Swift`数组`类型还提供了一个构造器【todo:初始化器】来创建指定大小的数组,该数组的数组项的值是默认的【todo:该数组的数据项设置为提供的默认值】。我们传递给构造器新加的数组项的大小(称为`count`),以及适合类型的默认值(称为`repeatedValue`)【todo:我们把新加的数组项的大小(称为`count`)和相应类型的默认值(称为`repeatedValue`)传递给初始化器】。 ``` var threeDoubles = Double[](count: 3, repeatedValue: 0.0) // threeDoubles is of type Double[], and equals [0.0, 0.0, 0.0] + +// threeDoubles 是 Double[] 类型,等于[0.0, 0.0, 0.0] ``` Thanks to type inference, you don’t need to specify the type to be stored in the array when using this initializer, because it can be inferred from the default value: 感谢类型推导,我们在使用构造器时不需要指定数组中数值的具体类型,因为类型可以从默认值中推导出来: +【todo:多亏有类型推导,使用初始化器时,可以不需要指定数组存储的类型,因为可以从默认值推导类型:】 ``` var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5) // anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5] + +// anotherThreeDoubles 推导为 Double[] 类型,等于 [2.5, 2.5, 2.5] ``` Finally, you can create a new array by adding together two existing arrays of compatible type with the addition operator (`+`). The new array’s type is inferred from the type of the two arrays you add together: @@ -304,37 +335,40 @@ Finally, you can create a new array by adding together two existing arrays of co ``` var sixDoubles = threeDoubles + anotherThreeDoubles // sixDoubles is inferred as Double[], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] + +// sixDoubles 推导为Double[]类型, 等于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] ``` ## Dictionaries ## 字典 + A *dictionary* is a container that stores multiple values of the same type. Each value is associated with a unique *key*, which acts as an identifier for that value within the dictionary. Unlike items in an array, items in a dictionary do not have a specified order. You use a dictionary when you need to look up values based on their identifier, in much the same way that a real-world dictionary is used to look up the definition for a particular word. -*字典*是存储多重相同类型数值的容器。每个值和字典中作为值的唯一标识符的*键*(key)相关联。和数组中的数据项不同,字典中的数据项没有顺序。我们可以使用字典查找基于标识符的数据,就像在现实世界中可以用字典来查找某个特定字词的定义。 +*字典*是存储多个相同类型数值的容器。每个值和字典中作为该值的唯一标识符的*键*(key)相关联。和数组中的数据项不同,字典中的数据项没有顺序。我们可以使用字典查找基于标识符的数据【todo:可以使用字典根据标识符来查找数据】,就像在现实世界中可以用字典来查找某个特定字词的定义。 Swift dictionaries are specific about the types of keys and values they can store. They differ from Objective-C’s `NSDictionary` and `NSMutableDictionary` classes, which can use any kind of object as their keys and values and do not provide any information about the nature of these objects. In Swift, the type of keys and values that a particular dictionary can store is always made clear, either through an explicit type annotation or through type inference. -Swift字典能够存储的键和值的类型是确定的。他们和Objective-C的类`NSDictionary`和`NSMutableDictionary`有所不同,这些类能够用任意一种对象作为他们的键和值,且不提供这些对象本质相关的任何信息。在Swift中,确定的字典能够存储的键和值的类型是确定的,要么通过显示的类型声明而来,要么通过类型推断而来。 +Swift字典存储的键和值的类型是确定的。他们和Objective-C的类`NSDictionary`和`NSMutableDictionary`有所不同,这些类可以用任意一种对象作为他们的键和值,且不提供这些对象本质相关的任何信息。在Swift中,某个字典可以存储的键和值的类型是确定的,要么通过显示的类型声明而来,要么通过类型推断而来【todo:可以使用显式类型声明,也可以使用类型推断】。 Swift’s dictionary type is written as `Dictionary`, where `KeyType` is the type of value that can be used as a dictionary key, and `ValueType` is the type of value that the dictionary stores for those keys. -Swift字典类型被写为`Dictionary`,这里的`KeyType`是能够被作为字典键的数据的类型,`ValueType`是字典中存储的与键相关联的数据的类型。 +Swift字典类型写为`Dictionary`,这里的`KeyType`是可以作为字典键的数据类型,`ValueType`是字典中存储的与键相对应的值的类型。 The only restriction is that `KeyType` must be *hashable*—that is, it must provide a way to make itself uniquely representable. All of Swift’s basic types (such as `String`, `Int`, `Double`, and `Bool`) are hashable by default, and all of these types can be used as the keys of a dictionary. Enumeration member values without associated values (as described in [Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md)) are also hashable by default. -`KeyType`的唯一限制是它必须是*可哈希的*——也就是说,它必须提供一个方法来使得自己能够被唯一表示。所有的Swift基础类型(如`String`, `Int`, `Double`, 和`Bool`)默认都是可哈希的,所有的这些类型都能够被用来作为字典的键。没有关联数值的枚举类型(参见[Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md))也是默认可枚举的。 +`KeyType`的唯一限制是它必须是*可哈希的*——也就是说,它必须提供一个方法来使得自己可以被唯一表示【todo:它必须提供一个方法可以唯一代表自己】。所有的Swift基础类型(如`String`、`Int`、 `Double` 和`Bool`)默认都是可哈希的,所有的这些类型都可以被用来作为字典的键。没有关联数值的枚举类型(参见[Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md))也是默认可枚举的【todo:没有对应值的枚举成员数据默认也是可哈希的】。 ‌ ### Dictionary Literals ### 字典字面量 You can initialize a dictionary with a *dictionary literal*, which has a similar syntax to the array literal seen earlier. A dictionary literal is a shorthand way to write one or more key-value pairs as a `Dictionary` collection. -你可以用*字典字面量*来初始化一个字典,这个和之前的数组字面量有着相似的语法。一个字典字面量是一个缩写的方式来表示作为`字典`集合的一个或多个键值对。 +你可以用*字典字面量*来初始化一个字典,这和之前的数组字面量有着相似的语法。一个字典字面量是一个缩写的方式来表示作为`字典`集合的一个或多个键值对【todo:字典字面量是一个或多个键-值对作为`字典`集合的简写方式】。 A *key-value pair* is a combination of a key and a value. In a dictionary literal, the key and value in each key-value pair are separated by a colon. The key-value pairs are written as a list, separated by commas, surrounded by a pair of square brackets: -一个*键-值对*是键和值的组合。在字典字面量中,每个键-值对中的键和值由冒号分隔开来。键值对被写作一个列表,用逗号隔开,由方括号括起来: +*键-值对*是键和值的组合。在字典字面量中,每个键-值对中的键和值由冒号分隔。键值对的列表,用逗号分隔,由方括号括起来: ``` [key 1: value 1, key 2: value 2, key 3: value 3] @@ -348,7 +382,7 @@ var airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin"] ``` The `airports` dictionary is declared as having a type of `Dictionary`, which means “a `Dictionary` whose keys are of type `String`, and whose values are also of type `String`”. -`airports`字典被声明为`Dictionary`类型,即“一个键和值的类型都是`String`类型的字典”。 +`airports`字典声明为`Dictionary`类型,即“一个键和值的类型都是`String`类型的字典”。 >NOTE @@ -356,30 +390,33 @@ The `airports` dictionary is declared as having a type of `Dictionary注意 ->`airports`字典被声明为变量(用关键字`var`),而不是常量(用关键字`let`),因为在下面的例子中,会有更多的机场被添加到这个字典里。 +>`airports`字典声明为变量(用关键字`var`),而不是常量(用关键字`let`),因为在下面的例子中,会有更多的机场被添加到这个字典里。 The `airports` dictionary is initialized with a dictionary literal containing two key-value pairs. The first pair has a key of `"TYO"` and a value of `"Tokyo"`. The second pair has a key of `"DUB"` and a value of `"Dublin"`. -`airports`字典由包含两对键值对的字典字面量初始化。第一对有一个键`“TYO”`和一个值`“Tokyo”`。第二对有一个键`“DUB”`和一个值`“Dublin”`。 +`airports`字典由包含两对键值对的字典字面量初始化。第一对有键`“TYO”`和值`“Tokyo”`。第二对有键`“DUB”`和值`“Dublin”`。 This dictionary literal contains two `String`: `String` pairs. This matches the type of the `airports` variable declaration (a dictionary with only `String` keys, and only `String` values) and so the assignment of the dictionary literal is permitted as a way to initialize the `airports` dictionary with two initial items. -这个字典字面量包含两个`String`:`String`类型的键值对。这和变量`airports`声明(只有`String`键和`String`值的字典)的类型一致,因此字典字面量的赋值被用来作为一种初始化方法来用两个初始项构建这个`airports`字典。 +这个字典字面量包含两个`String`:`String`类型的键值对。这和变量`airports`声明(只有`String`键和`String`值的字典)的类型一致,因此字典字面量的赋值被用来作为一种初始化方法来用两个初始项构建这个`airports`字典【todo:因此字典字面量的赋值作为一种方法,可以用两个初始项来初始化这个`airports`字典】。 As with arrays, you don’t have to write the type of the dictionary if you’re initializing it with a dictionary literal whose keys and values have consistent types. The initialization of `airports` could have been be written in a shorter form instead: -像数组那样,如用我们用键值类型相同的字典字面量来初始化字典,那么我们不需要写出它的类型。`airports`的初始化可以被简写为以下形式: +和数组一样,如用我们用键值类型相同的字典字面量来初始化字典,那么不需要写出它的类型。`airports`的初始化可以简写为以下形式: ``` var airports = ["TYO": "Tokyo", "DUB": "Dublin"] ``` Because all keys in the literal are of the same type as each other, and likewise all values are of the same type as each other, Swift can infer that `Dictionary` is the correct type to use for the `airports` dictionary. -由于字面量中的键和值都是相同类型的,因而Swift能够推断出`Dictionary` 是使用字典`airports`的正确类型。 + +由于字面量中所有的键和值都是相同类型的,因此Swift可以推断出`Dictionary` 是字典`airports`使用的正确类型。 ‌ ### Accessing and Modifying a Dictionary +### 访问和修改字典 + You access and modify a dictionary through its methods and properties, or by using subscript syntax. As with an array, you can find out the number of items in a `Dictionary` by checking its read-only `count` property: -我们能够通过字典的方法和属性,以及下标语法来访问和修改字典。像数组那样,我们可以通过查询只读属性`count`来得到一个`字典`中数据项的数量。 +我们可以通过字典的方法和属性,或下标语法来访问和修改字典。像数组那样,我们可以通过检查只读属性`count`来获取`字典`中数据项的个数。 ``` println("The dictionary of airports contains \(airports.count) items.") @@ -387,24 +424,28 @@ println("The dictionary of airports contains \(airports.count) items.") ``` You can add a new item to a dictionary with subscript syntax. Use a new key of the appropriate type as the subscript index, and assign a new value of the appropriate type: -我们可以通过下标语法给字典添加新的数据项。使用合适类型的键作为下标索引,赋予合适类型的值: +我们可以通过下标语法给字典添加新的数据项。使用相应类型的键作为下标索引,并赋予相应类型的值: ``` airports["LHR"] = "London" // the airports dictionary now contains 3 items + +// airports 字典现在包含3项 ``` You can also use subscript syntax to change the value associated with a particular key: -我们还可以使用下标语法来改变和某个特定键相关联的值: +我们还可以使用下标语法来改变和某个特定键相关联的值【还可以使用下标语法改变某个键对应的值】: ``` airports["LHR"] = "London Heathrow" // the value for "LHR" has been changed to "London Heathrow" + +// "LHR" 的值修改为 "London Heathrow" ``` As an alternative to subscripting, use a dictionary’s `updateValue(forKey:)` method to set or update the value for a particular key. Like the subscript examples above, the `updateValue(forKey:)` method sets a value for a key if none exists, or updates the value if that key already exists. Unlike a subscript, however, the `updateValue(forKey:)` method returns the old value after performing an update. This enables you to check whether or not an update took place. -字典的`updateValue(forKey:)`方法可作为下标的替代来设置或更新某个特定键相关联的值。像上面下标的那个例子,`updateValue(forKey:)`方法可以设置某个不存在的键的值或者更新某个已有的键的值。和下标不同的是,`updateValue(forKey:)`方法在更新数据后会返回更新之前的数值。这使得我们可以检查更新是否成功。 +字典的`updateValue(forKey:)`方法可作为下标的替代来设置或更新某个特定键对应的值。像上面下标的例子,`updateValue(forKey:)`方法可以设置某个不存在的键的值或者更新某个已有的键的值。和下标不同的是,`updateValue(forKey:)`方法在更新数据后会返回更新前的数值。这使得我们可以检查更新是否成功。 The `updateValue(forKey:)` method returns an optional value of the dictionary’s value type. For a dictionary that stores `String` values, for example, the method returns a value of type `String?`, or “optional `String`”. This optional value contains the old value for that key if one existed before the update, or `nil` if no value existed: @@ -418,7 +459,7 @@ if let oldValue = airports.updateValue("Dublin International", forKey: "DUB") { ``` You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type. If the dictionary contains a value for the requested key, the subscript returns an optional value containing the existing value for that key. Otherwise, the subscript returns `nil`: -我们也可以使用下标语法来访问一个字典中某个特定键对应的值。因为查询某个不存在对应值的键也是有可能的,字典的下标会返回字典数据类型的可选值。如果字典包含了与要查找的键相对应的值,下标返回的可选值包含那个键对应的值,否则下标返回`nil`。 +我们也可以使用下标语法来访问字典中某个特定键对应的值。因为查询某个不存在对应值的键也是有可能的【todo:因为有可能会查询一个没有对应值的键】,字典的下标会返回字典数据类型的可选值。如果字典包含了与要查找的键相对应的值,下标返回的可选值包含那个键对应的值,否则下标返回`nil`。 ``` if let airportName = airports["DUB"] { @@ -435,8 +476,12 @@ You can use subscript syntax to remove a key-value pair from a dictionary by ass ``` airports["APL"] = "Apple International" // "Apple International" is not the real airport for APL, so delete it + +// "Apple International" 不是APL的真实机场,所以删除它 airports["APL"] = nil // APL has now been removed from the dictionary + +// APL 已经从字典中移除了 ``` Alternatively, remove a key-value pair from a dictionary with the `removeValueForKey` method. This method removes the key-value pair if it exists and returns the removed value, or returns `nil` if no value existed: @@ -456,7 +501,7 @@ if let removedValue = airports.removeValueForKey("DUB") { ### 字典遍历 You can iterate over the key-value pairs in a dictionary with a `for-in` loop. Each item in the dictionary is returned as a (`key, value`) tuple, and you can decompose the tuple’s members into temporary constants or variables as part of the iteration: -我们可以用`for-in`循环遍历一个字典中的键值对。字典中的每个数据项返回相应的(`键, 值`)原则,我们可以把元组分解为临时常量或变量用于遍历: +我们可以用`for-in`循环遍历一个字典中的键值对。字典中的每个数据项返回相应的(`键, 值`)元组,我们可以把元组分解为临时常量或变量用于遍历: ``` for (airportCode, airportName) in airports { @@ -471,7 +516,7 @@ For more about the `for-in` loop, see [For Loops](https://github.com/trans4fun/T You can also retrieve an iteratable collection of a dictionary’s keys or values by accessing its `keys` and `values` properties: -我们还能够通过字典的`keys`或`values`属性来遍历字典的键或值。 +我们还可以通过字典的`keys`或`values`属性来遍历字典的键或值【todo:可以使用字典的`keys`或`values`属性得到字典的键和值的遍历集合】。 ``` for airportCode in airports.keys { @@ -490,6 +535,7 @@ for airportName in airports.values { If you need to use a dictionary’s keys or values with an API that takes an `Array` instance, initialize a new array with the `keys` or `values` property: 如果我们需要使用一个使用字典的键和值,并用`Array`实例作为参数的接口,可以用`keys`或`values`属性来初始化一个新的数组。 +【todo:如果需要使用字典的API 生成键和值的`Array`实例,可以使用`keys`或`values`属性初始化新数组】 ``` let airportCodes = Array(airports.keys) @@ -511,7 +557,7 @@ let airportNames = Array(airports.values) ### 创建空字典 As with arrays, you can create an empty `Dictionary` of a certain type by using initializer syntax: -如同字典,我们可以使用初始化语法创建一个特定类型的空`字典`。 +和数组一样,我们可以使用初始化语法创建一个特定类型的空`字典`。 ``` var namesOfIntegers = Dictionary() @@ -519,7 +565,7 @@ var namesOfIntegers = Dictionary() ``` This example creates an empty dictionary of type `Int`, `String` to store human-readable names of integer values. Its keys are of type `Int`, and its values are of type `String`. -这个例子创建了`Int`,`String`类型的空字典来存储整型数据的可读性名称。它的键的类型是`Int`,值的类型是`String`。 +这个例子创建了`Int`,`String`类型的空字典来存储整型的可读性名称。它的键的类型是`Int`,值的类型是`String`。 If the context already provides type information, create an empty dictionary with an empty dictionary literal, which is written as [`:`] (a colon inside a pair of square brackets): @@ -528,8 +574,13 @@ If the context already provides type information, create an empty dictionary wit ``` namesOfIntegers[16] = "sixteen" // namesOfIntegers now contains 1 key-value pair + +// namesOfIntegers 现在包含1个键-值对 + namesOfIntegers = [:] // namesOfIntegers is once again an empty dictionary of type Int, String + +// namesOfIntegers再一次成为 Int, String 类型的空字典 ``` >NOTE @@ -546,25 +597,25 @@ namesOfIntegers = [:] Arrays and dictionaries store multiple values together in a single collection. If you create an array or a dictionary and assign it to a variable, the collection that is created will be *mutable*. This means that you can change (or *mutate*) the size of the collection after it is created by adding more items to the collection, or by removing existing items from the ones it already contains. Conversely, if you assign an array or a dictionary to a constant, that array or dictionary is *immutable*, and its size cannot be changed. -数组和字典在单个集合中存储了多个数据。如果我们创建一个数组或字典并把它声明为变量,这个被创建出来的集合是*易变的*。这表示我们能够在创建集合之后通过添加更多的数据项到集合中或从中移除现有的数据项来*改变*它的大小。相反的,如果把一个数组或字典声明为常量,则这个数组或字典是*不可变*的,它的大小是不会变化的。 +数组和字典在单个集合中存储了多个数据。如果我们创建一个数组或字典并把它声明为变量,这个创建出来的集合是*易变的*。这表示我们可以在创建集合之后通过添加更多的数据项到集合中或从中移除现有的数据项来*改变*它的大小【todo:这意味着我们可以改变集合的大小,在集合中添加更多的数据项,或从中移除已有的数据项】。相反的,如果把一个数组或字典声明为常量,则这个数组或字典是*不可变*的,它的大小是不会变化的。 For dictionaries, immutability also means that you cannot replace the value for an existing key in the dictionary. An immutable dictionary’s contents cannot be changed once they are set. -对字典来说,不可变还意味着我们不能替换字典中某个现有的键对应的值。一个不可变字典的内容一旦被设置就不能再被改变。 +对字典来说,不可变还意味着我们不能替换字典中某个已有的键对应的值。一个不可变字典的内容一旦设置就不能再改变。 Immutability has a slightly different meaning for arrays, however. You are still not allowed to perform any action that has the potential to change the size of an immutable array, but you *are* allowed to set a new value for an existing index in the array. This enables Swift’s `Array` type to provide optimal performance for array operations when the size of an array is fixed. -对数组来说,不可变的意义稍有不同。我们仍不允许有改变不可变数组的大小的行为,但是,我们*被*允许改变数组中某个现有索引对应的值。这使得Swift的`Array`类型能够在操作固定大小的数组时提供最佳性能。 +对数组来说,不可变的意义稍有不同。我们仍不允许改变不可变数组的大小,但是,我们*被*允许改变数组中某个已有索引对应的值。这使得Swift的`Array`类型可以在操作固定大小的数组时提供最佳性能。 The mutability behavior of Swift’s `Array` type also affects how array instances are assigned and modified. For more information, see [Assignment and Copy Behavior for Collection Types](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/09_Classes_and_Structures.md#assignment-and-copy-behavior-for-collection-types). -Swift的`Array`类型的可变性还影响了数组实例是怎么被声明和修改的。更多介绍请参见[集合类型的声明和复制](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/09_Classes_and_Structures.md#%E9%9B%86%E5%90%88%E7%9A%84%E8%B5%8B%E5%80%BC%E4%B8%8E%E6%8B%B7%E8%B4%9D)。 +Swift的`Array`类型的可变性还影响了数组实例是怎么被声明和修改的【todo:Swift的`Array`类型的可变性还会影响数组实例如何赋值和修改】。更多介绍请参见[集合类型的声明和复制](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/09_Classes_and_Structures.md#%E9%9B%86%E5%90%88%E7%9A%84%E8%B5%8B%E5%80%BC%E4%B8%8E%E6%8B%B7%E8%B4%9D)。 >NOTE >It is good practice to create immutable collections in all cases where the collection’s size does not need to change. Doing so enables the Swift compiler to optimize the performance of the collections you create. >注意 ->当集合的大小不需要改变时,创建一个不可变的集合是比较好的做法。这样做使得Swift编译器优化我们创建的集合的性能。 +>当集合的大小不需要改变时,创建一个不可变的集合是比较好的做法。这样做使得Swift编译器优化我们创建的集合的性能【todo:这样做,Swift编译器会优化创建的集合性能】。 From 60aeb233d2dd1382fda0f051e0dcb260394fe064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=9C=E8=88=9F?= Date: Sat, 12 Jul 2014 10:11:40 +0800 Subject: [PATCH 254/261] Revert "23_Advanced_Operators reviewed" This reverts commit 9d6ba8c25cb3e209260d0d8e278fab36bc9dc159. --- src/chapter2/23_Advanced_Operators.md | 44 ++------------------------- 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index e57aaf6..a5cf5f9 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -2,27 +2,12 @@ 除了《基础操作符》里讲到的操作符,Swift还提供了一些高级操作符,用以完成更复杂的数值运算。比如位运算和移位操作符,其语法同C和Objective-C类似。 -> From 周源: -移位: 我读的时候, 感觉位移更顺口一点 - 和C语言的算术操作符不同,Swift默认不支持溢出运算。数值溢出会被捕获并报错。但是,Swift提供了另一套支持溢出运算的操作符,比如可溢出加操作符(&+),可溢出操作符都以&作为前缀。 -> From 周源: -&+ -> (&+) -So -& -> (&)? - 在自定义结构体、类或者枚举类型中,可以重载Swift操作符。通过操作符重载,可以简单地实现操作符的重定义。 -> From 周源: -我理解的 "简单的实现" 有二义性, 可表示 实现简单 和 简单实现, -这里作者的意思应该是实现简单, 我觉得 方便的实现 也可以表达作者的意思, 你怎么看? - Swift允许用户自定义操作符,并且可定制这些操作符的优先级和结合性。 -> From 周源: -这一段原文较长, 省略了部分翻译, 按照会长的意思...... - ## 位操作符 @@ -102,8 +87,6 @@ let outputBits = firstBits ^ otherBits // 等于 00010001 #### 无符号移位操作 -> From 周源: -移位 -> 位移? 无符号移位的规则如下: 1. 已有的位向左或向右移动指定的位数。 @@ -166,19 +149,12 @@ let blueComponent = pink & 0x0000FF // blueComponent是0x99, 即153 负数的编码方式称为二进制补码表示。这种表示方式看起来很奇怪,但它有几个优点。 -> From 周源: -The encoding for negative numbers is known as a two’s complement representation. -负数的编码方式称为二进制补码表示 -> 负数的编码方式用二进制补码表示? - 首先,对全部8个比特位(包括符号位)做标准的二进制加法就可以完成-1 加 -4 的操作,加法过程中丢弃超出的比特位。 ![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSignedAddition_2x.png) 第二,使用二进制补码表示方式,我们可以和正数一样对负数进行按位左移或右移,同样也是左移1位时乘于2,右移1位时除于2。但是,对有符号整型的右移有一个特别的要求: -> From 周源: -使用二进制补码表示方式 -> 使用二进制补码? - + 有符号和无符号整型按位右移时规则相同,但有符号整型移位后出现的空位使用符号位来填充,而不是0。 ![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSigned_2x.png) @@ -318,7 +294,7 @@ let y = x &/ 0 Swift操作符的优先级和结合性的完整规则,请看表达式。 -> 注意: +> 注意: > > Swift操作符的优先级和结合性的规则跟C系语言不太一样,相对于C语言和Objective-C更加简单且保守。所以在移植已有代码到Swift时,注意确认操作数的计算顺序。 @@ -394,9 +370,6 @@ let alsoPositive = -negative 加法运算之前定义过了,这里无需重新定义。加赋操作符函数使用已有的加法运算将左值加上右值: -> From 周源 -> 加赋操作符函数使用已有的加法运算将左值加上右值: -> 加法操作符... ? - ``` var original = Vector2D(x: 1.0, y: 2.0) let vectorToAdd = Vector2D(x: 3.0, y: 4.0) @@ -415,9 +388,6 @@ original += vectorToAdd 这个自加操作符函数使用了前面定义过的加赋运算,将自己加上一个值为 (1.0,1.0) 的对象然后将返回值赋给自己。 -> From 周源 -> 加赋运算 -> 加法运算... ? - ``` var toIncrement = Vector2D(x: 3.0, y: 4.0) let afterIncrement = ++toIncrement @@ -425,7 +395,7 @@ let afterIncrement = ++toIncrement // afterIncrement 也等于 (4.0, 5.0) ``` -> 注意: +> 注意: > > 默认的赋值符(=)是不可重载的。只有复合赋值符可以重载。条件操作符 a?b:c 也是不可重载的。 @@ -461,9 +431,6 @@ println("这两个向量相等") 除了标准的操作符,你还可以声明一些个性的操作符,但自定义操作符只能使用这些字符`/ = - + * % < >!& | ^ . ~` -> From 周源: -> 个性的操作符 -> 自定义的操作符 ? - 新的操作符需要在全局域使用`operator`关键字声明,可以声明为前置,中置或后置的。 ``` @@ -472,10 +439,6 @@ operator prefix +++ {} 这段代码定义了一个新的前置操作符+++,此前Swift并不存在这个操作符,此处针对`Vector2D` 对象的这个操作符具有个性化的含义。+++被定义为双自增操作符,它使用之前定义的加赋运算将自已加上自己然后返回。 -> From 周源: -> 个性化的含义 ? - - ``` @prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D { vector += vector @@ -513,9 +476,6 @@ let plusMinusVector = firstVector +- secondVector // plusMinusVector 是 Vector2D实例,等于 (4.0, -2.0) ``` -> From 周源: -> plusMinusVector 是 Vector2D实例 -> plusMinusVector 是 Vector2D的实例 ? - 这个操作符把两个向量的x相加, y相减。因为它实际上属于加减运算,所以让它保持了和加减法一样的结合性和优先级(左结合,优先级为140)。查阅完整的Swift默认优先级和结合性的设置,请移步[表达式](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-XID_655). From 06306118d57fd9f6f859226e6a752858f82c7108 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=9C=E8=88=9F?= Date: Sat, 12 Jul 2014 10:19:07 +0800 Subject: [PATCH 255/261] merge upsteam/master --- .gitignore | 1 - src/chapter1/01_About_Swift.md | 38 - src/chapter1/02_A_Swift_Tour.md | 211 ---- src/chapter2/09_Classes_and_Structures.md | 662 ----------- src/chapter2/10_Properties.md | 666 ------------ src/chapter2/14_Initialization.md | 895 --------------- src/chapter2/15_Deinitialization.md | 170 --- src/chapter2/17_Optional_Chaining.md | 300 ----- src/chapter2/19_Nested_Types.md | 180 --- src/chapter2/20_Extensions.md | 397 ------- src/chapter2/21_Protocols.md | 943 ---------------- src/chapter3/05_Statements.md | 577 ---------- src/chapter3/06_Declarations.md | 1208 --------------------- src/chapter3/07_Attributes.md | 208 ---- 14 files changed, 6456 deletions(-) delete mode 100644 .gitignore delete mode 100644 src/chapter1/01_About_Swift.md delete mode 100644 src/chapter1/02_A_Swift_Tour.md delete mode 100644 src/chapter2/09_Classes_and_Structures.md delete mode 100644 src/chapter2/10_Properties.md delete mode 100644 src/chapter2/14_Initialization.md delete mode 100644 src/chapter2/15_Deinitialization.md delete mode 100644 src/chapter2/17_Optional_Chaining.md delete mode 100644 src/chapter2/19_Nested_Types.md delete mode 100644 src/chapter2/20_Extensions.md delete mode 100644 src/chapter2/21_Protocols.md delete mode 100644 src/chapter3/05_Statements.md delete mode 100644 src/chapter3/06_Declarations.md delete mode 100644 src/chapter3/07_Attributes.md diff --git a/.gitignore b/.gitignore deleted file mode 100644 index e43b0f9..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.DS_Store diff --git a/src/chapter1/01_About_Swift.md b/src/chapter1/01_About_Swift.md deleted file mode 100644 index 098b988..0000000 --- a/src/chapter1/01_About_Swift.md +++ /dev/null @@ -1,38 +0,0 @@ -# About Swift -# Swift介绍 - -Swift is a new programming language for iOS and OS X apps that builds on the best of C and Objective-C, without the constraints of C compatibility.Swift adopts safe programming patterns and adds modern features to make programming easier, more flexible, and more fun.Swift’s clean slate, backed by the mature and much-loved Cocoa and Cocoa Touch frameworks, is an opportunity to reimagine how software development works. - -Swift是一款为iOS和OS X 应用打造的新式编程语言,它吸取了C语言和Objective-C语言的精华,同时完美兼容C语言。Swift采用了安全编程模式,增加了许多现代语言的特性,使编程工作更加简单,灵活,有趣。一款重新设计的语言,再加上成熟并且深受欢迎的Cocoa框架和Cocoa Touch框架,Swift为软件开发工作带来了无限遐想。 - - -Swift has been years in the making. Apple laid the foundation for Swift by advancing our existing compiler, debugger, and framework infrastructure. We simplified memory management with Automatic Reference Counting (ARC). Our framework stack, built on the solid base of Foundation and Cocoa, has been modernized and standardized throughout. Objective-C itself has evolved to support blocks, collection literals, and modules, enabling framework adoption of modern language technologies without disruption. Thanks to this groundwork, we can now -introduce a new language for the future of Apple software development. - -Swift已经持续研发多年了。苹果公司通过多年对已有编译器,调试器和基础架构的改进经验为Swift奠定了基础。我们通过ARC(Automatic Reference Counting,自动引用计数)简化内存管理。以Cocoa框架作为坚实的基础,我们的框架堆栈已然在各方面都更加的现代化和标准化了。Objective-C在发展过程中支持了块,字面量集合,模块,使框架与现代语言的衔接不至于中断。多亏了它,使我们能够向大家推荐为苹果软件开发的未来而生的编程语言----Swift。 - - -Swift feels familiar to Objective-C developers. It adopts the readability of Objective-C’s named parameters and the power of Objective-C’s dynamic object model. It provides seamless access to existing Cocoa frameworks and mix-and-match interoperability with Objective-C code. Building from this common ground, Swift introduces many new features and unifies the procedural and object-oriented portions of the language. - -Swift对于Object-C开发人员非常友好。它采用了Objective-C的参数命名和动态对象模型。它与现有的Cocoa框架无缝对接并与Objective-C实现了Mix-and-Match(混入内嵌式)互通。基于此,Swift还引入了一些新特性并结合了语言的面向过程和面向对象的功能。 - - -Swift is friendly to new programmers. It is the first industrial-quality systems programming language that is as expressive and enjoyable as a scripting language. It supports playgrounds, an innovative feature that allows programmers to experiment with Swift code and see the results immediately, without the overhead of building and running an app. - -Swift对于新手也是友好的,它是工业级品质的系统编程语言,而且像脚本语言一般生动有趣。它提供了Playground,允许程序开发人员实时预览效果,无需构建和运行整个app。 - - -Swift combines the best in modern language thinking with wisdom from the wider Apple engineering culture. The compiler is optimized for performance, and the language is optimized for development, without compromising on either. It’s designed to scale from “hello, world” to an entire operating system. All this makes Swift a sound future investment for developers and for Apple. - -Swift融入了博大的苹果的工程文化中富有智慧的现代语言思维。从“hello,world”开始到整个语言系统,编译器优化了性能,语言提升了开发效率,无需任何妥协,这一切,让Swift成为了开发者与Apple未来实用的选择。 - - -Swift is a fantastic way to write iOS and OS X apps, and will continue to evolve with new features and capabilities. Our goals for Swift are ambitious. We can’t wait to see what you create with it.” - -Swift是编写iOS和OS X应用的绝美方式,我们会持续引入新特性和新功能。我们对Swift充满了信息。我们已经迫不及待的想看到你用它来做点什么。 - -   -   -   -   - diff --git a/src/chapter1/02_A_Swift_Tour.md b/src/chapter1/02_A_Swift_Tour.md deleted file mode 100644 index b2d2ede..0000000 --- a/src/chapter1/02_A_Swift_Tour.md +++ /dev/null @@ -1,211 +0,0 @@ -A Swift Tour - -Tradition suggests that the first program in a new language should print the words “Hello, world” on the screen. In Swift, this can be done in a single line: -通常学习一门新语言都会输出一行“Hello,world”.在swift里只需要一行代码 - -“If you have written code in C or Objective-C, this syntax looks familiar to you—in Swift, this line of code is a complete program. You don’t need to import a separate library for functionality like input/output or string handling. Code written at global scope is used as the entry point for the program, so you don’t need a main function. You also don’t need to write semicolons at the end of every statement.” -如果你之前写过C或者Objective-C的代码,你会很熟悉这种语法。在swift里,这一行代码就是一个完整的程序,你不需要再去引入一个完成类似输入输出,字符串处理等操作的类库。在全局范围内编写的代码就是程序的入口,因此你不再需要main函数了,也不需要在每一条语句末尾写分号。 - -“This tour gives you enough information to start writing code in Swift by showing you how to accomplish a variety of programming tasks. Don’t worry if you don’t understand something—everything introduced in this tour is explained in detail in the rest of this book.” -这篇文章会充分向你展示如何用swift完成各种编程任务。不用担心一些细节不太理解,在这本书之后的章节中会详细的为你介绍。 - - -“Simple Values -Use let to make a constant and var to make a variable. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once. This means you can use constants to name a value that you determine once but use in many places.” -简单值 -使用let声明常量,var声明变量。在编译的时候不需要知道常量的值,但是你只能给常量显式地赋值一次。也就是说你可以给常量赋一次值然后在其他一些地方来使用。 - -“A constant or variable must have the same type as the value you want to assign to it. However, you don’t always have to write the type explicitly. Providing a value when you create a constant or variable lets the compiler infer its type. In the example above, the compiler infers that myVariable is an integer because its initial value is a integer.” -不管是常量还是变量必须与其所赋的值类型保持一致。你不一定要把常量或者变量的类型显式地写出来。因为编译器可以根据值来自动推断常量或者变量的类型。如上面的例子,编译器根据myVariable的初始值类型推断出它是一个整型变量。 - -“If the initial value doesn’t provide enough information (or if there is no initial value), specify the type by writing it after the variable, separated by a colon.” -如果初始值没有提供足够的信息或者没有初始值,可以在变量后面写上它的类型,变量和类型用冒号隔开。 - -“Values are never implicitly converted to another type. If you need to convert a value to a different type, explicitly make an instance of the desired type.” -值的类型不会自动转换,如果你需要把一个值转换成另外一种类型,需要强制转换。 - -“There’s an even simpler way to include values in strings: Write the value in parentheses, and write a backslash (\) before the parentheses. For example:” -有一种更简单的把值转换成字符串的方法:把值写在括号里,然后在括号前加一个反斜杠。例如: - -“Create arrays and dictionaries using brackets ([]), and access their elements by writing the index or key in brackets.” -用中括号创建数组和字典,通过中括号里的索引和键来访问集合中的元素。 - -“To create an empty array or dictionary, use the initializer syntax.” -用下面的初始化语法来创建一个空的数组或字典 - -“If type information can be inferred, you can write an empty array as [] and an empty dictionary as [:]—for example, when you set a new value for a variable or pass an argument to a function.” -如果类型可以被推断出来,你可以用[]来创建一个空数组,用[:]来创建一个空字典。例如,当你给一个变量赋值或者给一个函数传参 - -“Control Flow -Use if and switch to make conditionals, and use for-in, for, while, and do-while to make loops. Parentheses around the condition or loop variable are optional. Braces around the body are required.” -流控制 -使用if和switch来进行条件控制,使用for-in、for、while和do-while来进行循环控制。条件和循环变量外面的括号可以省略,但是语句体的大括号是必须的。 - -“In an if statement, the conditional must be a Boolean expression—this means that code such as if score { ... } is an error, not an implicit comparison to zero.” -在if语句里,条件必须是一个Boolean表达式。所以if score { ... }这种写法是错误的,score不会隐式地和0来比较。 - -“You can use if and let together to work with values that might be missing. These values are represented as optionals. An optional value either contains a value or contains nil to indicate that the value is missing. Write a question mark (?) after the type of a value to mark the value as optional.” -你可以一起使用if和let来处理值缺失的情况。有些变量的值是可选的。一个可选的值可能是一个具体的值或者是nil,表示值缺失。在类型后面加一个问号来标记这个变量的值是可选的。 - -“If the optional value is nil, the conditional is false and the code in braces is skipped. Otherwise, the optional value is unwrapped and assigned to the constant after let, which makes the unwrapped value available inside the block of code.” -如果变量的可选值是nil,则判断条件为false,大括号中的代码被略过。如果不为nil,可选值会赋值给let后的常量,并且该常量可以在代码块中使用。 - -“Switches support any kind of data and a wide variety of comparison operations—they aren’t limited to integers and tests for equality.” -Switch支持各种类型的数据以及大量的比较操作-它们不仅限于整数和比较大小。 - -“After executing the code inside the switch case that matched, the program exits from the switch statement. Execution doesn’t continue to the next case, so there is no need to explicitly break out of the switch at the end of each case’s code.” -与switch的case相匹配的代码执行完之后,程序不会继续执行下一个case中的代码,而是会自动退出switch语句,所以不需要在每一个case的代码后面显式的调用break。 - -“You use for-in to iterate over items in a dictionary by providing a pair of names to use for each key-value pair.” -你可以使用for-in来遍历字典,用两个变量来表示每对键值。 - -“Use while to repeat a block of code until a condition changes. The condition of a loop can be at the end instead, ensuring that the loop is run at least once.” -使用while来重复执行一段代码直到条件改变。循环条件也可也在末尾,以保证循环至少可执行一次。 - -“You can keep an index in a loop—either by using .. to make a range of indexes or by writing an explicit initialization, condition, and increment. These two loops do the same thing:” -在循环中可以使用..来表示索引范围或者使用传统的方式。两者是等价的。 - -“Use .. to make a range that omits its upper value, and use ... to make a range that includes both values.” -使用..会忽略范围中的上限值,使用...则不会忽略。 - -“Functions and Closures -Use func to declare a function. Call a function by following its name with a list of arguments in parentheses. Use -> to separate the parameter names and types from the function’s return type.” -函数和闭包 -使用func来声明一个函数。在函数名后的括号里加入参数来调用函数。使用->分隔开函数的参数和函数的返回值类型。 - -“Use a tuple to return multiple values from a function.” -使用元组来返回一组值。 - -“Functions can also take a variable number of arguments, collecting them into an array.” -函数可以有一组可变个数的参数,由array来表示。 - -“Functions can be nested. Nested functions have access to variables that were declared in the outer function. You can use nested functions to organize the code in a function that is long or complex.” -函数可以嵌套,被嵌套的函数可以访问外部函数中声明的变量。你可以使用嵌套函数来重构一段很长很复杂的函数。 - -“Functions are a first-class type. This means that a function can return another function as its value.” -函数是first-class类型,因此它可以作为另一个函数的返回值。 - -“A function can take another function as one of its arguments.” -函数可以作为另一个函数的参数。 - -“Functions are actually a special case of closures. You can write a closure without a name by surrounding code with braces ({}). Use in to separate the arguments and return type from the body.” -函数实际上是一个特殊的闭包。你可以把一段代码写在大括号{}中来表示一个匿名闭包,参数和返回类型与闭包体之间用in来分隔。 - -“You have several options for writing closures more concisely. When a closure’s type is already known, such as the callback for a delegate, you can omit the type of its parameters, its return type, or both. Single statement closures implicitly return the value of their only statement.” -有一些简洁表示闭包的方式。当一个闭包的类型已知,例如作为委托的回调,可以省略它的参数和返回类型。单个语句闭包会把它语句的值当做结果返回。 - -“You can refer to parameters by number instead of by name—this approach is especially useful in very short closures. A closure passed as the last argument to a function can appear immediately after the parentheses.” -你可以使用参数位置替代参数名来引用参数-这个方法特别是在很短的闭包里很好用。闭包作为函数最后一个参数的时候,可以直接跟在小括号后面。 - -“Objects and Classes -Use class followed by the class’s name to create a class. A property declaration in a class is written the same way as a constant or variable declaration, except that it is in the ” -“context of a class. Likewise, method and function declarations are written the same way.” -对象和类 -使用class和类名来创建一个类。类中的属性声明是和常量或者变量的声明方式一样的,唯一的区别是属性声明是在类的上下文之中的。同样的,方法和函数的声明也是一样的。 - -“Create an instance of a class by putting parentheses after the class name. Use dot syntax to access the properties and methods of the instance.” -类名后面跟小括号来创建一个类的实例。使用点语法来访问该实例的属性和方法。 - -“This version of the Shape class is missing something important: an initializer to set up the class when an instance is created. Use init to create one.” -这个版本的Shape类缺少了一个重要的东西:类实例化时候的一个构造器。使用init来创造一个构造器。 - -“Notice how self is used to distinguish the name property from the name argument to the initializer. The arguments to the initializer are passed like a function call when you create an instance of the class. Every property needs a value assigned—either in its declaration (as with numberOfSides) or in the initializer (as with name).” -注意用self来区分name属性和传递给构造器的name参数。像函数调用一样,把参数传递给构造器来创建一个类实例。每一个属性都需要赋值,在属性的声明中(如numberOfSides),或者在构造器中(如name) - -“Use deinit to create a deinitializer if you need to perform some cleanup before the object is deallocated.” -“Subclasses include their superclass name after their class name, separated by a colon. There is no requirement for classes to subclass any standard root class, so you can include or omit a superclass as needed.” -使用deinit来创建一个析构器来执行对象销毁前的清理工作。 -定义子类的时候是在类名后加上父类的名字,中间用冒号隔开。因为类不需要继承任何标准的基类,所以你可以省略父类。 - -“Methods on a subclass that override the superclass’s implementation are marked with override—overriding a method by accident, without override, is detected by the compiler as an error. The compiler also detects methods with override that don’t actually override any method in the superclass.” -子类方法重写父类方法的时候标记为override-这是为了防止意外的重写,如果没有override关键字,编译器会报错。编译器同样会检测在子类标记为override的方法是否真的重写了父类的某个方法。 - -“In addition to simple properties that are stored, properties can have a getter and a setter.” -属性也可以有getter和setter方法。 - -“In the setter for perimeter, the new value has the implicit name newValue. You can provide an explicit name in parentheses after set.” -在setter方法中,新的属性值被隐式地命名为newValue。你可以在set后的括号里显式地给属性值命名。 - -“Notice that the initializer for the EquilateralTriangle class has three different steps: -Setting the value of properties that the subclass declares. -Calling the superclass’s initializer. -Changing the value of properties defined by the ” -“superclass. Any additional setup work that uses methods, getters, or setters can also be done at this point.” -注意创建EquilateralTriangle类的构造器包含三个不同的步骤。 -1.在子类声明的时候设置属性值。 -2.调用父类的构造器。 -3.改变定义在父类中的属性值,还有调用方法,getter和setter方法都可以在这个步骤完成。 - -“If you don’t need to compute the property but still need to provide code that is run before and after setting a new value, use willSet and didSet. For example, the class below ensures that the side length of its triangle is always the same as the side length of its square.” -如果你不需要计算属性,但仍需要在给属性设置新值的前后运行一些代码,使用willSet和didSet。例如,下面的类会确保三角形的边长和方形的边长相等。 - -“Methods on classes have one important difference from functions. Parameter names in functions are used only within the function, but parameters names in methods are also used when you call the method (except for the first parameter). By default, a method has the same name for its parameters when you call it and within the method itself. You can specify a second name, which is used inside the method.” -类中的方法和函数有一个很重要的区别。函数中的参数只会在函数内部使用,但是方法中的参数还可以在方法调用的时候使用(除了第一个参数)。默认情况下,方法调用时候的参数名和方法内部使用的参数名保持一致。在方法内部使用的时候你也可以定义一个不同的名字。 - -“When working with optional values, you can write ? before operations like methods, properties, and subscripting. If the value before the ? is nil, everything after the ? is ignored and the value of the whole expression is nil. Otherwise, the optional value is unwrapped, and everything after the ? acts on the unwrapped value. In both cases, the value of the whole expression is an optional value.” -处理可选值的时候,你可以在?后面跟上方法,属性,子脚本等操作。如果?之前的值是nil,?后面的代码会被忽略,然后整个表达式的值返回nil。否则,?之后的代码会执行。在这两种情况下,整个表达式就是一个可选值。 - -“Enumerations and Structures -Use enum to create an enumeration. Like classes and all other named types, enumerations can have methods associated with them.” -枚举和结构体 -使用enum来创建一个枚举。像类和其他命名类型一样,枚举可以有方法。 - -“In the example above, the raw value type of the enumeration is Int, so you only have to specify the first raw value. The rest of the raw values are assigned in order. You can also use strings or floating-point numbers as the raw type of an enumeration.” -在上面的例子中,枚举的原始值类型是Int,所以你只需要指定第一个值,其余的会按照顺序进行赋值。你同样可以使用字符串和浮点数作为枚举的原始类型。 - -“Use the toRaw and fromRaw functions to convert between the raw value and the enumeration value.” -使用toRaw和fromRaw这两个函数用于在原始值和枚举值之间转换。 - -“The member values of an enumeration are actual values, not just another way of writing their raw values. In fact, in cases where there isn’t a meaningful raw value, you don’t have to provide one.” -枚举的成员值是实际值,并不是原始值的另一种表示方式。实际上,如果原始值没有意义,你就不需要提供。 - -“Notice the two ways that the Hearts member of the ” -“enumeration is referred to above: When assigning a value to the hearts constant, the enumeration member Suit.Hearts is referred to by its full name because the constant doesn’t have an explicit type specified. Inside the switch, the enumeration is referred to by the abbreviated form .Hearts because the value of self is already known to be a suit. You can use the abbreviated form anytime the value’s type is already known.” -注意,有两种方式可以引用Hearts成员:当给hearts常量赋值时,通过Suit.Hearts全名来引用枚举成员,因为常量没有显式指定其类型。在switch语句内部,因为已知self是一个suit,所以可以通过.Hearts这种简写的方式来引用枚举。在已知值类型的情况下你都可以采用简写的方式。 - -“Use struct to create a structure. Structures support many of the same behaviors as classes, including methods and initializers. One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.” -使用struct来创建一个结构体。结构体支持很多和类同样的操作,包括方法和构造器。两者之间最重要的差别是结构体在代码中传递采用的是拷贝的方式,但是类采用的是传递引用的方式。 - -“An instance of an enumeration member can have values associated with the instance. Instances of the same enumeration member can have different values associated with them. You provide the associated values when you create the instance. Associated values and raw values are different: The raw value of an enumeration member is the ”“same for all of its instances, and you provide the raw value when you define the enumeration.” -一个枚举成员的实例可以有对应的实例值。相同枚举成员的实例可以有不同的实例值。当你创建一个实例的时候提供对应的实例值。实例值和原始值是不同的:枚举成员所有的实例的原始值都是相同的,而且你是在定义枚举的时候提供原始值。 - -“For example, consider the case of requesting the sunrise and sunset time from a server. The server either responds with the information or it responds with some error information.” -例如,考虑从服务端获取日出和日落的时间。服务端要么返回正常信息,要么返回错误信息。 - -“Notice how the sunrise and sunset times are extracted from the ServerResponse value as part of matching the value against the switch cases.” -注意,如何从ServerResponse中提去日出和日落时间。 - -Protocols and Extensions -“Use protocol to declare a protocol.” -协议和扩展 -使用protocol来声明一个协议 - -“Classes, enumerations, and structs can all adopt protocols.” -类,枚举,结构体都可以遵循协议 - -“Notice the use of the mutating keyword in the declaration of SimpleStructure to mark a method that modifies the structure. The declaration of SimpleClass doesn’t need any of its methods marked as mutating because methods on a class can always modify the class.” -注意,在SimpleStructure的声明中使用关键字mutating来标记一个会修改结构体的方法。在SimpleClass的声明中不需要用关键字mutating来标记类中的方法,因为类中的方法总是可以修改类。 - -“Use extension to add functionality to an existing type, such as new methods and computed properties. You can use an extension to add protocol conformance to a type that is declared elsewhere, or even to a type that you imported from a library or framework.” -使用扩展给一个已存在的类型增加功能,例如一些新方法和计算过的属性。你可以使用扩展给一个在别处声明的类型增加协议,甚至是给一个从库和框架中引入的类型增加协议。 - -“You can use a protocol name just like any other named type—for example, to create a collection of objects that have different types but that all conform to a single protocol. When you work with values whose type is a protocol type, methods outside the protocol definition are not available.” -你可以像使用其他命名类型一样使用协议名-例如,创建一个具有不同类型但是遵循同一协议的对象集合。当你处理一些协议类型的值的时候,协议定义之外的方法是不可用的。 - -“Even though the variable protocolValue has a runtime type of SimpleClass, the compiler treats it as the given type of ExampleProtocol. This means that you can’t accidentally access methods or properties that the class implements in addition to its protocol conformance.” -虽然变量protocolValue具有一个运行时类型SimpleClass,编译器是把它当做一个协议类型来处理的。这意味着你不能够访问协议没有指定的方法和属性。 - -Generics -“Write a name inside angle brackets to make a generic function or type.” -泛型 -在尖括号中写一个名字来创建一个泛型函数或类型。 - -“You can make generic forms of functions and methods, as well as classes, enumerations, and structures.” -你可以使用泛型来创建函数,方法,类,枚举和结构体。 - -“Use where after the type name to specify a list of ” -“requirements—for example, to require the type to implement a protocol, to require two types to be the same, or to require a class to have a particular superclass.” -在类型名之后使用where来指定一些条件-例如,要求类型遵循某个协议,要求两个类型相同,或者要求一个类有一个特定的父类。 - -“In the simple cases, you can omit where and simply write the protocol or class name after a colon. Writing is the same as writing .” -在简单情况下,你可以省略where,然后在协议和类名之间用冒号隔开。 是等价的。 diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md deleted file mode 100644 index c3a543a..0000000 --- a/src/chapter2/09_Classes_and_Structures.md +++ /dev/null @@ -1,662 +0,0 @@ -## Classes and Structures -## 类与结构体 - -*Classes* and *structures* are general-purpose, flexible constructs that become the building blocks of your program’s code. You define properties and methods to add functionality to your classes and structures by using exactly the same syntax as for constants, variables, and functions.” - -*类*和*结构体*是通用的、灵活的结构,是您搭建代码的基石。您可以使用和定义常量、变量或函数相同的句法,为类添加属性和方法以增加新的功能。 - -Unlike other programming languages, Swift does not require you to create separate interface and implementation files for custom classes and structures. In Swift, you define a class or a structure in a single file, and the external interface to that class or structure is automatically made available for other code to use. - -与其他编程语言不同,Swift并不强制要求分隔自定义类或结构体的头文件和实现文件。在Swift中,你只需将类或结构体定义在一个文件中,这个类或结构体的外部接口就自动能被其他代码使用。 - -``` -NOTE - -An instance of a class is traditionally known as an object. However, Swift classes and structures are much closer in functionality than in other languages, and much of this chapter describes functionality that can apply to instances of either a class or a structure type. Because of this, the more general term instance is used. -``` - -``` -注意 -类的实例通常被当作为一个对象。但与其他语言相比,Swift中的类和结构体从功能上来说更为相似。本章中介绍的大部分功能,可以适用于任何一个类或者结构体的实例。因此我们将使用一个更加宽泛的词语--实例(instance)来描述类和结构体。 -``` - -### Comparing Classes and Structures -### 比较类和结构体 -Classes and structures in Swift have many things in common. Both can: - -* Define properties to store values -* Define methods to provide functionality -* Define subscripts to provide access to their values using subscript syntax -* Define initializers to set up their initial state -* Be extended to expand their functionality beyond a default implementation -* Conform to protocols to provide standard functionality of a certain kind - -For more information, see [Properties](), [Methods](), [Subscripts](), [Initialization](), [Extensions](), and [Protocols](). - - -在Swift中类和结构体有许多相同之处,它们都有如下功能: - -* 能定义属性以便存储数据 -* 能定义方法以便提供功能 -* ~~定义了下标以便使用下标语法来访问实例的值~~ -* 能定义设定初始状态的初始化方法 -* 能被扩展,使其有默认实现之外的功能 -* 遵从协议(protocol)规则,以便提供~~协议所规定类型的标准功能~~ - -欲了解更多信息,请参见[属性](),[方法](),[下标](),[构造过程](),[扩展]()和[协议]()章节。 - -Classes have additional capabilities that structures do not: - -* Inheritance enables one class to inherit the characteristics of another. -* Type casting enables you to check and interpret the type of a class instance at runtime. -* Deinitializers enable an instance of a class to free up any resources it has assigned. -* Reference counting allows more than one reference to a class instance. - -For more information, see [Inheritance](), [Type Casting](), [Initialization](), and [Automatic Reference Counting](). - -不过类也有一些结构体没有的额外功能: - -* 继承使得一个类能继承来自另一个类的特性。 -* 类型转换可以在运行时检查和解析一个类的实例的类型。 -* 析构方法让类的实例被~~指派给了其他内存~~时能够释放自己的资源。 -* 引用计数允许一个类的实例被多处引用。 - -欲了解更多信息,请参见[继承](),[类型转换](),[构造过程](),[自动引用计数]()章节。 - -``` -NOTE - -Structures are always copied when they are passed around in your code, and do not use reference counting. -``` - -``` -注意: -结构体在代码中被传递时始终是传值,不会涉及到引用计数 - -``` - -‌ -### Definition Syntax -### 定义语法 - -Classes and structures have a similar definition syntax. You introduce classes with the `class` keyword and structures with the `struct` keyword. Both place their entire definition within a pair of braces: - -定义类和结构体的语法相似。定义类以关键词`class`开头,而定义结构体以关键词`struct`开头。类和结构体的所有定义都写在一对大括号内: - -``` -class SomeClass { - // class definition goes here -} -struct SomeStructure { - // structure definition goes here -} -``` - - - -``` -NOTE - -Whenever you define a new class or structure, you effectively define a brand new Swift type. Give types UpperCamelCase names (such as SomeClass and SomeStructure here) to match the capitalization of standard Swift types (such as String, Int, and Bool). Conversely, always give properties and methods lowerCamelCase names (such as frameRate and incrementCount) to differentiate them from type names. -``` - - -``` -注意: - -当你定义一个新的类或者结构体时,你实际上定义了一种新的Swift类型。为了和Swift标准类型(像String,Int,Bool)保持一致,请使用首字母大写的驼峰命名法(例如SomeClass或者SomeStructure)。相反的,为了和类型名区分,属性和方法名建议使用小写驼峰命名法(如frameRate或者incrementCount)。 -``` - -Here’s an example of a structure definition and a class definition: - -下方给出了结构体和类定义的例子: - - -``` -struct Resolution { - var width = 0 - var height = 0 -} -class VideoMode { - var resolution = Resolution() - var interlaced = false - var frameRate = 0.0 - var name: String? -} -``` - -The example above defines a new structure called `Resolution`, to describe a pixel-based display resolution. This structure has two stored properties called `width` and `height`. Stored properties are constants or variables that are bundled up and stored as part of the class or structure. These two properties are inferred to be of type `Int` by setting them to an initial integer value of 0. - -例子定义了一个名叫`Resolution`的新结构体,用来描述一个基于像素的显示方案。这个结构体有两个~~属性~~:`宽`和`高`。~~属性~~是捆绑存储在类和结构体中的变量或常量。这两个属性的类型将被编译器推断为`Int`,并赋予初始值0。 - -The example above also defines a new class called `VideoMode`, to describe a specific video mode for video display. This class has four variable stored properties. The first, `resolution`, is initialized with a new `Resolution` structure instance, which infers a property type of `Resolution`. For the other three properties, new `VideoMode` instances will be initialized with an `interlaced` setting of `false` (meaning “non-interlaced video”), a playback frame rate of `0.0`, and an optional `String` value called `name`. The `name` property is automatically given a default value of `nil`, or “no `name` value”, because it is of an optional type. - -例子中也定义了一个名叫`VideoMode`的新类,用来表示视频显示的模式。VideoMode类中有四个属性。第一个是`resolution`,它在这里被初始化为一个新的`Resolution`结构体实例,而编译器将自动推断分辨率的类型为`Resolution`。除此之外新的`VideoMode`实例还将初始化三个属性,默认为`false`的`interlaced`(意味着这是个“不交错的视频”),默认值为`0.0`表示播放帧速率的`frameRate`,以及一个值可选类型为`String`的`name`。属性`name`将自动赋值为`nil`,或者说`name`无值,因为它的值是可选的。 - -### Class and Structure Instances -### 类和结构体的实例 - -The `Resolution` structure definition and the `VideoMode` class definition only describe what a `Resolution` or `VideoMode` will look like. They themselves do not describe a specific resolution or video mode. To do that, you need to create an instance of the structure or class. - -结构体`Resolution`和类`VideoMode`的定义只是告诉你`Resolution`和`VideoMode`含有什么内容。但他们本身并不描述一个特定的分辨率或者视频模式。要做到这一点,我们要生成一个他们的实例。 - -The syntax for creating instances is very similar for both structures and classes: - -生成结构体实例和生成类实例的语法非常类似: - -``` -let someResolution = Resolution() -let someVideoMode = VideoMode() -``` - -Structures and classes both use initializer syntax for new instances. The simplest form of initializer syntax uses the type name of the class or structure followed by empty parentheses, such as `Resolution()` or `VideoMode()`. This creates a new instance of the class or structure, with any properties initialized to their default values. Class and structure initialization is described in more detail in [Initialization](). - -结构体和类都是用初始化语法来生成新的实例。初始化语法最简单的形式是结构体或类的类型名后加上空括号,例如`Resolution()`和`VideoMode()`。这将创建一个所有的属性都是默认值的结构体或类。类和结构体的初始化在[构造过程]()章节中有更详细的说明。 - -### Accessing Properties -### 属性的访问 -You can access the properties of an instance using *dot syntax*. In dot syntax, you write the property name immediately after the instance name, separated by a period (.), without any spaces: - -你可以使用*点语法*访问实例的属性。使用点语法时,属性名将紧跟在实例名之后,中间以句号(.)隔开: - -``` -println("The width of someResolution is \(someResolution.width)") -// prints "The width of someResolution is 0 -``` - -In this example, `someResolution.width` refers to the `width` property of `someResolution`, and returns its default initial value of `0`. - -在这个例子中,`someResolution.width`表示`someResolution`的`width`属性,且返回默认初始值`0`。 - -You can drill down into sub-properties, such as the `width` property in the `resolution` property of a `VideoMode`: - -你可以继续使用点语法来访问属性的属性,例如`VideoMode`中`resolution`的属性`width`: - -``` -println("The width of someVideoMode is \(someVideoMode.resolution.width)") -// prints "The width of someVideoMode is 0" -``` - -You can also use dot syntax to assign a new value to a variable property: -我们还可以使用点语法来为属性变量赋值: - -``` -someVideoMode.resolution.width = 1280 -println("The width of someVideoMode is now \(someVideoMode.resolution.width)") -// prints "The width of someVideoMode is now 1280" -``` - -``` -NOTE - -Unlike Objective-C, Swift enables you to set sub-properties of a structure property directly. In the last example above, the width property of the resolution property of someVideoMode is set directly, without your needing to set the entire resolution property to a new value. -``` -``` -注意: - -与Objective-C不同,Swift允许直接为结构体的属性的子属性赋值。在上方的例子中,someVideoMode中属性resolution的子属性width被直接赋值了,不再需要给整个resolution属性赋予新值。 -``` -‌ -### Memberwise Initializers for Structure Types -### 结构体带参数的初始化方法 - -All structures have an automatically-generated memberwise initializer, which you can use to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name: - -所有结构体都有一个自动生成的带参数的初始化方法,用于新结构体实例成员属性的初始化。新实例属性的初值会通过变量名传递到带参数的初始化方法里: - -``` -let vga = Resolution(width: 640, height: 480) -``` - -Unlike structures, class instances do not receive a default memberwise initializer. Initializers are described in more detail in [Initialization](). -与结构体不同,类市里没有默认的带参数的初始化方法。对初始化方法的详细说明见[构造过程]()章节。 - -‌ -### Structures and Enumerations Are Value Types -### 结构体和枚举都是值类型 - -A value *type* is a type that is copied when it is assigned to a variable or constant, or when it is passed to a function. -值*类型*的变量在赋值给一个变量、常量或作为参数传给函数时,传递的是该变量值的拷贝。 - -You’ve actually been using value types extensively throughout the previous chapters. In fact, all of the basic types in Swift—integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types, and are implemented as structures behind the scenes. - -实际上在前面章节我们已经广泛使用了值类型。事实上Swift中几乎所有的基本类型---如整数、浮点数、布尔值、字符串、数组和字典,都是值类型,并在底层都以结构体的方式来实现。 - -All structures and enumerations are value types in Swift. This means that any structure and enumeration instances you create—and any value types they have as properties—are always copied when they are passed around in your code. - -Swift中的所有结构体和枚举都是值类型。这意味着你创建的任何一个结构体或枚举的实例,以及他们的属性在代码中被传递的时候都会被复制。 - -Consider this example, which uses the `Resolution` structure from the previous example: - -让我们来看看这个例子,它使用了先前例子中定义的`Resolution`: - -``` -let hd = Resolution(width: 1920, height: 1080) -var cinema = hd -``` - -This example declares a constant called `hd` and sets it to a `Resolution` instance initialized with the width and height of full HD video (`1920` pixels wide by `1080` pixels high). - -例子中声明了一个名叫`hd`的常量,并将它初始化为全高清视频分辨率(宽`1920`长`1080`)的`Resolution`实例。 - -It then declares a variable called `cinema` and sets it to the current value of `hd`. Because `Resolution` is a structure, a copy of the existing instance is made, and this new copy is assigned to `cinema`. Even though `hd` and `cinema` now have the same width and height, they are two completely different instances behind the scenes. -然后例子中声明了一个变量`cinema`,将`hd`的当前值赋给了它。由于`Resolution`是结构体,赋值操作会生成一个新的实例并传递给`cinema`。因此虽然`hd`和`cinema`有相同的宽高,但它们实际上仍是完全不同的实例。 - -Next, the `width` property of `cinema` is amended to be the width of the slightly-wider 2K standard used for digital cinema projection (`2048` pixels wide and `1080` pixels high): - -接下来,将`cinema`的`width`属性改为数字电影中2K宽屏的标准宽度(宽`2048`像素高`1080`像素): - -``` -cinema.width = 2048 -``` - -Checking the `width` property of `cinema` shows that it has indeed changed to be `2048`: - -检查一下`cinema`的`width`属性的确改成了`2048`: - -``` -println("cinema is now \(cinema.width) pixels wide") -// prints "cinema is now 2048 pixels wide" -``` - -However, the `width` property of the original `hd` instance still has the old value of `1920`: -不过,原来的`hd`实例的`width`属性还是旧值`1920`: - -``` -println("hd is still \(hd.width) pixels wide") -// prints "hd is still 1920 pixels wide" -``` - -When `cinema` was given the current value of `hd`, the *values* stored in `hd` were copied into the new `cinema` instance. The end result is two completely separate instances, which just happened to contain the same numeric values. Because they are separate instances, setting the width of `cinema` to `2048` doesn’t affect the width stored in `hd`. - -当使用`hd`给`cinema`赋值时,`hd`存储的*值*被复制了一份并传递给`cinema`实例。结果`hd`和`cinema`成为了仅仅是属性值相同的两个完全无关的实例。所以将`cinema`的`width`属性改为`2048`不会影响`hd`中的`width`值。 - -The same behavior applies to enumerations: -枚举也有相同的特性: - -``` -enum CompassPoint { - case North, South, East, West -} -var currentDirection = CompassPoint.West -let rememberedDirection = currentDirection -currentDirection = .East -if rememberedDirection == .West { - println("The remembered direction is still .West") -} -// prints "The remembered direction is still .West" -``` - -When `rememberedDirection` is assigned the value of `currentDirection`, it is actually set to a copy of that value. - -当`rememberedDirection`赋值为`currentDirection`时,实际上只是赋值了值拷贝而已。 - -Changing the value of `currentDirection` thereafter does not affect the copy of the original value that was stored in `rememberedDirection`. -改变`currentDirection`的值并不会影响存储了原始值副本的`rememberedDirection`。 -‌ -### Classes Are Reference Types -### 类是引用类型 - -Unlike value types, *reference types* are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used instead. - -与值类型不同,在赋值给变量、常量或者传参时,引用类型不会被复制,而是传递与当前值相同的引用。 - -Here’s an example, using the `VideoMode` class defined above: -请看这个例子,例子中使用了上文定义的`VideoMode`: - -``` -let tenEighty = VideoMode() -tenEighty.resolution = hd -tenEighty.interlaced = true -tenEighty.name = "1080i" -tenEighty.frameRate = 25.0 -``` - -This example declares a new constant called `tenEighty` and sets it to refer to a new instance of the `VideoMode` class. The video mode is assigned a copy of the HD resolution of `1920` by `1080` from before. It is set to be interlaced, and is given a name of `"1080i"`. Finally, it is set to a frame rate of `25.0` frames per second. - -例子中声明了一个名为`tenEighty`的新常量,并将它赋值为一个新的`VideoMode`实例。视频模式使用了上文的`hd`值的拷贝,其分辨率为`1920`x`1080`。`tenEighty`的`interlaced`为true,`name`为`1080i`,`frameRate`为`25.0`帧每秒。 - -Next, `tenEighty` is assigned to a new constant, called `alsoTenEighty`, and the frame rate of `alsoTenEighty` is modified: - -然后,一个新常量`alsoTenEighty`被赋值为`tenEighty`,`alsoTenEighty`的帧率做了如下修改: - -``` -let alsoTenEighty = tenEighty -alsoTenEighty.frameRate = 30.0 -``` - -Because classes are reference types, `tenEighty` and `alsoTenEighty` actually both refer to the same `VideoMode` instance. Effectively, they are just two different names for the same single instance. - -因为类是引用类型,`tenEighty`和`alsoTenEighty`都指向了同一个`VideoMode`实例。实际上它们是同一个实例的两个不同的名字而已。 - -Checking the `frameRate` property of `tenEighty` shows that it correctly reports the new frame rate of `30.0` from the underlying `VideoMode` instance: - -接下来我们检查一下`tenEighty`的属性`frameRate`,这能说明`VideoMode`实例的帧率真的变成了新值`30.0`。 - -``` -println("The frameRate property of tenEighty is now \(tenEighty.frameRate)") -// prints "The frameRate property of tenEighty is now 30.0" -``` - -Note that `tenEighty` and `alsoTenEighty` are declared as constants, rather than variables. However, you can still change `tenEighty.frameRate` and `alsoTenEighty.frameRate` because the values of the `tenEighty` and `alsoTenEighty` constants themselves do not actually change. `tenEighty` and `alsoTenEighty` themselves do not “store” the `VideoMode` instance—instead, they both refer to a `VideoMode` instance behind the scenes. It is the `frameRate` property of the underlying `VideoMode` that is changed, not the values of the constant references to that `VideoMode`. - -请注意`tenEighty`和`alsoTenEighty`都被声明成了常量而不是变量。但是因为修改其属性的值并不会改变`tenEighty`和`alsoTenEighty`的值,我们还是可以修改`tenEighty.frameRate`和`alsoTenEighty.frameRate`。`tenEighty`和`alsoTenEighty`并不存储`VideoMode`实例,而是引用一个`VideoMode`实例的地址。改变`frameRate`的值只是改变了引用的`VideoMode`实例的属性,并没有改变引用的`VideoMode`的地址。 -‌ -### Identity Operators -### 身份操作符 - -Because classes are reference types, it is possible for multiple constants and variables to refer to the same single instance of a class behind the scenes. (The same is not true for structures and enumerations, because they are value types and are always copied when they are assigned to a constant or variable, or passed to a function.) - -因为类是引用类型,因此允许多个常量和变量都引用同一个类实例。(结构体和枚举却不是,因为它们是值类型,并且在赋值给变量常量或者传值的时候传递的都是值的拷贝。) - -It can sometimes be useful to find out if two constants or variables refer to exactly the same instance of a class. To enable this, Swift provides two identity operators: - -* Identical to (===) -* Not identical to (!==) - -有时候需要判断两个常量或变量是否指向同一个类实例。Swift提供了两个身份操作符来实现这个功能: - - * 指向同一实例(===) - * 指向不同实例(!==) - -Use these operators to check whether two constants or variables refer to the same single instance: - -以下例子使用了这两个操作符来判断两个常量或变量是否是同一实例: - -``` -if tenEighty === alsoTenEighty { - println("tenEighty and alsoTenEighty refer to the same Resolution instance.") -} -// prints "tenEighty and alsoTenEighty refer to the same Resolution instance." -``` - -Note that “identical to” (represented by three equals signs, or ===) does not mean the same thing as “equal to” (represented by two equals signs, or ==): - -提示:三个等号(===)的身份相等与两个等号(==)的值相等操作符是不一样的。 - -* “Identical to” means that two constants or variables of class type refer to exactly the same class instance. -* “Equal to” means that two instances are considered “equal” or “equivalent” in value, for some appropriate meaning of “equal”, as defined by the type’s designer. - - * 身份相等操作符两端的变量或常量比较的是是否从同一个类实例化而来。 - * 值相等操作符比较的则是两端的值或者对象的内存地址是否相等,这更接近我们平常理解的相等比较。 - -When you define your own custom classes and structures, it is your responsibility to decide what qualifies as two instances being “equal”. The process of defining your own implementations of the “equal to” and “not equal to” operators is described in Equivalence Operators. - -每当你定义一个类或者结构体时,你就有义务对两个实例的“相等”标准作出决断。在[比较运算符](#)中会描述如何去对对相等和不等的比较进行实现。 -‌ -### Pointers -### 指针 - -If you have experience with C, C++, or Objective-C, you may know that these languages use pointers to refer to addresses in memory. A Swift constant or variable that refers to an instance of some reference type is similar to a pointer in C, but is not a direct pointer to an address in memory, and does not require you to write an asterisk (*) to indicate that you are creating a reference. Instead, these references are defined like any other constant or variable in Swift. - -如果你之前有过编写C、C++或者Objective-C的经验,你应该会知道这些语言的指针都是对一个内存中的地址做引用的。一个变量或常量在Swift中与C的指针类似引用一个可以被引用的实例,但它不直接指向内存的某一个地址,也不需要在申明引用的变量名前加上星号(*)。在Swift中除此之外,引用的定义与其他语言相同。 - -## Choosing Between Classes and Structures - -You can use both classes and structures to define custom data types to use as the building blocks of your program’s code. - -在定义时你可以在你的代码中同时使用类和结构体来表示合适的数据类型。 - -However, structure instances are always passed by value, and class instances are always passed by reference. This means that they are suited to different kinds of tasks. As you consider the data constructs and functionality that you need for a project, decide whether each data construct should be defined as a class or as a structure. - -他们拥有不同的特性,结构体实例被赋值时始终传递的是值的拷贝,而类实例则始终传递的是引用。将他们根据项目的实际情况去选择定义出合适的数据是代码构建者应该去仔细斟酌的。 - -As a general guideline, consider creating a structure when one or more of these conditions apply: - -通常来说,符合以下一个或多个条件时应该使用结构体去定义数据: - -* The structure’s primary purpose is to encapsulate a few relatively simple data values. -* It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure. -* Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced. -* The structure does not need to inherit properties or behavior from another existing type. - -* 结构体主要目的时用来将少量相关数据进行封装。 -* 当期望实例在赋值时传递的是封装的值的被拷贝而不是仅仅是引用。 -* 当期望数据结构中的只类型也一同拷贝传值而不是传递引用。 -* 这个数据结构不需要去继承别的类。 - -Examples of good candidates for structures include: - -适合使用结构体的场景: - -* The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double. -* A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int. -* A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double. - -In all other cases, define a class, and create instances of that class to be managed and passed by reference. In practice, this means that most custom data constructs should be classes, not structures. - -* 用来描述几何图形的尺寸,包含了浮点类型的宽和高两个属性。 -* 用来描述一个范围,包含一个整型开始值和一个整型长度。 -* 用来描述一个三维坐标系统,包含双精度的x,y和z三个属性。 - -所有其他情况请定义类并使用类的实例以引用方式传递。实际上大多数情况还是应该用类来作为主要的数据结构承载,结构体仅在必要时。 - -## Assignment and Copy Behavior for Collection Types - -## 集合的赋值与拷贝 - -Swift’s Array and Dictionary types are implemented as structures. However, arrays have slightly different copying behavior from dictionaries and other structures when they are assigned to a constant or variable, and when they are passed to a function or method. - -在Swift中Array和Dictionary类型都是使用结构体实现的。然而当Array被赋值给常量、变量或者当作参数传入一个方法或者函数中时拷贝操作与Dictionary和其他结构体略有不同。 - -The behavior described for Array and Dictionary below is different again from the behavior of NSArray and NSDictionary in Foundation, which are implemented as classes, not structures. NSArray and NSDictionary instances are always assigned and passed around as a reference to an existing instance, rather than as a copy. - -以下Array和Dictionary与Foundation框架中的NSArray和NSDictionary的实现方式是有去别的,后者使用类实现,其实例在传递过程中均以引用形式进行传递而不是拷贝。 - -> NOTE -> -> The descriptions below refer to the “copying” of arrays, dictionaries, strings, and other values. Where copying is mentioned, the behavior you see in your code will always be as if a copy took place. However, Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so. Swift manages all value copying to ensure optimal performance, and you should not avoid assignment to try to preempt this optimization. - -> 提示 -> -> 以下是对于数组,字典,字符串和其它值的拷贝的描述。 在你的代码中出现拷贝引用的地方便会一直时拷贝引用。然而,Swift只在确实有必要发生拷贝行为的场景下才回执行拷贝操作。为了性能的最优,Swift将会在最合适的实际进行拷贝操作,以达到性能最优的目的,而开发者不关心这方面的性能问题也没关系。 - -### Assignment and Copy Behavior for Dictionaries - -### Dictionary的赋值与拷贝 - -Whenever you assign a Dictionary instance to a constant or variable, or pass a Dictionary instance as an argument to a function or method call, the dictionary is copied at the point that the assignment or call takes place. This process is described in Structures and Enumerations Are Value Types. - -只要将一个字典实例进行赋值或者传参操作,就会产生拷贝行为,在[结构体和枚举都是值类型](#)小节中有详细描述过。 - -If the keys and/or values stored in the Dictionary instance are value types (structures or enumerations), they too are copied when the assignment or call takes place. Conversely, if the keys and/or values are reference types (classes or functions), the references are copied, but not the class instances or functions that they refer to. This copy behavior for a dictionary’s keys and values is the same as the copy behavior for a structure’s stored properties when the structure is copied. - -如果字典实例中所储存的键值是结构体或枚举类型,那么赋值的时候也是拷贝赋值。相反,如果键值是引用类型,那么赋值操作只传递会引用,而不是实例本身的拷贝。在结构体中的键值也具有相同特性。 - -The example below defines a dictionary called ages, which stores the names and ages of four people. The ages dictionary is then assigned to a new variable called copiedAges and is copied when this assignment takes place. After the assignment, ages and copiedAges are two separate dictionaries. - -下面的示例定义了一个名为ages的字典实例,存储了四个人的名字和年龄。ages被赋值给了一个名为copiedAges的新变量时字典实例被重新复制了一份。赋值结束后,ages和copiedAges成为两个相互独立的字典实例。 - -``` -var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19] -var copiedAges = ages -``` - -The keys for this dictionary are of type String, and the values are of type Int. Both types are value types in Swift, and so the keys and values are also copied when the dictionary copy takes place. - -这个字典的键是字符串型,值是整型。这两种类型在Swift 中都是值类型,所以当字典被拷贝时,它们也都会被一起拷贝。 - -You can prove that the ages dictionary has been copied by changing an age value in one of the dictionaries and checking the corresponding value in the other. If you set the value for "Peter" in the copiedAges dictionary to 24, the ages dictionary still returns the old value of 23 from before the copy took place: - -我们可以通过改变一个字典中的年龄,然后检查另一个字典中所对应的值,来证明ages字典确实是被拷贝了。如果在copiedAges字典中将Peter的值设为24,那么ages字典中Peter值仍然会返回23: - -``` -copiedAges["Peter"] = 24 -println(ages["Peter"]) -// prints "23" -``` - -### Assignment and Copy Behavior for Arrays -### 数组的赋值与拷贝 - -The assignment and copy behavior for Swift’s Array type is more complex than for its Dictionary type. Array provides C-like performance when you work with an array’s contents and copies an array’s contents only when copying is necessary. - -在Swift 中,数组(Arrays)类型的赋值和拷贝行为要比字典(Dictionary)类型的复杂的多。当操作数组内容时,数组(Array)能提供接近C语言的的性能,并且拷贝行为只有在必要时才会发生。 - -If you assign an Array instance to a constant or variable, or pass an Array instance as an argument to a function or method call, the contents of the array are not copied at the point that the assignment or call takes place. Instead, both arrays share the same sequence of element values. When you modify an element value through one array, the result is observable through the other. - -如果你将一个数组(Arrays)实例赋给一个变量或常量,或者将其作为参数传递给函数或方法,在事件发生时数组的内容不会被拷贝。而且两个数组使用的还是同一套序列。只有当你在一个数组内修改某一元素,修改结果才c会在另一数组显示。 - -For arrays, copying only takes place when you perform an action that has the potential to modify the length of the array. This includes appending, inserting, or removing items, or using a ranged subscript to replace a range of items in the array. If and when array copying does take place, the copy behavior for an array’s contents is the same as for a dictionary’s keys and values, as described in Assignment and Copy Behavior for Dictionaries. - -对数组来说,拷贝行为仅仅当操作有可能修改数组长度时才会发生。这种行为包括了附加(appending),插入(inserting),删除(removing)或者使用范围下标(ranged subscript)去替换这一范围内的元素。只有当数组拷贝确要发生时,数组内容的行为规则与字典中键值的相同,详见[Dictionary的赋值与拷贝](#)。 - -The example below assigns a new array of Int values to a variable called a. This array is also assigned to two further variables called b and c: - -下面的示例将一个整数数组赋给了一个名为a的变量,继而又被赋给了变量b和c: - -``` -var a = [1, 2, 3] -var b = a -var c = a -``` - -You can retrieve the first value in the array with subscript syntax on either a, b, or c: - -我们可以在a,b,c上使用下标语法以得到数组的第一个元素: - -``` -println(a[0]) -// 1 -println(b[0]) -// 1 -println(c[0]) -// 1 -``` - -If you set an item in the array to a new value with subscript syntax, all three of a, b, and c will return the new value. Note that the array is not copied when you set a new value with subscript syntax, because setting a single value with subscript syntax does not have the potential to change the array’s length: - -如果通过下标语法修改数组中某一元素的值,那么a,b,c中的相应值都会发生改变。请注意当你用下标语法修改某一值时,并没有拷贝行为伴随发生,因为下表语法修改值时没有改变数组长度的可能: - -``` -a[0] = 42 -println(a[0]) -// 42 -println(b[0]) -// 42 -println(c[0]) -// 42 -``` - -However, if you append a new item to a, you do modify the array’s length. This prompts Swift to create a new copy of the array at the point that you append the new value. Henceforth, a is a separate, independent copy of the array. - -然而,当你给a附加新元素时,数组的长度发生改变。 Swift 会创建这个数组的一个拷贝。此后,a将会是一个独立拷贝。 - -If you change a value in a after the copy is made, a will return a different value from b and c, which both still reference the original array contents from before the copy took place: - -拷贝发生后,如果再修改a中元素值的话,a将会返回与b,c不同的结果,因为后两者引用的是原来的数组: - -``` -a.append(4) -a[0] = 777 -println(a[0]) -// 777 -println(b[0]) -// 42 -println(c[0]) -// 42 -``` - -#### Ensuring That an Array Is Unique - -#### 确保数组的唯一性 - -It can be useful to ensure that you have a unique copy of an array before performing an action on that array’s contents, or before passing that array to a function or method. You ensure the uniqueness of an array reference by calling the unshare method on a variable of array type. (The unshare method cannot be called on a constant array.) - -在操作一个数组,或将其传递给函数以及方法调用之前是很有必要先确定这个数组是有一个唯一拷贝的。通过在数组变量上调用unshare方法来确定数组引用的唯一性。(当数组赋给常量时,不能调用unshare方法) - -If multiple variables currently refer to the same array, and you call the unshare method on one of those variables, the array is copied, so that the variable has its own independent copy of the array. However, no copying takes place if the variable is already the only reference to the array. - -如果一个数组被多个变量引用,在其中的一个变量上调用unshare方法,则会拷贝此数组,此时这个变量将会有属于它自己的独立数组拷贝。当数组仅被一个变量引用时,则不会有拷贝发生。 - -At the end of the previous example, b and c both reference the same array. Call the unshare method on b to make it become a unique copy: - -在上一个示例的最后,b和c都引用了同一个数组。此时在b上调用unshare方法则会将b变成一个唯一个拷贝: - -``` -b.unshare() -``` - -If you change the first value in b after calling the unshare method, all three arrays will now report a different value: - -在unshare方法调用后再修改b中第一个元素的值,这三个数组(a,b,c)会返回不同的三个值: - -``` -b[0] = -105 -println(a[0]) -// 777 -println(b[0]) -// -105 -println(c[0]) -// 42 -``` - -#### Checking Whether Two Arrays Share the Same Elements - -#### 判定两个数组是否共用相同元素 - -Check whether two arrays or subarrays share the same storage and elements by comparing them with the identity operators (=== and !==). - -我们通过使用恒等运算符(identity operators) (=== 和 !==)来判定两个数组或子数组共用相同的储存空间或元素。 - -The example below uses the “identical to” operator (===) to check whether b and c still share the same array elements: - -下面这个示例使用了“等同(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.") -} -// prints "b and c now refer to two independent sets of array elements." -``` - -Alternatively, use the identity operators to check whether two subarrays share the same elements. The example below compares two identical subarrays from b and confirms that they refer to the same 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.") -} -// prints "These two subarrays share the same elements." -``` - -#### Forcing a Copy of an Array - -#### 强制复制数组 - -Force an explicit copy of an array by calling the array’s copy method. This method performs a shallow copy of the array and returns a new array containing the copied items. - -我们通过调用数组的copy方法进行强制显式复制。这个方法对数组进行了浅拷贝(shallow copy),并且返回一个包含此拷贝数组的新数组。 - -The example below defines an array called names, which stores the names of seven people. A new variable called copiedNames is set to the result of calling the copy method on the names array: - -下面这个示例中定义了一个names数组,其包含了七个人名。还定义了一个copiedNames变量,用以储存在names上调用copy方法所返回的结果: - -``` -var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"] -var copiedNames = names.copy() -``` - -You can prove that the names array has been copied by changing an item in one of the arrays and checking the corresponding item in the other. If you set the first item in the copiedNames array to "Mo" rather than "Mohsen", the names array still returns the old value of "Mohsen" from before the copy took place: - -我们可以通过修改数组中某一个元素,并且检查另一个数组中对应元素的方法来判定names数组确已被复制。如果你将copiedNames中第一个元素从"Mohsen"修改为"Mo",则names数组返回的仍是拷贝发生前的"Mohsen": - -``` -copiedNames[0] = "Mo" -println(names[0]) -// prints "Mohsen" -``` - - -> NOTE -> -> If you simply need to be sure that your reference to an array’s contents is the only reference in existence, call the unshare method, not the copy method. The unshare method does not make a copy of the array unless it is necessary to do so. The copy method always copies the array, even if it is already unshared. - -> 提示: -> -> 如果你仅需要确保你对数组的引用是唯一引用,请调用unshare方法,而不是copy方法。unshare方法只在必要时才会创建数组拷贝。copy方法会在任何时候都创建一个新的拷贝,即使已经标记为唯一。 \ No newline at end of file diff --git a/src/chapter2/10_Properties.md b/src/chapter2/10_Properties.md deleted file mode 100644 index 76d3e6a..0000000 --- a/src/chapter2/10_Properties.md +++ /dev/null @@ -1,666 +0,0 @@ -# Properties -# 属性 - -Properties associate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value. Computed properties are provided by classes, structures, and enumerations. Stored properties are provided only by classes and structures. - -属性将值与特定的类,结构体或者枚举关联起来,存储属性将常量或变量值作为实力的一部分保存起来,而计算属性则用来计算(而非存储)一个值。计算属性可以用于类,结构体和枚举,存储属性只能用于类和结构体。 - - -Stored and computed properties are usually associated with instances of a particular type. However, properties can also be associated with the type itself. Such properties are known as type properties. - -存储和计算属性通常用于特定类型的实例。不过,属性也可以用于类型本身,这样的属性被称为类属性。 - - -In addition, you can define property observers to monitor changes in a property’s value, which you can respond to with custom actions. Property observers can be added to stored properties you define yourself, and also to properties that a subclass inherits from its superclass. - -另外,可以为属性定义监听器,以监听属性值的变化,这样就可以在属性值发生变化时触发自定义操作。可以在定义存储属性的时候为其添加属性监听器,也可以为子类继承父类的属性添加监听器。 - - -## Stored Properties -## 存储属性 - -In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure. Stored properties can be either variable stored properties (introduced by the var keyword) or constant stored properties (introduced by the let keyword). -简单而言,存储属性是一个特定类型实例或结构体中的常量或变量。存储属性可以是变量存储属性(用关键词 `var` 声明),也可以是常量属性(用关键词 `let` 声明)。 - - -You can provide a default value for a stored property as part of its definition, as described in Default Property Values. You can also set and modify the initial value for a stored property during initialization. This is true even for constant stored properties, as described in Modifying Constant Properties During Initialization. - -在定义存储属性时,可以为其指定默认值,详见 Default Property Values 。在存储属性初始化过程中,依然可以设置和修改它的初始值,甚至修改常量存储属性,详见 Modifying Constant Properties During Initialization。 - - -The example below defines a structure called FixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created: - -下面的示例定义了一个名为 `FixedLengthRange` 的结构体,它表示一个整型的范围,其范围长度一旦创建不能改变: - - struct FixedLengthRange { - var firstValue: Int - let length: Int - } - var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3) - // 表示整型值的范围为 0, 1, 2 - rangeOfThreeItems.firstValue = 6 - // 修改 firstValue 后, 表示的整型值的范围为: 6, 7, 8 - -Instances of FixedLengthRange have a variable stored property called firstValue and a constant stored property called length. In the example above, length is initialized when the new range is created and cannot be changed thereafter, because it is a constant property. - -`FixedLengthRange` 的实例包含一个名为 `firstValue` 的变量存储属性和一个名为 `length` 常量存储属性。在上面的示例中, `length` 在 `FixedLengthRange` 实例创建时初始化,并且在此后不能被修改,因为它是一个常量属性。 - - -###Stored Properties of Constant Structure Instances -###存储属性与常量实例 - - -If you create an instance of a structure and assign that instance to a constant, you cannot modify the instance’s properties, even if they were declared as variable properties: - -如果你为一个结构体创建一个实例, 并且把这个实例赋值给一个常量, 那么无论这个实例的属性是否为变量, 其属性都不能被修改。 - - let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) - // this range represents integer values 0, 1, 2, and 3 - // 表示取值范围为 整数的 0, 1, 2, 3 - rangeOfFourItems.firstValue = 6 - // this will report an error, even thought firstValue is a variable property - // 尽管firstValue是变量属性, 对其赋值也会报错 - -Because rangeOfFourItems is declared as a constant (with the let keyword), it is not possible to change its firstValue property, even though firstValue is a variable property. -This behavior is due to structures being value types. When an instance of a value type is marked as a constant, so are all of its properties. - -因为 `rangeOfFourItems`通过`let`关键词声明, 所以是个常量, 故, 无论它的属性是否为变量, 都无法改变它的属性值。 所以, 当一个实例是常量类型, 那么它的所有属性也会变成常量类型。 - - -The same is not true for classes, which are reference types. If you assign an instance of a reference type to a constant, you can still change that instance’s variable properties. - -这种情况对于引用类型(类)并不适用。 如果将某个引用类型的实例赋值给一个常量, 那么依然可以修改该实例的属性。 - -###Lazy Stored Properties -###惰性存储属性 - - -A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the @lazy attribute before its declaration. - -惰性存储属性只有在首次调用时才会进行初始化。 通过在存储属性声明前加上 `@lazy` 来声明一个惰性存储属性。 - -> NOTE -You must always declare a lazy property as a variable (with the var keyword), because its initial value may not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy. - -> 注意 -在声明一个惰性存储属性时, 必须将其定义为变量(通过`var`声明)。 这样做的原因是, 在实例初始化完成前, 可能无法获得惰性属性的初始值。 相反的, 常量属性的初始值必须在实例初始化完成之前赋值,所以常量属性不能被声明为惰性属性。 - -Lazy properties are useful when the initial value for a property is dependent on outside factors whose values are not known until after an instance’s initialization is complete. Lazy properties are also useful when the initial value for a property requires complex or computationally expensive setup that should not be performed unless or until it is needed. - -当某个属性的初始化依赖于其他实例的初始化时,惰性属性是非常有用的。惰性属性在需要复杂计算和耗费时间较长的属性初始化时,也是非常有用的,因为它可以在需要时再进行计算和初始化。 - -The example below uses a lazy stored property to avoid unnecessary initialization of a complex class. This example defines two classes called DataImporter and DataManager, neither of which is shown in full: - -下面这个例子中,演示了在一个复杂类的初始化过程中,如何通过惰性存储属性来避免不必要的初始化。示例中定义了两个类:`DataImporter`, `DataManager`(代码片段)。 - - class DataImporter { - /* - DataImporter is a class to import data from an external file. - The class is assumed to take a non-trivial amount of time to initialize. - - DataImporter 是一个可以从外部文件导入数据的类 - 该类的初始化会消耗很长一段时间 - - */ - var fileName = "data.txt" - // the DataImporter class would provide data importing functionality here - // 这里是DataImporter类导入数据的代码 - } - - class DataManager { - @lazy var importer = DataImporter() - var data = String[]() - // the DataManager class would provide data management functionality here - // DataManager类数据管理功能的代码 - } - - let manager = DataManager() - manager.data += "Some data" - manager.data += "Some more data" - // the DataImporter instance for the importer property has not yet been created - // importer 实例尚未初始化 - - -The DataManager class has a stored property called data, which is initialized with a new, empty array of String values. Although the rest of its functionality is not shown, the purpose of this DataManager class is to manage and provide access to this array of String data. - -`DataManager` 类拥有一个名为 `data` 的存储属性,该属性是一个空的字符串数组。虽然剩余的功能代码没有展示出来,不过 `DataManager` 类的目的是提供管理和访问该字符串数组的功能。 - - -Part of the functionality of the DataManager class is the ability to import data from a file. This functionality is provided by the DataImporter class, which is assumed to take a non-trivial amount of time to initialize. This might be because a DataImporter instance needs to open a file and read its contents into memory when the DataImporter instance is initialized. - -`DataManager`类的一个功能是从文件中导入数据。 该功能由 `DataImporter` 类提供,需要花费很长时间进行初始化。原因是 `DataImporter` 类的实例在初始化的时候需要读取文件并将文件内容写入内存。 - -It is possible for a DataManager instance to manage its data without ever importing data from a file, so there is no need to create a new DataImporter instance when the DataManager itself is created. Instead, it makes more sense to create the DataImporter instance if and when it is first used. - -对于 `DataManager` 类来说,无论是从文件中导入了数据,都不影响它管理自己的数据,所以没必要在它自己初始化的时候就去创建 `DataManager` 实例。更好的做法是,将 `DataImporter` 实例在第一次使用的时候初始化。 - - -Because it is marked with the @lazy attribute, the DataImporter instance for the importer property is only created when the importer property is first accessed, such as when its fileName property is queried: - -因为使用了 `@lazy`,故 `DataImporter` 的实例 `importer` 只会在 `importer`的实例第一次被访问的时候才会初始化,例如访问它的 `fileName` 属性: - -println(manager.importer.fileName) -// the DataImporter instance for the importer property has now been created -//此时, `DataImporter` 的实例 `importer` 才被创建 -// prints "data.txt" - -###Stored Properties and Instance Variables - -###存储属性和实例变量 - - -If you have experience with Objective-C, you may know that it provides two ways to store values and references as part of a class instance. In addition to properties, you can use instance variables as a backing store for the values stored in a property. - -`Object-C`中类的实例对象有两种存储值和引用的方法。除了属性,还可以使用实例变量保存值。 - -Swift unifies these concepts into a single property declaration. A Swift property does not have a corresponding instance variable, and the backing store for a property is not accessed directly. This approach avoids confusion about how the value is accessed in different contexts and simplifies the property’s declaration into a single, definitive statement. All information about the property including its name, type, and memory management characteristics—is defined in a single location as part of the type’s definition. - -在`Swift`中没有实例变量,`Swift` 将这些概念统一为了属性。这样避免了在不同上下文中值的不同访问方式的混淆,并且使属性声明简单明了。所有的属性信息:名称,类型,内存管理特征都包含在类型定义中。 - -##Computed Properties - -##计算属性 - - -In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly. - -除了存储属性外,类,结构体,枚举还可以定义计算属性。计算属性不能存储值,而是通过 `getter` 方法和 `setter` 方法(可选)间接的设置其他属性和值。 - - struct Point { - var x = 0.0, y = 0.0 - } - struct Size { - var width = 0.0, height = 0.0 - } - struct Rect { - var origin = Point() - var size = Size() - var center: Point { - get { - let centerX = origin.x + (size.width / 2) - let centerY = origin.y + (size.height / 2) - return Point(x: centerX, y: centerY) - } - set(newCenter) { - origin.x = newCenter.x - (size.width / 2) - origin.y = newCenter.y - (size.height / 2) - } - } - } - var square = Rect(origin: Point(x: 0.0, y: 0.0), - size: Size(width: 10.0, height: 10.0)) - 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))") - // prints "square.origin is now at (10.0, 10.0)" - // 输出 "square.origin is now at (10.0, 10.0)" - -This example defines three structures for working with geometric shapes: - -这个示例定义了三个结构体来表示一个几何形状: - -Point encapsulates an (x, y) coordinate. -`Point` 封装了坐标(x, y)。 - -Size encapsulates a width and a height. - -`Size` 封装了宽度和高度。 - -Rect defines a rectangle by an origin point and a size. - -`Rect` 用坐标原点和大小定义了一个矩形。 - -The Rect structure also provides a computed property called center. The current center position of a Rect can always be determined from its origin and size, and so you don’t need to store the center point as an explicit Point value. Instead, Rect defines a custom getter and setter for a computed variable called center, to enable you to work with the rectangle’s center as if it were a real stored property. - -`Rect` 结构体提供了一个名为 `center` 的计算属性。矩形的中心点总是可以通过它的原点坐标和大小计算出来,所以你没有必要保存一个确切的矩形中心点的值。这里的 `Rect` 为一个名为 `center` 的计算属性定义了自定义的 `getter` 和 `setter` 方法,以此来设置矩形的中心点。 - -The preceding example creates a new Rect variable called square. The square variable is initialized with an origin point of (0, 0), and a width and height of 10. This square is represented by the blue square in the diagram below. - -例子中接下来创建了一个名为 `square` 的 `Rect` 实例,`point` 初始值为(0,0), `width` 和 `height` 都是10,在下图中用蓝色正方形表示。 - -The square variable’s center property is then accessed through dot syntax (square.center), which causes the getter for center to be called, to retrieve the current property value. Rather than returning an existing value, the getter actually calculates and returns a new Point to represent the center of the square. As can be seen above, the getter correctly returns a center point of (5, 5). - -然后通过点运算符(`square.center`)访问了 `square` 实例的 `center` 属性,此时会触发 `center` 的 `getter` 方法,并返回当前的属性值。和直接返回值不同, `getter` 方法会计算并返回最新的属性值。从上面的代码可以看出, `getter` 方法正确的返回了中心点 `(5, 5)`。 - - -The center property is then set to a new value of (15, 15), which moves the square up and to the right, to the new position shown by the orange square in the diagram below. Setting the center property calls the setter for center, which modifies the x and y values of the stored origin property, and moves the square to its new position. - -接着为 `center` 属性设置了新值 `(15, 15)`,在下图中可以看出 `square` 向右上移动到了一个新的位置(橙色区域)。在设置 `center` 属性时调用了它的 `setter` 方法,修改了 `origin` 的 `x,y`值,并且改变了 `square` 的位置。 - -![Alt text](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/computedProperties_2x.png) - - -###Shorthand Setter Declaration - -###Setter声明简写 - -If a computed property’s setter does not define a name for the new value to be set, a default name of newValue is used. Here’s an alternative version of the Rect structure, which takes advantage of this shorthand notation: - -如果没有给属性的 `setter` 方法的新值指定名称,那么可以使用默认值 `newValue` 。下面是 `Rect` 结构体的简写形式: - - struct AlternativeRect { - var origin = Point() - var size = Size() - var center: Point { - get { - let centerX = origin.x + (size.width / 2) - let centerY = origin.y + (size.height / 2) - return Point(x: centerX, y: centerY) - } - set { - origin.x = newValue.x - (size.width / 2) - origin.y = newValue.y - (size.height / 2) - } - } - } - - -###Read-Only Computed Properties - -###只读计算属性 - -A computed property with a getter but no setter is known as a read-only computed property. A read-only computed property always returns a value, and can be accessed through dot syntax, but cannot be set to a different value. - -只有 `getter` 没有 `setter` 的计算属性是只读计算属性。只读计算属性可以通过点操作符访问,但不能为其设置其他值。 - - -> NOTE - -> You must declare computed properties—including read-only computed properties—as variable properties with the var keyword, because their value is not fixed. The let keyword is only used for constant properties, to indicate that their values cannot be changed once they are set as part of instance initialization. - - -> 注意 - -> 必须使用 `var` 关键词定义计算属性,包括只读计算属性,因为它们的值是可能改变的。 `let` 关键词只用于常量属性,其值在初始化后不可改变。 - -必须使用var关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。 - - -You can simplify the declaration of a read-only computed property by removing the get keyword and its braces: - -只读计算属性的声明可以去掉get关键词和花括号: - - struct Cuboid { - var width = 0.0, height = 0.0, depth = 0.0 - var volume: Double { - return width * height * depth - } - } - - let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0) - println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") - // prints "the volume of fourByFiveByTwo is 40.0" - // 输出 "the volume of fourByFiveByTwo is 40.0" - -This example defines a new structure called Cuboid, which represents a 3D rectangular box with width, height, and depth properties. This structure also has a read-only computed property called volume, which calculates and returns the current volume of the cuboid. It doesn’t make sense for volume to be settable, because it would be ambiguous as to which values of width, height, and depth should be used for a particular volume value. Nonetheless, it is useful for a Cuboid to provide a read-only computed property to enable external users to discover its current calculated volume. - -这个示例定义了一个名为 `Cuboid` 的结构体,表示一个3D的立方体,有 `width`,`height`,`depth`等属性。它还有一个名为 `volume` 的只读计算属性用来计算并返回 `cuboid` 当前的体积。我们没有必要去设置 `volume` 的值,因为 `volume` 的值可以通过 `width`,`height`,`depth`计算出来。所以比较合适的做法是,提供一个只读计算属性让用户可以获得当前的 `volume` 。 - - -###Property Observers - -###属性观察者 - -Property observers observe and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value. - -属性观察者用来观察并响应属性值的变化。在为属性赋值时,无论新值是否与原值相同,都会触发属性的观察者。 - -You can add property observers to any stored properties you define, apart from lazy stored properties. You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass. Property overriding is described in Overriding. - -可以为除了惰性属性外的其他任何存储属性定义观察者。通过属性重写,可以在子类中为它的父类属性(无论是存储或是计算属性)添加观察者。属性重写在重写一章有详细介绍。 - - -> NOTE -> -> You don’t need to define property observers for non-overridden -> computed properties, because you can observe and respond to changes to -> their value from directly within the computed property’s setter. - -> 注意 -> -> 不需要为非重写计算属性定义观察者,因为你可以直接使用计算属性的`setter`来完成。 - - -You have the option to define either or both of these observers on a property: -* willSet is called just before the value is stored. -* didSet is called immediately after the new value is stored. - -可以通过两种方式为属性定义观察者: -* `willSet` 在值发生改变之前调用 -* `didSet` 在值发生改变之后调用 - - -If you implement a willSet observer, it is passed the new property value as a constant parameter. You can specify a name for this parameter as part of your willSet implementation. If you choose not to write the parameter name and parentheses within your implementation, the parameter will still be made available with a default parameter name of newValue. - -`willSet` 会将新属性值作为常量参数,并且可以为该常量参数指定名称。如果没有为该参数指定名称,那么会使用默认的参数名称 `newValue`。 - - -Similarly, if you implement a didSet observer, it will be passed a constant parameter containing the old property value. You can name the parameter if you wish, or use the default parameter name of oldValue. - -与 `willSet` 类似,`didSet` 会将原属性值作为常量参数。同样可以为参数指定名称或者使用默认值 `oldValue`。 - -> NOTE -> -> willSet and didSet observers are not called when a property is first -> initialized. They are only called when the property’s value is set -> outside of an initialization context. - -> 注意 -> -> `willSet` 和 `didSet` 在属性初始化时不会被调用。 - -Here’s an example of willSet and didSet in action. The example below defines a new class called StepCounter, which tracks the total number of steps that a person takes while walking. This class might be used with input data from a pedometer or other step counter to keep track of a person’s exercise during their daily routine. - -这里有一个使用了 `willSet` 和 `didSet` 的示例。示例中定义了一个名为 `StepCounter` 的类,用来统计当人步行时的总步数,通过使用计步器等装置可以用这个类追踪人在日常工作中的运动量。 - - class StepCounter { - var totalSteps: Int = 0 { - willSet(newTotalSteps) { - println("About to set totalSteps to \(newTotalSteps)") - } - didSet { - if totalSteps > oldValue { - println("Added \(totalSteps - oldValue) steps") - } - } - } - } - let stepCounter = StepCounter() - stepCounter.totalSteps = 200 - // About to set totalSteps to 200 - // Added 200 steps - // 输出 About to set totalSteps to 200 - // 输出 Added 200 steps - stepCounter.totalSteps = 360 - // About to set totalSteps to 360 - // Added 160 steps - // 输出 About to set totalSteps to 360 - // 输出 Added 160 steps - stepCounter.totalSteps = 896 - // About to set totalSteps to 896 - // Added 536 steps - // 输出 About to set totalSteps to 896 - // 输出 Added 536 steps - -The StepCounter class declares a totalSteps property of type Int. This is a stored property with willSet and didSet observers. - -`StepCounter`定义了一个 `int` 类型的属性 `totalSteps`。 `totalSteps` 包含了两个观察者`willSet`和`didSet`。 - - -The willSet and didSet observers for totalSteps are called whenever the property is assigned a new value. This is true even if the new value is the same as the current value. - -当`totalSteps`的值改变时(不论新值是否与原值相同),`willSet` 和 `didSet` 都会被调用。 - - -This example’s willSet observer uses a custom parameter name of newTotalSteps for the upcoming new value. In this example, it simply prints out the value that is about to be set. - -示例中的`willSet`使用了一个名为`newTotalSteps`的参数接收新值。在这个例子中只是简单的将新值输出。 - - -The didSet observer is called after the value of totalSteps is updated. It compares the new value of totalSteps against the old value. If the total number of steps has increased, a message is printed to indicate how many new steps have been taken. The didSet observer does not provide a custom parameter name for the old value, and the default name of oldValue is used instead. - -`didSet`观察者会在`totalSteps`的值被修改后调用。它将`totalSteps`的新值与原值做比较,如果新值大于原值,则会输出新增了多少步。`didSet`观察者没有指定参数名,所以使用默认参数名`oldValue`。 - - -> NOTE -> -> If you assign a value to a property within its own didSet observer, -> the new value that you assign will replace the one that was just set. - - -> 注意 - -> 如果在`didSet`中给属性设置新值,那么新值会替换刚刚设置的值。 - -##Global and Local Variables - -##全局变量和局部变量 - - -The capabilities described above for computing and observing properties are also available to global variables and local variables. Global variables are variables that are defined outside of any function, method, closure, or type context. Local variables are variables that are defined within a function, method, or closure context. - -上面关于属性的计算和观察功能对于全局变量和局部变量同样适用。全局变量定义在所有函数,方法,闭包,类型之外。局部变量定义在函数,方法或闭包内部。 - - -The global and local variables you have encountered in previous chapters have all been stored variables. Stored variables, like stored properties, provide storage for a value of a certain type and allow that value to be set and retrieved. - -在前面的章节中全局和局部变量都是存储变量,类似于存储属性,它为特定类型的值提供存储空间,并允许对其进行读写。 - - -However, you can also define computed variables and define observers for stored variables, in either a global or local scope. Computed variables calculate rather than store a value, and are written in the same way as computed properties. - -另外,还可以在全局或局部作用域中定义计算变量,或者为存储变量定义观察者。计算变量用来计算而非存储一个值,声明方式和计算属性一样。 - - -> NOTE -> -> Global constants and variables are always computed lazily, in a -> similar manner to Lazy Stored Properties. Unlike lazy stored -> properties, global constants and variables do not need to be marked -> with the @lazy attribute. -> -> Local constants and variables are never computed lazily. - - -> 注意 -> -> 和惰性存储属性的方式类似,全局常量和变量总是延迟计算的。不同的是,全局常量和变量不需要使用`@lazy`属性进行声明。 -> -> 局部常量和变量则绝不会延迟计算。 - - -##Type Properties - -##类型属性 - - -Instance properties are properties that belong to an instance of a particular type. Every time you create a new instance of that type, it has its own set of property values, separate from any other instance. - -实例属性属于一个特定类型的实例。每次创建该类型的实例,它都拥有自己独立的一组属性,与其他实例对象无关。 - - -You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties. - -还可以定义属于类型自身的属性。不论该类型有多少实例,这些属性都只有一份。这种属性被称为类型属性。 - - -Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use (like a static constant in C), or a variable property that stores a value that is global to all instances of that type (like a static variable in C). - -类型属性用于定义所有特定的类型实例都可以使用的值,比如所有实例都可以使用同一个常量属性(类似于`C`中的静态常量),或者就像所有的实例都可以使用全局变量属性(类似于`C`中的静态常量)。 - - -For value types (that is, structures and enumerations), you can define stored and computed type properties. For classes, you can define computed type properties only. - -对于值类型(结构和枚举),可以定义存储和计算类型的属性。对于类,则只能定义计算类型的属性。 - - -Stored type properties for value types can be variables or constants. Computed type properties are always declared as variable properties, in the same way as computed instance properties. - -值类型的存储类型属性可以是变量和常量。计算类型属性和计算实例属性相同,通常声明为变量属性。 - -> NOTE -> -> Unlike stored instance properties, you must always give stored type -> properties a default value. This is because the type itself does not -> have an initializer that can assign a value to a stored type property -> at initialization time. - -> 注意 -> -> 与存储实例属性不同,必须为存储类型属性定义默认值。原因是类型本身没有一个可以在初始化时为类型属性赋值的构造器。 - - -###Type Property Syntax - -###类型属性语法 - - -In C and Objective-C, you define static constants and variables associated with a type as global static variables. In Swift, however, type properties are written as part of the type’s definition, within the type’s outer curly braces, and each type property is explicitly scoped to the type it supports. - -在`C`和`Objective-C`中,只能使用全局静态变量来定义依赖于某个属性的变量或常量。但在`Swift`中,类型属性可以作为类型定义的一部分,它的作用域也在类型的范围内。 - - -You define type properties for value types with the static keyword, and type properties for class types with the class keyword. The example below shows the syntax for stored and computed type properties: - -使用`static`关键词定义值类型的类型属性,`class`类型的类型属性用关键词`class`声明。下面的示例演示了存储类型属性和计算类型属性的语法: - - - struct SomeStructure { - static var storedTypeProperty = "Some value." - static var computedTypeProperty: Int { - // return an Int value here - // 这里将返回一个`Int`的值 - } - } - enum SomeEnumeration { - static var storedTypeProperty = "Some value." - static var computedTypeProperty: Int { - // return an Int value here - // 这里将返回一个`Int`的值 - } - } - class SomeClass { - class var computedTypeProperty: Int { - // return an Int value here - // 这里将返回一个`Int`的值 - } - } - - -> NOTE -> -> The computed type property examples above are for read-only computed -> type properties, but you can also define read-write computed type -> properties with the same syntax as for computed instance properties. - -注意 - -上面的计算类型属性的示例都是只读的,仍然可以定义可读写的计算类型属性。 - - -###Querying and Setting Type Properties - -###查询和设置类型属性 - - -Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type. For example: - -就像实例属性,类型属性通过点操作符查询和设置。不过,类型属性的是通过类型自身查询和设置,而非类型的实例: - - println(SomeClass.computedTypeProperty) - // prints "42" - // 输出 "42" - - println(SomeStructure.storedTypeProperty) - // prints "Some value." - // 输出 "Some value." - SomeStructure.storedTypeProperty = "Another value." - println(SomeStructure.storedTypeProperty) - // prints "Another value." - // 输出 "Another value." - -The examples that follow use two stored type properties as part of a structure that models an audio level meter for a number of audio channels. Each channel has an integer audio level between 0 and 10 inclusive. - -下面的示例定义了一个结构体和两个类型属性来为声道音量建模。每一个声道的音量范围是0到10。 - - -The figure below illustrates how two of these audio channels can be combined to model a stereo audio level meter. When a channel’s audio level is 0, none of the lights for that channel are lit. When the audio level is 10, all of the lights for that channel are lit. In this figure, the left channel has a current level of 9, and the right channel has a current level of 7: - -下图演示了如何将两个声道合并为一个立体声道。当某个声道的音量值是0时,所有灯都不会亮。当音量值是10时,所有灯都会亮起。下图中,左侧的音量值为9,右侧的音量值为7: - - -![Alt text](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/staticPropertiesVUMeter_2x.png) - -The audio channels described above are represented by instances of the AudioChannel structure: - -上面的声道通过`AudioChannel`的结构体实例表示如下: - - struct AudioChannel { - static let thresholdLevel = 10 - static var maxInputLevelForAllChannels = 0 - var currentLevel: Int = 0 { - didSet { - if currentLevel > AudioChannel.thresholdLevel { - // cap the new audio level to the threshold level - // 将音量值设置为最大值 - currentLevel = AudioChannel.thresholdLevel - } - if currentLevel > AudioChannel.maxInputLevelForAllChannels { - // store this as the new overall maximum input level - // 将音量值设置为当前值 - AudioChannel.maxInputLevelForAllChannels = currentLevel - } - } - } - } - -The AudioChannel structure defines two stored type properties to support its functionality. The first, thresholdLevel, defines the maximum threshold value an audio level can take. This is a constant value of 10 for all AudioChannel instances. If an audio signal comes in with a higher value than 10, it will be capped to this threshold value (as described below). - -`AudioChannel`定义了两个存储属性。首先,定义了音量最大值`thresholdLevel`,它是一个对所有实例可见的常量值。如果音量大于10,那么就取上限值10。 - - -The second type property is a variable stored property called maxInputLevelForAllChannels. This keeps track of the maximum input value that has been received by any AudioChannel instance. It starts with an initial value of 0. - -第二个类型属性是一个名为`maxInputLevelForAllChannels`的变量存储属性,用来表示所有实例的最大音量值。初始值为0。 - - -The AudioChannel structure also defines a stored instance property called currentLevel, which represents the channel’s current audio level on a scale of 0 to 10. - -`AudioChannel`结构体还定义了一个实例属性`currentLevel`,用来表示当前声道的音量值,取值0到10。 - - -The currentLevel property has a didSet property observer to check the value of currentLevel whenever it is set. This observer performs two checks: - - -`currentLevel`的值在每次设置时都会通过`didSet`进行两种检查: - -* If the new value of currentLevel is greater than the allowed thresholdLevel, the property observer caps currentLevel to thresholdLevel. -* If the new value of currentLevel (after any capping) is higher than any value previously received by any AudioChannel instance, the property observer stores the new currentLevel value in the maxInputLevelForAllChannels static property. - -* 如果`currentLevel`的新值大于允许的最大值`thresholdLevel`,则属性监听器将`currentLevel`设置为`thresholdLevel`。 -* 如果`currentLevel`的新值大于之前所有`AudioChannel`实例的值。那么属性监听器会将新值保存在静态属性`maxInputLevelForAllChannels`中。 - - -> NOTE -> -> In the first of these two checks, the didSet observer sets -> currentLevel to a different value. This does not, however, cause the -> observer to be called again. - -> 注意 -> -> 在第一次检查过程中,`didSet`监听器将`currentLevel`设置为了不同的值,但此时不会再次调用属性监听器。 - - -You can use the AudioChannel structure to create two new audio channels called leftChannel and rightChannel, to represent the audio levels of a stereo sound system: - -可以使用`AudioChannel`创建两个声道实例:`leftChannel`和`rightChannel`: - - var leftChannel = AudioChannel() - var rightChannel = AudioChannel() - -If you set the currentLevel of the left channel to 7, you can see that the maxInputLevelForAllChannels type property is updated to equal 7: - - -如果将`currentLevel`的左声道的值置为7,则可以看到类型属性`maxInputLevelForAllChannels`也更新为了7: - - leftChannel.currentLevel = 7 - println(leftChannel.currentLevel) - // prints "7" - // 输出 "7" - println(AudioChannel.maxInputLevelForAllChannels) - // print "7" - // 输出 "7" - -If you try to set the currentLevel of the right channel to 11, you can see that the right channel’s currentLevel property is capped to the maximum value of 10, and the maxInputLevelForAllChannels type property is updated to equal 10: - -如果想将`currentLevel`的右声道设置为11,你会发现右声道的`currentLevel`值被设置为了10,同时`maxInputLevelForAllChannels` 也更新为10。 - - - rightChannel.currentLevel = 11 - println(rightChannel.currentLevel) - // prints "10" - // 输出 "10" - println(AudioChannel.maxInputLevelForAllChannels) - // prints "10" - // 输出 "10" \ No newline at end of file diff --git a/src/chapter2/14_Initialization.md b/src/chapter2/14_Initialization.md deleted file mode 100644 index d278db2..0000000 --- a/src/chapter2/14_Initialization.md +++ /dev/null @@ -1,895 +0,0 @@ -## 问题 - -* `initializer` 的定义?『构造方法』 -* `deinitializer` 的定义?『析构方法』 -* `Stored Properties` 的定义?『属性值』 -* `observers` 的定义?『观察者方法』 -* `external name` 的定义?『外部名称』 -* `local name` 的定义?『内部名称』 -* `constant properties` 的定义?『恒定属性』 -* `Optional Property Types` 的定义?『可选属性类型』 -* `Memberwise` 的定义?『成员式』 -* `Initializer Delegation` 的定义?『构造代理』 -* `designated initializers` 的定义?『指定构造方法』 -* `convenience initializers` 的定义?『便利构造方法』 -* `delegates up` 的定义?『向上委托』 -* `nonetheless` 的定义?『仍然』 - -## 构造过程 (Initialization) - -_构造过程_是准备实例化类、结构或枚举的过程。该过程需要为当前实例化对象的每个属性值设置初始值,并且在其准备好之前执行所需的设置或初始化。 - -> “Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that is required before the new instance is ready to for use.” - -你通过定义_构造方法_来实现构造过程,就好比能够创建特定类型的新实例化对象的特殊方法。与 Objective-C 不同的是,Swift 的构造方法没有返回值。其主要作用是保证一个类的新实例在其首次使用之前能够被正确地初始化。 - -> “You implement this initialization process by defining initializers, which are like special methods that can be called to create a new instance of a particular type. Unlike Objective-C initializers, Swift initializers do not return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they are used for the first time.” - -你也可以为类的实例实现一个_析构方法_,这可以让该实例在被释放前执行任意自定义的清理工作。需要了解更多关于析构方法的信息,请见『析构过程』章节。 - -> “Instances of class types can also implement a deinitializer, which performs any custom cleanup just before an instance of that class is deallocated. For more information about deinitializers, see Deinitialization.” - -### 初始化属性值 (Setting Initial Values for Stored Properties) - -类和结构都_必须_在该类(或结构)的实例被创建时为其属性值设定合适的初始值。属性值不能是一个不确定的状态。 - -> “Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties cannot be left in an indeterminate state.” - -你可以在构造方法中为属性值设定初始值,或者在属性值的定义中指定一个默认值。我们会在接下来的章节中描述这些操作。 - -> “You can set an initial value for a stored property within an initializer, or by assigning a default property value as part of the property’s definition. These actions are described in the following sections.” - -提示: - -> 无论是你为属性值指定默认值,还是通过构造方法设定初始值,该属性值的真实值被直接设定,而不会调用属性值观察者方法。 -> > “When you assign a default value to a stored property, or set its initial value within an initializer, the value of that property is set directly, without calling any property observers.” - -### 构造方法 (Initializers) - -_构造方法_用来创建类的新实例对象。其最简单的形式就是使用 `init` 关键字,类似一个没有参数的实例方法。 - -> “Initializers are called to create a new instance of a particular type. In its simplest form, an initializer is like an instance method with no parameters, written using the init keyword.” - -在接下来的例子中定义了一个叫 `Fahrenheit` 的结构来存储用华氏表示的温度。`Fahrenheit` 结构拥有一个类型为 `Double` 的属性值 `temperature`: - -> “The example below defines a new structure called Fahrenheit to store temperatures expressed in the Fahrenheit scale. The Fahrenheit structure has one stored property, temperature, which is of type Double:” - -``` -struct Fahrenheit { - var temperature: Double - init() { - temperature = 32.0 - } -} -var f = Fahrenheit() -println("The default temperature is \(f.temperature)° Fahrenheit") -// prints "The default temperature is 32.0° Fahrenheit -``` - -该结构只定义了一个不带任何参数的构造方法 `init`,该构造方法为属性值 `temperature` 设定了初始值 `32.0`(在华氏温度中表示水的冰点温度)。 - -> “The structure defines a single initializer, init, with no parameters, which initializes the stored temperature with a value of 32.0 (the freezing point of water when expressed in the Fahrenheit scale).” - -### 默认属性值 (Default Property Values) - -如上所示,你可以在一个构造方法中设定属性值的初始值。另外,你也可以在属性值声明时为其指定_默认值_。 - -> “You can set the initial value of a stored property from within an initializer, as shown above. Alternatively, specify a default property value as part of the property’s declaration. You specify a default property value by assigning an initial value to the property when it is defined.” - -提示: - -> 如果一个属性值总是拥有相同的初始值,请为其提供默认值,而不是在构造方法中设定初始值。虽然结果是一样的,*但默认值将属性值声明和初始化更紧密地绑在一起。这样不仅更简短,也更清晰,能够让你通过默认值来判断该属性值的数据类型。默认值也能让你更容易理解默认构造方法与构造方法继承,我们会在接下来的章节中描述它们。 -> > “If a property always takes the same initial value, provide a default value rather than setting a value within an initializer. The end result is the same, but the default value ties the property’s initialization more closely to its declaration. It makes for shorter, clearer initializers and enables you to infer the type of the property from its default value. The default value also makes it easier for you to take advantage of default initializers and initializer inheritance, as described later in this chapter.” - -你可以将上面的 `Fahrenheit` 结构简单写成在属性 `temperature` 被申明时提供一个默认值: - ->“You can write the Fahrenheit structure from above in a simpler form by providing a default value for its temperature property at the point that the property is declared:” - -``` -struct Fahrenheit { - var temperature = 32.0 -} -``` - -### 自定义构造过程 (Customizing Initialization) - -你可以自定义构造过程中的输入参数和可选属性类型,也可以在构造过程中修改常量,我们会在接下来的章节中描述它们。 - -> “You can customize the initialization process with input parameters and optional property types, or by modifying constant properties during initialization, as described in the following sections.” - -#### 初始化参数 (Initialization Parameters) - -要自定义构造过程,你可以在构造方法的定义中提供_初始化参数_,并定义其类型和名字。初始化参数的作用和语法与函数和方法的参数相同。 - -> “You can provide initialization parameters as part of an initializer’s definition, to define the types and names of values that customize the initialization process. Initialization parameters have the same capabilities and syntax as function and method parameters.” - -在接下来的例子中定义了一个 `Celsius` 的结构来存储用摄氏表示的温度。`Celsius` 结构实现了两个自定义的构造方法,分别是 `init(fromFahrenheit:)` 和 `init(fromKelvin:)`,能够通过不同的温标值分别初始化该结构的实例。 - -> “The following example defines a structure called Celsius, which stores temperatures expressed in the Celsius scale. The Celsius structure implements two custom initializers called init(fromFahrenheit:) and init(fromKelvin:), which initialize a new instance of the structure with a value from a different temperature scale:” - -``` -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 is 100.0 -let freezingPointOfWater = Celsius(fromKelvin: 273.15) -// freezingPointOfWater.temperatureInCelsius is 0.0 -``` - -第一个构造方法拥有一个外部名称为 `fromFahrenheit` 内部名称为 `fahrenheit` 的初始化参数。第二个构造方法拥有一个外部名称为 `fromKelvin` 内部名称为 `kelvin` 的初始化参数。这两个构造方法都将各自的参数转换为摄氏温标值,并保存在属性值 `temperatureInCelsius` 中。 - -> “The first initializer has a single initialization parameter with an external name of fromFahrenheit and a local name of fahrenheit. The second initializer has a single initialization parameter with an external name of fromKelvin and a local name of kelvin. Both initializers convert their single argument into a value in the Celsius scale and store this value in a property called temperatureInCelsius.” - -##### 参数的外部名称和内部名称 (Local and External Parameter Names) - -如同函数和方法的参数一样,初始化参数能同时拥有在构造方法体内使用的内部名称,和构造方法被调用时的外部名称。 - -> “As with function and method parameters, initialization parameters can have both a local name for use within the initializer’s body and an external name for use when calling the initializer.” - -可是,构造方法不像函数和方法那样在其括号前有确定的方法名。因此,初始化参数的类型和名字在明确哪个构造方法被调用时起到了特别重要的作用。正因如此,如果你没有提供外部名称,Swift 会自动为构造方法中的_每个_参数提供外部名称。自动生成的外部名称与内部名称相同,就如你在每个初始化参数前写了 # 符号。 - -> “However, initializers do not have an identifying function name before their parentheses in the way that functions and methods do. Therefore, the names and types of an initializer’s parameters play a particularly important role in identifying which initializer should be called. Because of this, Swift provides an automatic external name for every parameter in an initializer if you don’t provide an external name yourself. This automatic external name is the same as the local name, as if you had written a hash symbol before every initialization parameter.” - -提示: - -> 如果你不想在构造方法的参数中提供外部名称,请将下划线(_)作为申明为该参数的外部名称以复写上面描述中的默认行为。 -> > “If you do not want to provide an external name for a parameter in an initializer, provide an underscore (_) as an explicit external name for that parameter to override the default behavior described above.” - -在接下来的例子中定义了一个 `Color` 的结构,其拥有三个恒定属性 `red`,`green` 和 `blue`。这些属性值在 `0.0` 到 `1.0` 之间,分别用来表示颜色值中的红、绿、蓝数值。 - -> “The following example defines a structure called Color, with three constant properties called red, green, and blue. These properties store a value between 0.0 and 1.0 to indicate the amount of red, green, and blue in the color.” - -`Color` 定义了一个拥有三个 `Double` 类型且参数名合适的构造方法: - -> “Color provides an initializer with three appropriately named parameters of type 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 - } -} -``` - -当你创建 `Color` 实例时,你通过这三种颜色名作为外部名称调用该构造方法: - -> “Whenever you create a new Color instance, you call its initializer using external names for each of the three color components:” - -``` -let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) -``` - -请注意,想不使用外部名称直接调用该构造方法是不可能的。外部名称一旦被定义,在调用时必须使用它,否则会产生编译错误: - -> “Note that it is not possible to call this initializer without using the external names. External names must always be used in an intializer if they are defined, and omitting them is a compile-time error:” - -``` -let veryGreen = Color(0.0, 1.0, 0.0) -// this reports a compile-time error - external names are required -``` - -#### 可选属性类型 (Optional Property Types) - -如果你有一个自定义类型的属性值允许设置为『空值』——可能因为该属性值不能在构造过程中赋值,也可能因为在某些时候允许为『空值』——定义该属性值为_可选_类型。可选类型的属性值会被自动初始化为 `nil`,申明该属性值在构造过程有意设定为『空值』。 - -> “If your custom type has a stored property that is logically allowed to have “no value”—perhaps because its value cannot be set during initialization, or because it is allowed to have “no value” at some later point—declare the property with an optional type. Properties of optional type are automatically initialized with a value of nil, indicating that the property is deliberately intended to have “no value yet” during initialization.” - -在接下来的例子中定义了一个 `SurveyQuestion` 的结构,其拥有一个可选的 `String` 类型属性值 `response`: - -> “The following example defines a class called SurveyQuestion, with an optional String property called 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() -// prints "Do you like cheese?" -cheeseQuestion.response = "Yes, I do like cheese. -``` - -你无法知道一个调查问题的回应直到它被回答了,因此属性值 `response` 被声明为 `String?` 类型,或称 『可选 `String`』。当一个新的 `SurveyQuestion` 实例被初始化时,它会被自动分配默认值 `nil`,表示『空字符串』。 - -> “The response to a survey question cannot be known until it is asked, and so the response property is declared with a type of String?, or “optional String”. It is automatically assigned a default value of nil, meaning “no string yet”, when a new instance of SurveyQuestion is initialized.” - -### 在构造过程中修改恒定属性 (Modifying Constant Properties During Initialization) - -你可以在构造过程中的任意时候修改恒定属性的值,只要在构造过程结束前设定为一个明确的值。 - -> “You can modify the value of a constant property at any point during initialization, as long as it is set to a definite value by the time initialization finishes.” - -提示: - -> 对于类的实例,一个恒定属性值只能在申明它的类初始化期间进行修改。它不能由子类修改。 - -> > “For class instances, a constant property can only be modified during initialization by the class that introduces it. It cannot be modified by a subclass.” - -你可以修改上面的 `SurveyQuestion` 例子,使问题的 `text` 属性使用一个恒定属性而不是一个可变属性,以表明一旦 `SurveyQuestion` 的实例被创建,问题属性便不能改变。即使 `text` 属性现在是一个恒定属性,它仍然可以在类的构造方法中设定: - -> “You can revise the SurveyQuestion example from above to use a constant property rather than a variable property for the text property of the question, to indicate that the question does not change once an instance of SurveyQuestion is created. Even though the text property is now a constant, it can still be set within the class’s initializer:” - -``` -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() -// prints "How about beets?" -beetsQuestion.response = "I also like beets. (But not with cheese.) -``` - -### 默认构造方法 (Default Initializers) - -Swift 为每个结构或基类提供了_默认构造方法_来为它们的所有属性值提供默认值,**?并不提供一个构造方法。默认构造方法简单的创建一个设定了所有属性值为默认值的新实例。 - -> “Swift provides a default initializer for any structure or base class that provides default values for all of its properties and does not provide at least one initializer itself. The default initializer simply creates a new instance with all of its properties set to their default values.” - -在接下来的例子中定义了一个叫 `ShoppingListItem` 的类,其封装了购物清单中一件商品的名字、数量和支付状态: - -> “This example defines a class called ShoppingListItem, which encapsulates the name, quantity, and purchase state of an item in a shopping list:” - -``` -class ShoppingListItem { - var name: String? - var quantity = 1 - var purchased = false -} -var item = ShoppingListItem() -``` - -因为 `ShoppingListItem` 类中所有的属性值都拥有默认值,且这是一个没有父类的基类,`ShoppingListItem` 自动获得了一个默认构造方法,该方法创建一个设定了所有属性值为默认值的新实例。(`name` 属性是一个可选的 `String` 类型属性,因此它自动获得默认值为 `nil`,尽管这个值并没有写在代码中。)上面的例子使用默认构造方法为 `ShoppingListItem` 类创建实例化对象,构造方法语法写作 `ShoppingListItem()` 并将此实例赋值给 `item` 变量。 - -> “Because all properties of the ShoppingListItem class have default values, and because it is a base class with no superclass, ShoppingListItem automatically gains a default initializer implementation that creates a new instance with all of its properties set to their default values. (The name property is an optional String property, and so it automatically receives a default value of nil, even though this value is not written in the code.) The example above uses the default initializer for the ShoppingListItem class to create a new instance of the class with initializer syntax, written as ShoppingListItem(), and assigns this new instance to a variable called item.” - -#### 结构类型的成员式构造方法 (Memberwise Initializers for Structure Types) - -除了上面提到的默认构造方法,如果结构类型为其所有属性值提供了默认值且没有自定义构造方法,那么该结构类型自动接收一个_成员式构造方法_。 - -> “In addition to the default initializers mentioned above, structure types automatically receive a memberwise initializer if they provide default values for all of their stored properties and do not define any of their own custom initializers.” - -成员式构造方法是初始化新结构实例的成员属性的一种简写方式。新实例的属性的初始值可以通过名称传递给成员式构造方法。 - -> “The memberwise initializer is a shorthand way to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name.” - -在接下来的例子中定义了一个叫 `Size` 的结构,其拥有两个属性值分别是 `width` 和 `height`。通过分配了 `0.0` 作为它们的默认值,两个属性均被推断为 `Double` 类型。 - -> “The example below defines a structure called Size with two properties called width and height. Both properties are inferred to be of type Double by assigning a default value of 0.0.” - -由于所有属性值均拥有默认值,`Size` 这个结构自动接受一个成员式构造方法 `init(width:height:)`,你可以通过这个成员式构造方法创建新的 `Size` 实例: - -> “Because both stored properties have a default value, the Size structure automatically receives an init(width:height:) memberwise initializer, which you can use to initialize a new Size instance:” - -``` -struct Size { - var width = 0.0, height = 0.0 -} -let twoByTwo = Size(width: 2.0, height: 2.0) -``` - -### 值类型的构造代理 (Initializer Delegation for Value Types) - -构造方法可以调用其他的构造方法作为实例构造过程的一部分。这个过程称为_构造代理_,其避免了在多个构造方法中的重复代码。“ - -> “Initializers can call other initializers to perform part of an instance’s initialization. This process, known as initializer delegation, avoids duplicating code across multiple initializers.” - -构造代理的工作原理,以及哪些形式的代理是被允许的,针对值类型和类类型是不同的。值类型(结构和枚举)不支持继承,因此他们的构造代理过程比较简单,因为它们只能委托给由它们自己提供的其他构造方法。但是,类类型可以从其他类继承,如『继承』这一章节所描述。这意味着类有更多的责任去确保它们继承了的所有属性值在构造过程中被分配一个合适的值。这些责任将在接下来的『类的继承和初始化』中说明。 - -> “The rules for how initializer delegation works, and for what forms of delegation are allowed, are different for value types and class types. Value types (structures and enumerations) do not support inheritance, and so their initializer delegation process is relatively simple, because they can only delegate to another initializer that they provide themselves. Classes, however, can inherit from other classes, as described in Inheritance. This means that classes have additional responsibilities for ensuring that all stored properties they inherit are assigned a suitable value during initialization. These responsibilities are described in Class Inheritance and Initialization below.” - -对于值类型,当你自定义构造方法时,你使用 `self.init` 来关联同一值类型的其他构造方法。你只能在构造方法中调用 `self.init`。 - -> “For value types, you use self.init to refer to other initializers from the same value type when writing your own custom initializers. You can only call self.init from within an initializer.” - -请注意,如果你为值类型定义一个自定义构造方法,你将不再能够访问该类型的默认构造方法(或成员式构造方法,如果它是一个结构)。这个约束防止一种情况的出现,即你提供了一个更为复杂的构造方法来执行必要的设置,但有人却不小心绕过它使用了自动生成构造方法。 - -> “Note that if you define a custom initializer for a value type, you will no longer have access to the default initializer (or the memberwise structure initializer, if it is a structure) for that type. This constraint prevents a situation in which you provide a more complex initializer that performs additional essential setup is circumvented by someone accidentally using one of the automatic initializers instead.” - -提示: - -> 如果你期望你自定义的值类型能够被默认构造方法和成员式构造方法初始化,并且同时也能够被自定义构造方法初始化,把你的自定义构造方法写在扩展中,而不是该值类型源生实现中的一部分。请参见『扩展』章节了解更多信息。 - -> > “If you want your custom value type to be initializable with the default initializer and memberwise initializer, and also with your own custom initializers, write your custom initializers in an extension rather than as part of the value type’s original implementation. For more information, see Extensions.” - -在接下来的例子中定义了一个叫 `Rect` 的结构来表示一个几何矩形。该例子需要 `Size` 和 `Point` 这两个结构的支持,两个结构均使用 `0.0` 作为它们属性值的默认值: - -> “The following example defines a custom Rect structure to represent a geometric rectangle. The example requires two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties:” - -``` -struct Size { - var width = 0.0, height = 0.0 -} -struct Point { - var x = 0.0, y = 0.0 -} -``` -你可以通过下面三种方式中的一种来初始化 `Rect` 结构: - -* 使用 `origin` 和 `size` 的默认属性值 -* 提供一个特定的原始点和大小 -* 提供一个中心点和大小 - -这些构造过程选项由三个自定义构造方法提供,它们均定义在 `Rect` 结构中: - -> “You can initialize the Rect structure below in one of three ways—by using its default zero-initialized origin and size property values, by providing a specific origin point and size, or by providing a specific center point and size. These initialization options are represented by three custom initializers that are part of the Rect structure’s definition:” - -``` -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)`: - -> “The first Rect initializer, init(), is functionally the same as the default initializer that the structure would have received if it did not have its own custom initializers. This initializer has an empty body, represented by an empty pair of curly braces {}, and does not perfom any initialization. Calling this initializer returns a Rect instance whose origin and size properties are both initialized with the default values of Point(x: 0.0, y: 0.0) and Size(width: 0.0, height: 0.0) from their property definitions:” - -``` -let basicRect = Rect() -// basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0) -``` - -第二个 `Rect` 构造方法 `init(origin:size:)` 在功能上和没有提供自定义构造方法的成员式构造方法相同。该构造方法简单地将 `origin` 和 `size` 参数分配给恰当的属性值: - -> “The second Rect initializer, init(origin:size:), is functionally the same as the memberwise initializer that the structure would have received if it did not have its own custom initializers. This initializer simply assigns the origin and size argument values to the appropriate stored properties:” - -``` -let originRect = Rect(origin: Point(x: 2.0, y: 2.0), - size: Size(width: 5.0, height: 5.0)) -// originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0) -``` - -第三个 `Rect` 构造方法 `init(center:size:)` 稍微复杂一些。它从基于中心点和大小值计算相应的原点开始。然后,它调用(或委托)到 `init(origin:size:)` 构造方法,将新的原点和大小保存到合适的属性中: - -> “The third Rect initializer, init(center:size:), is slightly more complex. It starts by calculating an appropriate origin point based on a center point and a size value. It then calls (or delegates) to the init(origin:size:) initializer, which stores the new origin and size values in the appropriate properties:” - -``` -let centerRect = Rect(center: Point(x: 4.0, y: 4.0), - size: Size(width: 3.0, height: 3.0)) -// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0) -``` - -尽管构造方法 `init(center:size:)` 也能够自己将新的 `origin` 和 `size` 分配给合适的属性。可是,构造方法 `init(center:size:)` 使用已经具有相同功能的构造函数来实现更简单(逻辑清楚)。 - -> “The init(center:size:) initializer could have assigned the new values of origin and size to the appropriate properties itself. However, it is more convenient (and clearer in intent) for the init(center:size:) initializer to take advantage of an existing initializer that already provides exactly that functionality.” - -提示: - -> 如果你想通过不定义 `init()` 和 `init(origin:size:)` 构造方法来替代例子中的方法,请见『扩展』章节。 - -> > “For an alternative way to write this example without defining the init() and init(origin:size:) initializers yourself, see Extensions.” - -### 类的继承与构造过程 - -一个类的所有属性值——包括所有它从父类继承的属性——_必须_在构造过程中分配初始值。 - -> “All of a class’s stored properties—including any properties the class inherits from its superclass—must be assigned an initial value during initialization.” - -Swift 定义了两种类类型的构造方法来保证所有的属性值接收到初始值。它们被称为指定构造方法和便利构造方法。 - -> “Swift defines two kinds of initializers for class types to help ensure all stored properties receive an initial value. These are known as designated initializers and convenience initializers.” - -#### 指定构造方法和便利构造方法 (Designated Initializers and Convenience Initializers) - -_指定构造方法_是类的主要构造方法。一个指定构造方法完全初始化所有该类申明的属性并调用合适的父类构造方法来继续向上追溯构造过程的父类链。 - -> “Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.” - -类往往只有少数指定构造方法,而且只有一个指定构造方法也是很常见的。**?指定构造方法是通过构造过程发生的『漏斗』点,并通过其继续向上追溯构造过程的父类链。 - -> “Classes tend to have very few designated initializers, and it is quite common for a class to have only one. Designated initializers are “funnel” points through which initialization takes place, and through which the initialization process continues up the superclass chain.” - -每个类必须至少拥有一个指定构造方法。在某些情况下,这一要求由从父类继承一个或多个指定构造方法满足,这将在接下来的『自动构造方法继承』中说明。 - -> “Every class must have at least one designated initializer. In some cases, this requirement is satisfied by inheriting one or more designated initializers from a superclass, as described in Automatic Initializer Inheritance below.” - -_便利构造方法_是次要的,是类的辅助构造方法。你可以在同一个类下定义一个便利构造方法来调用指定构造方法,该便利构造方法定义了指定构造方法参数的默认值。你也可以定义一个便利构造方法用于创建特定用例或**?输入值类型的实例。 - -> “Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.” - -如果你的类不需要便利构造方法,你可以不提供它。每当一个通用构造过程模型的快捷方式能够节省事件或让该类的构造过程的意图更清晰,请使用创建便利构造方法。 - -> “You do not have to provide convenience initializers if your class does not require them. Create convenience initializers whenever a shortcut to a common initialization pattern will save time or make initialization of the class clearer in intent.” - -#### 构造方法链 (Initializer Chaining) - -为了简化指定构造方法和便利构造方法的关系,在构造方法委托调用中 Swift 应用了以下三条规则: - -> “To simplify the relationships between designated and convenience initializers, Swift applies the following three rules for delegation calls between initializers:” - -* __规则一:__指定构造方法只能从其直接父类中调用指定构造方法。 -* __规则二:__便利构造方法只能调用_该类自身_定义的其他构造方法。 -* __规则三:__便利构造方法必须在最终调用一个指定构造方法。 - -> * __Rule 1__ “Designated initializers must call a designated initializer from their immediate superclass.” -> * __Rule 2__ “Convenience initializers must call another initializer available in the same class.” -> * __Rule 3__ “Convenience initializers must ultimately end up calling a designated initializer.” - -一个简单的方法来记住这些: - -* **?指定构造方法必须总是_向上_委托 -* **?便利构造方法必须总是_穿过_委托 - -> “A simple way to remember this is:” -> -> * “Designated initializers must always delegate up.” -> * “Convenience initializers must always delegate across.” - -这些规则如下图所示: - -> “These rules are illustrated in the figure below:” - -**?插图[1] Page 408 - -在这里,父类只有一个指定构造方法和两个便利构造方法。一个便利构造方法调用了其中另一个便利构造方法,而该构造方法调用了唯一那个便利构造方法。这符合上面的规则 2 和 3。该父类自身没有父类,因此不适用规则 1。 - -> “Here, the superclass has a single designated initializer and two convenience initializers. One convenience initializer calls another convenience initializer, which in turn calls the single designated initializer. This satisfies rules 2 and 3 from above. The superclass does not itself have a further superclass, and so rule 1 does not apply.” - -上图中的子类拥有两个指定构造方法和一个便利构造方法。这个便利构造方法必须调用那两个指定构造方法中的一个,因为便利构造方法必须调用其类自身的其他构造方法。这符合上面的规则 2 和 3。该子类中两个指定构造方法都必须调用父类中唯一那个指定构造方法,来符合上面的规则 1。 - -> “The subclass in this figure has two designated initializers and one convenience initializer. The convenience initializer must call one of the two designated initializers, because it can only call another initializer from the same class. This satisfies rules 2 and 3 from above. Both designated initializers must call the single designated initializer from the superclass, to satisfy rule 1 from above.” - -提示: - -> 这些规则并不会影响你的类用户如何_创建_各类的实例。上图中的任何构造方法都能用于创建其所在类的完整实例。这些规则只会影响你如何写这些类的实现。 - -> > “These rules don’t affect how users of your classes create instances of each class. Any initializer in the diagram above can be used to create a fully-initialized instance of the class they belong to. The rules only affect how you write the class’s implementation.” - -下面的图显示了一个更为复杂的 4 个类的层次结构。它表现了指定构造方法如何在类构造过程中用作『漏斗』点,简化了这些类层级间的相互关联。 - -> “The figure below shows a more complex class hierarchy for four classes. It illustrates how the designated initializers in this hierarchy act as “funnel” points for class initialization, simplifying the interrelationships among classes in the chain:” - -**?插图[2] Page 410 - -#### 构造过程的两个阶段 (Two-Phase Initialization) - -在 Swift 中类的构造过程有两个阶段。在第一个阶段,每个属性值被申明它的类分配一个初始值。一旦每个属性值的初始状态被确认,第二阶段便开始,每个类能够在新实例被认为是可以使用之前进一步制定其属性值。 - -> “Class initialization in Swift is a two-phase process. In the first phase, each stored property is assigned an initial value by the class that introduced it. Once the initial state for every stored property has been determined, the second phase begins, and each class is given the opportunity to customize its stored properties further before the new instance is considered ready for use.” - -构造过程的两个阶段使构造过程更安全,同时仍然给予一个类层级中每个类以完全的灵活性。构造过程的两个阶段防止属性值在它们被初始化之前被访问,并防止属性值被另一个构造方法意外地设置为其他值。 - -> “The use of a two-phase initialization process makes initialization safe, while still giving complete flexibility to each class in a class hierarchy. Two-phase initialization prevents property values from being accessed before they are initialized, and prevents property values from being set to a different value by another initializer unexpectedly.” - -提示: - -> Swift 的构造过程的两个阶段和 Objective-C 的构造过程类似。主要的不同之处在第一阶段 Objective-C 分配 0 或 null (如 `0` 或 `nil`) 值给每个属性。Swift 的构造过程更加灵活,因此它可以让你设置自定义初始值,并可以应付 `0` 或 `nil` 不是一个有效默认值的类型。 - -> > “Swift’s two-phase initialization process is similar to initialization in Objective-C. The main difference is that during phase 1, Objective-C assigns zero or null values (such as 0 or nil) to every property. Swift’s initialization flow is more flexible in that it lets you set custom initial values, and can cope with types for which 0 or nil is not a valid default value.” - -Swift 的编译器执行了四个安全检查,来保证构造过程的两个阶段过程中没有错误: - -> “Swift’s compiler performs four helpful safety-checks to make sure that two-phase initialization is completed without error:” - -* __安全检查一:__指定构造方法必须保证其所在类申明的属性在向上委托到父类构造方法前被初始化。 - -> * __Safety Check 1__ “A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.” - -正如上面所提到的,一个对象的内存只会被初始化一次,该对象的所有属性值的初始化状态都是已知的。为了符合这条规范,一个指定构造方法必须保证其所有属性在它脱手给继承链前是已经被初始化了的。 - -> “As mentioned above, the memory for an object is only considered fully initialized once the initial state of all of its stored properties is known. In order for this rule to be satisfied, a designated initializer must make sure that all its own properties are initialized before it hands off up the chain.” - -* __安全检查二:__一个指定构造方法在给继承的属性赋值之前必须向上委托至一个父类的构造方法。如果不是这样,该指定构造方法分配的新值会被父类的构造过程覆盖。 -* __安全检查三:__一个便利构造方法必须在给_任何_属性(包裹其所在类定义的属性)赋值前委托给另一个构造方法。如果不是这样,该便利构造方法分配的新值会被其自身类委托的构造方法覆盖。 -* __安全检查四:__直到构造过程的第一阶段完成前,任何构造方法都不能调用实例方法,不能读取任何实例属性,或引用自身为一个值。 - -> * __Safety Check 2__ “A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property. If it doesn’t, the new value the designated initializer assigns will be overwritten by the superclass as part of its own initialization.” -> * __Safety Check 3__ “A convenience initializer must delegate to another initializer before assigning a value to any property (including properties defined by the same class). If it doesn’t, the new value the convenience initializer assigns will be overwritten by its own class’s designated initializer.” -> * __Safety Check 4__ “An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.” - -在第一阶段完成前,类的实例并不是完全有效的。当在第一阶段结束时,类实例被认为是有效的,属性只能被访问,方法只能被调用,“ - -> “The class instance is not fully valid until the first phase ends. Properties can only be accessed, and methods can only be called, once the class instance is known to be valid at the end of the first phase.” - -下面是构造过程的两个阶段如何基于上面的 4 个安全检查实现的: - -> “Here’s how two-phase initialization plays out, based on the four safety checks above:” - -##### 第一阶段 - -* 一个指定或便利构造方法在一个类中被调用。 -* 该类的一个新实例内存被分配。但内存还未被初始化。 -* 该类的一个指定构造方法确保该类中申明的所有属性值拥有一个值。这些属性值的内存现在被初始化了。 -* 该指定构造方法脱手给父类的构造方法来为它拥有的属性值执行相同的任务。 -* 该过程持续向上追溯继承链,直到到达链条顶端。 -* 一旦达到继承链的顶端,最终的类必须保证其所有的属性值都拥有一个值,然后该实例的内存被认为是完全初始化的,第一阶段结束。 - -> * “A designated or convenience initializer is called on a class.” -> * “Memory for a new instance of that class is allocated. The memory is not yet initialized.” -> * “A designated initializer for that class confirms that all stored properties introduced by that class have a value. The memory for these stored properties is now initialized.” -> * “The designated initializer hands off to a superclass initializer to perform the same task for its own stored properties.” -> * “This continues up the class inheritance chain until the top of the chain is reached.” -> * “Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance’s memory is considered to be fully initialized, and phase 1 is complete.” - -##### 第二阶段 - -* 从继承链的顶端向下工作,继承链中每个指定构造方法都能够进一步自定义该实例。现在构造方法可以访问 `self` 并且能够修改其属性,调用实例方法,等等。 -* 最后,继承链中每个便利构造方法能够自定义该实例,并且使用 `self` 操作。 - -> * “Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access self and can modify its properties, call its instance methods, and so on.” -> * “Finally, any convenience initializers in the chain have the option to customize the instance and to work with self.” - -下图显示了第一阶段在假想的子类和父类中如何寻找构造过程的调用: - -> “Here’s how phase 1 looks for an initialization call for a hypothetical subclass and superclass:” - -**?插图[3] Page 415 - -在这个例子中,构造过程开始于对子类中便利构造方法的调用。该便利构造方法当前还不能修改任何属性。它委托给同一类下的一个指定构造方法。 - -> “In this example, initialization begins with a call to a convenience initializer on the subclass. This convenience initializer cannot yet modify any properties. It delegates across to a designated initializer from the same class.” - -该指定构造方法确保所有子类中的属性都拥有一个值,如安全检查 1。然后它调用了父类的一个指定构造方法来继续向上追溯构造过程。 - -> “The designated initializer makes sure that all of the subclass’s properties have a value, as per safety check 1. It then calls a designated initializer on its superclass to continue the initialization up the chain.” - -父类的指定构造方法确保了父类的所有属性都拥有一个值。在没有往上的父类可以追溯,也不需要进一步的委托。 - -> “The superclass’s designated initializer makes sure that all of the superclass properties have a value. There are no further superclasses to initialize, and so no further delegation is needed.” - -在所有的父类属性都拥有值的时候,内存被认为完全初始化,第一阶段结束。 - -> “As soon as all properties of the superclass have an initial value, its memory is considered fully initialized, and Phase 1 is complete.” - -下图显示了第二阶段如何寻找构造过程的调用: - -> “Here’s how phase 2 looks for the same initialization call:” - -**?插图[4] Page 416 - -父类的指定构造方法已经可以进一步自定义实例(这不是必须的)。 - -> “The superclass’s designated initializer now has an opportunity to customize the instance further (although it does not have to).” - -一旦父类的指定构造方法结束,子类的指定构造方法便可执行额外的自定义操作(同样的,这不是必须的)。 - -> “Once the superclass’s designated initializer is finished, the subclass’s designated initializer can perform additional customization (although again, it does not have to).” - -最后,一旦子类的指定构造方法结束,最早被调用的便利构造方法可以执行额外的自定义操作了。 - -> “Finally, once the subclass’s designated initializer is finished, the convenience initializer that was originally called can perform additional customization.” - -#### 构造方法的继承与重写 (Initializer Inheritance and Overriding) - -与 Objective-C 的子类不同,Swift 的子类会默认继承它们父类的构造方法。Swift 可以防止一种情况:一个简单的父类构造方法被一个更专业的子类自动继承,并用于创建不完整或不正确的子类实例。 - -> “Unlike subclasses in Objective-C, Swift subclasses do not not inherit their superclass initializers by default. Swift’s approach prevents a situation in which a simple initializer from a superclass is automatically inherited by a more specialized subclass and is used to create a new instance of the subclass that is not fully or correctly initialized.” - -如果你希望你的自定义子类能够提供一个多个与父类相同的构造方法——可能在构造过程中需要一些自定义——你可以在你自定义的子类中提供一个相同构造方法的重写来实现。 - -> “If you want your custom subclass to present one or more of the same initializers as its superclass—perhaps to perform some customization during initialization—you can provide an overriding implementation of the same initializer within your custom subclass.” - -如果你重写的构造方法是一个指定构造方法,你可以在你的子类中重写它的实现,并且能够在子类的重写版方法中调用父类父类版方法。 - -> “If the initializer you are overriding is a designated initializer, you can override its implementation in your subclass and call the superclass version of the initializer from within your overriding version.” - -如果你重写的构造方法是一个便利构造方法,你重写的方法必须调用子类自身申明的另一个指定构造方法,正如前面『构造方法链』说明的规则那样。 - -> “If the initializer you are overriding is a convenience initializer, your override must call another designated initializer from its own subclass, as per the rules described above in Initializer Chaining.” - -提示: - -> 与方法、属性和下标不同,当你重写一个构造方法时不需要写 `override` 关键字。 - -> > “Unlike methods, properties, and subscripts, you do not need to write the override keyword when overriding an initializer.” - -#### 自动继承构造方法 (Automatic Initializer Inheritance) - -正如上面所描述的,子类会默认继承它们父类的构造方法。可是,在某些情况下,父类的构造方法会被自动继承。在实践中,**?这意味着​​在许多常见情况下你不需要重写构造方法,并且可以最小影响地继承父类的构造方法,这样做是安全。 - -> “As mentioned above, subclasses do not not inherit their superclass initializers by default. However, superclass initializers are automatically inherited if certain conditions are met. In practice, this means that you do not need to write initializer overrides in many common scenarios, and can inherit your superclass initializers with minimal effort whenever it is safe to do so.” - -假设你为你的子类中申明的任何新属性提供默认值,有下面两个规则要遵守: - -> “Assuming that you provide default values for any new properties you introduce in a subclass, the following two rules apply:” - -* __规则一:__如果你的子类没有定义任何指定构造方法,它会自动继承父类所有的指定构造方法。 -* __规则二:__如果你的子类提供了其父类所有的指定构造方法的实现——或者仅仅如『规则一』所说的继承它们,或者在其自身定义中提供自定义的实现——那么该子类会自动继承父类所有的便利构造方法。 - -> * __Rule 1__ “If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.” -> * __Rule 2__ “If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers.” - -即使你在子类中添加了更多的便利构造方法,这两个规则依然适用。 - -> “These rules apply even if your subclass adds further convenience initializers.” - -提示: - -> 一个子类可以实现一个父类的指定构造方法为子类的一个便利构造方法,这是符合『规则二』的。 - -> > “A subclass can implement a superclass designated initializer as a subclass convenience initializer as part of satisfying rule 2.” - -#### 指定与便利构造方法的语法 (Syntax for Designated and Convenience Initializers) - -类的指定构造方法的编写方法如值类型的构造方法一样简单: - -> “Designated initializers for classes are written in the same way as simple initializers for value types:” - -``` -init(parameters) { - statements -} -``` - -便利构造方法的编写方法也是如此,但必须在 `init` 关键字前面加上 `convenience` 关键字,并以空格分隔: - -> “Convenience initializers are written in the same style, but with the convenience keyword placed before the init keyword, separated by a space:” - -``` -convenience init(parameters) { - statements -} -``` - -#### 指定与便利构造方法的行为 (Designated and Convenience Initializers in Action) - -在接下来的例子显示了指定构造方法,便利构造方法和自动继承的构造方法的行为。这个例子定义了叫 `Food`,`RecipeIngredient` 和 `ShoppingListItem` 三个类的层级关系,并示范了它们之间是如何相互作用的。 - -> “The following example shows designated initializers, convenience initializers, and automatic initializer inheritance in action. This example defines a hierarchy of three classes called Food, RecipeIngredient, and ShoppingListItem, and demonstrates how their initializers interact.” - -该层级中的基类是 `Food`,它是一个仅仅描述了食物名字的简单类。`Food` 类仅有一个 `String` 类型的属性 `name`,并有两个构造方法来创造 `Food` 的实例: - -> “The base class in the hierarchy is called Food, which is a simple class to encapsulate the name of a foodstuff. The Food class introduces a single String property called name and provides two initializers for creating Food instances:” - -``` -class Food { - var name: String - init(name: String) { - self.name = name - } - convenience init() { - self.init(name: "[Unnamed]") - } -} -``` - -下图显示了 `Food` 类的构造方法链: - -> “The figure below shows the initializer chain for the Food class:” - -**?插图[5] Page 421 - -类并没有默认的成员式构造方法,因此 `Food` 类提供了一个仅拥有一个 `name` 参数的指定构造方法。该构造方法可以用来创建指定了名字的 `Food` 实例: - -``` -let namedMeat = Food(name: "Bacon") -// namedMeat's name is "Bacon" -``` - -在 `Food` 类中的 `init(name: String)` 构造方法是一个_指定构造方法_,因为它保证了 `Food` 实例中的所有属性值是完全初始化的。`Food` 并没有父类,因此构造方法 `init(name: String)` 并不需要在其构造过程中调用 `super.init()`。 - -> “The init(name: String) initializer from the Food class is provided as a designated initializer, because it ensures that all stored properties of a new Food instance are fully initialized. The Food class does not have a superclass, and so the init(name: String) initializer does not need to call super.init() to complete its initialization.” - -该 `Food` 类也提供了一个没有参数的_便利构造方法_ `init()`。构造方法 `init()` 通过将赋值为 `[Unnamed]` 的 `name` 参数委托给 `Food` 类的 `init(name: String)`,提供了食物的默认名字: - -> “The Food class also provides a convenience initializer, init(), with no arguments. The init() initializer provides a default placeholder name for a new food by delegating across to the Food class’s init(name: String) with a name value of [Unnamed]:” - -``` -let mysteryMeat = Food() -// mysteryMeat's name is "[Unnamed]" -``` - -该层级中的第二个类是 `Food` 的一个子类,叫做 `RecipeIngredient`。该 `RecipeIngredient` 类创建了一个烹饪食谱的原料模型。它申明了一个 `Int` 类型的属性 `quantity`(从 `Food` 中继承了 `name` 属性)并定义了两个构造方法来创建 `RecipeIngredient` 实例: - -> “The second class in the hierarchy is a subclass of Food called RecipeIngredient. The RecipeIngredient class models an ingredient in a cooking recipe. It introduces an Int property called quantity (in addition to the name property it inherits from Food) and defines two initializers for creating RecipeIngredient instances:” - -``` -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` 类的构造方法链: - -> “The figure below shows the initializer chain for the RecipeIngredient class:” - -**?插图[6] Page 423 - -类 `RecipeIngredient` 拥有唯一一个指定构造方法 `init(name: String, quantity: Int)`,它可以完成新 `RecipeIngredient` 实例的所有属性的填充。该构造方法开始于将传入的 `quantity` 参数赋值给在 `RecipeIngredient` 中申明的新属性 `quantity`。而后,该构造方法向上委托给 `Food` 的构造方法 `init(name: String)`。该过程符合之前『构造过程的两个阶段』章节中的安全检查 1。 - -> “The RecipeIngredient class has a single designated initializer, init(name: String, quantity: Int), which can be used to populate all of the properties of a new RecipeIngredient instance. This initializer starts by assigning the passed quantity argument to the quantity property, which is the only new property introduced by RecipeIngredient. After doing so, the initializer delegates up to the init(name: String) initializer of the Food class. This process satisfies safety check 1 from Two-Phase Initialization above.” - -同时 `RecipeIngredient` 定义了一个便利构造方法 `init(name: String)`,它用于只使用名字来创建 `RecipeIngredient` 实例。该便利构造方法假定了所有没有明确数量的 `RecipeIngredient` 实例的数量为 `1`。该构造方法的定义使创建 `RecipeIngredient` 更加便捷快速,并能够避免创造多个单数量 `RecipeIngredient` 实例时产生的代码冗余。该便利构造方法简单得委托给了其所在类的指定构造方法。 - -> “RecipeIngredient also defines a convenience initializer, init(name: String), which is used to create a RecipeIngredient instance by name alone. This convenience initializer assumes a quantity of 1 for any RecipeIngredient instance that is created without an explicit quantity. The definition of this convenience initializer makes RecipeIngredient instances quicker and more convenient to create, and avoids code duplication when creating several single-quantity RecipeIngredient instances. This convenience initializer simply delegates across to the class’s designated initializer.” - -请注意,`RecipeIngredient` 类提供的便利构造方法 `init(name: String)` 使用了与 `Food` 类中制_指定构造方法_ `init(name: String)` 一样的参数。尽管 `RecipeIngredient` 将其作为便利构造方法,`RecipeIngredient` 仍然提供了其父类所有指定构造方法的实现。因此,`RecipeIngredient` 自动继承了其父类所有的便利构造方法。 - -> “Note that the init(name: String) convenience initializer provided by RecipeIngredient takes the same parameters as the init(name: String) designated initializer from Food. Even though RecipeIngredient provides this initializer as a convenience initializer, RecipeIngredient has nonetheless provided an implementation of all of its superclass’s designated initializers. Therefore, RecipeIngredient automatically inherits all of its superclass’s convenience initializers too.” - -在这个例子中,`RecipeIngredient` 的父类是 `Food`,`Food` 只有一个叫 `init()` 的便利构造方法。因此该构造方法被 `RecipeIngredient` 所继承。继承了的 `init()` 方法和 `Food` 中的一样,只是它委托的是 `RecipeIngredient` 中的 `init(name: String)` 而不是 `Food` 中的。 - -> “In this example, the superclass for RecipeIngredient is Food, which has a single convenience initializer called init(). This initializer is therefore inherited by RecipeIngredient. The inherited version of init() functions in exactly the same way as the Food version, except that it delegates to the RecipeIngredient version of init(name: String) rather than the Food version.” - -这三种构造方法均可以用于创建 `RecipeIngredient` 对象: - -> “All three of these initializers can be used to create new RecipeIngredient instances:” - -``` -let oneMysteryItem = RecipeIngredient() -let oneBacon = RecipeIngredient(name: "Bacon") -let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6) -``` - -第三个并且是最后一个类是 `RecipeIngredient` 的子类,叫做 `ShoppingListItem`。该 `ShoppingListItem` 类创建了一个食谱购物清单的模型。 - -> “The third and final class in the hierarchy is a subclass of RecipeIngredient called ShoppingListItem. The ShoppingListItem class models a recipe ingredient as it appears in a shopping list.” - -购物清单中的所有商品的初始状态都是『未支付』。为了实现它,`ShoppingListItem` 申明了一个默认值为 `false` 的 `Boolean` 的属性 `purchased`。同时,`ShoppingListItem` 也申明了一个计算过的 `description` 属性,它提供了对 `ShoppingListItem` 实例的文本描述: - -> “Every item in the shopping list starts out as “unpurchased”. To represent this fact, ShoppingListItem introduces a Boolean property called purchased, with a default value of false. ShoppingListItem also adds a computed description property, which provides a textual description of a ShoppingListItem instance:” - -``` -class ShoppingListItem: RecipeIngredient { - var purchased = false - var description: String { - var output = "\(quantity) x \(name.lowercaseString)" - output += purchased ? " ✔" : " ✘" - return output - } -} -``` - -提示: - -> `ShoppingListItem` 并没有定义为 `purchased` 提供初始值的构造方法,因为在购物清单中的商品(按这里的模型)的初始状态总是未支付。 - -> > “ShoppingListItem does not define an initializer to provide an initial value for purchased, because items in a shopping list (as modeled here) always start out unpurchased.” - -因为 `ShoppingListItem` 为所有其申明的属性均提供了默认值,并且其自身没有定义任何构造方法。`ShoppingListItem` 自动继承了其父类的所有指定和便利构造方法。 - -> “Because it provides a default value for all of the properties it introduces and does not define any initializers itself, ShoppingListItem automatically inherits all of the designated and convenience initializers from its superclass.” - -下图显示了这三个类的构造方法链的概览: - -> “The figure below shows the overall initializer chain for all three classes:” - -**?插图[7] Page 427 - -这三个继承的构造方法均可以用于创建 `ShoppingListItem` 对象: - -> “You can use all three of the inherited initializers to create a new ShoppingListItem instance:” - -``` -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 ✘ -``` - -至此,一个包含了三个新 `ShoppingListItem` 实例的数组 `breakfastList` 被创建出来。这个数组的类型被推断为 `ShoppingListItem[]`。在该数组被创建后,该数组的第一个 `ShoppingListItem` 实例的名字从 `[Unnamed]` 改变为 `Orange`,并且其被标记为已支付状态。输出数组中每个实例的详细描述,显示出它们的默认状态均被按预期地设置了。 - -> “Here, a new array called breakfastList is created from an array literal containing three new ShoppingListItem instances. The type of the array is inferred to be ShoppingListItem[]. After the array is created, the name of the ShoppingListItem at the start of the array is changed from "[Unnamed]" to "Orange juice" and it is marked as having been purchased. Printing the description of each item in the array shows that their default states have been set as expected.” - -### 通过闭包或方法设置默认属性 (Setting a Default Property Value with a Closure or Function) - -如果一个属性值的默认值需要一些自定义或者设置,你可以使用闭包或者全局方法来为该属性提供自定义默认值。无论该属性所在类的实例何时被初始化,闭包或方法会被调用,并且其返回值会被分配给该属性作为默认值。 - -> “If a stored property’s default value requires some customization or setup, you can use a closure or global function to provide a customized default value for that property. Whenever a new instance of the type that the property belongs to is initialized, the closure or function is called, and its return value is assigned as the property’s default value.” - -这种类型的闭包和方法为该属性创建了一个相同类型的临时值,**?定制的该值是初始状态所期望的,然后返回这个临时值作为该属性的默认值。 - -> “These kinds of closures or functions typically create a temporary value of the same type as the property, tailor that value to represent the desired initial state, and then return that temporary value to be used as the property’s default value.” - -下面是一个如何使用闭包给属性提供默认值的概览: - -> “Here’s a skeleton outline of how a closure can be used to provide a default property value:” - -``` -class SomeClass { - let someProperty: SomeType = { - // create a default value for someProperty inside this closure - // someValue must be of the same type as SomeType - return someValue - }() -} -``` - -请注意,闭包结束的花括号后面紧跟着一堆空的圆括号。这会告诉 Swift 立即执行该闭包。如果你漏掉了圆括号,你会把闭包本身赋值给该属性,而不是这个闭包的返回值。 - -> “Note that the closure’s end curly brace is followed by an empty pair of parentheses. This tells Swift to execute the closure immediately. If you omit these parentheses, you are trying to assign the closure itself to the property, and not the return value of the closure.” - -提示: - -> 如果你使用一个闭包来初始化一个属性,请记住,在该闭包被执行的时候该实例的其他部分还没有被初始化。这意味着你无法在闭包中访问任何其他属性,即使这些属性有默认值也不行。你也不能使用 `self` 属性,或调用任何实例方法。 - -> > “If you use a closure to initialize a property, remember that the rest of the instance has not yet been initialized at the point that the closure is executed. This means that you cannot access any other property values from within your closure, even if those properties have default values. You also cannot use the implicit self property, or call any of the instance’s methods.” - -在接下来的例子中定义了一个叫 `Checkerboard` 的结构,它创建了一个_跳棋_游戏桌面的模型: - -> “The example below defines a structure called Checkerboard, which models a board for the game of Checkers (also known as Draughts):” - -**?插图[8] Page 431 - -_跳棋_游戏在一个黑白相间的 10x10 方格的桌面上进行。为了表示这个游戏桌面,`Checkerboard` 结构有唯一一个属性 `boardColors`,该属性是一个拥有 100 个 `Bool` 值的数组。数组中的 `true` 值表示一个黑色方块,`false` 表示一个白色方块。数组中的第一个对象表示桌面左上角的方块,最后一个对象表示桌面右下角的方块。 - -> “The game of Checkers is played on a ten-by-ten board, with alternating black and white squares. To represent this game board, the Checkerboard structure has a single property called boardColors, which is an array of 100 Bool values. A value of true in the array represents a black square and a value of false represents a white square. The first item in the array represents the top left square on the board and the last item in the array represents the bottom right square on the board.” - -`boardColors` 数组由一个闭包来初始化其颜色值: - -> “The boardColors array is initialized with a closure to set up its color values:” - -``` -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` 中使用。 - -> “Whenever a new Checkerboard instance is created, the closure is executed, and the default value of boardColors is calculated and returned. The closure in the example above calculates and sets the appropriate color for each square on the board in a temporary array called temporaryBoard, and returns this temporary array as the closure’s return value once its setup is complete. The returned array value is stored in boardColors and can be queried with the squareIsBlackAtRow utility function:” - -``` -let board = Checkerboard() -println(board.squareIsBlackAtRow(0, column: 1)) -// prints "true" -println(board.squareIsBlackAtRow(9, column: 9)) -// prints "false" -``` - - - - - diff --git a/src/chapter2/15_Deinitialization.md b/src/chapter2/15_Deinitialization.md deleted file mode 100644 index e265c80..0000000 --- a/src/chapter2/15_Deinitialization.md +++ /dev/null @@ -1,170 +0,0 @@ -======= -# 析构过程 (Deinitialization) - -A deinitializer is called immediately before a class instance is deallocated. You write deinitializers with the deinit keyword, similar to how intializers are written with the init keyword. Deinitializers are only available on class types.” - -> 析构函数会在一个类的实例被释放之前被立即调用。用`deinit`关键词来声明析构函数,用`init`来标示类似于初始化的函数。析构函数仅在类中有效。 - -#### How Deinitialization Works - -> #### 析构过程是如何工作的 - -Swift automatically deallocates your instances when they are no longer needed, to free up resources. Swift handles the memory management of instances through automatic reference counting (ARC), as described in Automatic Reference Counting. Typically you don’t need to perform manual clean-up when your instances are deallocated. However, when you are working with your own resources, you might need to perform some additional clean-up yourself. For example, if you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated. - -> Swift 会自动释放不再需要的实例以释放资源。如自动引用计数那一章描述,Swift 通过自动引用计数(ARC)处理实例的内存管理。通常当你的实例被释放时不需要手动地去清理。但是,当使用自己的资源时,你可能需要进行一些额外的清理。例如,如果创建了一个自定义的类来打开一个文件,并写入一些数据,你可能需要在类实例被释放之前关闭该文件。 - - -Class definitions can have at most one deinitializer per class. The deinitializer does not take any parameters and is written without parentheses: - -> 在类的定义中,每个类最多只能有一个析构函数。析构函数不带任何参数,在写法上不带括号: - -```` -deinit { - // 执行析构过程 -} -```` - - -Deinitializers are called automatically, just before instance deallocation takes place. You are not allowed to call a deinitializer yourself. Superclass deinitializers are inherited by their subclasses, and the superclass deinitializer is called automatically at the end of a subclass deinitializer implementation. Superclass deinitializers are always called, even if a subclass does not provide its own deinitializer. - - -> 析构函数会自动在实例释放之前被调用,且不支持手动调用。子类会继承父类的析构函数,在子类析构函数实现的之后,将自动调用父类的析构函数。即便子类没有提供自身的析构函数,其父类的析构函数也总是被调用。 - - -Because an instance is not deallocated until after its deinitializer is called, a deinitializer can access all properties of the instance it is called on and can modify its behavior based on those properties (such as looking up the name of a file that needs to be closed). - -> 因为实例直到实例的析构函数被调用时才会被释放,所以析构函数有权访问所有被调用实例的属性,同时根据那些属性修改其行为(例如查找一个需被关闭文件的名称)。 - - - -#### Deinitializers in Action - -> #### 析构函数操作 - - -Here’s an example of a deinitializer in action. This example defines two new types, Bank and Player, for a simple game. The Bank structure manages a made-up currency, which can never have more than 10,000 coins in circulation. There can only ever be one Bank in the game, and so the Bank is implemented as a structure with static properties and methods to store and manage its current state:” - -> 下面是一个析构函数操作的例子。它是一个简单的游戏,定义了两种新类型,Bank和Player。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) { - coinsInBank += coins - } -} -```` - - -Bank keeps track of the current number of coins it holds with its coinsInBank property. It also offers two methods—vendCoins and receiveCoins—to handle the distribution and collection of coins. - -> Bank根据它的coinsInBank属性来侦听当前存有的货币数。除此之外Bank还提供两个其它方法,分别是receiveCoins和vendCoins,用于处理货币的存取。 - - - -vendCoins checks that there are enough coins in the bank before distributing them. If there are not enough coins, Bank returns a smaller number than the number that was requested (and returns zero if no coins are left in the bank). vendCoins declares numberOfCoinsToVend as a variable parameter, so that the number can be modified within the method’s body without the need to declare a new variable. It returns an integer value to indicate the actual number of coins that were provided. - -> vendCoins方法在 bank 取出货币之前检查是否有足够的量。如果货币不足,Bank则返会所有的剩余量(如果货币量为空则返回 0)。vendCoins方法中将numberOfCoinsToVend声明为一个变量,这样就可以在其它方法中对它进行修改,而无需定义一个新的变量。最终vendCoins方法将为取出的货币返回一个整型值。 - - - -The receiveCoins method simply adds the received number of coins back into the bank’s coin store. - -> 而 receiveCoins 方法更加简单, 将 bank 的货币存量和接收到的货币量相加后再保存回 bank 的货币存量。 - - - -The Player class describes a player in the game. Each player has a certain number of coins stored in their purse at any time. This is represented by the player’s coinsInPurse property: - -> 这里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) - } -} -```` - -Each Player instance is initialized with a starting allowance of a specified number of coins from the bank during initialization, although a Player instance may receive fewer than that number if not enough coins are available. - -> 每一个Player都由一个初始化函数加上指定货币量入参实例化得到,他们将在初始化的过程中从 bank 获得货币。如果 Bank 没有足够的货币存量用于支付,Player 取得的货币量可能会比指定的少。 - - - -The Player class defines a winCoins method, which retrieves a certain number of coins from the bank and adds them to the player’s purse. The Player class also implements a deinitializer, which is called just before a Player instance is deallocated. Here, the deinitializer simply returns all of the player’s coins to the bank: - -> Player类还定义了一个winCoins的方法,该方法可以让player从bank赢取一定数量的硬币存入自己钱包。同时Player类还实现了一个析构函数,它在Player实例释放前一步会被调用。这里的析构函数很简单:将所有player的货币都返还给银行: - - - - -```` -var playerOne: Player? = Player(coins: 100) -println("A new player has joined the game with \(playerOne!.coinsInPurse) coins") -// 打印 "新玩家加入游戏,为其分配100货币" -println("There are now \(Bank.coinsInBank) coins left in the bank") -// 打印 "目前银行货币存量为: 9900" -```` - - -A new Player instance is created, with a request for 100 coins if they are available. This Player instance is stored in an optional Player variable called playerOne. An optional variable is used here, because players can leave the game at any point. The optional lets you track whether there is currently a player in the game. - -> 这里创建了一个新的Player实例,如果银行存量充足他将获取100货币。由于玩家可能随时离开游戏,所以将Player实例存储在一个名为playerOne的可选Player变量中。这样您可以侦听当前是否还有玩家在游戏中。 - - - - - -Because playerOne is an optional, it is qualified with an exclamation mark (!) when its coinsInPurse property is accessed to print its default number of coins, and whenever its winCoins method is called: - -> 因为playerOne是可选的,所以由一个感叹号(!)来作前缀,每当其winCoins方法被调用时,会访问其coinsInPurse属性并打印出他的货币数目。 - - - - - -```` -playerOne!.winCoins(2_000) -println("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins") -// 打印 "PlayerOne 赢取 2000 货币,目前他拥有 2100 个货币" -println("The bank now only has \(Bank.coinsInBank) coins left") -// 打印 "目前银行货币存量为: 7900" -```` - - - - -Here, the player has won 2,000 coins. The player’s purse now contains 2,100 coins, and the bank has only 7,900 coins left. - -> 以上代码运行后,player 赢取了 2,000 货币。他的钱包目前有 2,100 个货币,bank 剩余 7,900 个货币。 - - - -```` -playerOne = nil -println("PlayerOne has left the game") -// 打印 "PlayerOne 离开了游戏" -println("The bank now has \(Bank.coinsInBank) coins") -// 打印 "目前银行货币存量为: 10000" -```` - - -The player has now left the game. This is indicated by setting the optional playerOne variable to nil, meaning “no Player instance.” At the point that this happens, the playerOne variable’s reference to the Player instance is broken. No other properties or variables are still referring to the Player instance, and so it is deallocated in order to free up its memory. Just before this happens, its deinitializer is called automatically, and its coins are returned to the bank. - -> 现在player要离开这个游戏。这将把可选的playerOne变量设置为nil,可以理解为“没有Player实例”的意思。这时playerOne变量对Player实例的引用断开。再没有其它属性或者变量还会引用player实例,为了清空内存,它将被释放掉。析构函数会在这一切发生前自动被触发调用,之后所有的货币将回归到银行,这还真是个游戏。 diff --git a/src/chapter2/17_Optional_Chaining.md b/src/chapter2/17_Optional_Chaining.md deleted file mode 100644 index 85642a5..0000000 --- a/src/chapter2/17_Optional_Chaining.md +++ /dev/null @@ -1,300 +0,0 @@ -> 翻译:[zearlin](https://github.com/zearlin) - -# 可选链 ------------------ - -可选链(Optional Chaining)是针对当前可能为空值(`nil`)的可选元素的属性,方法及下标调用和查寻的一种处理。 若可选元素为赋值对应的属性,方法或下标都会被成功调用;反之当可选成员为空值(`nil`)时,侧其属性,方法或下标调为会返回空值(`nil`)。多个的查寻可一起链式调用,并当链路的任意一环为nil时链路调用失败。 - -> 注意: -Swift中的可选链与Object-C中空值的方法调用相似,是一种更为全面的实现,适用于所有的类型及支持调用成功与否的判断。 - -## 可选链,强制解析的一种替代方案 - -当你想调用一个属性,方法或下标时通过在可选元素(`optional value`)后添置一个问号(?)来声明一个为可选链,当可选元素为非空时,侧与通过添置感叹号(!)来强解析其值的做法非常相似。主要的区别在于当可选元素为空时可选链会得体地以调用失败结束,而强制解析则会引发一个运行时错误。 - -考虑到可选链空值调用这一情况,可选链的返回值一定为可选值,即使你所查寻的属性,方法或下标返回的并不是是一个可选值。你可以通过返回的可选值来判断可选链的调用是成功的(返回的可选元素有值),还是因为链式中的空值元素而调用失败(返回的可选元素为空)。 - -具体来说,可选链的返回值类型与预期的返回值类型一致,但封装为了一个可选元素。原本返回为整型的属性,在可选链调用中会返回为可选整型(Int?) - -我们将在后续的几个代码片段中解释可选链与强制解析的区别及让你了解如果判断调用成功与否。 - -首先,我们先定义Person与Residence两个类: - -```swift -class Person { - var residence: Residence? -} - -class Residence { - var numberOfRooms = 1 -} -``` - -`Residence`实例拥有一个命名为`numberOfRooms`的整型属性。而`Person`实例有一个可选属性`residence`其类型为`Residence?`。 - -如果你创建一个新的`Person`实例,它的`residence`属性由于是被定义为可选型的,此属性将默认初始化为空。下面的代码中,john的residence属性值为空: - - -```swift -let john = Person() -``` - -如果你在`residence`后添置感叹号(`!`)以强制解析的方式来访问`person`的`residence`的属性`numberOfRooms`时,会引发一个运行时错误,因为`residence`为空无法被解析。 - -```swift -let roomCount = john.residence!.numberOfRooms -//将导致运行时错误 -``` -当`john.residence`为非空及为`roomCount`设一个可理的房间数时以述的代码会被成功调用。然后如上面所演示的,当`residence`为空这段代码就会触发一个运行时错误。 - -可选链提供了访问`numberOfRooms`值的另一种方式。 在这里通过以问号来取代先前的感叹号以可选链的方式调用。 - -```swift -if let roomCount = john.residence?.numberOfRooms { - println("John's residence has \(roomCount) room(s).") -} else { - println("Unable to retrieve the number of rooms.") -} -// 打印 "Unable to retrieve the number of rooms. -``` - -这将告诉Swift将可选的`residence`属于链式中的一环并得到`numberOfRooms`的值当`residence`存在时。 - -因为尝试访问`numberOfRooms`时存在失败的可能,所以可选链返回一个类型为`Int?` 或称之为“可选整型”的值。 当`residence`为空时,这个可选整型也将为空,以表示`numberOfRooms`无法被访问。 - -需要注意一点即使`numberOfRooms`为非可选整型。通来可选链的方式来调用`numberOfRooms`的值查询时返回的类型是`Int?`而不是一个常规的`Int`。 - -我们给`john.residence`分配一个`Residence`实例让它不在为一个空值: - -```swift -john.residence = Residence() -``` - -此时`john.residence`包含了一个真实的`Residence`实例而不再为空了。如果你以先前相同的可选链方式去访问`numberOfRooms`,它将返回一个包含默认值 1 的`Int?`: - -```swift -if let roomCount = john.residence?.numberOfRooms { - println("John's residence has \(roomCount) room(s).") -} else { - println("Unable to retrieve the number of rooms.") -} -// 打印 "John's residence has 1 room(s)"。 -``` - -##定义可选链的模型(实体)类 - -可选链支持多层的属性,方法及下标调用。这一特性让你可以进一步的调用关联类型的复杂模型中的子属性及判断这些子属性对应的属性,方法及下标下否可以访问。 - -在下面的代码片段中为后续的几个例子使用定义了四个实体类,这些类都是基于`Person`和`Residence`模型通过增加`Room`及`Address`类及一些相关的属性,方法及下标进行扩展的。 - -`Person`类还是于先前定义的相同: - -```swift -class Person { - var residence: Residence? -} -``` - -`Residence `类比之前复杂些。这次我们为 `Residence `声明了一个名为 `rooms `的变量,其初始值为 `Room[] `类型的空数值。 - -```swift -class Residence { - var rooms = Room[]() - var numberOfRooms: Int { - return rooms.count - } - subscript(i: Int) -> Room { - return rooms[i] - } - func printNumberOfRooms() { - println("The number of rooms is \(numberOfRooms)") - } - var address: Address? -} -``` -因为在这一版的`Residence`中存储了一个Room实例数组,所以其`numberOfRooms`属性以计算属性的方式实现。计算的`numberOfRooms`属性只是简单的返回了`rooms`数组的`count`属性。 - -为了更便捷的访问它的`rooms`数组,在这一版中`Residence`提供了一个只读下标,一开始我们假设传参的引索是有效的。如果索引是有效的,下标将返回`rooms`数组与请求索引相对应的`room`对象。 - -`Residence`还提供了一个名为`printNumberOfRooms`的方法,用于简单地打印房间数。 - -最后,`Residence`还定义了一个类型为`Address?`的可选属性`address`,对应的`Address`类会在下文中定义。 - -`rooms`数组中用到的`Room`类非常简单只拥有一个`name`属性及对应设置房间名的构造器。 - -```swift -class Room { - let name: String - init(name: String) { self.name = name } -} -``` - -模型中最后的一个类叫`Address`。类中有三个类型为`String?`的可选属性。作为地址信息中的一部分头两个属性`buildingName`及`buildingNumber`是两个可供选择的方式来定位特定的建筑物。 第三个属性,`stree`,则用来保存地址中的街道名称的: - -```swift -class Address { - var buildingName: String? - var buildingNumber: String? - var street: String? - func buildingIdentifier() -> String? { - if buildingName { - return buildingName - } else if buildingNumber { - return buildingNumber - } else { - return nil - } - } -} -``` -`Address`类中还提供了一个名为`buildingIdentifier`的方法,其返回类型为`String?`。 这个方法检查`buildingName`及`buildingName`是否有值,若`buildingName`有值则返回`buildingName`,若非则返回`buildingNumber`的值,如果两者均无则返回空。 - -##以可选链方式的属性调用 - -如先前演示的可选链做为强制解析的一个替代方式,你可以利用可选链来访问可选元素的属性,及检测属性的访问是否能成功,但你不能通过可选链的方式为属性赋值。 - -利用前先写好的类一个新的`Person`实例,并与之前先一样尝试访问它的`numberOfRooms`属性: - -```swift -let john = Person() -if let roomCount = john.residence?.numberOfRooms { - println("John's residence has \(roomCount) room(s).") -} else { - println("Unable to retrieve the number of rooms.") -} -// 打印 "Unable to retrieve the number of rooms。 -``` - -因为`john.residence`为空,所以这个可选链与先前的一样调用失败并没引错误。 - -##以可选链方式的方法调用法 - -你能以可选链的方式去调用一个可选元素的方法,及检测是否方法调用不否成功。即使在方法没有定义返回值的情况下一样可行。 - -`Residence`的`printNumberOfRooms`方法会打印`numberOfRooms`的当前值。方法如下: - -```swift -func printNumberOfRooms(){ - println(“The number of rooms is \(numberOfRooms)”) -} -``` -这个方法没有声明返回值,无返回值函数及方法都会带有一个隐式的返回类型为`Void`(参见Function Without Return Values)。 - -如果你通过可选链的方式去调用一个可选元素的方法,该方法返回的将是`Void?`,而非`Void`,因为通过可选链方式调用的方法返回的均为可选类型。这样让你可以通过一个`If`语句去测试`printNumberOfRooms`方法是否可调用,即使该方法本身没有定义返回值。当`printNumberOfRooms`方法通过可选链调用成功时隐式的返回值为`Void`,否非为空: - -```swift -if john.residence?.printNumberOfRooms() { - println("It was possible to print the number of rooms.") -} else { - println("It was not possible to print the number of rooms.") -} -// 打印 "It was not possible to print the number of rooms."。 -``` - -##以可选链方式的下标调用 - -你可以通过可选链的方式去获取可选元素对应下标的值,及判断下标调用是否成功,然而,你不能在可选链中去设置一个下标的值。 - -> 注意: -当你要通过可选链的试访问对应可选元素的下标时,你应该将问号置于下标所带的括号前,而非后。可选链的问号通常都是紧随表达式中的可选元素后的。 - -下面的例子中我们将通过在`Residence`类中定义的下标去获取`rooms`数组中第一间房间的名称。由于`john.residence`当前为空,所以下标的调用失败。 - -```swift -if let firstRoomName = john.residence?[0].name { - println("The first room name is \(firstRoomName).") -} else { - println("Unable to retrieve the first room name.") -} -// 打印 "Unable to retrieve the first room name."。 -``` - -下标调用时我们将可选链的问号置于`john.residence`后于下标的括号前。因为`john.residence`为可选链需要尝试调用的可选元素。 - -如果我们为`john.residence`创建并分配一个`Residence`实体且其`rooms`属性带一个或多个Room实体,你就可以通过`Residence`的下标在可选链中访问对应的成员了: - -```swift -let johnsHouse = Residence() -johnsHouse.rooms += Room(name: "Living Room") -johnsHouse.rooms += Room(name: "Kitchen") -john.residence = johnsHouse - -if let firstRoomName = john.residence?[0].name { - println("The first room name is \(firstRoomName).") -} else { - println("Unable to retrieve the first room name.") -} -// 打印 "The first room name is Living Room."。 -``` - -##多层链式 - -你可以通过多层链式来访问实体中的属性,方法及下标。多层可选链式调用并不会增加返回值的可选性/形成可选嵌套。 - -也就是说: - -通过可选链得到的值一定为可选类型,无论你想获取的目标值是否为可选。同理一个目标值原为可选元素,不过因为链式的调用而加深变可选性。 - -因此: - -当你想从可选链中得到一个`Int`时,你得到的总会是一个`Int?`类型的值,无论通过多少层的可选链。相同的,原为`Int?`类型的返回值也一样,无论经过多少层得到的还是`Int?`类型。 - -下面的例子中我们将尝试访问从`john`的`residence`属性中的`address`属于获取期其`street`属性的值。这里我们将有两层的可选链调用,链式中的两环`residence`和`address`均为可选类型的属性: - -```swift -if let johnsStreet = john.residence?.address?.street { - println("John's street name is \(johnsStreet).") -} else { - println("Unable to retrieve the address.") -} -// 打印 "Unable to retrieve the address.”。 -``` - -虽然当前的`john.residence`含有一个有效的`Residence`实例。然而`john.residence.address`的还是为空值,所以调用`john.residence?.address?.street`失败了。 - -值得注意在下面的例子中,你将尝试去获得`street`属性的值。 这个属性的类型为`String?`。所以`john.residence?.address?`的返回值也是`String?`,即使经过了两层的可选链路来访问。 - -如果你为`john.street.address`分配一个真实的`Address`实例并为其`street`赋值,你就可以通过多层可用选连的试去访问相关的值。 - -```swift -let johnsAddress = Address() -johnsAddress.buildingName = "The Larches" -johnsAddress.street = "Laurel Street" -john.residence!.address = johnsAddress -``` - -```swift -if let johnsStreet = john.residence?.address?.street { - println("John's street name is \(johnsStreet).") -} else { - println("Unable to retrieve the address.") -} -// 打印 "John's street name is Laurel Street."。 -``` - -注意我们需要通过感叹号来为`jonh.residence.address`赋值。 因为`john.residence`属性是一个可选类型,所以在为`residence`的`address`属性赋值前,我们需要用感叹得到它的实际值先。 - -##返回可选值方法的链式调用 - -先前的例子中我们展示了如果通过可选链路来获取一个可选属性的值。如有需要我们也可以用可选链的方式去调用返回值为可选类型的方法,并也可将其返回值做为链式中的一环。 - -下下面的例子中通过可选链调用了`Address`类的`buildingIdentifier`方法。 这个方法的返回类型为`String?`。 如先前所述,通过可选链调用该方法的最终返回类型也是为`String?`: - -```swift -if let buildingIdentifier = john.residence?.address?.buildingIdentifier() { - println("John's building identifier is \(buildingIdentifier).") -} -// 打印 "John's building identifier is The Larches."。 -``` - -如果你想将该方法的返回值也置于链式中,只需将可选链路的问号置于方法调用的括号后: - -```swift -if let upper = john.residence?.address?.buildingIdentifier()?.uppercaseString { - println("John's uppercase building identifier is \(upper).") -} -// 打印 "John's uppercase building identifier is THE LARCHES."。 -``` - -> 注意: -在上面的例子中,你将可选链的问号置于括后面是因为你想加入链式中的可选元素是`buildingIdentifier`的返回值,而不是该方法本身。 diff --git a/src/chapter2/19_Nested_Types.md b/src/chapter2/19_Nested_Types.md deleted file mode 100644 index 6b0805a..0000000 --- a/src/chapter2/19_Nested_Types.md +++ /dev/null @@ -1,180 +0,0 @@ -* ` Memberwise Initializers for Structure Types` 引自 `Initialization`,中文翻译参考了刘康的`《结构类型的成员式构造方法》` -* `Initializers`: 构造方法 -* `raw Character`: 字符? 原生字符? -* `raw Int`: 整型?原生整型? -* `computed property`: 计算属性? - -> 备注: -> 以下翻译并未遵循英文的第二人称叙事方式,整体使用第一人称讲述嵌套类型。 -> 由于中英文表达的差异,为兼顾译文的流畅性,本人擅自改动了一些原文的语言结构。更正时还请麻烦告知我,鄙人渴望多听取专家意见、希望在翻译的道路上越走越深~ 谢谢~ - - -#Nested Types -#嵌套类型 - -Enumerations are often created to support a specific class or structure’s functionality. Similarly, it can be convenient to define utility classes and structures purely for use within the context of a more complex type. To accomplish this, Swift enables you to define nested types, whereby you nest supporting enumerations, classes, and structures within the definition of the type they support. - -我们常常创建枚举类型来支持特定类或结构体的功能。同样的,枚举类型可以被方便的用于定义工具类(utility classes)和结构体,而这些工具类和结构体仅仅用在更复杂类型的上下文中。为实现这些功能,Swift可以定义嵌套类型,因此我们可以把枚举类型、类、结构体嵌套到支持他们的类型的定义中。 - -To nest a type within another type, write its definition within the outer braces of the type it supports. Types can be nested to as many levels as are required. - -要嵌套一个类型到另一个类型,只需把它的定义写在外层类型的大括号{}内,这个操作有个前提:外层类型支持嵌套内层类型。嵌套类型没有层数限制,想嵌多少层都可以。 - -##Nested Types in Action -##嵌套类型实例 - -The example below defines a structure called `BlackjackCard`, which models a playing card as used in the game of Blackjack. The `BlackJack` structure contains two nested enumeration types called `Suit` and `Rank`. - -下面的例子定义了一个`BlackjackCard`(21点牌)的结构体,来模仿21点出牌。`BlackJack`结构体包含了两个嵌套类型`Suit`和`Rank`。 - -In Blackjack, the Ace cards have a value of either one or eleven. This feature is represented by a structure called Values, which is nested within the Rank enumeration: - -在21点规则中,A牌(Ace)即可算作1点也可算作11点。这一特征用一个嵌套在枚举类型Rank中的结构体Values来代表。 - -``` -struct BlackjackCard { - - // nested Suit enumeration - enum Suit: Character { - case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣" - } - - // nested Rank enumeration - 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.toRaw(), second: nil) - } - } - } - - // BlackjackCard properties and methods - let rank: Rank, suit: Suit - var description: String { - var output = "suit is \(suit.toRaw())," - output += " value is \(rank.values.first)" - if let second = rank.values.second { - output += " or \(second)" - } - return output - } -} - -``` - -``` -struct BlackjackCard { - - // nested Suit enumeration - enum Suit: Character { - case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣" - } - - // nested Rank enumeration - 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.toRaw(), second: nil) - } - } - } - - // BlackjackCard的属性和方法 - let rank: Rank, suit: Suit - var description: String { - var output = "suit is \(suit.toRaw())," - output += " value is \(rank.values.first)" - if let second = rank.values.second { - output += " or \(second)" - } - return output - } -} - -``` - -The `Suit` enumeration describes the four common playing card suits, together with a raw `Character` value to represent their symbol. - -枚举类型`Suit`描述了扑克牌中的4种花色,每一种花色用一个`字符`(Character)代表。 - -The `Rank` enumeration describes the thirteen possible playing card ranks, together with a raw `Int` value to represent their face value. (This raw `Int` value is not used for the Jack, Queen, King, and Ace cards.) - -枚举类型`Rank`描述了相同花色的13张牌,每张牌的面值用一个`整型值`(Int)代表。(这个整型值不用再J、Q、K、A这四张牌上。) - -As mentioned above, the `Rank` enumeration defines a further nested structure of its own, called `Values`. This structure encapsulates the fact that most cards have one value, but the Ace card has two values. The `Values` structure defines two properties to represent this: - -* `first`, of type `Int` -* `second`, of type `Int?`, or “optional `Int`” - -如上所述,枚举类型`Rank`定义了一个内嵌的结构体`Values`。结构体`Values`通过定义两个属性描述了一个实事:大部分牌只有一个面值,而A牌有两个面值。属性如下: - -* `first`, `Int`型 -* `second`, `Int?`型,或者 “optional `Int`” - - -`Rank` also defines a computed property, `values`, which returns an instance of the `Values` structure. This computed property considers the rank of the card and initializes a new `Values` instance with appropriate values based on its rank. It uses special values for `Jack`, `Queen`, `King`, and `Ace`. For the numeric cards, it uses the rank’s raw `Int` value. - -`Rank`还定义了一个返回结构体`Values`实例的计算属性`values`。这个计算属性依据扑克牌的点数,初始化一个基于扑克牌点数推算出正确值的`Values`实例。计算属性`values`赋予J、Q、K和A这四张牌特定的值,赋予其他数字牌rank中定义的原始整型值(raw `Int`)。 - -The `BlackjackCard` structure itself has two properties—`rank` and `suit`. It also defines a computed property called `description`, which uses the values stored in `rank` and `suit` to build a description of the name and value of the card. The `description` property uses optional binding to check whether there is a second value to display, and if so, inserts additional description detail for that second value. - -结构体`BlackjackCard`定义了两个属性`rank`和`suit`,同时还定义了一个计算属性`description`,这个计算属性使用了`rank`和`suit`中存储的值来描述扑克牌的花色和点数。`description`使用可选绑定(optional binding)来判断是否存在第二个值,如果存在,则为第二个值插入额外的描述。 - -Because `BlackjackCard` is a structure with no custom initializers, it has an implicit memberwise initializer, as described in [Memberwise Initializers for Structure Types](). You can use this initializer to initialize a new constant called `theAceOfSpades`: - -因为结构体`BlackjackCard`没有自定义构造方法,所以它有一个默认的成员式构造方法(memberwise initializer),正如[《结构类型的成员式构造方法》]()所描述的。我们可以使用这个构造方法创建一个新的常量(constant)`theAceOfSpades`: - -``` -let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades) -println("theAceOfSpades: \(theAceOfSpades.description)") -// prints "theAceOfSpades: suit is ♠, value is 1 or 11 - -``` - -``` -let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades) -println("theAceOfSpades: \(theAceOfSpades.description)") -// 输出 "theAceOfSpades: suit is ♠, value is 1 or 11 - -``` - -Even though `Rank` and `Suit` are nested within `BlackjackCard`, their type can be inferred from context, and so the initialization of this instance is able to refer to the enumeration members by their member names (`.Ace` and `.Spades`) alone. In the example above, the `description` property correctly reports that the Ace of Spades has a value of `1` or `11`. - -即使`Rank`和`Suit`被嵌套在`BlackjackCard`里,他们依然可以被~~更外层的~~上下文引用。所以构造`BlackjackCard`实例时,可以仅通过成员名称(`.Ace` 和 `.Spades`)来引用枚举类型的成员。上面的例子中,属性`description`如我们所愿,输出了黑桃A的值`1`或`11`。 - -##Referring to Nested Types -##引用嵌套类型 - -To use a nested type outside of its definition context, prefix its name with the name of the type it is nested within: - -外部引用嵌套类型时,仅需在其名称前加上外层类型的名称即可: - -``` -let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw() -// heartsSymbol is "♡" -``` - -For the example above, this enables the names of `Suit`, `Rank`, and `Values` to be kept deliberately short, because their names are naturally qualified by the context in which they are defined. - -正如上例所示,嵌套类型的引用方式可以使`Suit`、`Rank`和`Values`的名字尽可能的简短,因为他们的名字会自然地被所定义的上下文限制。 - diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md deleted file mode 100644 index fe6a95a..0000000 --- a/src/chapter2/20_Extensions.md +++ /dev/null @@ -1,397 +0,0 @@ -# Extensions - -# 扩展(Extensions) - - -Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) - -扩展为已有的类,结构,枚举添加新的功能。其中包括扩展没有代码访问权限的类型(即追溯建模,retroactive modeling)。扩展和 Objective-C 当中的分类(category)很相似。(与 Objective-C 中的分类不同的是,Swift 的扩展没有名字) - -Extensions in Swift can: -- Add computed properties and computed static properties -- Define instance methods and type methods -- Provide new initializers -- Define subscripts -- Define and use new nested types -- Make an existing type conform to a protocol - -Swift 中的扩展可以: -- 增加计算属性和静态计算属性 -- 定义实例方法和类型方法 -- 提供新的构造器 -- 定义下标 -- 定义和使用新的嵌套类型 -- 将已有的类型转换为符合某一个协议 - -> Note -> -> If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined. - - -> 提示 -> -> 如果定义一个扩展用来在已有的类型上增加新的功能,那么新功能会应用在所有已经存在的实例上,即使是在扩展被定义之前实例化的。 - -## Extension Syntax - -## 扩展的语法 - -Declare extensions with the extension keyword: - -使用 ``extension`` 关键字来声明扩展: - -``` -extension SomeType { - // new functionality to add to SomeType goes here -} -``` - -An extension can extend an existing type to make it adopt one or more protocols. Where this is the case, the protocol names are written in exactly the same way as for a class or structure: - -一个扩展可以扩展一个已有的类型,使它能适配一个或多个的协议(protocol)。如果是这种情况的话,协议的命名方式应该与类和结构体的命名方式完全一致。 - -``` -extension SomeType: SomeProtocol, AnotherProtocol { - // implementation of protocol requirements goes here -} -``` - -Adding protocol conformance in this way is described in Adding Protocol Conformance with an Extension. - -这种增加协议一致性(protocol conformance)的方式在 [通过扩展增加协议一致性](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_355) 一文中有记述。 - - -## Computed Properties - -## 计算属性(Computed Properties) - -Extensions can add computed instance properties and computed type properties to existing types. This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units: - -扩展可以为已有的类型增加实例计算属性和类型计算属性。这个例子向 Swift 内建类型 ``Double`` 添加五个实例计算类型,用来提供转换为距离单位的基本功能: - -``` -extension Double { - var km: Double { return self * 1_000.0 } - var m: Double { return self } - var cm: Double { return self / 100.0 } - var mm: Double { return self / 1_000.0 } - var ft: Double { return self / 3.28084 } -} -let oneInch = 25.4.mm -println("One inch is \(oneInch) meters") -// prints "One inch is 0.0254 meters" -let threeFeet = 3.ft -println("Three feet is \(threeFeet) meters") -// prints "Three feet is 0.914399970739201 meters" -``` - -These computed properties express that a Double value should be considered as a certain unit of length. Although they are implemented as computed properties, the names of these properties can be appended to a floating-point literal value with dot syntax, as a way to use that literal value to perform distance conversions. - -这些计算属性表达的是一个 ``Double`` 类型的值是某种长度单位下的值。尽管是计算属性,但他们仍然可以接在一个带有 dot 语法的字面值的后面,用来将字面值转换成距离。 - -In this example, a Double value of 1.0 is considered to represent “one meter”. This is why the m computed property returns self—the expression 1.m is considered to calculate a Double value of 1.0. - -在上述的例子中,``Double`` 类型的 ``1.0`` 代表 “一米” 。这是为什么计算属性 ``m`` 仅仅返回 ``self`` ——表达式 ``1.m`` 最终结果是 ``Double`` 类型的值 ``1.0`` 。 - -Other units require some conversion to be expressed as a value measured in meters. One kilometer is the same as 1,000 meters, so the km computed property multiplies the value by 1_000.00 to convert into a number expressed in meters. Similarly, there are 3.28024 feet in a meter, and so the ft computed property divides the underlying Double value by 3.28024, to convert it from feet to meters. - -其他单位转换为以米为单位的数值需要进行一些转换。1千米等于1,000米,所以计算属性 ``km`` 要把数值转换成以米为单位,需要把值乘以 ''1_000.00''。同样,1英尺等于 ''3.28084'' 米,所以计算属性 ''ft'' 需要把值除以 ''3.28024'' 才能把英尺转换成米。 - -These properties are read-only computed properties, and so they are expressed without the get keyword, for brevity. Their return value is of type Double, and can be used within mathematical calculations wherever a Double is accepted: - -因为这些都是只读的计算属性,所以为了简便起见,不需要关键字 ''keyword'' 进行表示。他们的返回值都是 ``Double`` 类型的,所以可以用在所有可以接受 ``Double`` 类型的数学计算中: - -``` -let aMarathon = 42.km + 195.m -println("A marathon is \(aMarathon) meters long") -// prints "A marathon is 42195.0 meters long" -``` - -> Note -> -> Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties. - - -> 提示 -> -> 扩展可以添加新的计算属性,但是不能添加存储属性,也不能向已有属性添加属性观察器(property observer)。 - - -## Initializers - -## 构造器(Initializers) - -Extensions can add new initializers to existing types. This enables you to extend other types to accept your own custom types as initializer parameters, or to provide additional initialization options that were not included as part of the type’s original implementation. - -扩展能向已有类型添加新的构造器。这允许你用自己定义的类型作为构造器参数扩展其他的类型,或者提供原始实现没有提供的额外的初始化选项 - -Extensions can add new convenience initializers to a class, but they cannot add new designated initializers or deinitializers to a class. Designated initializers and deinitializers must always be provided by the original class implementation. - -扩展能向类添加新的简便构造器,但是不能添加新的指定构造器或者析构器。指定构造器和析构器必须在类的原始实现中提供。 - - -> Note -> -> If you use an extension to add an initializer to a value type that provides default values for all of its stored properties and does not define any custom initializers, you can call the default initializer and memberwise initializer for that value type from within your extension’s initializer. -> This would not be the case if you had written the initializer as part of the value type’s original implementation, as described in Initializer Delegation for Value Types. - - -> 提示 -> -> 如果使用扩展向一个值类型添加构造器,该构造器向所有存储属性提供默认值并且未定义任何其他的自定义构造器,你可以调用默认的构造和成员构造器来为你扩展的构造器当中的值类型赋值。 -> 正如 [构造器对值类型的构造委托](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_281) 一文所说的那样,如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 - -The example below defines a custom Rect structure to represent a geometric rectangle. The example also defines two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties: - -在下面的例子里,定义了一个用于描述几何矩形的结构体 ``Rect`` 。同时定义了两个辅助性结构体 ``Size``,``Point``,两个结构体当中的属性默认值都为 ``0.0``: - -``` -struct Size { - var width = 0.0, height = 0.0 -} -struct Point { - var x = 0.0, y = 0.0 -} -struct Rect { - var origin = Point() - var size = Size() -} -``` - -Because the Rect structure provides default values for all of its properties, it receives a default initializer and a memberwise initializer automatically, as described in Default Initializers. These initializers can be used to create new Rect instances: - -因为 结构体 ``Rect`` 为所有的属性都提供了默认值,正如默认构造器一节所说的,它可以自动接受默认构造器和成员构造器。这些构造器可以用来创建新的 ``Rect`` 实例: - -``` -let defaultRect = Rect() -let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), - size: Size(width: 5.0, height: 5.0)) -``` - -You can extend the Rect structure to provide an additional initializer that takes a specific center point and size: - -你可以使用扩展来为结构体 ``Rect`` 额外提供一个以中心点和大小作为参数的构造器: - -``` -extension Rect { - 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) - } -} -``` - -This new initializer starts by calculating an appropriate origin point based on the provided center point and size value. The initializer then calls the structure’s automatic memberwise initializer init(origin:size:), which stores the new origin and size values in the appropriate properties: - -新构造器通过中心点和大小两个参数计算出合适的原点值,然后调用结构体的自动成员构造器 ``init(origin:size:)`` ,把计算出的值存储到合适的属性上: - -``` -let centerRect = Rect(center: Point(x: 4.0, y: 4.0), - size: Size(width: 3.0, height: 3.0)) -// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0) -``` - -> Note -> -> If you provide a new initializer with an extension, you are still responsible for making sure that each instance is fully initialized once the initializer completes. - - -> 提示 -> -> 如果使用扩展来提供新的构造器,那么你仍要确保构造过程中,每一个实例都被完全初始化了。 - - -## Methods - -## 方法(Methods) - -Extensions can add new instance methods and type methods to existing types. The following example adds a new instance method called repetitions to the Int type: - -扩展可以向已有类型添加新的实例方法和类型方法。下面的例子中,向 类型 ``Int`` 中添加了新的实例方法 ``repetitions``: - -``` -extension Int { - func repetitions(task: () -> ()) { - for i in 0..self { - task() - } - } -} -``` - -The repetitions method takes a single argument of type () -> (), which indicates a function that has no parameters and does not return a value. - -``repetitions`` 方法的参数是 ``() -> ()``,说明参数是一个无参数无返回值的函数 - -After defining this extension, you can call the repetitions method on any integer number to perform a task that many number of times: - -扩展被定义之后,你就可以在任何整数上调用 ``repetitions`` 方法,来多次执行某个任务: - -``` -3.repetitions({ - println("Hello!") -}) -// Hello! -// Hello! -// Hello! -``` - -Use trailing closure syntax to make the call more succinct: - -使用尾随闭包(trailing closure)语法可以使调用更简洁: - -``` -3.repetitions { - println("Goodbye!") -} -// Goodbye! -// Goodbye! -// Goodbye! -``` - - -## Mutating Instance Methods - -## 可变实例方法(Mutating Instance Methods) - -Instance methods added with an extension can also modify (or mutate) the instance itself. Structure and enumeration methods that modify self or its properties must mark the instance method as mutating, just like mutating methods from an original implementation. - -通过扩展添加的实例方法也可以修改实例本身。结构体和枚举类型的方法中改变 ``self`` 或者其中的属性,必须标记实例的方法为 ``mutating`` ,就像原始实现中的声明变异方法(mutating method)一样。 - -The example below adds a new mutating method called square to Swift’s Int type, which squares the original value: - -下面的例子为 Swift 中的 ``Int`` 类型添加了一个新的变异方法 ``square``,用来计算原始值的平方: - -``` -extension Int { - mutating func square() { - self = self * self - } -} -var someInt = 3 -someInt.square() -// someInt is now 9 -``` - - -## Subscripts - -## 下标(Subscripts) - -Extensions can add new subscripts to an existing type. This example adds an integer subscript to Swift’s built-in Int type. This subscript [n] returns the decimal digit n places in from the right of the number: - -扩展可以为已有类型添加新的下标。下面的例子为 Swift 中的内建类型 ``Int`` 添加一个整型下标。下标 ``[n]`` 返回 十进制数从右往左第 n 位上的数字: - -- 123456789[0] returns 9 -- 123456789[1] returns 8 - -…and so on: - -……以此类推: - -``` -extension Int { - subscript(digitIndex: Int) -> Int { - var decimalBase = 1 - for _ in 1...digitIndex { - decimalBase *= 10 - } - return (self / decimalBase) % 10 - } -} -746381295[0] -// returns 5 -746381295[1] -// returns 9 -746381295[2] -// returns 2 -746381295[8] -// returns 7 -``` - -If the Int value does not have enough digits for the requested index, the subscript implementation returns 0, as if the number had been padded with zeroes to the left: - -如果该 ``Int`` 值没有足够的位数与请求对应,即下标越界,则下标会返回 ``0`` ,就好像它自动在数字左边补0一样: - -``` -746381295[9] -// returns 0, as if you had requested: -0746381295[9] -``` - - -## Nested Types - -## 嵌套类型(Nested Types) - -Extensions can add new nested types to existing classes, structures and enumerations: - -扩展可以向已有的类,结构体和枚举类型添加新的嵌套类型: - -``` -extension Character { - enum Kind { - case Vowel, Consonant, Other - } - var kind: Kind { - switch String(self).lowercaseString { - case "a", "e", "i", "o", "u": - return .Vowel - case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", - "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": - return .Consonant - default: - return .Other - } - } -} -``` - -This example adds a new nested enumeration to Character. This enumeration, called Kind, expresses the kind of letter that a particular character represents. Specifically, it expresses whether the character is a vowel or a consonant in a standard Latin script (without taking into account accents or regional variations), or whether it is another kind of character. - -上面的例子为 ``Character`` 添加了新的嵌套枚举。枚举类型的 ``Kind`` 表示一个字符所属的种类。具体来说就是一个字符是拉丁字母的元音,辅音,还是其他种类的字符(不考虑口语和地方变种的情况下)。 - -This example also adds a new computed instance property to Character, called kind, which returns the appropriate Kind enumeration member for that character. - -这个例子中同时也为 ``Character`` 添加了一个新的实例计算属性 ``kind``,用来返回字符对应的枚举成员 ``Kind`` - -The nested enumeration can now be used with Character values: - -现在嵌套枚举可以在 ``Character`` 上面使用了: - -``` -func printLetterKinds(word: String) { - println("'\(word)' is made up of the following kinds of letters:") - for character in word { - switch character.kind { - case .Vowel: - print("vowel ") - case .Consonant: - print("consonant ") - case .Other: - print("other ") - } - } - print("\n") -} -printLetterKinds("Hello") -// 'Hello' is made up of the following kinds of letters: -// consonant vowel consonant consonant vowel -``` - -This function, printLetterKinds, takes an input String value and iterates over its characters. For each character, it considers the kind computed property for that character, and prints an appropriate description of that kind. The printLetterKinds function can then be called to print the kinds of letters in an entire word, as shown here for the word "Hello". - -``printLetterKinds`` 函数迭代 ``String`` 类型的参数的每一个字母。每次迭代都根据当前字母包含的计算属性 ``kind`` 输出对应的类型描述。这样,``printLetterKinds`` 函数就输出了一个单词内所有字母的类型,正如上面例子中的单词 "word" 一样。 - - -> Note -> -> character.kind is already known to be of type Character.Kind. Because of this, all of the Character.Kind member values can be written in shorthand form inside the switch statement, such as .Vowel rather than Character.Kind.Vowel. - - -> 提示 -> -> 因为已知 ``character.kind`` 的类型是 ``Character.Kind``,所以所有 ``Character.Kind`` 的成员值都可以在 ``switch`` 语句中使用简写形式,比如使用 ``.Vowel`` 来代替 ``Character.Kind.Vowel``。 - - diff --git a/src/chapter2/21_Protocols.md b/src/chapter2/21_Protocols.md deleted file mode 100644 index ce4150f..0000000 --- a/src/chapter2/21_Protocols.md +++ /dev/null @@ -1,943 +0,0 @@ -#Protocols -A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol doesn’t actually provide an implementation for any of these requirements—it only describes what an implementation will look like. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol. - - -#协议 - -一个协议(protocol)定义了适合特定的任务或功能的方法、属性和其他需求。协议并不提供这些需求的实现,只描述了这个实现应该是怎样的。 - -协议能够被类(class),结构体(structure),枚举(enumeration)适配(adopted),同时,这些类型如果了满足一个协议需求,则被称为遵循(conform to)协议 - -Protocols can require that conforming types have specific instance properties, instance methods, type methods, operators, and subscripts. - -协议可以要求遵循(conforming)的类型有特定的实例属性(instance properties),实例方法(instance methods),类型方法(type methods),操作符(operators)和下标(subscripts)。 - - -##Protocol Syntax -##协议语法 -You define protocols in a very similar way to classes, structures, and enumerations: - -定义协议,与定义类,结构体,枚举的方式非常相似,如下所示: - - protocol SomeProtocol { - // protocol definition goes here - } - -Custom types state that they adopt a particular protocol by placing the protocol’s name after the type’s name, separated by a colon, as part of their definition. Multiple protocols can be listed, and are separated by commas: - -在类型名称后添加协议名称,并以冒号`:`分割,表示自定义类型(Custom types)适配一个特定协议;实现多个协议时,各协议之间用逗号`,`分隔,如下所示: - - struct SomeStructure: FirstProtocol, AnotherProtocol { - // structure definition goes here - } -If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma: - -若某个类有父类,要把父类放在所有其适配的协议之前,且用逗号`,`分割,如下所示: - - class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol { - // class definition goes here - } - -Property Requirements - -##属性要求 - -A protocol can require any conforming type to provide an instance property or type property with a particular name and type. The protocol doesn’t specify whether the property should be a stored property or a computed property—it only specifies the required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable. - -协议可以要求任何遵循(conforming)类型,提供一个特定名称和类型的实例属性(instance property)或类型属性(type property)。协议不指定属性是存储型属性(stored property)还是计算型属性(calculate property)。 -协议同时指定了每个属性是否是可读(gettable)或可读写(gettable and settable) - - -If a protocol requires a property to be gettable and settable, that property requirement cannot be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for it also to be settable if this is useful for your own code. - -如果协议要求属性可读写(gettable and settable),那常量存储属性(constant stored property)或者只读计算属性(read-only computed property)都无法满足此要求。如果协议只要求属性可读(gettable),那任何类型的属性都满足这个要求,即使这些属性是可写(settable)的。 - -Property requirements are always declared as variable properties, prefixed with the var keyword. Gettable and settable properties are indicated by writing { get set } after their type declaration, and gettable properties are indicated by writing { get }. - -协议里的属性要求,通常都是通过使用`var`关键字来声明的变量属性。 -在类型声明之后用{ get set }表示属性为可读写的。{ get }表示属性为可读的。 - - protocol SomeProtocol { - var mustBeSettable: Int { get set } - var doesNotNeedToBeSettable: Int { get } - } - -Always prefix type property requirements with the class keyword when you define them in a protocol. This is true even though type property requirements are prefixed with the static keyword when implemented by a structure or enumeration: - -当你在一个协议中定义一个某种类型的属性要求,总要前置`class` 关键字。同样某类型属性要求使用`static`关键字前缀,来定义结构体(structure)或枚举类型(enumeration) - -> 这样翻译正确么? - - protocol AnotherProtocol { - class var someTypeProperty: Int { get set } - } - -Here’s an example of a protocol with a single instance property requirement: - -下面是协议的一个例子,这个协议只有一个实例属性(instance property)要求: - - - protocol FullyNamed { - var fullName: String { get } - } - -The FullyNamed protocol defines any kind of thing that has a fully-qualified name. It doesn’t specify what kind of thing it must be—it only specifies that the thing must be able to provide a full name for itself. It specifies this requirement by stating that any FullyNamed type must have a gettable instance property called fullName, which is of type String. - -`FullyNamed`协议可以定义任何需要一个完整`name`的类型(方法,属性或者其他需求)。这个协议并不指定什么,只有一个需求:这个类型本身必须提供一个完整的名称。这个需求通过声明一个`String`类型的实例属性`fullName`,且这个属性必须是可读的(gettable)来指定。 - - - -Here’s an example of a simple structure that adopts and conforms to the FullyNamed protocol: - -下面的例子中,一个简单的结构体适配且遵循`FullyNamed`协议 - - struct Person: FullyNamed { - var fullName: String - } - let john = Person(fullName: "John Appleseed") - // john.fullName is "John Appleseed" - -This example defines a structure called Person, which represents a specific named person. It states that it adopts the FullyNamed protocol as part of the first line of its definition. - -这个例子中定义了一个名为`Person`的结构体,代表一个有名字的人。它在第一行的结构体定义中,声明了其适配`FullyNamed`协议。 - -Each instance of Person has a single stored property called fullName, which is of type String. This matches the single requirement of the FullyNamed protocol, and means that Person has correctly conformed to the protocol. (Swift reports an error at compile-time if a protocol requirement is not fulfilled.) - -每个`Person`实例都有一个单独存储的,`String`类型的属性`fullName`。拥有这个属性代表满足了`FullyNamed`协议的要求,这意味着`Person`遵循协议。(在编译时如果不满足协议要求,swift会报告一个错误)。 - - -Here’s a more complex class, which also adopts and conforms to the FullyNamed protocol: -下面有一个更复杂的类,同样适配且遵循`FullyNamed`协议 - - class Starship: FullyNamed { - var prefix: String? - var name: String - init(name: String, prefix: String? = nil) { - self.name = name - self.prefix = prefix - } - var fullName: String { - return (prefix ? prefix! + " " : "") + name - } - } - var ncc1701 = Starship(name: "Enterprise", prefix: "USS") - // ncc1701.fullName is "USS Enterprise" - -This class implements the fullName property requirement as a computed read-only property for a starship. Each Starship class instance stores a mandatory name and an optional prefix. The fullName property uses the prefix value if it exists, and prepends it to the beginning of name to create a full name for the starship. -这个类提供了`fullName`属性,这个属性是`starship`这个类的一个只读的计算属性。 -每个`starship`类的实例存储一个强制性的名称和一个可选的前缀。当存在前缀时,`fullName`属性会把前缀添加到名称前面,从而创建了一个`starship`的全名。 - - -Method Requirements - -Protocols can require specific instance methods and type methods to be implemented by conforming types. These methods are written as part of the protocol’s definition in exactly the same way as for normal instance and type methods, but without curly braces or a method body. Variadic parameters are allowed, subject to the same rules as for normal methods. - - - -方法需求 - -若某种类型遵循协议,协议可以要求指定特定的实例方法和类型方法。这些方法作为协议定义的一部分,跟通常定义实例与类型方法的途径完全一样,但不需要书写大括号或方法的主体。方法允许含有可变参数,且与通常的方法遵循同样的规则。 - -NOTE - -Protocols use the same syntax as normal methods, but are not allowed to specify default values for method parameters. - -注意 - -协议与通常的方法语法相同,但不允许指定方法中参数的默认值 - -As with type property requirements, you always prefix type method requirements with the class keyword when they are defined in a protocol. This is true even though type method requirements are prefixed with the static keyword when implemented by a structure or enumeration: - - protocol SomeProtocol { - class func someTypeMethod() - } - -当你在一个协议中定义一个某种类型的方法要求,要前置`class` 关键字。同样某类型方法要求使用`static`关键字前缀,来定义结构体(structure)或枚举类型(enumeration) - -The following example defines a protocol with a single instance method requirement: -下面的例子中,定义了一个协议,协议要求一个实例方法。 - - protocol RandomNumberGenerator { - func random() -> Double - } -This protocol, RandomNumberGenerator, requires any conforming type to have an instance method called random, which returns a Double value whenever it is called. (Although it is not specified as part of the protocol, it is assumed that this value will be a number between 0.0 and 1.0 inclusive.) - -`RandomNumberGenerator`,该协议要求任何遵循协议的类型调用一个名为random的实例方法,这个方法无论何时调用,都会返回一个Double类型的值。(这个值在0.0与1.0之间,这一点没有在协议中指出)。 - - -The RandomNumberGenerator protocol does not make any assumptions about how each random number will be generated—it simply requires the generator to provide a standard way to generate a new random number. - -Here’s an implementation of a class that adopts and conforms to the RandomNumberGenerator protocol. This class implements a pseudorandom number generator algorithm known as a linear congruential generator: - - `RandomNumberGenerator`协议不会描述如何建立一个随机数,只需要指定一个随机数生成器,从而提供一种标准的方式来生成一个新随机数。 -   - 下面是一个类的实现,遵循`RandomNumberGenerator`协议。这个类实现了一种伪随机数发生器算法,称为线性同余(linear congruential)发生器: - - - class LinearCongruentialGenerator: RandomNumberGenerator { - var lastRandom = 42.0 - let m = 139968.0 - let a = 3877.0 - let c = 29573.0 - func random() -> Double { - lastRandom = ((lastRandom * a + c) % m) - return lastRandom / m - } - } - let generator = LinearCongruentialGenerator() - println("Here's a random number: \(generator.random())") - // prints "Here's a random number: 0.37464991998171" - println("And another one: \(generator.random())") - // prints "And another one: 0.729023776863283" - -Mutating Method Requirements - -突变方法要求 - -It is sometimes necessary for a method to modify (or mutate) the instance it belongs to. For instance methods on value types (that is, structures and enumerations) you place the mutating keyword before a method’s func keyword to indicate that the method is allowed to modify the instance it belongs to and/or any properties of that instance. This process is described in Modifying Value Types from Within Instance Methods. - -有时,实例的一个方法需要修改(或突变)实例的类型。对值类型(value types)(即结构体和枚举类型)的实例方法中,使用`mutating`关键字,写在方法的函数关键字`fun`前面,来表明实例中该方法允许修改其类型及任何属性。这个过程在 `在实例方法中修改值类型`章节中有详细的描述。 - -If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement. - -如果你定义的协议中,某个实例适配此协议,而实例方法需要改变其类型,协议定义时要在此方法前加上关键字`mutating`。这样可以让结构体及枚举类型适配协议,且满足实例方法的需求。 - -NOTE -注意 - -If you mark a protocol instance method requirement as mutating, you do not need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations. - - -如果你在一个协议中实现的突变方法是为一个类服务的,不需要为其加`上mutating`关键字。 -mutating`关键字只用在结构体与枚举类型中。 -` - -The example below defines a protocol called Togglable, which defines a single instance method requirement called toggle. As its name suggests, the toggle method is intended to toggle or invert the state of any conforming type, typically by modifying a property of that type. - -下面的例子中定义了一个`togglable`协议,包含一个名为`togger`的突变实例方法。正如名称所表达的,适配此协议的某实例中,toggle方法通常会通过改变实例的某个属性,来切换或恢复其类型。 - -The toggle method is marked with the mutating keyword as part of the Togglable protocol definition, to indicate that the method is expected to mutate the state of a conforming instance when it is called: - -`toggle`方法前面加上了`mutating`关键字,作为`Togglabel`协议定义的一部分,则表示一个适配`toggleabel`协议的实例中,这个方法会在调用时改变实例的类型。 - - protocol Togglable { - mutating func toggle() - } - -If you implement the Togglable protocol for a structure or enumeration, that structure or enumeration can conform to the protocol by providing an implementation of the toggle method that is also marked as mutating. - -当你提供的枚举或结构体遵循`Togglable`协议时,需要提供一个带有`mutating`前缀的`toggle`方法。 - - -The example below defines an enumeration called OnOffSwitch. This enumeration toggles between two states, indicated by the enumeration cases On and Off. The enumeration’s toggle implementation is marked as mutating, to match the Togglable protocol’s requirements: - - enum OnOffSwitch: Togglable { - case Off, On - mutating func toggle() { - switch self { - case Off: - self = On - case On: - self = Off - } - } - } - var lightSwitch = OnOffSwitch.Off - lightSwitch.toggle() - // lightSwitch is now equal to .On - -Protocols as Types - -协议类型 - -Protocols do not actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use in your code. - -尽管协议本身并不实现任何功能,但协议可以作为完整的类型来使用。 - -Because it is a type, you can use a protocol in many places where other types are allowed, including: - -你可以把协议类型用在其他类型适用的场景里,比如: - -As a parameter type or return type in a function, method, or initializer - -在函数,方法或构造方法中作为形参类型(parameter type)或返回值类型(return type) - -As the type of a constant, variable, or property - -作为常量、变量或属性这三种类型之一 - -As the type of items in an array, dictionary, or other container - -作为数组,字典或其他容器中的元素类型 - -NOTE -注意 - -Because protocols are types, begin their names with a capital letter (such as FullyNamed and RandomNumberGenerator) to match the names of other types in Swift (such as Int, String, and Double). - -注意: 协议是一种类型,因此协议类型的名称应与Swift中其他类型(Int,Double,String)的写法相同,每一个单字的首字母都采用大写字母(大驼峰写法) - -Here’s an example of a protocol used as a type: - -下面的例子中,协议被当作类型使用: - - class Dice { - let sides: Int - let generator: RandomNumberGenerator - init(sides: Int, generator: RandomNumberGenerator) { - self.sides = sides - self.generator = generator - } - func roll() -> Int { - return Int(generator.random() * Double(sides)) + 1 - } - } - -This example defines a new class called Dice, which represents an n-sided dice for use in a board game. Dice instances have an integer property called sides, which represents how many sides they have, and a property called generator, which provides a random number generator from which to create dice roll values. - -例子中定义了一个`Dice`类,用来表示桌游中的拥有N个面的骰子。`Dice`的实例包含`sides`和`generator`两个属性,前者是整型(integer),用来表示骰子有几个面,后者提供了一个随机数生成器,来表示骰子掷出的值。 - -The generator property is of type RandomNumberGenerator. Therefore, you can set it to an instance of any type that adopts the RandomNumberGenerator protocol. Nothing else is required of the instance you assign to this property, except that the instance must adopt the RandomNumberGenerator protocol. - -`generator`属性的类型为`RandomNumberGenerator`,因此任何类型,若适配`RandomNumberGenerator`协议,其实例都可以赋值给`generator`,除此以外没有其他要求。 - -Dice also has an initializer, to set up its initial state. This initializer has a parameter called generator, which is also of type RandomNumberGenerator. You can pass a value of any conforming type in to this parameter when initializing a new Dice instance. - -`Dice`类也包含一个构造方法,用于设置其初始状态。这个方法包含一个同样是`RandomNumberGenerator`类型的参数`generator`。在构造一个新的`Dice`的实例时,可以传入任何遵循`RandomNumberGenerator`协议的类型作为`generator` - -Dice provides one instance method, roll, which returns an integer value between 1 and the number of sides on the dice. This method calls the generator’s random method to create a new random number between 0.0 and 1.0, and uses this random number to create a dice roll value within the correct range. Because generator is known to adopt RandomNumberGenerator, it is guaranteed to have a random method to call. - -Dice类提供了一个实例方法`roll`,此方法会返回一个整型值,介于1和骰子面的数量之间。这个方法调用`generator`的随机数方法,来创建一在0.0和1.0之间的随机数,并使用这个随机数来确保骰子的滚动值在正确的范围内。因为`generator`适配`RandomNumberGenerator`协议,因此它可以保证有一个`random`方法供调用。 - -Here’s how the Dice class can be used to create a six-sided dice with a LinearCongruentialGenerator instance as its random number generator: - -下面的例子中,展示了如何使用线性同余发生器(LinearCongruentialGenerator)的实例作为随机数生成器,从而创建一个六面的骰子: - - - var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator()) - for _ in 1...5 { - println("Random dice roll is \(d6.roll())") - } - // Random dice roll is 3 - // Random dice roll is 5 - // Random dice roll is 4 - // Random dice roll is 5 - // Random dice roll is 4 - -Delegation -代理 - -Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source. - -代理(Delegation)是一种设计模式,它允许类或结构体将一些他们负责的功能转交(代理)给其他类型的实例。 -委托模式的实现需要定义一个协议,这个协议封装了那些需要被代理的功能,而一个遵循此协议的实例则拥有这些功能 - -The example below defines two protocols for use with dice-based board games: - -下面的例子中定义了两个基于骰子游戏的协议: - - protocol DiceGame { - var dice: Dice { get } - func play() - } - protocol DiceGameDelegate { - func gameDidStart(game: DiceGame) - func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) - func gameDidEnd(game: DiceGame) - } - -The DiceGame protocol is a protocol that can be adopted by any game that involves dice. The DiceGameDelegate protocol can be adopted by any type to track the progress of a DiceGame. - -`DiceGame`协议可以被任意含有骰子的游戏所适配,`DiceGameDelegate`协议可以被任意用来追踪`DiceGame`过程的类型所适配 - -Here’s a version of the Snakes and Ladders game originally introduced in Control Flow. This version is adapted to use a Dice instance for its dice-rolls; to adopt the DiceGame protocol; and to notify a DiceGameDelegate about its progress: - -这里有一个,`Snakes and Ladders`游戏的新版本(之前的版本在流程控制这一节中介绍过)。新版本使用`Dice`类的实例作为掷骰子的需求,并且适配了`DiceGame`协议。同时通知(notify)`DiceGameDelegate`协议,用来记录游戏过程: - - class SnakesAndLadders: DiceGame { - let finalSquare = 25 - let dice = Dice(sides: 6, generator: LinearCongruentialGenerator()) - var square = 0 - var board: Int[] - init() { - board = Int[](count: finalSquare + 1, repeatedValue: 0) - board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 - board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 - } - var delegate: DiceGameDelegate? - func play() { - square = 0 - delegate?.gameDidStart(self) - gameLoop: while square != finalSquare { - let diceRoll = dice.roll() - delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll) - switch square + diceRoll { - case finalSquare: - break gameLoop - case let newSquare where newSquare > finalSquare: - continue gameLoop - default: - square += diceRoll - square += board[square] - } - } - delegate?.gameDidEnd(self) - } - } -For a description of the Snakes and Ladders gameplay, see the Break section of the Control Flow chapter. - -你可以参考流程控制章节中对此游戏的介绍 - -> 译者注 Snakes and Ladders 是蛇梯棋游戏,一种类似大富翁的游戏。 - -This version of the game is wrapped up as a class called SnakesAndLadders, which adopts the DiceGame protocol. It provides a gettable dice property and a play method in order to conform to the protocol. (The dice property is declared as a constant property because it does not need to change after initialization, and the protocol only requires that it is gettable.) - -这个版本的游戏封装为`SnakesAndLadders`类,该类适配`DiceGame`协议。这个类还提供了可读的`dice`属性和`play`方法,从而遵循了`DiceGame`协议。(`dice`属性声明为常量,因为构造之后dice属性就不在改变,且协议只要求`dice`为只读) - - - -The Snakes and Ladders game board setup takes place within the class’s init() initializer. All game logic is moved into the protocol’s play method, which uses the protocol’s required dice property to provide its dice roll values. - -`Snakes And Ladders`游戏通过构造方法(initializer)`init`初始化游戏。所有的游戏逻辑移到了`play`方法中,`play`方法使用协议要求的`dice`属性,来提供骰子掷出的值。 - -Note that the delegate property is defined as an optional DiceGameDelegate, because a delegate isn’t required in order to play the game. Because it is of an optional type, the delegate property is automatically set to an initial value of nil. Thereafter, the game instantiator has the option to set the property to a suitable delegate. - -注意,`delegate`属性并不是游戏运行所必须的,因此`delegate`被定义为`DiceGameDelegate`协议类型的可选属性,`delegate`使用nil作为初始值。此后,游戏实例可以选择将其设置为一个合适的代理。 - - - -DiceGameDelegate provides three methods for tracking the progress of a game. These three methods have been incorporated into the game logic within the play method above, and are called when a new game starts, a new turn begins, or the game ends. - -`DicegameDelegate`协议提供了三个方法来跟踪游戏过程。这三个方法存在于游戏的逻辑中,即上面的play()方法内。分别在游戏开始时,新一轮开始时,游戏结束时被调用。 - - -Because the delegate property is an optional DiceGameDelegate, the play method uses optional chaining each time it calls a method on the delegate. If the delegate property is nil, these delegate calls fail gracefully and without error. If the delegate property is non-nil, the delegate methods are called, and are passed the SnakesAndLadders instance as a parameter. - -因为`delegate`属性是一个遵循`DiceGameDelegate`的可选属性,因此在`play`方法中使用了可选链(optional chaining )来在代理时调用方法。 若`delegate`属性为`nil`, 则`delegate`所调用的方法正常失败(fail gracefully)且不报错。若`delegate`不为`nil`,则方法能够被调用,且作为一个参数传入`SnakesAndLadders`实例中 - -This next example shows a class called DiceGameTracker, which adopts the DiceGameDelegate protocol: - -下一个例子展示了一个名为`DiceGameTracker`的类,适配`DiceGameDelegate`协议。 - - class DiceGameTracker: DiceGameDelegate { - var numberOfTurns = 0 - func gameDidStart(game: DiceGame) { - numberOfTurns = 0 - if game is SnakesAndLadders { - println("Started a new game of Snakes and Ladders") - } - println("The game is using a \(game.dice.sides)-sided dice") - } - func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) { - ++numberOfTurns - println("Rolled a \(diceRoll)") - } - func gameDidEnd(game: DiceGame) { - println("The game lasted for \(numberOfTurns) turns") - } - } - -DiceGameTracker implements all three methods required by DiceGameDelegate. It uses these methods to keep track of the number of turns a game has taken. It resets a numberOfTurns property to zero when the game starts; increments it each time a new turn begins; and prints out the total number of turns once the game has ended. - -DiceGameTracker提供了DiceGameDelegate所要求的三个方法。它使用这三个方法来跟踪游戏进行的轮数。当游戏开始时,将numberOfTurns属性重置为0。每轮开始后递增这个值。当游戏结束时打印游戏进行的总轮数 - -The implementation of gameDidStart shown above uses the game parameter to print some introductory information about the game that is about to be played. The game parameter has a type of DiceGame, not SnakesAndLadders, and so gameDidStart can access and use only methods and properties that are implemented as part of the DiceGame protocol. However, the method is still able to use type casting to query the type of the underlying instance. In this example, it checks whether game is actually an instance of SnakesAndLadders behind the scenes, and prints an appropriate message if so. - -在如上所示的gameDidStart方法的实现中,游戏即将开始时使用了game参数来打印一些介绍性信息。game参数拥有一个DiceGame类型,而不是SnakesAndLadders,所以gameDidStart方法只能访问和使用DiceGame协议中的方法和属性。然而,该方法仍然能够使用类型检查(type casting)查询底层实例的类型。在这个例子中,它在幕后检查游戏是否是SnakesAndLadders的一个实例,当确认后打印一个适当的消息。 - -gameDidStart also accesses the dice property of the passed game parameter. Because game is known to conform to the DiceGame protocol, it is guaranteed to have a dice property, and so the gameDidStart method is able to access and print the dice’s sides property, regardless of what kind of game is being played. - -gameDidStart方法也能够访问dice属性,这个属性存在于被传递为参数的game中。game遵循DiceGame协议,因此被赋予了dice属性,不管运行何种游戏,gameDidStart方法都可以访问且打印骰子的边数。 - - -下面是DiceGameTracker的运行过程: -Here’s how DiceGameTracker looks in action: - - let tracker = DiceGameTracker() - let game = SnakesAndLadders() - game.delegate = tracker - game.play() - // Started a new game of Snakes and Ladders - // The game is using a 6-sided dice - // Rolled a 3 - // Rolled a 5 - // Rolled a 4 - // Rolled a 5 - // The game lasted for 4 turns - -Adding Protocol Conformance with an Extension - -使用扩展添加协议一致性 - -You can extend an existing type to adopt and conform to a new protocol, even if you do not have access to the source code for the existing type. Extensions can add new properties, methods, and subscripts to an existing type, and are therefore able to add any requirements that a protocol may demand. For more about extensions, see Extensions. - -即便不能修改现有类型的代码,你也可以扩展现有类型,从而适配和遵循新协议。扩展(extensions)可以在现有的类型上添加新属性、方法和下标,因此能够满足任何一个协议的需要。更多关于扩展相关的内容,请参考扩展。 - -NOTE -注意 - -Existing instances of a type automatically adopt and conform to a protocol when that conformance is added to the instance’s type in an extension. - -当你使用一个扩展,为一个实例的类型添加上某种对协议的适配后,这个类型已存在的所有实例,都会自动适配与遵循此协议。 - -For example, this protocol, called TextRepresentable, can be implemented by any type that has a way to be represented as text. This might be a description of itself, or a text version of its current state: - -举例来讲,下面的TextRepersentable协议,可以被任何能表现为文字的类型所适配。这有可能是其自身的描述,或是其状态的文字版本。 - - protocol TextRepresentable { - func asText() -> String - } - -The Dice class from earlier can be extended to adopt and conform to TextRepresentable: - -之前的Dice类可以扩展为适配并遵循TextRepresentable协议: - - extension Dice: TextRepresentable { - func asText() -> String { - return "A \(sides)-sided dice" - } - } - -This extension adopts the new protocol in exactly the same way as if Dice had provided it in its original implementation. The protocol name is provided after the type name, separated by a colon, and an implementation of all requirements of the protocol is provided within the extension’s curly braces. - -这个扩展以完全相同的方式适配了新协议,就像骰子提供了最初(适配协议)的实现。协议名称放在类型名称后,用`:`隔开,协议所要求的实现则提供在扩展的花括号内。 - - -Any Dice instance can now be treated as TextRepresentable: - -现在Dice类型的实例可被当作是TextRepresentable类型: - - let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator()) - println(d12.asText()) - // prints "A 12-sided dice" - -Similarly, the SnakesAndLadders game class can be extended to adopt and conform to the TextRepresentable protocol: - -同样,SnakesAndLadders类也可以扩展为适配且遵循TextRepresentable协议: - - extension SnakesAndLadders: TextRepresentable { - func asText() -> String { - return "A game of Snakes and Ladders with \(finalSquare) squares" - } - } - println(game.asText()) - // prints "A game of Snakes and Ladders with 25 squares" - -Declaring Protocol Adoption with an Extension - -通过扩展声明协议适配 - -If a type already conforms to all of the requirements of a protocol, but has not yet stated that it adopts that protocol, you can make it adopt the protocol with an empty extension: - -若一个类型已经遵循了一个协议的所有要求,但未声明此类型适配这个协议,你可以使用一个空的扩展来让其适配协议。 - - struct Hamster { - var name: String - func asText() -> String { - return "A hamster named \(name)" - } - } - extension Hamster: TextRepresentable {} - -Instances of Hamster can now be used wherever TextRepresentable is the required type: - -从现在起,Hamster的实例可以作为TextRepresentable所需要的类型来使用 - - let simonTheHamster = Hamster(name: "Simon") - let somethingTextRepresentable: TextRepresentable = simonTheHamster - println(somethingTextRepresentable.asText()) - // prints "A hamster named Simon" - -NOTE -注意 - -Types do not automatically adopt a protocol just by satisfying its requirements. They must always explicitly declare their adoption of the protocol. - -注意: 即使满足了协议的所有要求,类型也不会自动适配一个协议,因此你必须显式的声明协议适配。 - -Collections of Protocol Type - -集合中的协议类型 - -A protocol can be used as the type to be stored in a collection such as an array or a dictionary, as mentioned in Protocols as Types. This example creates an array of TextRepresentable things: - -协议可以作为集合(数组,字典)内所存储的类型使用,就像之前所讲的一样,协议作为类型使用: - - let things: TextRepresentable[] = [game, d12, simonTheHamster] - -It is now possible to iterate over the items in the array, and print each item’s textual representation: - -如下所示,可以遍历things数组的元素,并打印每个元素的文本(通过asText方法) - - for thing in things { - println(thing.asText()) - } - // A game of Snakes and Ladders with 25 squares - // A 12-sided dice - // A hamster named Simon - -Note that the thing constant is of type TextRepresentable. It is not of type Dice, or DiceGame, or Hamster, even if the actual instance behind the scenes is of one of those types. Nonetheless, because it is of type TextRepresentable, and anything that is TextRepresentable is known to have an asText method, it is safe to call thing.asText each time through the loop. - -注意,thing常量是TextRepresentable类型的。它并非Dice、DiceGame或Hamster类型,即使thing所代表的实例,背后其实是其中一个类型。 -尽管如此,因为thing是TextRepresentable协议类型,此类型都包含asText方法,因此在每次循环中可以安全的调用一次asText方法 - -Protocol Inheritance -协议继承 - -A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to list multiple inherited protocols, separated by commas: - -协议能够继承一或多个其他协议,也可进一步在继承的协议上添加更多的需求。语法与类的继承相似,此外可以用逗号`,`分隔表示继承多个协议 - - protocol InheritingProtocol: SomeProtocol, AnotherProtocol { - // protocol definition goes here - } - -Here’s an example of a protocol that inherits the TextRepresentable protocol from above: -下面的例子中,一个协议继承了之前的TextRepresentable协议: - - protocol PrettyTextRepresentable: TextRepresentable { - func asPrettyText() -> String - } - -This example defines a new protocol, PrettyTextRepresentable, which inherits from TextRepresentable. Anything that adopts PrettyTextRepresentable must satisfy all of the requirements enforced by TextRepresentable, plus the additional requirements enforced by PrettyTextRepresentable. In this example, PrettyTextRepresentable adds a single requirement to provide an instance method called asPrettyText that returns a String. - -这个例子定义了一个新的协议PrettyTextRepresentable,继承自TextRepresentable。若适配PrettyTextRepresentable协议,必须同时满足TextRepresentable协议的需求,且满足由PrettyTextRepresentable添加的额外需求。在这个例子中,PrettyTextRepresentable添加了另一需求,要求提供一个称为asPrettyText的实例方法,用于返回一个字符串。 -The SnakesAndLadders class can be extended to adopt and conform to PrettyTextRepresentable: -可以扩展SnakesAndLadders类,来使之适配且遵循PrettyTextRepresentable协议。 - - extension SnakesAndLadders: PrettyTextRepresentable { - func asPrettyText() -> String { - var output = asText() + ":\n" - for index in 1...finalSquare { - switch board[index] { - case let ladder where ladder > 0: - output += "▲ " - case let snake where snake < 0: - output += "▼ " - default: - output += "○ " - } - } - return output - } - } - -This extension states that it adopts the PrettyTextRepresentable protocol and provides an implementation of the asPrettyText method for the SnakesAndLadders type. Anything that is PrettyTextRepresentable must also be TextRepresentable, and so the asPrettyText implementation starts by calling the asText method from the TextRepresentable protocol to begin an output string. It appends a colon and a line break, and uses this as the start of its pretty text representation. It then iterates through the array of board squares, and appends an emoji representation for each square: - -这个扩展声明其适配PrettyTextRepresentable协议,并提供了SnakesAndLadders类型PrettyText方法的一个实现。任何PrettyTextRepresentable协议也是TextRepresentable的扩展,所以,asPrettyText方法的实现过程是这样的:首先调用来自TextRepresentable协议的asText方法开始输出字符串。方法的输出会附加一个冒号和一个换行符,使用这个作为美化文本输出的开始。然后遍历这个方格板数组中的每一个格子,用一个符号来表示: - -If the square’s value is greater than 0, it is the base of a ladder, and is represented by ▲. -If the square’s value is less than 0, it is the head of a snake, and is represented by ▼. -Otherwise, the square’s value is 0, and it is a “free” square, represented by ○. -The method implementation can now be used to print a pretty text description of any SnakesAndLadders instance: - -当遍历出的元素的值大于0时,表示一个梯子的底部,用`▲`符号表示 -当遍历出的元素的值小于0时,表示一个蛇头,用`▲`符号表示 -当遍历出的元素的值等于0时,表示一个空白方块,用`○`符号表示 - - println(game.asPrettyText()) - // A game of Snakes and Ladders with 25 squares: - // ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○ - -Protocol Composition -协议合成 - -It can be useful to require a type to conform to multiple protocols at once. You can combine multiple protocols into a single requirement with a protocol composition. Protocol compositions have the form protocol. You can list as many protocols within the pair of angle brackets (<>) as you need, separated by commas. - -有一种很有用的方式,来表示一种适配多个协议的类型。你可以使用协议合成(Protocol Composition)来组合多个协议。 -协议合成的格式为protocal``。你可以在尖括号(`<>`)内列出多个协议,用逗号`,`分隔。 - - - -Here’s an example that combines two protocols called Named and Aged into a single protocol composition requirement on a function parameter: - -下面的例子中,把两个协议Named与Aged组合为一个协议合成,并作为函数的参数使用 - - protocol Named { - var name: String { get } - } - protocol Aged { - var age: Int { get } - } - struct Person: Named, Aged { - var name: String - var age: Int - } - func wishHappyBirthday(celebrator: protocol) { - println("Happy birthday \(celebrator.name) - you're \(celebrator.age)!") - } - let birthdayPerson = Person(name: "Malcolm", age: 21) - wishHappyBirthday(birthdayPerson) - // prints "Happy birthday Malcolm - you're 21!" - - -This example defines a protocol called Named, with a single requirement for a gettable String property called name. It also defines a protocol called Aged, with a single requirement for a gettable Int property called age. Both of these protocols are adopted by a structure called Person. - -这个例子中,定义了一个Named协议,要求一个可读的String类型的属性`name`。同时定义了一个Aged协议,要求一个可读的Int类型的属性`Aged`。两个协议被`Person`结构体所适配。 - -The example also defines a function called wishHappyBirthday, which takes a single parameter called celebrator. The type of this parameter is protocol, which means “any type that conforms to both the Named and Aged protocols.” It doesn’t matter what specific type is passed to the function, as long as it conforms to both of the required protocols. - -这个例子也定义了带有参数`celebrator`的函数`wishHappyBirthday`。参数的类型是`protocol`,表示任何同时遵循Named与Aged协议的类型。不管向函数传递何种参数,只要遵循两个协议即可。 - - -The example then creates a new Person instance called birthdayPerson and passes this new instance to the wishHappyBirthday function. Because Person conforms to both protocols, this is a valid call, and the wishHappyBirthday function is able to print its birthday greeting. - -这个例子也创建了一个`Person`的实例`birthdayPerson`,且将这个实例作为参数传入`wishHappyBirthday`函数。因为Person同时适配 -两个协议,因此函数可以正常调用,并打印一个生日祝福。 - -NOTE -注意 - -Protocol compositions do not define a new, permanent protocol type. Rather, they define a temporary local protocol that has the combined requirements of all protocols in the composition. - -注意: 协议合成并不会生成一个新的协议类型,而是将多个协议合成为一个临时协议。 - -Checking for Protocol Conformance - -协议遵循检查 - -You can use the is and as operators described in Type Casting to check for protocol conformance, and to cast to a specific protocol. Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a type: - -你可以使用类型检查中介绍的`is`,`as`操作符,来检测某类型是否遵循某协议, - -The is operator returns true if an instance conforms to a protocol and returns false if it does not. -The as? version of the downcast operator returns an optional value of the protocol’s type, and this value is nil if the instance does not conform to that protocol. -The as version of the downcast operator forces the downcast to the protocol type and triggers a runtime error if the downcast does not succeed. - -is操作符用于检查实例是否遵循某个协议,若不遵循则返回`false`。 -as?根据协议类型返回一个可选值,当实例遵循协议时,返回该协议类型;否则返回nil -as操作符可以对协议类型进行强制向下转型。若若换失败则会报一个运行时错误。 - -> 译者注: 向下转型就是把基类转换到继承类,向上转型就是把继承类转换为基类。 - -This example defines a protocol called HasArea, with a single property requirement of a gettable Double property called area: - -下面的例子定义了协议HasArea,需要一个可读的Double类型的属性area。 - - @objc protocol HasArea { - var area: Double { get } - } - -NOTE -注意 -You can check for protocol conformance only if your protocol is marked with the @objc attribute, as seen for the HasArea protocol above. This attribute indicates that the protocol should be exposed to Objective-C code and is described in Using Swift with Cocoa and Objective-C. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to be able to check for protocol conformance. - -注意: 只有用`@objc`属性标注的协议,才可以做协议遵循检查。这个属性表示协议会暴露给Objective-C的代码,可以参考Using Siwft with Cocoa and Objectivei-c。即使你不打算与 Objective-C进行交互,当你需要进行协议遵循检查时,也要在协议前面添加`@objc`. - -Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to check for conformance, you will be able to apply that protocol only to class types. - -还要注意一点,`@objc`协议只适用于类,不能用于结构体或枚举。因此只有协议被应用在类上,才能使用`@objc`检查协议的遵循。 - -Here are two classes, Circle and Country, both of which conform to the HasArea protocol: - -下面两个类`Circle`与`Country`都遵循`HasArea`协议 - - class Circle: HasArea { - let pi = 3.1415927 - var radius: Double - var area: Double { return pi * radius * radius } - init(radius: Double) { self.radius = radius } - } - class Country: HasArea { - var area: Double - init(area: Double) { self.area = area } - } - -The Circle class implements the area property requirement as a computed property, based on a stored radius property. The Country class implements the area requirement directly as a stored property. Both classes correctly conform to the HasArea protocol. - -`Circle`类把`area`属性实现为基于存储属性 `radius`的计算属性, `Country`类则把`area`属性直接实现为存储型属性。这两个类都遵循`haxArea`协议。 - - -Here’s a class called Animal, which does not conform to the HasArea protocol: - -这个例子中`Animal`类不遵循`HasArea`协议: - - class Animal { - var legs: Int - init(legs: Int) { self.legs = legs } - } - -The Circle, Country and Animal classes do not have a shared base class. Nonetheless, they are all classes, and so instances of all three types can be used to initialize an array that stores values of type AnyObject: -`Circle`类,`Country`类,`Animal`类并没有一个相同的基类,可以采用`AnyObject`类型的数组来承载他们构造后的实例: - - let objects: AnyObject[] = [ - Circle(radius: 2.0), - Country(area: 243_610), - Animal(legs: 4) - ] -The objects array is initialized with an array literal containing a Circle instance with a radius of 2 units; a Country instance initialized with the surface area of the United Kingdom in square kilometers; and an Animal instance with four legs. - -The objects array can now be iterated, and each object in the array can be checked to see if it conforms to the HasArea protocol: - -objects数组使用数组字面量(array literal)初始化,数组包含一个`radius`为2的`Circle` 实例,aear属性等于英国面积的`Country`实例和一个`legs`属性为4的`Animal`实例。 - -现在objects数组可以被迭代,且可以对迭代出的每一个元素进行检查,看其是否遵循了`HasArea`协议: - - for object in objects { - if let objectWithArea = object as? HasArea { - println("Area is \(objectWithArea.area)") - } else { - println("Something that doesn't have an area") - } - } - // Area is 12.5663708 - // Area is 243610.0 - // Something that doesn't have an area - -Whenever an object in the array conforms to the HasArea protocol, the optional value returned by the as? operator is unwrapped with optional binding into a constant called objectWithArea. The objectWithArea constant is known to be of type HasArea, and so its area property can be accessed and printed in a type-safe way. - -Note that the underlying objects are not changed by the casting process. They continue to be a Circle, a Country and an Animal. However, at the point that they are stored in the objectWithArea constant, they are only known to be of type HasArea, and so only their area property can be accessed. - -迭代出的元素使用可选绑定(optional binding)将其绑定到`objectWithArea`常量上,使用as?操作符判断其是否遵循`HasArea`协议。`objectWithArea`常量是遵循HasArea协议类型的实例,因此其`area`属性是可以被访问和打印的。 - -`objects`数组中元素的类型并不会因为向下转型而改变,它们仍然是`Circle`,`Country`,`Animal`类型。然而,当它们被存储到`objectWithArea`常量后,只会被认为是`HasArea`类型,因此只有`area`属性能够被访问。 -Optional Protocol Requirements - -可选的协议要求 - -You can define optional requirements for protocols, These requirements do not have to be implemented by types that conform to the protocol. Optional requirements are prefixed by the @optional keyword as part of the protocol’s definition. - -您可以定义可选的协议要求,这些要求不需要类型实现符合协议。可选要求使用`@optional`关键字,作为协议的定义的一部分。 - -An optional protocol requirement can be called with optional chaining, to account for the possibility that the requirement was not implemented by a type that conforms to the protocol. For information on optional chaining, see Optional Chaining. - -You check for an implementation of an optional requirement by writing a question mark after the name of the requirement when it is called, such as someOptionalMethod?(someArgument). Optional property requirements, and optional method requirements that return a value, will always return an optional value of the appropriate type when they are accessed or called, to reflect the fact that the optional requirement may not have been implemented. - -可选协议要求通过可选链(optional chaining)进行调用,为一个类型实现不遵循协议预留可能,详细内容可以参考可选链章节。 - -你可以在实现名称后加上?来检查该实现,比如`someOptionalMethod?(someArgument)`。可选方法需求和可选属性要求,在调用或访问时都会返回一个可选值(optional value),当可选的要求可能没有被实施时,这个值也会反映出来。 - - - -NOTE - -Optional protocol requirements can only be specified if your protocol is marked with the @objc attribute. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to specify optional requirements. - -注意: 可选协议要求只能在含有`@objc`前缀的协议中指定。即使你不准备与Objective-c进行交互,当你要指定可选协议需求时,也需要添加这个前缀。 - -Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to specify optional requirements, you will only be able to apply that protocol to class types. - -还要注意,`@objc`协议只适用于类,不能用于结构体或枚举。因此只有协议被应用在类上,才能通过`@objc`指定可选协议要求。 - -The following example defines an integer-counting class called Counter, which uses an external data source to provide its increment amount. This data source is defined by the CounterDataSource protocol, which has two optional requirements: - -下面的例子定义了一个计数器类`Counter`,它使用一个外部数据源提供其增量。这个数据源是`CounterDataSource`定义的协议,它有两个可选的要求: - - @objc protocol CounterDataSource { - @optional func incrementForCount(count: Int) -> Int - @optional var fixedIncrement: Int { get } - } - -The CounterDataSource protocol defines an optional method requirement called incrementForCount and an optional property requirement called fixedIncrement. These requirements define two different ways for data sources to provide an appropriate increment amount for a Counter instance. - -`CounterDataSource`协议定义了一个可选的方法要求incrementForCount和一个可选的属性要求`fixedIncrement` 。这些要求定义了两种不同的方式的数据源,来给Counter实例提供一个适当的增量。 - - -NOTE -注意 -Strictly speaking, you can write a custom class that conforms to CounterDataSource without implementing either protocol requirement. They are both optional, after all. Although technically allowed, this wouldn’t make for a very good data source. - -严格来讲,你可以实现一个类来适配协议`CounterDataSource`,而不去实现协议中的两个要求,因为`CounterDataSource`中的属性和方法要求都是可选的。尽管这样写是可以的,但这并不是一个好的数据源的实现。 - -The Counter class, defined below, has an optional dataSource property of type CounterDataSource?: -Counter类含有`CounterDataSource?`类型的可选属性`dataSource`,如下所示: - - @objc class Counter { - var count = 0 - var dataSource: CounterDataSource? - func increment() { - if let amount = dataSource?.incrementForCount?(count) { - count += amount - } else if let amount = dataSource?.fixedIncrement? { - count += amount - } - } - } -The Counter class stores its current value in a variable property called count. The Counter class also defines a method called increment, which increments the count property every time the method is called. - -`Counter`类通过`count`属性来存储当前值,`increment`方法在每次调用后增加`count`的值。 - - -The increment method first tries to retrieve an increment amount by looking for an implementation of the incrementForCount method on its data source. The increment method uses optional chaining to try to call incrementForCount, and passes the current count value as the method’s single argument. - -`increment`方法首先通过可选链调用`incrementForCount`方法内数据源的实现,从而获取增量,并将当前的`count`值作为参数传入方法 - - - -Note two levels of optional chaining at play here. Firstly, it is possible that dataSource may be nil, and so dataSource has a question mark after its name to indicate that incrementForCount should only be called if dataSource is non-nil. Secondly, even if dataSource does exist, there is no guarantee that it implements incrementForCount, because it is an optional requirement. This is why incrementForCount is also written with a question mark after its name. - -注意,这里有两级可选链。首先,`dataSource`可能为`nil`,所以`dataSource`后使用问好,表明只有在`dataSource`不为`nil`时才调用`incrementForCount`方法。其次,即使`dataSource`存在,也不能保证它实现了`incrementForCount`方法,因为这是一个可选的要求。这就是为什么`incrementForCount`的名字后面也跟着一个问号。 - -Because the call to incrementForCount can fail for either of these two reasons, the call returns an optional Int value. This is true even though incrementForCount is defined as returning a non-optional Int value in the definition of CounterDataSource. - -以上原因表明,即使`CounterDataSource`协议中`incrementForCount`方法被定义为返回一个非可选的Int类型的值,在调用`incrementForCount`方法后,也会返回一个Int类型的可选值。 - -After calling incrementForCount, the optional Int that it returns is unwrapped into a constant called amount, using optional binding. If the optional Int does contain a value—that is, if the delegate and method both exist, and the method returned a value—the unwrapped amount is added onto the stored count property, and incrementation is complete. - -当调用完incrementForCount方法后,返回的可选值通过可选绑定,赋值给常量`amont`。 -如果可选值包含值-代表如果代理和方法都存在,方法返回了值-`amount`会赋给存储属性`count`,这个增量过程就完成了。 - -If it is not possible to retrieve a value from the incrementForCount method—either because dataSource is nil, or because the data source does not implement incrementForCount—then the increment method tries to retrieve a value from the data source’s fixedIncrement property instead. The fixedIncrement property is also an optional requirement, and so its name is also written using optional chaining with a question mark on the end, to indicate that the attempt to access the property’s value can fail. As before, the returned value is an optional Int value, even though fixedIncrement is defined as a non-optional Int property as part of the CounterDataSource protocol definition. - -如果不能从incrementForCount方法获取到值 -可能`dataSource`为`nil`,或dataSource没有实现`incrementForCount方法`-increment方法会尝试从数据源中获取fixedIncrement属性的值来代替。`fixedIncrement`属性也是一个可选的要求,所以它也使用可选链,以一个问号结束,表明试图访问属性的值时可以失败。和之前一样,即使`CounterDataSource`协议中,`fixedIncrement`属性被定义为返回一个非可选的Int类型的值,返回值也是一个可选的Int类型的值。 - -Here’s a simple CounterDataSource implementation where the data source returns a constant value of 3 every time it is queried. It does this by implementing the optional fixedIncrement property requirement: - -这里有一个简单的CounterDataSource的实现,通过实现了可选属性fixedIncrement,每次查询都会返回一个常量3。 - - class ThreeSource: CounterDataSource { - let fixedIncrement = 3 - } - -You can use an instance of ThreeSource as the data source for a new Counter instance: - -你可以使用ThreeSource的实例作为Counter实例的数据源: - - var counter = Counter() - counter.dataSource = ThreeSource() - for _ in 1...4 { - counter.increment() - println(counter.count) - } - // 3 - // 6 - // 9 - // 12 - -The code above creates a new Counter instance; sets its data source to be a new ThreeSource instance; and calls the counter’s increment method four times. As expected, the counter’s count property increases by three each time increment is called. - -上面的代码创建了一个新的Counter实例,同时把数据源设置为ThreeSource的实例,之后调用了四次计数器的increment方法。正如我们所期望的,increment方法调用一次,计数器的count属性会增加3。 - -Here’s a more complex data source called TowardsZeroSource, which makes a Counter instance count up or down towards zero from its current count value: -这里有一个更加复杂的数据源例子`TowardsZeroSource`,使计数器实例会从当前计数值向上或向下计数,直到零: - - class TowardsZeroSource: CounterDataSource { - func incrementForCount(count: Int) -> Int { - if count == 0 { - return 0 - } else if count < 0 { - return 1 - } else { - return -1 - } - } - } -The TowardsZeroSource class implements the optional incrementForCount method from the CounterDataSource protocol and uses the count argument value to work out which direction to count in. If count is already zero, the method returns 0 to indicate that no further counting should take place. - -You can use an instance of TowardsZeroSource with the existing Counter instance to count from -4 to zero. Once the counter reaches zero, no more counting takes place: - -`TowardsZeroSource`类实现了`CounterDataSource`协议中可选的`incrementForCount`方法,使用`count`参数值来决定计数方向。如果`count`已经是零,方法返回0,表明不会有进一步计算了。 -   - 你可以在`Counter`实例中使用`TowardsZeroSource`实例,从-4计数至零。一旦计数器达到零就不会在计数了: - - counter.count = -4 - counter.dataSource = TowardsZeroSource() - for _ in 1...5 { - counter.increment() - println(counter.count) - } - // -3 - // -2 - // -1 - // 0 - // 0 diff --git a/src/chapter3/05_Statements.md b/src/chapter3/05_Statements.md deleted file mode 100644 index 8d982e9..0000000 --- a/src/chapter3/05_Statements.md +++ /dev/null @@ -1,577 +0,0 @@ -> 翻译:玩家 - - -#Statements# ---------- -# 语句章节 # ----------- - -本页包含内容 - - [循环语句](#loop_statements) - - [分支语句](#branch_statements) - - [带标签的语句](#labeled_statement) - - [控制传递语句](#control_transfer_statements) - -In Swift, there are two kinds of statements: simple statements and control flow statements. Simple statements are the most common and consist of either an expression or a declaration. Control flow statements are used to control the flow of execution in a program. There are three types of control flow statements in Swift: loop statements, branch statements, and control transfer statements. - -swift和其他语言一样,语句可大致分为简单语句和控制流语句,控制流语句也可分为循环语句:用来重复的执行代码块;分支语句:用来执行满足特定条件的代码块;控制语句用来决定代码的执行顺序。后续会详细阐述各控制流语句的使用。 - -Loop statements allow a block of code to be executed repeatedly, branch statements allow a certain block of code to be executed only when certain conditions are met, and control transfer statements provide a way to alter the order in which code is executed. Each type of control flow statement is described in detail below. - -A semicolon (;) can optionally appear after any statement and is used to separate multiple statements if they appear on the same line. - -和javascript类似,在一行语句的结束尾可以不添加分号(;),但是如果一行有多个独立语句必须要添加。在语法上讲,在语句末尾是否添加分好都是可以的,但是从团队协助以及减少错误方面来讲,最好统一加上,一般而言大公司的svn服务器上都会添加一个钩子,用来减少出错的可能,所以最好还是养成添加的习惯。 - -> statement -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression);opt -> statement -> [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration);opt -> statement -> [loop-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement);opt -> statement -> [branch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/branch-statement);opt -> statement -> [labeled-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/branch-statement) -> statement -> [control-transfer-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/control-transfer-statement);opt -> statement -> [statement statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/control-transfer-statement);opt - - - --------- - - -> 语句语法 -> *语句* → [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) **;** _可选_ -> *语句* → [*声明*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) **;** _可选_ -> *语句* → [*循环语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement) **;** _可选_ -> *语句* → [*分支语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/branch-statement) **;** _可选_ -> *语句* → [*标记语句(Labeled Statement)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/labeled-statement) -> *语句* → [*控制转移语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/control-transfer-statement) **;** _可选_ -> *多条语句(Statements)* → [*语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement) [*多条语句(Statements)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) _可选_ - - - -##Loop Statements## -##循环语句## - -Loop statements allow a block of code to be executed repeatedly, depending on the conditions specified in the loop. Swift has four loop statements: a for statement, a for-in statement, a while statement, and a do-while statement. - -Control flow in a loop statement can be changed by a break statement and a continue statement and is discussed in Break Statement and Continue Statement below. - -> loop-statement -> [for-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-statement) -> loop-statement -> [for-in-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-in-statement) -> loop-statement -> [while-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-statement) -> loop-statement -> [do-while-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/do-while-statement) - -各个编程语言从语法上讲,基本的变量,语句都是类似的,swift循环语句也提供四种方式来循环语句:`for`语句 `for in`语句 `while`语句 `do-shile`语句 -通过`break`和`continue`可以改变循环语句的控制流,和其他语言类似,具体可参考break和continue - -> 循环语句语法 -> *循环语句* → [*for语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-statement) -> *循环语句* → [*for-in语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-in-statement) -> *循环语句* → [*while语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-statement) -> *循环语句* → [*do-while语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/do-while-statement) - - -##For Statement## -##for语句## - -A for statement allows a block of code to be executed repeatedly while incrementing a counter, as long as a condition remains true. - -A for statement has the following form: - - for initialization; condition; increment { - statements - } - -`for`语句可以重复的执行一端代码,并且可以递增一个计数器 -`for`语句的形式如下 - - for `initialzation`; `condition`; `increment` { - `statements` - } - -The semicolons between the initialization, condition, and increment are required. The braces around the statements in the body of the loop are also required. - -A for statement is executed as follows: - -The initialization is evaluated only once. It is typically used to declare and initialize any variables that are needed for the remainder of the loop. -The condition expression is evaluated. -If true, the program executes the statements, and execution continues to step 3. If false, the program does not execute the statements or the increment expression, and the program is finished executing the for statement. -The increment expression is evaluated, and execution returns to step 2. -Variables defined within the initialization are valid only within the scope of the for statement itself. - -The value of the condition expression must have a type that conforms to the LogicValue protocol. - -> for-statement -> for [for-init](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init);[expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt; [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) -> for-statement -> for ([for-init](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init)opt;[expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt; [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) -> for-init -> [variable-declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/variable-declaration) | [expression-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression-list) - - -`initialzation` `condition`和`increment`之间的分号 不可少,`{`也不可少 - - 1. `initialzation`只是被执行一次,通常用于声明和初始化在接下来循环中需要的变量 - 2. `condition`:如果为真(`true`)`statements`将会执行,进行第3步,如果为`false`则`statements`和`increment`都不会被执行,for至此执行完毕 - 3. 计算`increment`表达式,然后转到第2步。 - -定义在`initialzation`中的变量仅在`for`语句的作用域以内有效。`condition`表达式的值的类型必须遵循LogicValue协议。 - -> For 循环语法 -> *for语句* → for [*for初始条件*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ [*代码块*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) -> for语句 → for [*for初始条件*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ **)** [*代码块*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) -> *for初始条件* → [*变量声明*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/variable-declaration) | [*表达式列表*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression-list) - - -##For-In Statement## -##For-In 语句## - -A for-in statement allows a block of code to be executed once for each item in a collection (or any type) that conforms to the Sequence protocol. - -A for-in statement has the following form: - - for item in collection { - statements - } - -`for-in`语句允许在重复执行代码块的同时,迭代集合(或遵循Sequence协议的任意类型)中的每一项。 - -`for-in`语句的形式如下: - - for `item` in `collection` { - `statements` - } - -The generate method is called on the collection expression to obtain a value of a generator type—that is, a type that conforms to the Generator protocol. The program begins executing a loop by calling the next method on the stream. If the value returned is not None, it is assigned to the item pattern, the program executes the statements, and then continues execution at the beginning of the loop. Otherwise, the program does not perform assignment or execute the statements, and it is finished executing the for-in statement - -> GRAMMAR OF A FOR-IN STATEMENT -> for-in-statement -> for [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) in [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) - -`for-in`语句在循环开始前会调用`collection`表达式的`generate`方法来获取一个生成器类型(这是一个遵循Generator协议的类型)的值。接下来循环开始,调用`collection`表达式的`next`方法。如果其返回值不是`None`,它将会被赋给`item`,然后执行`statements`,执行完毕后回到循环开始处;否则,将不会赋值给`item`也不会执行`statements`,`for-in`至此执行完毕。这和`javascript`中的`for in`语句是一样的,可以理解为循环`collection`,如果有key的取出,去执行接下来的`statements` - -`For-In`循环语法 -> *for-in语句* → **for** [*模式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) **in** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) [*代码块*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) - - -##While Statement## -##While语句## - -A while statement allows a block of code to be executed repeatedly, as long as a condition remains true. - -A while statement has the following form: - - while condition { - statements - } - -`while`语句允许重复执行代码块 -`while`语句的形式如下: - - while `condition` { - `statements` - } - -A while statement is executed as follows: - - 1. The condition is evaluated. -If true, execution continues to step 2. If false, the program is finished executing the while statement. - 2. The program executes the statements, and execution returns to step 1. - -Because the value of the condition is evaluated before the statements are executed, the statements in a while statement can be executed zero or more times. - -The value of the condition must have a type that conforms to the LogicValue protocol. The condition can also be an optional binding declaration, as discussed in [Optional Bindind](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_432) - -> GRAMMAR OF A WHILE STATEMENT -> while-statement -> whild [while-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-condition) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) -> while-condition -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) | [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) - - -`while`语句的执行流程为判断`condition`,如果为真(`true`),这会执行`statements`,否则`while`语句执行到此结束 -由于`condition`的值在`statements`执行前就已计算出,因此`while`语句中的`statements`可能会被执行若干次,也可能不会被执行。 -`condition`表达式的值的类型必须遵循LogicValue协议。同时,`condition`表达式也可以使用可选绑定,请参考可选绑定待添加链接。 - -> While 循环语法 -> *while语句* → **while** [*while-condition*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-condition) [*code-block*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) -> *while条件* → [*expression*](..\chapter3\04_Expressions.html#expression) | [*declaration*](..\chapter3\05_Declarations.html#declaration) - - -##Do-While Statement## -##Do-While 语句## - -A do-while statement allows a block of code to be executed one or more times, as long as a condition remains true. - -A do-while statement has the following form: - - do { - statements - } while condition - -`do-while`语句允许代码块被执行一次或多次。 -`do-while`语句的形式如下: - - do { - `statements` - } while `condition` - -A do-while statement is executed as follows: - - 1. The program executes the statements, and execution continues to step 2 - 2. The condition is evaluated.If true, execution returns to step 1. If false, the program is finished executing the do-while statement. - -`do-while`语句的执行流程如下: - - 1. 执行`statements`,完后钻到2 - 2. 计算condition表达式,如果返回(`true`)继续回到1新一轮执行,否则`do-while`至此执行完毕 - -Because the value of the condition is evaluated after the statements are executed, the statements in a do-while statement are executed at least once. - -The value of the condition must have a type that conforms to the LogicValue protocol. The condition can also be an optional binding declaration, as discussed in [Optional Binding](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_432) - - 由于`condition`是在`statements`执行之后才会计算,因此可见,相比较`while`而言,`do-while`至少会执行一次 -`condition`表达式的值的类型必须遵循`LogicValue`协议。同时,`condition`表达式也可以使用可选绑定,请参考可选绑定。 -> do-while-statement→ do [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) while [while-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-condition) - - - -##Branch Statements## -##分支语句## - -Branch statements allow the program to execute certain parts of code depending on the value of one or more conditions. The values of the conditions specified in a branch statement control how the program branches and, therefore, what block of code is executed. Swift has two branch statements: an if statement and a switch statement. - -Control flow in a switch statement can be changed by a break statement and is discussed in Break Statement below - -> GRAMMAR OF A BRANCH STAREMENT -> branch-statement -> [if-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) -> brach-statement -> [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) - -通过一个或者多个条件的值,来决定语句允许程序执行指定部分的代码,swift和其他语言类似提供了`if`语句和`switch`语句 -`switch`语句中的控制流可以用`break`语句修改,请参考[Break](http://chinaz.com/swift/chapter3/10_Statements.html#break_statement) 语句。 ->branch-statement → [if-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) ->branch-statement → [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) - - -##If Statement## -##if语句## - -An if statement is used for executing code based on the evaluation of one or more conditions. - -There are two basic forms of an if statement. In each form, the opening and closing braces are required. - -The first form allows code to be executed only when a condition is true and has the following form: - - if condition { - statements - } - -通过一个或多个条件的值来决定执行哪一块的代码,if语句主要有三种使用方式,但无乱哪种方式都需要添加`{`和`}` -第一种形式是当且仅当条件为真时执行代码,像下面这样: - - if `condition` { - `statements` - } - -The second form of an if statement provides an additional else clause (introduced by the else keyword) and is used for executing one part of code when the condition is true and another part code when the same condition is false. When a single else clause is present, an if statement has the following form: - - - if condition { - statements to execute if condition is true - } else { - statements to execute if condition is false - } - -The else clause of an if statement can contain another if statement to test more than one condition. An if statement chained together in this way has the following form: - - if condition 1 { - statements to execute if condition 1 is true - } else if condition 2 { - statements to execute if condition 2 is true - } else { - statements to execute if both conditions are false - } - - -第二种形式是在第一种形式的基础上添加else语句,当只有一个else语句时,像下面这样: - - if `condition` { - `statements to execute if condition is true` - } else { - `statements to execute if condition is false` - } - -第三种则是else中又需要进行判断,即有多种判断情况: - - if `condition 1` { - `statements to execute if condition 1 is true` - } else if `condition 2` { - `statements to execute if condition 2 is true` - } - else { - `statements to execute if both conditions are false` - } - -The value of any condition in an if statement must have a type that conforms to the LogicValue protocol. The condition can also be an optional binding declaration, as discussed in[Option Binding](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_432) - -> GRAMMAR OF AN IF STATEMENT -> if-statement -> if [if-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-condition) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) [else-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/else-clause) opt -> if-condition -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) | [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) -> else-clause -> else [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) | else [if-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) - - -`if`语句中条件的值的类型必须遵循`LogicValue`协议。同时,条件也可以使用可选绑定,请参考可选绑定`待添加链接` ->if-statement → if [if-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-condition) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-condition) [else-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/else-clause) opt - ->if-condition → [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) | [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) - ->else-clause → else [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) | else [if-statement opt](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) - - -##Switch Statement## -##Switch 语句## - -A switch statement allows certain blocks of code to be executed depending on the value of a control expression. -A switch statement has the following form: - - switch control expression { - case pattern 1: - statements - case pattern 2 where condition: - statements - case pattern 3 where condition, - pattern 4 where condition: - statements - default: - statements - } - -取决于`switch~语句的控制表达式(control expression),`switch`语句将决定执行哪一块代码。 - -switch语句的形式如下: - - switch `control expression` { - case `pattern 1`: - `statements` - case `pattern 2` where `condition`: - `statements` - case `pattern 3` where `condition`, - `pattern 4` where `condition`: - `statements` - default: - `statements` - } -The control expression of the switch statement is evaluated and then compared with the patterns specified in each case. If a match is found, the program executes the statements listed within the scope of that case. The scope of each case can’t be empty. As a result, you must include at least one statement following the colon (:) of each case label. Use a single break statement if you don’t intend to execute any code in the body of a matched case. - -`switch`语句的表达式`control expression`会首选被计算,然后与下面的每个`case`的模式进行匹配,如果匹配成功,程序将会执行对应`case`中的`statements`,需要注意的是每个case不能为空,也就是说在case中至少有一条语句,如果在相应case中不想执行代码,只需要在程序中写个`break`即可 - - -The values of expressions your code can branch on is very flexible. For instance, in addition to the values of scalar types, such as integers and characters, your code can branch on the values of any type, including floating-point numbers, strings, tuples, instances of custom classes, and optionals. The value of the control expression can even be matched to the value of a case in an enumeration and checked for inclusion in a specified range of values. For examples of how to use these various types of values in switch statements, see Switch in the Control Flow chapter. - -A switch case can optionally contain a guard expression after each pattern. A guard expression is introduced by the keyword where followed by an expression, and is used to provide an additional condition before a pattern in a case is considered matched to the control expression. If a guard expression is present, the statements within the relevant case are executed only if the value of the control expression matches one of the patterns of the case and the guard expression evaluates to true. For instance, a control expression matches the case in the example below only if it is a tuple that contains two elements of the same value, such as (1, 1). - -case let (x, y) where x == y: - -可以用作控制表达式的值是什么灵活的,除了标量类型(scalartypes,如`Int`、`Character`)之外,你还可以使用其他任何类型的值,包括浮点数,字符串,远组,自定义类的实例以及可选(`optional`)类型,甚至是枚举类型中的成员和指定的范围(`range`)等。关于在`switch`语句中使用这些类型,请参考控制流章节的Switch. - -你可以在模式后端添加一个保护作用的表达式(guard expression),构成是这样的:关键字`where`后面跟着一个作为额外测试条件的表达式,因此当且仅当表达式匹配的一个case的某个模式在保护作用的表达式为真时,对应case中的`statements`才会被执行,在下面例子中,控制表达式只会匹配含有两个相等元素的元组 - - case let (x, y) where x == y: - } - - -As the above example shows, patterns in a case can also bind constants using the keyword let (they can also bind variables using the keyword var). These constants (or variables) can then be referenced in a corresponding guard expression and throughout the rest of the code within the scope of the case. That said, if the case contains multiple patterns that match the control expression, none of those patterns can contain constant or variable bindings. - - -正如上面的例子,也可以在模式中使用let(或var)语句来绑定常量(或变量)。这些常量(或变量)可以在其对应的起保护作用的表达式和其对应的case块里的代码中引用。但是,如果case中有多个模式匹配控制表达式,那么这些模式都不能绑定常量(或变量)。 - -A switch statement can also include a default case, introduced by the keyword default. The code within a default case is executed only if no other cases match the control expression. A switch statement can include only one default case, which must appear at the end of the switch statement. - -Although the actual execution order of pattern-matching operations, and in particular the evaluation order of patterns in cases, is unspecified, pattern matching in a switch statement behaves as if the evaluation is performed in source order—that is, the order in which they appear in source code. As a result, if multiple cases contain patterns that evaluate to the same value, and thus can match the value of the control expression, the program executes only the code within the first matching case in source order. - -switch语句也可以包含默认(default)块,只有其它case块都无法匹配控制表达式时,默认块中的代码才会被执行。一个switch语句只能有一个默认块,而且必须在switch语句的最后面。 - -尽管模式匹配操作的实际执行顺序,并且计算顺序是不可知的,但是Swift规定能够了swift中的语句中的模式匹配顺序和书写源码的顺序保持一致。因此,当多个模式含有相通的值并且能够匹配控制表达式时,程序只会执行源码中第一个匹配`case`中的代码 - -##Switch Statements Must Be Exhaustive## -##Switch 语句必须是完备的## - -In Swift, every possible value of the control expression’s type must match the value of at least one pattern of a case. When this simply isn’t feasible (for instance, when the control expression’s type is Int), you can include a default case to satisfy the requirement - -`switch`语句中包含多个`case`,每个`case`都是`switch`的一个分支,由`switch`来决定执行哪一个分支代码,`switch`语句必须是完整的,也就是值必须与`case`中的某一个对应,可以通过`default`来指定默认就不符合`case`条件时执行的代码块,并且这个`default`分支必须在最后。 - -##Execution Does Not Fall Through Cases Implicitly## -##不存在隐式的贯穿(fall through)## - -After the code within a matched case has finished executing, the program exits from the switch statement. Program execution does not continue or “fall through” to the next case or default case. That said, if you want execution to continue from one case to the next, explicitly include a fallthrough statement, which simply consists of the keyword fallthrough, in the case from which you want execution to continue. For more information about the fallthrough statement, see Fallthrough Statement below - -> switch-statement -> switch [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) {[switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt} -> switch-cases -> [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-case) [switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt -> switch-case -> [case-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) -> switch-case [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label): | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label): -> case-label -> case [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list): -> case-item-list -> [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause) opt | [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause)opt , [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list) -> default-label -> default -> guard-clause -> where [guard-expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-expression) -> guard-expression -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) - -当匹配的`case`代码在执行完毕后,程序会终止`switch`语句,而不会继续执行下一个`case`语句,这就意味着,如果你想执行下一个case块,需要显式地在你需要的case块里使用fallthrough语句。关于fallthrough语句的更多信息,请参考Fallthrough 语句。 - -> switch-statement -> switch [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) {[switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt} -> switch-cases -> [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-case) [switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt -> switch-case -> [case-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) -> switch-case [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label): | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label): -> case-label -> case [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list): -> case-item-list -> [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause) opt | [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause)opt , [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list) -> default-label -> default -> guard-clause -> where [guard-expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-expression) -> guard-expression -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) - - -##Labeled Statement## -##带标签的语句## - -You can prefix a loop statement or a switch statement with a statement label, which consists of the name of the label followed immediately by a colon (:). Use statement labels with break and continue statements to be explicit about how you want to change control flow in a loop statement or a switch statement, as discussed in Break Statement and Continue Statement below. - -你可以在循环语句和`switch`语句前面加上标签,它由标签名和`:`组成,在`break`和`continue`后面跟上标签名可以显式的在循环语句和switch语句中更改控制流,把控制权传递给指定标签标记的语句。关于这两条语句用法,请参考[Break](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-XID_976) 语句和[Continue](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-XID_976) 语句 - -The scope of a labeled statement is the entire statement following the statement label. You can nest labeled statements, but the name of each statement label must be unique. - -For more information and to see examples of how to use statement labels, see Labeled Statements in the Control Flow chapter - -> labeld-statement -> [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [loop-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement) | [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) -> statement-label -> [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name): -> label-name -> [identifier](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier) - - - -标签的作用域是该标签所标记的语句之后的所有语句。你可以不使用带标签的语句,但只要使用它,标签名就必唯一。 - -关于使用带标签的语句的例子,请参考控制流一章的带标签的语句 - -> labeld-statement -> [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [loop-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement) | [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) -> statement-label -> [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name): -> label-name -> [identifier](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier) - - -##Control Transfer Statements## -##控制传递语句## - -Control transfer statements can change the order in which code in your program is executed by unconditionally transferring program control from one piece of code to another. Swift has four control transfer statements: a break statement, a continue statement, a fallthrough statement, and a return statement. - -> control-transfer-statement -> [break-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/break-statement) -> control-transfer-statement -> [continue-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/continue-statement) -> continue-statement -> [fallthrougth-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/fallthrough-statement) -> continue-statement -> [return-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/return-statement) - -能够无条件的把控制权从一片代码传递到另一片代码,控制传递语句能够改变代码的执行顺序,Swift 提供四种类型的控制传递语句: `break`语句,`continue`语句,`fallthrough`语句和`return`语句 - -> control-transfer-statement -> [break-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/break-statement) -> control-transfer-statement -> [continue-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/continue-statement) -> continue-statement -> [fallthrougth-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/fallthrough-statement) -> continue-statement -> [return-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/return-statement) - -##Break Statement## -##break语句## -A break statement ends program execution of a loop or a switch statement. A break statement can consist of only the keyword break, or it can consist of the keyword break followed by the name of a statement label, as shown below. - - break - break label name - -`break`用于终止循环或是`switch`语句,用break语句时,可以只写break这个关键词,也可以在break后面跟上标签名(label name),像下面这样: - - break - break label name - -When a break statement is followed by the name of a statement label, it ends program execution of the loop or switch statement named by that label. - -When a break statement is not followed by the name of a statement label, it ends program execution of the switch statement or the innermost enclosing loop statement in which it occurs. - -当`break`后面带有标签名时,可用于终止这个标签标记的循环或`switch`语句的执行 - -而当只有`break`关键词时,则会终止`switch`语句或上下文中包含`break` -的最内层的循环的执行 - -In both cases, program control is then transferred to the first line of code following the enclosing loop or switch statement, if any. - -For examples of how to use a break statement, see Break and Labeled Statements in the Control Flow chapter. - -> break-statement -> break [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name) opt - -在这两种情况下,控制权都会被传递给循环或switch语句外面的第一行语句 - -关于使用break语句的例子,请参考控制流一章的Break和带标签的语句 - -> break-statement -> break [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name) opt - -##Continue Statement## -##Continue 语句## -A continue statement ends program execution of the current iteration of a loop statement but does not stop execution of the loop statement. A continue statement can consist of only the keyword continue, or it can consist of the keyword continue followed by the name of a statement label, as shown below. - - continue - continue label name - -continue语句用于终止循环中当前迭代的执行,但不会终止该循环的执行。使用continue语句时,和break一样,可以只写continue这个关键词,也可以在continue后面跟上标签名(label name),像下面这样: - - continue - continue label name - -When a continue statement is followed by the name of a statement label, it ends program execution of the current iteration of the loop statement named by that label. - -When a continue statement is not followed by the name of a statement label, it ends program execution of the current iteration of the innermost enclosing loop statement in which it occurs. - -当continue语句后面带标签名时,可用于终止由这个标签标记的循环中当前迭代的执行 - -而当只写break时,可用于终止上下文中包含continue语句的最内层循环中当前迭代的执行 - -In both cases, program control is then transferred to the condition of the enclosing loop statement. - -In a for statement, the increment expression is still evaluated after the continue statement is executed, because the increment expression is evaluated after the execution of the loop’s body. - -For examples of how to use a continue statement, see Continue and Labeled Statements in the Control Flow chapter - -> continue-statement -> continue [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name)opt - -在这两种情况下,控制权都会被传递给循环外面的第一行语句。 - -在for语句中,continue语句执行后,increment表达式还是会被计算,这是因为每次循环体执行完毕后increment表达式都会被计算。 - -关于使用continue语句的例子,请参考控制流一章的Continue和带标签的语句 - -> continue-statement -> continue [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name)opt - - -##Fallthrough Statement## -##Fallthrough 语句## - -A fallthrough statement consists of the fallthrough keyword and occurs only in a case block of a switch statement. A fallthrough statement causes program execution to continue from one case in a switch statement to the next case. Program execution continues to the next case even if the patterns of the case label do not match the value of the switch statement’s control expression. - -A fallthrough statement can appear anywhere inside a switch statement, not just as the last statement of a case block, but it can’t be used in the final case block. It also cannot transfer control into a case block whose pattern contains value binding patterns. - -`fallthrough`语句用于在`switch`语句中传递控制权。`fallthrough`语句会把控制权从`switch`语句中的一个`case`无条件的传递给下一个case,即使下一个`case`的值与`switch`语句的控制表达式的值不匹配 - -For an example of how to use a fallthrough statement in a switch statement, see Control Transfer Statements in the Control Flow chapter. - -> fallthrough-statement -> fallthrough - -关于在switch语句中使用fallthrough语句的例子,请参考控制流一章的控制传递语句 - -> fallthrough-statement -> fallthrough - -##Return Statement## -##Return 语句## - -A return statement occurs only in the body of a function or method definition and causes program execution to return to the calling function or method. Program execution continues at the point immediately following the function or method call. - -A return statement can consist of only the keyword return, or it can consist of the keyword return followed by an expression, as shown below. - - return - return expression - -`return`用于在函数或是方法中,将控制权传递给调用者,接着程序将会从调用者的位置继续的往下执行 -使用return语句时,可以只写return这个关键词,也可以在return后面跟上表达式,像下面这样 - - return - return `expression` - -When a return statement is followed by an expression, the value of the expression is returned to the calling function or method. If the value of the expression does not match the value of the return type declared in the function or method declaration, the expression’s value is converted to the return type before it is returned to the calling function or method. - -当`return`后面跟有表达式时,会把表达式的值返回给调用者,如果表达式值的类型与调用者期望的类型不匹配,swift会在返回表达式的值之前把表达式值的类型转为调用者期望的类型 - -When a return statement is not followed by an expression, it can be used only to return from a function or method that does not return a value (that is, when the return type of the function or method is Void or ()). - -> return-statement -> return [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt - -而当只写return时,仅仅是将控制权从该函数或方法传递给调用者,而不返回一个值。(这就是说,该函数或方法的返回类型为Void或()) - -> return-statement -> return [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md deleted file mode 100644 index 85e263f..0000000 --- a/src/chapter3/06_Declarations.md +++ /dev/null @@ -1,1208 +0,0 @@ -# 声明 -A declaration introduces a new name or construct into your program. For example, you use declarations to introduce functions and methods, variables and constants, and to define new, named enumeration, structure, class, and protocol types. You can also use a declaration to extend the the behavior of an existing named type and to import symbols into your program that are declared elsewhere. - -声明将新的名字或者结构引入到程序中。例如,使用声明可以引入函数、方法、变量和常量;可以定义新的,命名的枚举类型,结构,类和协议类型。也可以使用声明来扩展已存在命名类型的行为,在程序中引入在其它地方声明的符号。 - -In Swift, most declarations are also definitions in the sense that they are implemented or initialized at the same time they are declared. That said, because protocols don’t implement their members, most protocol members are declarations only. For convenience and because the distinction isn’t that important in Swift, the term declaration covers both declarations and definitions. - -在Swift中,大多数声明在某种意义上也是定义,可以在声明的同时实现和初始化他们。也就是说,因为协议并不会实现他们的成员,所以大多数协议成员仅仅是声明。为了方便,由于这个不同在Swift里不是那么重要,因此术语declaration同时包含了声明和定义。 - ->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 - -## 模块范围 - -The module scope defines the code that’s visible to other code in Swift source files that are part of the same module. The top-level code in a Swift source file consists of zero or more statements, declarations, and expressions. Variables, constants, and other named declarations that are declared at the top-level of a source file are visible to code in every source file that is part of the same module。 - -模块范围定义了对模块中其它Swift源文件可见的代码。在Swift源文件中顶层的代码由0或多个语句、声明和表达式组成。在源文件的顶层声明的变量、常量和其它命名的声明对同一模块的其它源文件代码都是可见的。 - ->GRAMMAR OF A TOP-LEVEL DECLARATION - ->top-level-declaration → statements­opt - -Code Blocks - -代码块 - -A code block is used by a variety of declarations and control structures to group statements together. It has the following form: - -通过代码块把不同的声明和控制结构语句分组,有如下的形式: - - { - `statements` - } - -The statements inside a code block include declarations, expressions, and other kinds of statements and are executed in order of their appearance in source code. - -在代码块里的语句包括声明,表达式,和其它类型的语句,按照在源代码里出现的顺序执行。 - ->GRAMMAR OF A CODE BLOCK ->code-block → {­statements­opt­} - -##Import Declaration - -## Import 声明 - -An import declaration lets you access symbols that are declared outside the current file. The basic form imports the entire module; it consists of the import keyword followed by a module name: - - -import声明可以让你访问当前文件之外声明的符号。基本的形式是引入整个模块。由import关键字后面跟着一个模块名进行声明。 - - - import module - -Providing more detail limits which symbols are imported—you can specify a specific submodule or a specific declaration within a module or submodule. When this detailed form is used, only the imported symbol (and not the module that declares it) is made available in the current scope. - -如果提供更多的细节限制,还可以明确限制引入一个具体的子模块或者模块子模块里的一个具体的声明。如果采用这种形式的声明,只有被引入的符号(而不是声明它的模块)可以在当前范围里被访问到。 - - 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 - -##Constant Declaration - -##常量声明 - -A constant declaration introduces a constant named value into your program. Constant declarations are declared using the keyword let and have the following form: - -常量声明引入一个不变的命名值到程序中。常量声明使用关键字let,采用如下的形式: - - let constant name: type = expression - -A constant declaration defines an immutable binding between the constant name and the value of the initializer expression; after the value of a constant is set, it cannot be changed. That said, if a constant is initialized with a class object, the object itself can change, but the binding between the constant name and the object it refers to can’t. - -常量声明在常量名和初始化表达式的值之间定义了一个不可变的绑定;在值被设置之后,它就不能改变了。也就是说,如果常量用一个class对象实例化,对象本身可以改变,但是在常量名和对象之间的绑定是不会改变的。 - -When a constant is declared at global scope, it must be initialized with a value. When a constant declaration occurs in the context of a class or structure declaration, it is considered a constant property. Constant declarations are not computed properties and therefore do not have getters or setters. - -如果一个常量在全局范围里声明,它就必须有一个初始值。当一个常量在类或者结构声明中声明,它会被认为是一个常量属性。常量声明不是计算型属性,因此没有getters和setters方法。 - -If the constant name of a constant declaration is a tuple pattern, the name of each item in the tuple is bound to the corresponding value in the initializer expression. - -如果一个常量声明的名字是一个元组,元组中的每一项在初始化表达式里都会绑定到相应的值。 - - let (firstNumber, secondNumber) = (10, 42) - -In this example, firstNumber is a named constant for the value 10, and secondNumber is a named constant for the value 42. Both constants can now be used independently: - -在这个例子,firstNumer是一个命名常量,值是10。secondNumber是一个命名常量,值是4。这两个常量现在都可以独立的使用。 - - println("The first number is \(firstNumber).") - // prints "The first number is 10." - println("The second number is \(secondNumber).") - // prints "The second number is 42." - -The type annotation (: type) is optional in a constant declaration when the type of the constant name can be inferred, as described in Type Inference. - -如Type Inference里描述的一样,如果常量名的类型可以被推断出来,类型标识(:type)是可选的。 - -To declare a static constant property, mark the declaration with the static keyword. Static properties are discussed in Type Properties. - -为了声明一个静态的常量属性,使用关键字static来标记声明。静态属性会在Type Proerties里讨论。 - -For more information about constants and for guidance about when to use them, see Constants and Variables and Stored Properties - -想获得更多关于常量的信息或者想在使用中获得帮助,请查看常量和变量和存储属性(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 - - -##Variable Declaration - -##变量声明 - -A variable declaration introduces a variable named value into your program and is declared using the keyword var. - -变量声明会引入一个可变的命名值到程序中,使用关键字var进行声明。 - -Variable declarations have several forms that declare different kinds of named, mutable values, including stored and computed variables and properties, stored variable and property observers, and static variable properties. The appropriate form to use depends on the scope at which the variable is declared and the kind of variable you intend to declare. - -变量声明有好几种不同的形式来声明不同类型的命名的,可变的值,包括存储型和计算型的变量和属性,存储型变量和属性观察者,还有静态的变量属性。要使用哪种适合的形式取决于变量声明的范围和你打算声明的变量种类。 - ->注意: - - -You can override a property in a subclass by prefixing the subclass’s property declaration with the override keyword, as described in Overriding. - -通过在子类中的属性声明的前面使用override,可以在子类中重写一个属性。 - - -##Stored Variables and Stored Variable Properties - -##存储型变量和存储型变量属性 - -The following form declares a stored variable or stored variable property: - -下面的形式声明了一个存储型变量或存储型的变量属性 - - var variable name: type = expression - -You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class or structure declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, it is referred to as a stored variable. When it is declared in the context of a class or structure declaration, it is referred to as a stored variable property. - -你可以在全局范围、函数的局部范围或者类或结构声明的上下文环境里定义变量声明。如果这种形式的变量声明在全局范围或者函数局部范围里声明,它指的就是存储型变量。如果是在类或者结构声明的环境里声明的,它就是指的存储型变量属性。 - -The initializer expression can’t be present in a protocol declaration, but in all other contexts, the initializer expression is optional. That said, if no initializer expression is present, the variable declaration must include an explicit type annotation (: type). - -初始化表达式不能在协议声明里出现,但是可以出现在其它所有的上下文环境里。初始化表达式是可选的。也就是说,如果没有初始化表达式存在,变量声明必须包括一个显式的类型表示(:type)。 - -As with constant declarations, if the variable name is a tuple pattern, the name of each item in the tuple is bound to the corresponding value in the initializer expression. - -和常量声明一样,如果变量名字是一个元组,元组中每一项的名字都会被绑定到初始化表达式的对应的值。 - - -As their names suggest, the value of a stored variable or a stored variable property is stored in memory. - -顾名思义,存储型变量或者存储型属性的值是存储在内存中的。 - -##Computed Variables and Computed Properties - -##计算型变量和计算型属性 - -The following form declares a computed variable or computed property: - -下面的形式声明了一个计算型变量或者计算型属性 - - var variable name: type { - get { - statements - } - set(setter name) { - statements - } - } -You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class, structure, enumeration, or extension declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, it is referred to as a computed variable. When it is declared in the context of a class, structure, or extension declaration, it is referred to as a computed property. - -可以在全局范围,局部范围,或者类、结构、枚举或者扩展声明里定义这种形式的声明。如果这类型是的变量声明在全局范围或者函数的局部范围声明的,它指的是计算型变量。如果它在类,结构或者扩展声明里声明的,它指的就是计算型属性。 - - -The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly, as described in Read-Only Computed Properties. But if you provide a setter clause, you must also provide a getter clause. - -getter用于读取值,setter用于写入值。setter子句是可选的,仅仅getter方法是必须的,你可以把两者都忽略,只是简单的直接返回请求值,如在Read-Only Comuted Properties描述的一样。但是如果你提供一个setter子句,你也必须要提供一个getter子句。 - -The setter name and enclosing parentheses is optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is newValue, as described in Shorthand Setter Declaration. - -setter名字和封闭的括号是可选的。如果你提供了一个setter名字。如果你提供一个setter名字,它会被作为setter的参数的名称。如果你美欧提供setter名称,setter缺省的参数名是newvalue,如在Shorthand Setter Declaration描述的那样. - -Unlike stored named values and stored variable properties, the value of a computed named value or a computed property is not stored in memory. - -不像存储型命名值和存储型变量属性,计算型命名值或者计算型属性的值不会存储到内存中。 - -For more information and to see examples of computed properties, see Computed Properties. - -获得更多信息和如何使用属性监视器的例子,请查看属性监视器(prpperty observers)一节。 - -##Stored Variable Observers and Property Observers - -##存储型变量监视器和属性监视器 - -You can also declare a stored variable or property with willSet and didSet observers. A stored variable or property declared with observers has the following form: - -也可以使用willset和didset监视器声明一个存储型的变量或者属性。用监视器声明的存储型变量或者属性有以下的形式: - - var variable name: type = expression { - willSet(setter name) { - statements - } - didSet(setter name) { - statements - } - } - -You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class or structure declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, the observers are referred to as stored variable observers. When it is declared in the context of a class or structure declaration, the observers are referred to as property observers. - -可以在全局范围,函数的局部返回,或类,结构的上下文环境里声明这种形式的变量。当这种类型是在在全局范围或者函数的局部范围里声明的时候,监视器会被作为存储型变量监视器。当在类或者结构声明中声明的时候,监视器会被作为属性监视器。 - -You can add property observers to any stored property. You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass, as described in Overriding Property Observers. - -可以为任何存储型属性增加监视器。也可以为继承的属性通过使用子类覆盖增加属性监视器(无论是存储型的或是计算型的),就像Overriding PropertyOververs里描述的一样。 - -The initializer expression is optional in the context of a class or structure declaration, but required elsewhere. The type annotation is required in all variable declarations that include observers, regardless of the context in which they are declared. - -在类或者结构声明里,初始化表达式是可选的。但是在其它所有地方是必须的。类型标识在所有变量声明里是必须的,包括监视器,无论他们声明的环境。 - -The willSet and didSet observers provide a way to observe (and to respond appropriately) when the value of a variable or property is being set. The observers are not called when the variable or property is first initialized. Instead, they are called only when the value is set outside of an initialization context. - -willset 和 didset 监视器提供了一种方式来观察(适当的响应)什么时候变量或者属性的值被设置。监视器在变量或属性在第一次初始化的时候不会被调用,仅仅在初始化环境的外边设置的时候会被调用。 - -A willSet observer is called just before the value of the variable or property is set. The new value is passed to the willSet observer as a constant, and therefore it can’t be changed in the implementation of the willSet clause. The didSet observer is called immediately after the new value is set. In contrast to the willSet observer, the old value of the variable or property is passed to the didSet observer in case you still need access to it. That said, if you assign a value to a variable or property within its own didSet observer clause, that new value that you assign will replace the one that was just set and passed to the willSet observer. - -willset监视器只是在变量或是属性值被设置的时候调用。新值会被作为常量传递给willset语句,因此在willset子句实现的时候不能改变。didSet监视器在新值被设置的时候会立即被调用。与willset监视器相比,变量或属性的旧值会传给didSet监视器,以应对万一需要访问它 - -The setter name and enclosing parentheses in the willSet and didSet clauses are optional. If you provide setter names, they are used as the parameter names to the willSet and didSet observers. If you do not provide setter names, the default parameter name to the willSet observer is newValue and the default parameter name to the didSet observer is oldValue. - -在willset和didset语句里 setter名字和括号是可选的。如果你提供你不提供setter名字,willset 缺省的参数名是newValue好缺省的参数名是oldValue. - -The didSet clause is optional when you provide a willSet clause. Likewise, the willSet clause is optional when you provide a didSet clause. - -如果你提供一个willset语句,didset语句是可选的。同样的,如果你提供一个didset 语句,willset语句是可选的 - -For more information and to see an example of how to use property observers, see Property Observers. - -获得更多信息,查看如何使用属性监视器的例子,请查看属性监视器(prpperty observers)一节。 - -##Class and Static Variable Properties - -##类和静态变量属性 - -To declare a class computed property, mark the declaration with the class keyword. To declare a static variable property, mark the declaration with the static keyword. Class and static properties are discussed in Type Properties. - -要声明一个类的计算型属性,要用关键字class标记声明。声明静态的变量属性,用关键字static标记。类和静态属性在Type属性里有讨论。 - ->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-bloc - - -##Type Alias Declaration - -##类型的别名声明 - -A type alias declaration introduces a named alias of an existing type into your program. Type alias declarations begin with the keyword typealias and have the following form: - -类型别名声明引入了存在类型的名字到程序中,以关键字typelias开头,采用如下的形式: - - typealias name = existing type - -After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. The existing type can be a named type or a compound type. Type aliases do not create new types; they simply allow a name to refer to an existing type. - -在声明一个类型别名后,那个别名可以使用在你的程序的的任何有那个类型的地方使用了。存在的类型可能是命名类型或是复合类型。类型 别名不是创造新类型,它们只是简单的把名字指向一个存在的类型。 - -See also Protocol Associated Type Declaration. - -也可以参看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 - -##Function Declaration - -##函数声明 - -A :newTerm`function declaration` introduces a function or method into your program. A function declared in the context of class, structure, enumeration, or protocol is referred to as a method. Function declarations are declared using the keyword func and have the following form: - -新术语”函数声明“引入了一个函数或者方法到程序中。在类,结构,枚举或者协议里声明的函数会被当做方法。函数声明使用关键字func,采用以下的形式。 - - func function name(parameters) -> return type { - statements - } - -If the function has a return type of Void, the return type can be omitted as follows: - -如果函数的返回类型是void,返回类型可像下面这样忽略: - -func function name(parameters) { - statements -} - -The type of each parameter must be included—it can’t be inferred. By default, the parameters to a function are constants. Write var in front of a parameter’s name to make it a variable, scoping any changes made to the variable just to the function body, or write inout to make those changes also apply to the argument that was passed in the caller’s scope. For a discussion of in-out parameters, see In-Out Parameters. - -必须包含每个参数的类型-参数类型不能通过推断。默认情况下,函数的参数是常量。在参数名的前面写一个var会让它成为一个变量,对变量的做的任何变化只会在函数内有效,或者用inout使的这些改变可以在调用域内生效。 - -Functions can return multiple values using a tuple type as the return type of the function. - -函数可以使用元组类型作为函数的返回类型来返回多个值。 - -A function definition can appear inside another function declaration. This kind of function is known as a nested function. For a discussion of nested functions, see Nested Functions. - -函数定义可以出现在另一个函数声明之内。这种函数叫做嵌入函数。对于嵌入函数的讨论,请参见Nested Function。 - -Parameter Names - -Function parameters are a comma separated list where each parameter has one of several forms. The order of arguments in a function call must match the order of parameters in the function’s declaration. The simplest entry in a parameter list has the following form: - -函数参数是一个逗号分隔的列表,每个参数可以有好几种形式。函数调用的时候参数的顺序必须匹配函数声明的参数顺序。在参数列表里最简单的输入形式: - - parameter name: parameter type - - -For function parameters, the parameter name is used within the function body, but is not used when calling the function. For method parameters, the parameter name is used as within the function body, and is also used as a label for the argument when calling the method. The name of a method’s first parameter is used only within the function body, like the parameter of a function. For example: - -对于函数参数,参数名字在函数体内部使用,但是在调用函数的时候不会使用。对于方法参数,参数名可以在函数体使用,在调用方法时也可以作为参数的标签使用。函数的一个参数名字仅仅在函数内使用,就像函数的参数。例如 - - - func f(x: Int, y: String) -> String { - return y + String(x) - } - f(7, "hello") // x and y have no name - - class C { - func f(x: Int, y: String) -> String { - return y + String(x) - } - } - let c = C() - c.f(7, y: "hello") // x没有名称,y有名称 - - -You can override the default behavior for how parameter names are used with one of the following forms: - -可以重写参数名字使用的默认行为,采用如下的形式: - - - external parameter name local parameter name: parameter type - #parameter name: parameter type - _ local parameter name: parameter type - - -A second name before the local parameter name gives the parameter an external name, which can be different than the local parameter name. The external parameter name must be used when the function is called. The corresponding argument must have the external name in function or method calls. - -本地参数名前的第二个名字给参数了一个外部的名字,这个不同于本地的参数名。外部的参数名必须在函数调用的时候调用。相应的参数必须在函数或者方法调用时有外部名字。 - -A hash symbol (#) before a parameter name indicates that the name should be used as both an external and a local parameter name. It has the same meaning as writing the local parameter name twice. The corresponding argument must have this name in function or method calls. - -参数名前的#显示了名字应该同时被作为外部和本地参数使用。它和写入本地参数名两次有同样的意义。相应的参数在函数或者参数调用时必须有这个名字。 - -An underscore (_) before a local parameter name gives that parameter no name to be used in function calls. The corresponding argument must have no name in function or method calls. - -本地参数名前面的下划线在函数调用的时候让参数可以没有名字。相应的参数在函数或者方法调用的时候没有名字。 - -##Special Kinds of Parameters - -##特殊类型的参数 - -Parameters can be ignored, take a variable number of values, and provide default values using the following forms: - -参数可以忽略,需要不同数量的值,会提供默认值,使用如下的形式: - - - _ : <#parameter type#. - parameter name: parameter type... - parameter name: parameter type = default argument value - - -A parameter named with an underscore (_) is explicitly ignored an can’t be accessed within the body of the function. - -带有下划线的参数会显式的被忽略,在函数内部不能被访问到。 - -A parameter with a base type name followed immediately by three dots (...) is understood as a variadic parameter. A function can have at most one variadic parameter, which must be its last parameter. A variadic parameter is treated as an array that contains elements of the base type name. For instance, the variadic parameter Int... is treated as Int[]. For an example that uses a variadic parameter, see Variadic Parameters. - -基本类型名的参数,如果紧跟着三个点(...),被理解为是可变参数。一个函数最多可以有一个可变参数,且必须是最后一个参数。可变参数被作包含基本类型的元素数组。举例来讲,可变参数int...被看做是int[]。 查看可变参数的使用例子,详见可变参数(variadic parameters)一节。 - -A parameter with an equals sign (=) and an expression after its type is understood to have a default value of the given expression. If the parameter is omitted when calling the function, the default value is used instead. If the parameter is not omitted, it must have its name in the function call. For example, f() and f(x: 7) are both valid calls to a function with a single default parameter named x, but f(7) is invalid because it provides a value without a name. - -带有等号(=)的参数和它的类型后面的表达式会被当作给定表达式的默认类型。如果参数在调用函数的时候被忽略,默认值会被使用。例如,对于带有单个默认的的参数名x的函数,f()和f(x:7)都是有效的调用,但是f(7)是有效的,因为它提供了没有名字的值。 - -Special Kinds of Methods on an enumeration or a structure that modify self must be marked with the mutating keyword at the start of the function declaration. - -会修改self的枚举类型或者结构上的方法,必须在函数声明的开始标记为mutating关键字 - -Methods that override a superclass method must be marked with the override keyword at the start of the function declaration. It is an error to override a method without the override keyword or to use the overridekeyword on a method that doesn’t override a superclass method. - -重写超类方法的方法必须在函数声明的开头override关键词标记。没有override就重写方法会产生错误或者使用override在没有重载超类的方法 - -Methods associated with a type rather than an instance of a type must be marked with the static attribute for enumerations and structures or the class attribute for classes. - -与type相关而不是类型实例相关的方法必须使用使用static属性来标记枚举、结构或者类的class属性。 - -##Curried Functions and Methods - -##科里化函数和方法 - -Curried functions and methods have the following form: - -科里化函数和方法有以下的形式: - - - func function name(parameters)(parameters) -> return type { - statements - } - -以这种形式定义的函数的返回值是另一个函数。举例来说,下面的两个声明时等价的: - - func addTwoNumbers(a: Int)(b: Int) -> Int { - return a + b - } - func addTwoNumbers(a: Int) -> (Int -> Int) { - func addTheSecondNumber(b: Int) -> Int { - return a + b - } - return addTheSecondNumber - } - - addTwoNumbers(4)(5) // Returns 9 - -多级柯里化应用如下 - ->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­: - -A function declared this way is understood as a function whose return type is another function. For example, the following two declarations are equivalent: - -用这种方式声明的函数会被当做一个函数,它的返回类型是另外一个函数。例如,下面2个声明是一样的: - - -##Enumeration Declaration - -##枚举声明 - -An enumeration declaration introduces a named enumeration type into your program. - -枚举声明引入了名叫枚举的类型程序中。 - - -Enumeration declarations have two basic forms and are declared using the keyword enum. The body of an enumeration declared using either form contains zero or more values—called enumeration cases—and any number of declarations, including computed properties, instance methods, static methods, initializers, type aliases, and even other enumeration, structure, and class declarations. Enumeration declarations can’t contain destructor or protocol declarations. - -枚举声明有2种基本的形式,使用关键字enum声明。一个枚举类型的的主体会使用这2种形式之一,包含0或多个值-被称作枚举类型。还有任何数量的声明,包括计算型的属性,实例方法,静态方法,初始化,类型别名,和其它的枚举、结构和类声明。枚举声明不能包含析构或者协议声明。 - -Unlike classes and structures, enumeration types do not have an implicitly provided default initializer; all initializers must be declared explicitly. Initializers can delegate to other initializers in the enumeration, but the initialization process is complete only after an initializer assigns one of the enumeration cases to self. - -不像类或者结构,枚举类型没有一个默认的初始化,但是初始化过程仅仅在初始化赋值给枚举类型的一个给self的时候。 - -Like structures but unlike classes, enumerations are value types; instances of an enumeration are copied when assigned to variables or constants, or when passed as arguments to a function call. For information about value types, see Structures and Enumerations Are Value Types. - -类似结构但是不像类,枚举是值类型;一个枚举实例在赋值给变量或者常量的时候会被复制,或者在传递参数给函数调用的的时候。 - -You can extend the behavior of an enumeration type with an extension declaration, as discussed in Extension Declaration. - - -可以使用extension声明扩展枚举类型的行为,如果Extension Declaration Enumerations with Cases of Any Type描述的那样。 - -The following form declares an enumeration type that contains enumeration cases of any type: - -下面的形式声明了一个枚举类型,包含了所有类型的枚举。 - - - enum enumeration name { - case enumeration case 1 - case enumeration case 2(associated value types) - } - - - -Enumerations declared in this form are sometimes called discriminated unions in other programming languages. - -用这种形式声明的枚举在其它语言里有时候被叫做discriminated unions - -In this form, each case block consists of the keyword case followed by one or more enumeration cases, separated by commas. The name of each case must be unique. Each case can also specify that it stores values of a given type. These types are specified in the associated value types tuple, immediately following the name of the case. For more information and to see examples of cases with associated value types, seeAssociated Values. - -用这种方式,每个cast块由关键字case组成,case后跟着一个或者多个逗号分隔的枚举case。每个case的名字必须是唯一的。每个case也能够确定它存储一个给定类型的值。这些类型用关联值类型元组来设置,后面紧跟着case的名字。获取更多信息,或关联值类型的的例子,请看Assiciated Values Enumerations with Raw Cases Values - -The following form declares an enumeration type that contains enumeration cases of the same basic type: - -下面的形式声明了一种枚举类型,包含同样基本类型的枚举case - - - enum enumeration name: raw value type { - case enumeration case 1 = raw value 1 - case enumeration case 2 = raw value 2 - } - - - -In this form, each case block consists of the keyword case, followed by one or more enumeration cases, separated by commas. Unlike the cases in the first form, each case has an underlying value, called a raw value, of the same basic type. The type of these values is specified in the raw value type and must represent a literal integer, floating-point number, character, or string. - -通过这种形式,每种caes块是由关键字case后面跟着一个或者多个由多个逗号分隔的枚举case。不像第一种形式的case,每个case有一个underlying值,叫做原生值。这些值的类型在rsw值的类型设置,必须表示一个字面量整数,浮点数,字符和字符串。 - -Each case must have a unique name and be assigned a unique raw value. If the raw value type is specified as Int and you don’t assign a value to the cases explicitly, they are implicitly assigned the values 0, 1, 2, and so on. Each unassigned case of type Int is implicitly assigned a raw value that is automatically incremented from the raw value of the previous case. - -每个case必须有一个唯一的名字,然后被赋值为一个单独的原生值。如果原生值用Int设置,你不需要要显式的赋值,他们可以默认的赋值1,1,2等等。每个没有赋值的Int类型会被赋值为原生类型,可以自动的从之前的case的原生值递增。 - - - enum ExampleEnum: Int { - case A, B, C = 5, D - } - - -In the above example, the value of ExampleEnum.A is 0 and the value of ExampleEnum.B is 1. And because the value of ExampleEnum.C is explicitly set to 5, the value of ExampleEnum.D is automatically incremented from 5 and is therefore 6. - -在上面的例子中,ExampleEnum。A的值是o.ExampleEnum.B值是1。因为ExampleEnum.C是显式的设置为5,ExampleEnumd.D的值会从5自动的增加,所以是6. - -The raw value of an enumeration case can be accessed by calling its toRaw method, as inExampleEnum.B.toRaw(). You can also use a raw value to find a corresponding case, if there is one, by calling the fromRaw method, which returns an optional case. For more information and to see examples of cases with raw value types, see Raw Values. - -枚举类型的原生值可以通过toRaw方法访问,比如ExampleEnum.B.toRaw()。你也可以使用一个原生值来找到对应的case通过调用fromRaw方法。 - -##Accessing Enumeration Cases - -##访问枚举case - -To reference the case of an enumeration type, use dot (.) syntax, as in EnumerationType.EnumerationCase. When the enumeration type can be inferred from context, you can omit it (the dot is still required), as described in Enumeration Syntax and Implicit Member Expression. - -和EnumerationType.EnumerationCase一样,可以使用语法.来引用一个enumeration类型的case,就像inEnumeration Syntax and Implicit Member Expression所描述的。 - -To check the values of enumeration cases, use a switch statement, as shown in Matching Enumeration Values with a Switch Statement. The enumeration type is pattern-matched against the enumeration case patterns in the case blocks of the switch statement, as described in Enumeration Case Pattern. - -使用switch语句来检验枚举事件的值,如使用switch语句匹配枚举值(Matching Enumeration Values with a Switch Statement)一节描述的那样。 - ->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­ - -##Structure Declaration - -##结构声明 - -A structure declaration introduces a named structure type into your program. Structure declarations are declared using the keyword struct and have the following form: - -结构声明引入了命名的类型到程序中。结构声明使用关键字struct,采用如下的形式: - - struct structure name: adopted protocols { - declarations - } - - -The body of a structure contains zero or more declarations. These declarations can include both stored and computed properties, static properties, instance methods, static methods, initializers, type aliases, and even other structure, class, and enumeration declarations. Structure declarations can’t contain destructor or protocol declarations. For a discussion and several examples of structures that include various kinds of declarations, see Classes and Structures. - -结构体包含0或者更多的声明。这个声明能包括存储型和计算型的属性,静态属性,示例方法,静态方法,构造器,类型别名,甚至其它结构,类和枚举声明。结构声明不能包含析构或者协议声明。在Classes and Structures里,包括好几种了不同类型的声明的结构例子。 - -Structure types can adopt any number of protocols, but can’t inherit from classes, enumerations, or other structures. - -结构类型可以采用任何数量的协议,但是不能从classes,枚举或者它结构继承。 - -There are three ways create an instance of a previously declared structure: - -有3种方式创建过去声明过的示例结构的示例。 - - -- Call one of the initializers declared within the structure, as described in Initializers. - 就像Initializers描述的,调用结构里的一个初始器之一。 - -- If no initializers are declared, call the structure’s memberwise initializer, as described in Memberwise Initializers for Structure Types. - 如果没有初始器被声明,就可以调用结构区的成员 - -- If no initializers are declared, and all properties of the structure declaration were given initial values, call the structure’s default initializer, as described in Default Initializers. - 如果没有初始化器被声明,结构所有其他声明的属性就会被给予初始化的值,调用结构的某人初始化器,正如Default Initializers .描述的那样。 - - - -The process of initializing a structure’s declared properties is described in Initialization. - -初始化一个结构的声明的属性的过程在Initialization描述。 - -Properties of a structure instance can be accessed using dot (.) syntax, as described in Accessing Properties. - -一个结构实例的属性使用通过.语来访问。 - -Structures are value types; instances of a structure are copied when assigned to variables or constants, or when passed as arguments to a function call. For information about value types, see Structures and Enumerations Are Value Types. - -结构是值类型;一个结构的实例在赋值给变量或者常量或者在传递参数给函数调用的时候采用复制的形式。关于值类型的信息,请参看Structures and Enumerations Are Value Types. - -You can extend the behavior of a structure type with an extension declaration, as discussed in Extension Declaration. - -你可以用一个扩展声明来扩展结构类型的行为,正如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­} - -##Class Declaration - -##类声明 - - -A class declaration introduces a named class type into your program. Class declarations are declared using the keyword class and have the following form: - -类型声明引入了命名的类型到程序中。类声明使用关键字class声明,采用下面的形式: - - - class class name: superclass, adopted protocols { - declarations - } - - -The body of a class contains zero or more declarations. These declarations can include both stored and computed properties, instance methods, class methods, initializers, a single destructor method, type aliases, and even other class, structure, and enumeration declarations. Class declarations can’t contain protocol declarations. For a discussion and several examples of classes that include various kinds of declarations, see Classes and Structures. - -一个class的主题会包含0或多个声明。这些声明可以包括存储型和计算型的属性,实例方法,类方法,构造器,单个析构函数,类型 别名,和甚至其它的class,结构,枚举声明。类声明不能包括协议声明。详细讨论和例子请看 Classes and Structures - -A class type can inherit from only one parent class, its superclass, but can adopt any number of protocols. The superclass appears first in the type-inheritance-clause, followed by any adopted protocols. -一个class类只能从一个父类中继承,但是可以有多个协议。超类首先出现在类型继承语句中,后面跟着采用的协议。 - -As discussed in Initializer Declaration, classes can have designated and convenience initializers. When you declare either kind of initializer, you can require any subclass to override it by marking the initializer with therequired attribute. The designated initializer of a class must initialize all of the class’s declared properties and it must do so before calling any of its superclass’s designated initializers. - -正如在初始化声明讨论的一样,类可以有指定和便利的构造器。当你声明某种构造器时,可以使用required属性要求所有子类重写。这个特定的构造器必须初始化类的所有声明的属性。在调用任何超类的特定的构造器时都必须这么做。 - -A class can override properties, methods, and initializers of its superclass. Overridden methods and properties must be marked with the override keyword. - -类可以重写它超类的属性,方法和构造器。重写的方法和属性必须都使用override来标记。 - -Although properties and methods declared in the superclass are inherited by the current class, designated initializers declared in the superclass are not. That said, if the current class overrides all of the superclass’s designated initializers, it inherits the superclass’s convenience initializers. Swift classes do not inherit from a universal base class. - -尽管在子类中声明的属性和方法可以被当前的类继承,但是在超类中指定的构造器却不可以。也就是说,如果当前类重写了超类的所有指定的构造器,它就会继续超类的便利构造器。Swift类不会从通用的基类中继承。 - -There are two ways create an instance of a previously declared class: - -有两种方式创建过去声明的类的实例: - -- Call one of the initializers declared within the class, as described in Initializers. - 在类的内部调用声明的初始化器。 -- If no initializers are declared, and all properties of the class declaration were given initial values, call the class’s default initializer, as described in Default Initializers. - 如果没有声明的初始化器,类声明的素有属性会有一个初始化值,是通过调用类的默认的初始化器来完成的。正如Default Initializers描述的。 - - - -Access properties of a class instance with dot (.) syntax, as described in Accessing Properties. - -使用.语法访问类的属性,如Accessing Properties描述的一样。 - - -Classes are reference types; instances of a class are referred to, rather than copied, when assigned to variables or constants, or when passed as arguments to a function call. For information about reference types, see Structures and Enumerations Are Value Types. - -类是引用类型;在被赋值给变量或常量的时候,或者当被作为参数传递给函数调用的时候,类的实例会被引用而不是被复制。更多信息,参考Structures and Enumerations Are Value Types.。 - - -You can extend the behavior of a class type with an extension declaration, as discussed in Extension Declaration. - -可以使用extension声明来扩展类的行为,如Extension Desclaration描述的那样. - - - > 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­} - -##Protocol Declaration - -##协议声明 - -A protocol declaration introduces a named protocol type into your program. Protocol declarations are declared using the keyword protocol and have the following form: - -协议声明引入命名的协议类型到程序中,用关键字protocol来声明,有如下的形式: - - - protocol protocol name: inherited protocols { - protocol member declarations - } - -The body of a protocol contains zero or more protocol member declarations, which describe the conformance requirements that any type adopting the protocol must fulfill. In particular, a protocol can declare that conforming types must implement certain properties, methods, initializers, and subscripts. Protocols can also declare special kinds of type aliases, called associated types, that can specify relationships among the various declarations of the protocol. The protocol member declarations are discussed in detail below. - -协议的主体包含0或多个协议成员声明,它描述了任何实现它的协议都必须满足的一致性要求。特别是,一致性的协议必须实现某个属性,方法,构造器,和附属脚本。协议也能声明特殊种类的类型别名,被、称作关联类型,设置协议里的不同声明的关系。下面会对协议成员声明会做详细的讨论 - -Protocol types can inherit from any number of other protocols. When a protocol type inherits from other protocols, the set of requirements from those other protocols are aggregated, and any type that inherits from the current protocol must conform to all those requirements. For an example of how to use protocol inheritance, see Protocol Inheritance. - -协议类型可以继承任意数量的其它协议。如果一个协议类型从其它协议继承时任何从当前协议继承的类型都必须和从那些协议中的要求集合一致。如何使用协议继承,请查看Protocol Inheritance. - - -NOTE -注意 - -You can also aggregate the conformance requirements of multiple protocols using protocol composition types, as described in Protocol Composition Type and Protocol Composition. - -你也可以使用协议符合类型聚合多个协议的一致性要求。 - -You can add protocol conformance to a previously declared type by adopting the protocol in an extension declaration of that type. In the extension, you must implement all of the adopted protocol’s requirements. If the type already implements all of the requirements, you can leave the body of the extension declaration empty. - -你可以增加协议conformance到任何一个过去声明的类型通过在那个类型的extendsion中声明。在这个扩展里,你必须实现所有使用的协议的需求。如果那个类型已经实现了所有的要求,扩展声明的主题可以是空的。 - -By default, types that conform to a protocol must implement all properties, methods, and subscripts declared in the protocol. That said, you can mark these protocol member declarations with the optional attribute to specify that their implementation by a conforming type is optional. The optional attribute can be applied only to protocols that are marked with the objc attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. For more information about how to use the optionalattribute and for guidance about how to access optional protocol members—for example, when you’re not sure whether a conforming type implements them—see Optional Protocol Requirements. - -默认情况下,与协议一致的类型必须实现所有的属性,方法,和声明的附属脚本。也就是说,你可以用opaional属性来标记协议成员,表示他们的实现是可选的。option属性仅仅能被应用到objc标记的属性。结构,仅仅class类型能采纳和玉包含可选的成员变量的协议一致。对于如何访问可选的协议成员-例如,如果你不确定一个一致性类型是否要实现-查看一下 Optional Protocol Requirements. - -To restrict the adoption of a protocol to class types only, mark the entire protocol declaration with theclass_protocol attribute. Any protocol that inherits from a protocol marked with the class_protocol attribute can likewise be adopted only by a class type. - -为了限制协议的的只应用到某个class type,用 class_protocol属性标记整个协议声明。任何从标记class_protocol 协议继承的协议可以只被class类型采纳。 - -NOTE -注意 - -If a protocol is already marked with the objc attribute, the class_protocol attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the class_protocol attribute explicitly. - -如果协议已经用objc标记过了,class_protocol会隐式的应用到那个协议;没有必要显式的用class_protocol标记协议。 - -Protocols are named types, and thus they can appear in all the same places in your code as other named types, as discussed in Protocols as Types. However, you can’t construct an instance of a protocol, because protocols do not actually provide the implementations for the requirements they specify. - -协议是命名类型,因此在你的代码里它们可以像其它命名类型一样出现在左右同样的地方,如在协议里的类型一样。不管怎么样,你不能构造协议的实例,因为协议实际上不能提供它们 - -You can use protocols to declare which methods a delegate of a class or structure should implement, as described in Delegation. -你可以使用协议来声明类或者结构应该实现那个方法,如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 Property Declaration - -##协议属性声明 - -Protocols declare that conforming types must implement a property by including a protocol property declaration in the body of the protocol declaration. Protocol property declarations have a special form of a variable declaration: - -协议声明一致性类型必须通过在协议声明体里包括一个协议属性声明来实现属性。协议属性声明有一个特殊形式的变量声明: - - var property name: type { get set } - -As with other protocol member declarations, these property declarations declare only the getter and setter requirements for types that conform to the protocol. As a result, you don’t implement the getter or setter directly in the protocol in which it is declared. - -与其它协议成员声明一样,这些属性声明只声明了与协议一致的类型的getter和setter要求。结果,你不能在它声明的协议里实现getter货setter - -The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can’t be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property. For examples of conforming types that implement the property requirements of a protocol, see Property Requirements. - -getter和setter要求可以通过一致性类型以各种方式满足。如果属性声明包含get和set关键词,一致性类型就可以用可读写(实现了getter和setter)的存储型变量属性或计算型属性,但是属性不能以常量属性或只读计算型属性实现。如果属性声明仅仅包含get关键词的话,它可以作为任意类型的属性被实现。比如说实现了协议的属性要求的一致性类型,参见属性要求。 - -See also Variable Declaration. - -更多参见变量声明 - -GRAMMAR OF A PROTOCOL PROPERTY DECLARATION - -protocol-property-declaration → variable-declaration-head­variable-name­type-annotation­getter-setter-keyword-block­ - - -##Protocol Method Declaration - -##协议方法声明 - -Protocols declare that conforming types must implement a method by including a protocol method declaration in the body of the protocol declaration. Protocol method declarations have the same form as function declarations, with two exceptions: They don’t include a function body, and you can’t provide any default parameter values as part of the function declaration. For examples of conforming types that implement the method requirements of a protocol, see Method Requirements. - -协议声明一致性类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 - - -To declare a class or static method requirement in a protocol declaration, mark the method declaration with the class keyword. Classes that implement this method also declare the method with the class keyword. Structures that implement it must declare the method with the static keyword instead. If you’re implementing the method in an extension, use the class keyword if you’re extending a class and the static keyword if you’re extending a structure. - -在协议声明里,为了声明一个类或者静态方法要求,使用class关键字来标记方法声明。实现这个方法的类也用class来声明方法。实现它的结构必须用static进行声明。如果你在extension里实现,如果你扩展class使用class,如果是结构使用static - - ->GRAMMAR OF A PROTOCOL METHOD DECLARATION - ->protocol-method-declaration → function-head­function-name­generic-parameter-clause­opt­function-signature­ - -##Protocol Initializer Declaration - -##协议构造器声明 - -Protocols declare that conforming types must implement an initializer by including a protocol initializer declaration in the body of the protocol declaration. Protocol initializer declarations have the same form as initializer declarations, except they don’t include the initializer’s body. - -协议声明了一致性类型必须在协议声明的主体里通过引入一个协议构造器声明来实现一个构造器。协议构造器声明除了不包含构造器体外,和构造器声明有着相同的形式. - -See also Initializer Declaration. - -更多请参阅构造器声明。 - ->GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION - ->protocol-initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­ - - -##Protocol Subscript Declaration - -Protocols declare that conforming types must implement a subscript by including a protocol subscript declaration in the body of the protocol declaration. Protocol property declarations have a special form of a subscript declaration: - -协议声明了一致性类型必须在协议声明的主体里通过引入一个协议附属脚本声明来实现一个附属脚本。协议属性声明对附属脚本声明有一个特殊附属脚本声明形式: - ->subscript (parameters) -> return type { get set } - - -Subscript declarations only declare the minimum getter and setter implementation requirements for types that conform to the protocol. If the subscript declaration includes both the get and set keywords, a conforming type must implement both a getter and a setter clause. If the subscript declaration includes only the get keyword, a conforming type must implement at least a getter clause and optionally can implement a setter clause. -See also Subscript Declaration. - -附属脚本声明只为和协议一致的类型声明了必需的最小数量的的getter和setter。如果附属脚本声明包含get和set关键字, 一致的类型也必须有一个getter和setter语句。如果附属脚本声明值包含get关键字,一致的类型必须至少包含一个 getter语句,可以选择是否包含setter语句。 - ->GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION - ->protocol-subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ - -##Protocol Associated Type Declaration - -##协议关联类型声明 - -Protocols declare associated types using the keyword typealias. An associated type provides an alias for a type that is used as part of a protocol’s declaration. Accosiated types are similiar to type paramters in generic parameter clauses, but they’re associated with Self in the protocol in which they’re declared. In that context, Self refers to the eventual type that conforms to the protocol. For more information and examples, see Associated Types. - -协议用关键字typealias声明关联类型。关联类型为类型提供了一个别名,这个被用作协议声明的一部分。关联类型与在通用参数子句的类型参数相似,但是他们与声明他们的协议中的self相似。在那个环境下,self指的是时间类型。 - -See also Type Alias Declaration. - -也可以参看 Type Alias Declaration. - ->GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION - ->protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­op - - -##Initializer Declaration - -##构造器声明 - -An initializer declaration introduces an initializer for a class, structure, or enumeration into your program. Initializer declarations are declared using the keyword init and have two basic forms. - -构造器声明引入了类的构造器器到程序中。初始化声明使用关键字init声明,有两种基本形式: - -Structure, enumeration, and class types can have any number of initializers, but the rules and associated behavior for class initializers are different. Unlike structures and enumerations, classes have two kinds of initializers: designated initializers and convenience initializers, as described in Initialization. - -结构,枚举和类类型可以有很多构造器,但是类构造器的规则和关联行为是不同的。不像结构和枚举类型。类有两种构造器:指定的和便利的构造器器。 - -The following form declares initializers for structures, enumerations, and designated initializers of classes: - -下面的形式声明了结构,枚举和类指定的构造器 - - init(parameters) { - statements - } - - -A designated initializer of a class initializes all of the class’s properties directly. It can’t call any other initializers of the same class, and if the class has a superclass, it must call one of the superclass’s designated initializers. If the class inherits any properties from its superclass, one of the superclass’s designated initializers must be called before any of these properties can be set or modified in the current class. - -类的指定构造器将类的所有属性直接初始化。如果类有超类,它不能调用该类的其它构造器,它只能调用超类的一个 指定构造器。如果该类从它的超类处继承了任何属性,这些属性在当前类内被赋值或修饰时,必须带调用一个超类的 指定构造器。 - -Designated initializers can be declared in the context of a class declaration only and therefore can’t be added to a class using an extension declaration. - -指定构造器可以在类声明的上下文中声明,因此它不能用扩展声明的方法被加入到一个类中。 - -Initializers in structures and enumerations can call other declared initializers to delegate part or all of the initialization process. - -结构体和枚举的构造器可以调用其它的已声明的构造器,来委托部分或全部初始化过程。 - -To declare convenience initializers for a class, prefix the initializer declaration with the context-sensitive keyword convenience. - -以关键字convenience来声明一个类的便利构造器: - - convenience init(parameters) { - statements - } - - -Convenience initializers can delegate the initialization process to another convenience initializer or to one of the class’s designated initializers. That said, the initialization processes must end with a call to a designated initializer that ultimately initializes the class’s properties. Convenience initializers can’t call a superclass’s initializers. - -便利构造器可以将初始化过程委托给另一个便利构造器或类的一个指定构造器。这意味着,类的初始化过程必须 以一个将所有类属性完全初始化的指定构造器的调用作为结束。便利构造器不能调用超类的构造器。 - -You can mark designated and convenience initializers with the required attribute to require that every subclass implement the initializer. Because designated initializers are not inherited by subclasses, they must be implemented directly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or overrides the designated initializers with convenience initializers). Unlike methods, properties, and subscripts, you don’t need to mark overridden initializers with the override keyword. - -你可以使用requierd关键字,将便利构造器和指定构造器标记为每个子类的构造器都必须拥有的。因为指定构造器 不被子类继承,他们必须被立即执行。当子类直接执行所有超类的指定构造器(或使用便利构造器重写指定构造器)时, 必需的便利构造器可以被隐式的执行,亦可以被继承。不像方法,附属脚本那样,你不需要为这些重写的构造器标注 overrride关键字。 - -To see examples of initializers in various type declarations, see Initialization. - -查看更多关于不同声明方法的构造器的例子,参阅构造过程一节。 - ->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­ - -A deinitializer declaration declares a deinitializer for a class type. Deinitializers take no parameters and have the following form: - -析构声明在类中声明了一个析构器。析构器不需要参数,遵循如下的格式: - - deinit { - statements - } - - -A deinitializer is called automatically when there are no longer any references to a class object, just before the class object is deallocated. A deinitializer can be declared only in the body of a class declaration—but not in an extension of a class—and each class can have at most one. - -当类中没有对任何其它对象的引用时,在类对象释放之前,析构器会自动的被调用。析构器只能在类的声明体内、而不能在 类的扩展内声明,每个类最多只能有一个析构器声明。 - -A subclass inherits its superclass’s deinitializer, which is implicitly called just before the subclass object is deallocated. The subclass object is not deallocated until all deinitializers in its inheritance chain have finished executing. - -子类继承了它的超类的析构器,在子类帝乡将要被释放时会被隐式的调用。子类在所有析构器被执行完毕前不会被释放。 - -Deinitializers are not called directly. - -析构器不会被直接调用。 - -For an example of how to use a deinitializer in a class declaration, see Deinitialization. -如何使用类声明中的析构器,请查看Deinitialization - ->GRAMMAR OF A DEINITIALIZER DECLARATION - ->deinitializer-declaration → attributes­opt­deinit­code-block - -##Extension Declaration -##扩展声明 - -An extension declaration allows you to extend the behavior of existing class, structure, and enumeration types. Extension declarations begin with the keyword extension and have the following form: - -扩展声明用于扩展一个已存在的类,结构体,枚举的行为。扩展声明以关键字extension开始,有如下的形式: - - - extension type: adopted protocols { - declarations - } - - - -The body of an extension declaration contains zero or more declarations. These declarations can include computed properties, computed static properties, instance methods, static and class methods, initializers, subscript declarations, and even class, structure, and enumeration declarations. Extension declarations can’t contain destructor or protocol declarations, store properties, property observers, or other extension declarations. For a discussion and several examples of extensions that include various kinds of declarations, see Extensions. - -扩展声明体包括零个或多个声明。这些声明可以包括计算型属性,计算型静态属性,实例方法,静态和类方法,构造器,附属脚本声明,甚至其它类,结构和枚举声明。扩展声明不能包含析构器,协议声明,存储型属性,属性监测器或其它的扩展属性。详细讨论和查看包含多种扩展声明的实例,参见Extensions一节。 - -Extension declarations can add protocol conformance to an existing class, structure, and enumeration type in the adopted protocols. Extension declarations can’t add class inheritance to an existing class, and therefore the type-inheritance-clause in an extension declaration contains only a list of protocols. - -扩展声明可以向存在的类,结构体,枚举添加一致的协议。扩展声明不能向一个类中添加类的继承,因此type-inheritance-clause只包含协议的列表。 - - -Properties, methods, and initializers of an existing type can’t be overridden in an extension of that type. -现存类型的属性,方法,构造器不能被它们的扩展重写。 - -Extension declarations can contain initializer declarations. That said, if the type you’re extending is defined in another module, an initializer declaration must delegate to an initializer already defined in that module to ensure members of that type are properly initialized. -扩展声明可以包含构造器声明,这意味着,如果你扩展的类型在其他模块中定义,构造器声明必须委托另一个在 那个模块里声明的构造器来恰当的初始化。 - ->GRAMMAR OF AN EXTENSION DECLARATION - ->extension-declaration → extension­type-identifier­type-inheritance-clause­opt­extension-body­ ->extension-body → {­declarations­opt­}­ - - -##Subscript Declaration - -##附属脚本声明 - -A subscript declaration allows you to add subscripting support for objects of a particular type and are typically used to provide a convenient syntax for accessing the elements in a collection, list, or sequence. Subscript declarations are declared using the keyword subscript and have the following form: - -附属脚本声明用于向特定类型的对象添加附属脚本支持,通常为访问集合,列表和序列的元素提供便利的语法。使用关键字subscript,声明形式如下: - - -> subscript (`parameter`) -> (return type){ - get{ - `statements` - } - set(`setter name`){ - `statements` - } -} - - -Subscript declarations can appear only in the context of a class, structure, enumeration, extension, or protocol declaration. - -附属脚本声明只能出现在类,结构,枚举类型,扩展或协议声明的上下文中。 - -The parameters specify one or more indexes used to access elements of the corresponding type in a subscript expression (for example, the i in the expression object[i]). Although the indexes used to access the elements can be of any type, each parameter must include a type annotation to specify the type of each index. The return type specifies the type of the element being accessed. - -参数(parameters)指定了一个或多个用于在相应类型的附属脚本表达式中访问元素的索引(例如,表达式object[i]中的i)。尽管用于访问元素的索引可以是任意类型,但是每个参数必须包含一个类型标注来指定每种索引的类型。返回类型(return type)指定被访问的元素的类型。 - - -As with computed properties, subscript declarations support reading and writing the value of the accessed elements. The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly. That said, if you provide a setter clause, you must also provide a getter clause. - -和计算型属性一样,附属脚本声明支持对访问元素的读写。getter用于读取,setter用于写入。setter子句是可选的,当仅需要一个getter子句时,可以将二者都忽略,直接返回请求的值即可。也就是说,如果提供了setter子句,getter子句也必须要有。 - -The setter name and enclosing parentheses are optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is value. That type of the setter name must be the same as the return type. - -setter的名字和封闭的括号是可选的。如果提供了setter名称,它会被setter的参数名。如果没有提供setter名称,那么传给setter的参数的名称默认是value。setter名称的类型必须与返回类型(return type)的类型相同。 - -You can overload a subscript declaration in the type in which it is declared, as long as the parameters or the return type differ from the one you’re overloading. You can also override a subscript declaration inherited from a superclass. When you do so, you must mark the overridden subscript declaration with the override keyword. - -在附属脚本声明的类型中,可以重载附属脚本,只要参数(parameters)或返回类型(return type) 与先前的不同即可。如果这样做的话,必须使用override关键字声明那个被覆盖的附属脚本。 - -You can also declare subscripts in the context of a protocol declaration, as described in Protocol Subscript Declaration. -在协议声明的上下文中,也声明附属脚本,正如Protocol Subscript Declaration描述的一样。 - -For more information about subscripting and to see examples of subscript declarations, see Subscripts。. - -获取更多关于附属脚本的信息和例子,请参看Subscripts。 - ->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­ - -##Operator Declaration - -##运算符声明 - -An operator declaration introduces a new infix, prefix, or postfix operator into your program and is declared using the contextual keyword operator. - -运算符声明引入了新的中缀,前缀或后缀运算到程序中,使用上下文关键字operator声明。 - -You can declare operators of three different fixities: infix, prefix, and postfix. The fixity of an operator specifies the relative position of an operator to its operands. - -可以声明3种不同的缀:中缀、前缀和后缀。一个运算符的缀规定了一个它相对于它的操作数的相对位置。 - -There are three basic forms of an operator declaration, one for each fixity. The fixity of the operator is specified by including the contextual keyword infix, prefix, or postfix between operator and the name of the operator. In each form, the name of the operator can contain only the operator characters defined in Operators. - -运算符声明有三种基本形式,每种缀性各一种。运算符的缀性通过在operator和运算符之间添加上下文关键字infix,prefix或postfix来指定。对于每种形式,运算符的名字只能包含Operators中定义的运算符字符。 - -The following form declares a new infix operator: - -下面这种形式声明了一个新的中缀运算符: - -> operator infix `operator name`{ - precedence `precedence level` - associativity `associativity` - } - - -An infix operator is a binary operator that is written between its two operands, such as the familiar addition operator (+) in the expression 1 + 2. - -中缀运算符是二元运算符,置于两个操作数之间,比如我们熟悉的表达式1 + 2 中的加法运算符(+)。 - -Infix operators can optionally specify a precedence, associativity, or both. - -中缀运算符可以指定优先级,结合性,或两者同时指定。 - -The precedence of an operator specifies how tightly an operator binds to its operands in the absence of grouping parentheses. You specify the precedence of an operator by writing the contextual keyword precedence followed by the precedence level. The precedence level can be any whole number (decimal integer) from 0 to 255; unlike decimal integer literals, it can’t contain any underscore characters. Although the precedence level is a specific number, it is significant only relative to another operator. That is, when two operators compete with each other for their operands, such as in the expression 2 + 3 * 5, the operator with the higher precedence level binds more tightly to its operands. - -运算符的优先级指定了在没有分组括号的情况下,运算符与它的操作数绑定的紧密程度。可以使用上下文关键字precedence和优先等级一起来指定一个运算符的优先级。优先级可以是0到255之间的任何一个数字(十进制整数);与十进制整数字面量不同的是,它不可以包含任何下划线字符。尽管优先级是一个特定的数字,但它仅用作与另一个运算符比较(大小)。也就是说,一个操作数可以同时被两个运算符使用时,例如2 + 3 * 5,优先级更高的运算符将优先与操作数绑定。 - -The associativity of an operator specifies how a sequence of operators with the same precedence level are grouped together in the absence of grouping parentheses. You specify the associativity of an operator by writing the contextual keyword associativity followed by the associativity, which is one of the contextual keywords left, right, or none. Operators that are left-associative group left-to-right. For example, the subtraction operator (-) is left-associative, and therefore the expression 4 - 5 - 6 is grouped as (4 - 5) - 6 and evaluates to -7. Operators that are right-associative group right-to-left, and operators that are specified with an associativity of none don’t associate at all. Nonassociative operators of the same precedence level can’t appear adjacent to each to other. For example, 1 < 2 < 3 is not a valid expression. - -运算符的结合性明确了,没有分组的括号包围的情况下,优先级相同的运算符以何种顺序被分组的。使用上下文关键字associativity和结合性(associativity)一起来指定一个运算符的结合性,其中结合性的值是上下文关键字left,right或none之一。左结合运算符以从左到右的形式分组。例如,减法运算符(-)具有左结合性,因此表达式4 - 5 - 6以(4 - 5) - 6的形式分组,其结果为-7。 右结合运算符以从右到左的形式分组,对于设置为none的非结合运算符,它们不以任何形式分组。具有相同优先级的非结合运算符,不可以互相邻接。例如,1 < 2 < 3 就是一个无效的表达式 - -Infix operators that are declared without specifying a precedence or associativity are initialized with a precedence level of 100 and an associativity of none. - -如果再声明时不指定任何优先级或结合性,中缀运算符的优先级会被初始化为100,结合性被初始化为none。 - -The following form declares a new prefix operator: - -下面的形式声明了一个新的前缀运算符: - -> operator prefix `operator name`{} - - -A prefix operator is a unary operator that is written immediately before its operand, such as the prefix increment operator (++) is in the expression ++i. - -前缀运算符一元运算符,紧跟在操作数之前,比如表达式 ++i 中的前缀递增运算符(++)。 - -Prefix operators declarations don’t specify a precedence level. Prefix operators are nonassociative. - -前缀缀运算符的声明中不指定优先级。前缀运算符是非结合的。 - -The following form declares a new postfix operator: - -下面的形式声明了一个新的后缀运算符: - - -> operator postfix `operator name`{} - - - -A postfix operator is a unary operator that is written immediately after its operand, such as the postfix increment operator (++) is in the expression i++. - -后缀运算符一元运算符,紧跟在操作数之前,比如表达式 i++ 中的前后缀递增运算符(++)。 - -As with prefix operators, postfix operator declarations don’t specify a precedence level. Postfix operators are nonassociative. - -与前缀运算符一样,后缀运算符声明不会指定优先级。后缀运算符也是非结合性的。 - -After declaring a new operator, you implement it by declaring a function that has the same name as the operator. To see an example of how to create and implement a new operator, see Custom Operators. - -在声明了一个新的运算符之后,要声明一个和运算符同名的函数来实现它。如何创建和实现新的操作符,请看Custom Operators。 - - - ->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 - diff --git a/src/chapter3/07_Attributes.md b/src/chapter3/07_Attributes.md deleted file mode 100644 index b285b60..0000000 --- a/src/chapter3/07_Attributes.md +++ /dev/null @@ -1,208 +0,0 @@ -# Attributes - -# 特性 - -*Attributes* provide more information about a declaration or type. There are two kinds of attributes in Swift, those that apply to declarations and those that apply to types. For instance, the `required` attribute—when applied to a designated or convenience initializer declaration of a class—indicates that every subclass must implement that initializer. And the `noreturn` attribute—when applied to a function or method type—indicates that the function or method doesn’t return to its caller. - -*特性* 为声明和类型提供了更多的信息。在Swift中有两种类型的特性,一种用于修饰声明,另一种用于修饰类型。比如,`required`特性——当被用来修饰一个类的预设构造函数声明或者便利构造函数声明时——表明其所有的子类都必须实现这个构造函数。`noreturn`特性——当修饰函数或者方法类型时——表明这个函数或者方法不会返回任何值给其调用者。 - -You specify an attribute by writing the `@` symbol followed by the attribute’s name and any arguments that the attribute accepts: - -``` - @attribute name - @attribute name(attribute arguments) -``` - -你可以通过`@`符号以及紧随其后的特性名称和该特性可以接受的参数来使用特性。 - -``` - @attribute name - @attribute name(attribute arguments) -``` - -Some declaration attributes accept arguments that specify more information about the attribute and how it applies to a particular declaration. These *attribute arguments* are enclosed in parentheses, and their format is defined by the attribute they belong to. - -有些声明特性可以通过给定参数来补充该特性相关的更多信息,并说明该特性将如何应用于这个声明中。这些`特性参数`写在小括号里面,他们的具体格式需要根据他们所属的特性来确定。 - -## Declaration Attributes - -## 声明特性 - -You can apply a declaration attribute to declarations only. However, you can also apply the `noreturn` attribute to a function or method *type*. - -声明特性只能描述声明。不过你还是可以使用`noreturn`特性来描述函数或者方法*类型*。 - -`assignment` -> Apply this attribute to functions that overload a compound assignment operator. Functions that overload a compound assignment operator must mark their initial input parameter as `inout`. For an example of how to use the assignment attribute, see [Compound Assignment Operators](#). - -`assignment` -> 这个特性用于描述重载了复合赋值运算符的函数。一个重载了复合赋值运算符的函数必须将它的初始化输入参数标记为`inout`.关于如何使用assigment特性请查看[符合赋值运算符](#)中的一个例子。 - -`class_protocol` -> Apply this attribute to a protocol to indicate that the protocol can be adopted by class types only. - -> If you apply the `objc` attribute to a protocol, the `class_protocol` attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the `class_protocol` attribute explicitly. - -`class_protocol` -> 这个特性用于描述协议,它表明被修饰的协议只能被类使用[//todo adopted]。 - -> 如果一个协议已经添加了`objc`特性,那么`class_protocol`特性就已经被隐形地添加在这个协议上了,不需要再显性地添加一次。 - -`exported` -> Apply this attribute to an import declaration to export the imported module, submodule, or declaration from the current module. If another module imports the current module, that other module can access the items exported by the current module. - -`exported` -> 这个特性被用于修饰导入声明。当一个导入声明具有该特性时,所有通过该声明导入的的模块,子模块或者声明都可以被导出。如果另一个模块导入了这个模块,那么那个模块可以访问所有被这个模块导出的项。 - -`final` -> Apply this attribute to a class or to a property, method, or subscript member of a class. It’s applied to a class to indicate that the class can’t be subclassed. It’s applied to a property, method, or subscript of a class to indicate that that class member can’t be overridden in any subclass. - -`final` -> 这个特性用于描述类或者类的属性、方法、或者下标上。如若一个类具有该特性,则表明这个类不能被继承。如果一个类的属性、方法或者下标具有该特性,则表明这个类的成员不能被任何子类覆盖。 - -`lazy` -> Apply this attribute to a stored variable property of a class or structure to indicate that the property’s initial value is calculated and stored at most once, when the property is first accessed. For an example of how to use the `lazy` attribute, see [Lazy Stored Properties](#). - -`lazy` -> 如果一个类或者结构体的存储变量属性具有该特性,则这个属性的初始值最多只被计算和存储一次,且这一次的计算和存储发生在第一次被访问时。查看[懒惰存储属性](#)中给出的关于如何使用`lazy`的例子。 - -`noreturn` -> Apply this attribute to a function or method declaration to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. You can mark a function or method type with this attribute to indicate that the function or method doesn’t return to its caller. - -> You can override a function or method that is not marked with the `noreturn` attribute with a function or method that is. That said, you can’t override a function or method that is marked with the `noreturn` attribute with a function or method that is not. Similar rules apply when you implement a protocol method in a conforming type. - -`noreturn` -> 可以通过将这个特性应用在函数或者方法声明中来指定这个函数或者方法,`T`,是`@noreturn T`类型。你可以通过使用这个特性来标记函数或者方法,借此来表明这个函数或者方法不返回任何值给它的调用者。 - -> 你可以使用一个标记了这个特性的函数或者方法来覆盖一个没有标记过这个特性的函数或者方法,但是反过来不行。同样的,当你要实现一个协议方法时,也需要遵循这个规则。 - -`NSCopying` -> Apply this attribute to a stored variable property of a class. This attribute causes the property’s setter to be synthesized with a *copy* of the property’s value—returned by the `copyWithZone` method—instead of the value of the property itself. The type of the property must conform to the `NSCopying` protocol. - -> The `NSCopying` attribute behaves in a way similar to the Objective-C `copy` property attribute. - -`NSCopying` -> 这个特性用于修饰一个类的储存变量属性。该特性将使得这个类的属性的setter方法与这个属性的返回值的*副本*合成——通过`copyWithZone`方法进行返回——而不是这个属性值本身。这个属性值的类型必须遵循`NSCopying`协议。 - -> `NSCopying`特性与Objective-C中的`copy`属性特性类似。 - -`NSManaged` -> Apply this attribute to a stored variable property of a class that inherits from `NSManagedObject` to indicate that the storage and implementation of the property are provided dynamically by Core Data at runtime based on the associated entity description. - -`NSManaged` -> 这个特性用于修饰继承了`NSManagedObject`的类的成员,通过该特性来表明这个成员的存储和实现由Core Data在运行时根据相关实体描述来动态地提供。 - -`objc` -> Apply this attribute to any declaration that can be represented in Objective-C—for example, non-nested classes, protocols, properties and methods (including getters and setters) of classes and protocols, initializers, deinitializers, and subscripts. The `objc` attribute tells the compiler that a declaration is available to use in Objective-C code. - -> If you apply the `objc` attribute to a class or protocol, it’s implicitly applied to the members of that class or protocol. The compiler also implicitly adds the `objc` attribute to a class that inherits from another class marked with the `objc` attribute. Protocols marked with the `objc` attribute can’t inherit from protocols that aren’t. - -> The `objc` attribute optionally accepts a single attribute argument, which consists of an identifier. Use this attribute when you want to expose a different name to Objective-C for the entity the `objc` attribute applies to. You can use this argument to name classes, protocols, methods, getters, setters, and initializers. The example below exposes the getter for the enabled property of the `ExampleClass` to Objective-C code as `isEnabled` rather than just as the name of the property itself. - -``` - @objc - class ExampleClass { - var enabled: Bool { - @objc(isEnabled) get { - // Return the appropriate value - } - } - } -``` - -`objc` -> 这个特性用于描述任何可以在Objective-C中表示的声明,如非嵌套类,协议,类和协议的属性和方法(包括getter和setter),构造函数,析构函数和下标。`objc`特性告诉编译器该声明可以在Objective-C的代码中被使用。 - -> 如果一个类或者协议具有`objc`特性,那么这个类或者协议的所有成员都将隐形地具有`objc`特性。编译器甚至会隐形地添加`objc`特性给具有`objc`特性的类的子类。被标记`objc`特性的协议不能继承没有被标记`objc`特性的协议。 - -> `objc`特性可选地接收一个标识符作为参数。你就可以使用这个特性参数让被标记的对象对Objective-C暴露一个不一样的名字。你可以使用这个参数来重新命名类,协议,方法,getter,setter和构造函数。下面的例子通过给定特性参数使得类`ExampleClass`的enabled这个属性以`isEnabled`这个名字暴露给Objective-C. - -``` - @objc - class ExampleClass { - var enabled: Bool { - @objc(isEnabled) get { - // 返回合适的值 - } - } - } -``` - -`optional` -> Apply this attribute to a protocol’s property, method, or subscript members to indicate that a conforming type isn’t required to implement those members. - -> You can apply the `optional` attribute only to protocols that are marked with the `objc` attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. For more information about how to use the `optional` attribute and for guidance about how to access optional protocol members—for example, when you’re not sure whether a conforming type implements them—see [Optional Protocol Requirements](#). - -`optional` - -> 这个特性用于描述协议的属性,方法和下标,以此来表明遵循了该协议的类型,只需要可选地实现这些被标记的成员。 - -> 这个特性只能被用于描述具有`objc`特性的协议。也就是说,只有类才能接受和遵循一个具有optional特性成员的协议。更多关于如何使用`optional`特性,以及对于一个遵循了具有`optional`特性的协议的类型,在无法明确它实现了哪些可选成员的情况下,如何正确地读取其可选成员的问题,请参考[可选协议要求](#)。 - -`required` -> Apply this attribute to a designated or convenience initializer of a class to indicate that every subclass must implement that initializer. - -> Required designated initializers must be implemented explicitly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or when the subclass overrides the designated initializers with convenience initializers). - -`required` -> 通过为一个类的预设构造函数或者便利构造函数添加该特性来表明这个类的每一个子类都必须实现这个构造函数。 - -> 具有该特性的预设构造函数必须被显性地实现。具有该特性的便利构造函数可以被显性地实现,或者当子类直接实现了所有父类的预设构造函数时(或者子类使用便利构造函数重写了预设构造函数),可以直接继承这个便利构造函数。 - -### Declaration Attributes Used by Interface Builder - -## 在Interface Builder中使用声明特性 - -Interface Builder attributes are declaration attributes used by Interface Builder to synchronize with Xcode. Swift provides the following Interface Builder attributes: `IBAction`, `IBDesignable`, `IBInspectable`, and `IBOutlet`. These attributes are conceptually the same as their Objective-C counterparts. - -Interface Builder特性是Interface Builder用来和Xcode同步的声明特性。Swift提供了以下几种Interface Builder特性: `IBAction`,`IBDesignable`,`IBInspectable`和`IBOutlet`。这些特性在概念上和Objective-C中对应的特性是一样的。 - -You apply the `IBOutlet` and `IBInspectable` attributes to property declarations of a class. You apply the `IBAction` attribute to method declarations of a class and the `IBDesignable` attribute to class declarations. - -`IBOutlet`和`IBInspectable`特性用于描述类的属性声明,`IBAction`特性用于描述类的方法声明而`IBDesignable`用于描述类的声明。 - -## Type Attributes - -## 类型特性 - -You can apply type attributes to types only. However, you can also apply the `noreturn` attribute to a function or method *declaration*. - -类型特性只能描述类型。尽管如此,你还是可以使用`noreturn`特性去修饰函数和方法的声明。 - -`auto_closure` -> This attribute is used to delay the evaluation of an expression by automatically wrapping that expression in a closure with no arguments. Apply this attribute to a function or method type that takes no arguments and that returns the type of the expression. For an example of how to use the `auto_closure` attribute, see [Function Type](#). - -`auto_closure` -> 这个特性通过自动地将表达式包裹在一个没有参数的闭包中来延迟表达式的求值。将该特性用于描述不带任何参数的函数和方法,而这些函数和方法返回表达式的类型。关于如何使用`auto_closure`特性,参考[函数类型](#)中的例子。 - -`noreturn` -> Apply this attribute to the type of a function or method to indicate that the function or method doesn’t return to its caller. You can also mark a function or method declaration with this attribute to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. - -`noreturn` -> 使用这个特性来描述函数或者方法,以此表明该函数或者方法不返回任何值给它的调用者。你也可以使用这个特性来标记函数或者方法声明,借此来表明这个函数或者方法,`T`,是`@noreturn T`类型。 - -## GRAMMAR OF AN ATTRIBUTE - -## 特性语法总结 - -> attribute → @attribute-nameattribute-argument-clauseopt - -> attribute-name → identifier - -> attribute-argument-clause → (balanced-tokensopt) - -> attributes → attributeattributesopt - -> balanced-tokens → balanced-tokenbalanced-tokensopt - -> balanced-token → (balanced-tokensopt) - -> balanced-token → [balanced-tokensopt] - -> balanced-token → {balanced-tokensopt} - -> balanced-token → Any identifier, keyword, literal, or operator - -> balanced-token → Any punctuation except (, ), [, ], {, or } - - From 33417122bc0f19306d876230ac3487a0a8ef9034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=9C=E8=88=9F?= Date: Sat, 12 Jul 2014 10:20:59 +0800 Subject: [PATCH 256/261] Revert "Revert "23_Advanced_Operators reviewed"" This reverts commit 60aeb233d2dd1382fda0f051e0dcb260394fe064. --- src/chapter2/23_Advanced_Operators.md | 44 +++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/src/chapter2/23_Advanced_Operators.md b/src/chapter2/23_Advanced_Operators.md index a5cf5f9..e57aaf6 100644 --- a/src/chapter2/23_Advanced_Operators.md +++ b/src/chapter2/23_Advanced_Operators.md @@ -2,12 +2,27 @@ 除了《基础操作符》里讲到的操作符,Swift还提供了一些高级操作符,用以完成更复杂的数值运算。比如位运算和移位操作符,其语法同C和Objective-C类似。 +> From 周源: +移位: 我读的时候, 感觉位移更顺口一点 + 和C语言的算术操作符不同,Swift默认不支持溢出运算。数值溢出会被捕获并报错。但是,Swift提供了另一套支持溢出运算的操作符,比如可溢出加操作符(&+),可溢出操作符都以&作为前缀。 +> From 周源: +&+ -> (&+) +So +& -> (&)? + 在自定义结构体、类或者枚举类型中,可以重载Swift操作符。通过操作符重载,可以简单地实现操作符的重定义。 +> From 周源: +我理解的 "简单的实现" 有二义性, 可表示 实现简单 和 简单实现, +这里作者的意思应该是实现简单, 我觉得 方便的实现 也可以表达作者的意思, 你怎么看? + Swift允许用户自定义操作符,并且可定制这些操作符的优先级和结合性。 +> From 周源: +这一段原文较长, 省略了部分翻译, 按照会长的意思...... + ## 位操作符 @@ -87,6 +102,8 @@ let outputBits = firstBits ^ otherBits // 等于 00010001 #### 无符号移位操作 +> From 周源: +移位 -> 位移? 无符号移位的规则如下: 1. 已有的位向左或向右移动指定的位数。 @@ -149,12 +166,19 @@ let blueComponent = pink & 0x0000FF // blueComponent是0x99, 即153 负数的编码方式称为二进制补码表示。这种表示方式看起来很奇怪,但它有几个优点。 +> From 周源: +The encoding for negative numbers is known as a two’s complement representation. +负数的编码方式称为二进制补码表示 -> 负数的编码方式用二进制补码表示? + 首先,对全部8个比特位(包括符号位)做标准的二进制加法就可以完成-1 加 -4 的操作,加法过程中丢弃超出的比特位。 ![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSignedAddition_2x.png) 第二,使用二进制补码表示方式,我们可以和正数一样对负数进行按位左移或右移,同样也是左移1位时乘于2,右移1位时除于2。但是,对有符号整型的右移有一个特别的要求: +> From 周源: +使用二进制补码表示方式 -> 使用二进制补码? + + 有符号和无符号整型按位右移时规则相同,但有符号整型移位后出现的空位使用符号位来填充,而不是0。 ![有符号移位操作](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/bitshiftSigned_2x.png) @@ -294,7 +318,7 @@ let y = x &/ 0 Swift操作符的优先级和结合性的完整规则,请看表达式。 -> 注意: +> 注意: > > Swift操作符的优先级和结合性的规则跟C系语言不太一样,相对于C语言和Objective-C更加简单且保守。所以在移植已有代码到Swift时,注意确认操作数的计算顺序。 @@ -370,6 +394,9 @@ let alsoPositive = -negative 加法运算之前定义过了,这里无需重新定义。加赋操作符函数使用已有的加法运算将左值加上右值: +> From 周源 +> 加赋操作符函数使用已有的加法运算将左值加上右值: -> 加法操作符... ? + ``` var original = Vector2D(x: 1.0, y: 2.0) let vectorToAdd = Vector2D(x: 3.0, y: 4.0) @@ -388,6 +415,9 @@ original += vectorToAdd 这个自加操作符函数使用了前面定义过的加赋运算,将自己加上一个值为 (1.0,1.0) 的对象然后将返回值赋给自己。 +> From 周源 +> 加赋运算 -> 加法运算... ? + ``` var toIncrement = Vector2D(x: 3.0, y: 4.0) let afterIncrement = ++toIncrement @@ -395,7 +425,7 @@ let afterIncrement = ++toIncrement // afterIncrement 也等于 (4.0, 5.0) ``` -> 注意: +> 注意: > > 默认的赋值符(=)是不可重载的。只有复合赋值符可以重载。条件操作符 a?b:c 也是不可重载的。 @@ -431,6 +461,9 @@ println("这两个向量相等") 除了标准的操作符,你还可以声明一些个性的操作符,但自定义操作符只能使用这些字符`/ = - + * % < >!& | ^ . ~` +> From 周源: +> 个性的操作符 -> 自定义的操作符 ? + 新的操作符需要在全局域使用`operator`关键字声明,可以声明为前置,中置或后置的。 ``` @@ -439,6 +472,10 @@ operator prefix +++ {} 这段代码定义了一个新的前置操作符+++,此前Swift并不存在这个操作符,此处针对`Vector2D` 对象的这个操作符具有个性化的含义。+++被定义为双自增操作符,它使用之前定义的加赋运算将自已加上自己然后返回。 +> From 周源: +> 个性化的含义 ? + + ``` @prefix @assignment func +++ (inout vector: Vector2D) -> Vector2D { vector += vector @@ -476,6 +513,9 @@ let plusMinusVector = firstVector +- secondVector // plusMinusVector 是 Vector2D实例,等于 (4.0, -2.0) ``` +> From 周源: +> plusMinusVector 是 Vector2D实例 -> plusMinusVector 是 Vector2D的实例 ? + 这个操作符把两个向量的x相加, y相减。因为它实际上属于加减运算,所以让它保持了和加减法一样的结合性和优先级(左结合,优先级为140)。查阅完整的Swift默认优先级和结合性的设置,请移步[表达式](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/doc/uid/TP40014097-CH32-XID_655). From a396e6d2f8339fdc03ceed8c3ee4425d31086b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=98=E5=A2=83?= Date: Sun, 13 Jul 2014 11:51:18 +0800 Subject: [PATCH 257/261] =?UTF-8?q?=E5=90=88=E5=B9=B6review=E5=90=8E?= =?UTF-8?q?=E7=9A=84=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 合并review后的修改 --- src/chapter2/04_Collection_Types.md | 129 +++++++++++++++------------- 1 file changed, 70 insertions(+), 59 deletions(-) diff --git a/src/chapter2/04_Collection_Types.md b/src/chapter2/04_Collection_Types.md index c416241..89a9e92 100644 --- a/src/chapter2/04_Collection_Types.md +++ b/src/chapter2/04_Collection_Types.md @@ -3,11 +3,11 @@ Swift provides two *collection types*, known as arrays and dictionaries, for storing collections of values. Arrays store ordered lists of values of the same type. Dictionaries store unordered collections of values of the same type, which can be referenced and looked up through a unique identifier (also known as a *key*). -Swift提供了两种*集合类型* 来存储数据集合,分别是数组(arrays)和字典(dictionaries)。数组用来存储有序的相同类型数据的列表。字典用来存储无序的相同类型数据的集合,这些数据可以通过唯一的标识符(称为*键*)引用和查找。 +Swift 提供了两种*集合类型* 来存储数据集合,分别是数组(arrays)和字典(dictionaries)。数组用来存储有序的相同类型数据的列表。字典用来存储无序的相同类型数据的集合,这些数据可以通过唯一的标识符(称为*键*)引用和查找。 Arrays and dictionaries in Swift are always clear about the types of values and keys that they can store. This means that you cannot insert a value of the wrong type into an array or dictionary by mistake. It also means you can be confident about the types of values you will retrieve from an array or dictionary. Swift’s use of explicitly typed collections ensures that your code is always clear about the types of values it can work with and enables you to catch any type mismatches early in your code’s development. -在Swift中,数组和字典可以存储的键值类型一直是很明确的【todo:总是明确的】。这意味着我们不能错误地把类型不正确的数据插入到一个数组或字典中【todo:这意味着不会把错误类型的值意外地插入到数组或字典中】。这也意味着我们可以清楚的知道从数组或字典中获取的数据类型。Swift的显式类型的集合使得我们清楚代码中可以处理哪种类型的数据,并使得我们可以更早的在代码开发过程中发现任何类型错误【todo:Swift 使用显示类型集合,这确保了代码中可以处理的数据类型是明确的,并让我们可以提前发现开发中得任何类型错误】。 +在Swift中,数组和字典可以存储的键值类型总是明确的。这意味着不会把错误类型的值意外地插入到数组或字典中。这也意味着我们可以清楚的知道从数组或字典中获取的数据类型。Swift 使用显示类型集合,这确保了代码中可以处理的数据类型是明确的,并让我们可以提前发现开发中的任何类型错误。 >NOTE @@ -26,13 +26,13 @@ An *array* stores multiple values of the same type in an ordered list. The same Swift arrays are specific about the kinds of values they can store. They differ from Objective-C’s `NSArray` and `NSMutableArray` classes, which can store any kind of object and do not provide any information about the nature of the objects they return. In Swift, the type of values that a particular array can store is always made clear, either through an explicit type annotation, or through type inference, and does not have to be a class type. If you create an array of `Int` values, for example, you can’t insert any value other than `Int` values into that array. Swift arrays are type safe, and are always clear about what they may contain. -Swift数组可以存储的数据类型是确定的。这与Objective-C的类`NSArray`和`NSMutableArray`不同,这两个类可以存储任何类型的对象,并且不会提供它们返回的对象的任何信息。在Swift中,某个数组可以存储的数据类型是确定的,不是通过显式的类型声明,就是通过类型推断,不需要为class类型【todo:可以使用显式的类型声明,也可以使用类型推断,且不必一定是class类型】。假如你创建了一个`Int`型的数组,那么就不能插入其他任何非`Int`型的值到这个数组中【todo:那么就不能在这个数组中插入其他任何非`Int`型的值】。Swift数组是类型安全的,并且它们可以包含的类型是明确的。 +Swift 数组可以存储的数据类型是确定的。这与 Objective-C 的类 `NSArray` 和 `NSMutableArray` 不同,这两个类可以存储任何类型的对象,并且不会提供它们返回的对象的任何信息。在 Swift 中,某个数组可以存储的数据类型是确定的,可以使用显式的类型声明,也可以使用类型推断,且不必一定是 class 类型。假如你创建了一个 `Int` 型的数组,那么就不能在这个数组中插入其他任何非 `Int` 型的值。Swift 数组是类型安全的,并且它们可以包含的类型是明确的。 ‌ ### Array Type Shorthand Syntax ### 数组类型简写语法 The type of a Swift array is written in full as `Array`, where `SomeType` is the type that the array is allowed to store. You can also write the type of an array in shorthand form as `SomeType[]`. Although the two forms are functionally identical, the shorthand form is preferred, and is used throughout this guide when referring to the type of an array. -Swift数组类型的完整写法是`Array`, 这里的`SomeType`指的是数组可以存储的类型。我们也可以把它简写为`SomeType[]`。这两种形式的数组在功能上完全相同,不过建议使用缩写的形式,本书中提到数组类型时都会以这种形式表示【todo:尽管这两种形式在功能上完全相同,但更推荐简写形式,且本书中提到数组类型时都会使用这种形式】。 +Swift 数组类型的完整写法是 `Array`, 这里的 `SomeType` 指的是数组可以存储的类型。我们也可以把它简写为 `SomeType[]`。尽管这两种形式在功能上完全相同,但更推荐简写形式,且本书中提到数组类型时都会使用这种形式。 ‌ ### Array Literals ### 数组字面量 @@ -47,7 +47,7 @@ You can initialize an array with an *array literal*, which is a shorthand way to The example below creates an array called `shoppingList` to store `String` values: -下面这个例子创建了一个名为`shoppingList`的数组来存储`String`类型的数据。 +下面这个例子创建了一个名为 `shoppingList` 的数组来存储 `String` 类型的数据。 ``` var shoppingList: String[] = ["Eggs", "Milk"] @@ -57,7 +57,7 @@ var shoppingList: String[] = ["Eggs", "Milk"] The `shoppingList` variable is declared as “an array of `String` values”, written as `String[]`. Because this particular array has specified a value type of `String`, it is *only* allowed to store `String` values. Here, the `shoppingList` array is initialized with two `String` values (`"Eggs" `and `"Milk"`), written within an array literal. -变量shoppingList声明为“`String`类型的数组”,写为`String[]`。由于这个特定数组指定了`String`的数据类型,因此它*只能*存储`String`类型的数据。这里的`shoppingList`数组被写在一个数组字面量中的两个`String`值(`“Egg”`和`"Milk"`)初始化【todo:这里的`shoppingList`数组由两个`String`值(`"Eggs" `和 `"Milk"`)以数组字面量来初始化】。 +变量shoppingList声明为“`String` 类型的数组”,写为 `String[]`。由于这个特定数组指定了 `String` 的数据类型,因此它*只能*存储 `String` 类型的数据。这里的 `shoppingList` 数组由两个`String` 值(`"Eggs" `和 `"Milk"`)以数组字面量来初始化。 >NOTE @@ -65,15 +65,15 @@ The `shoppingList` variable is declared as “an array of `String` values”, wr >注意 ->数组`shoppingList`声明为变量(通过关键字`var`)而不是常量(通过关键字`let`),因为在下面的例子中,会有更多的数组项添加到这个购物列表中。 +>数组 `shoppingList` 声明为变量(通过关键字 `var` )而不是常量(通过关键字 `let`),因为在下面的例子中,会有更多的数组项添加到这个购物列表中。 In this case, the array literal contains two `String `values and nothing else. This matches the type of the `shoppingList` variable’s declaration (an array that can only contain `String` values), and so the assignment of the array literal is permitted as a way to initialize `shoppingList` with two initial items. -在这个例子中,该数组字面量只包含了两个`String`值。这和shoppingList变量的声明(只能包含`String`值的数组)是一致的,因此数组字面量的赋值被用来作为一种用两个初始项来初始化shopplingList的方式【todo:因此数组字面量的赋值作为一种方式,可以使用两个初始项初始化`shoppingList`】。 +在这个例子中,该数组字面量只包含了两个 `String` 值。这和 `shoppingList` 变量的声明(只能包含 `String` 值的数组)是一致的,因此数组字面量的赋值作为一种方式,可以使用两个初始项初始化`shoppingList`。 Thanks to Swift’s type inference, you don’t have to write the type of the array if you’re initializing it with an array literal containing values of the same type. The initialization of `shoppingList` could have been written in a shorter form instead: -感谢Swift的类型推断,通过包含相同类型数据的数组字面量,我们不需要去写正在初始化的数组的类型【todo:多亏了Swift的类型推断,如果使用包含相同类型数据的数组字面量,我们不需要写出数组的类型】。`shopplingList`的初始化可以简写为: +多亏了 Swift 的类型推断,如果使用包含相同类型数据的数组字面量,我们不需要写出数组的类型。`shopplingList`的初始化可以简写为: ``` var shoppingList = ["Eggs", "Milk"] @@ -81,7 +81,7 @@ var shoppingList = ["Eggs", "Milk"] Because all values in the array literal are of the same type, Swift can infer that `String[]` is the correct type to use for the `shoppingList` variable. -因为数组字面量中所有的值的类型是相同的,Swift可以推断出`String[]`是`shoppingList`变量使用的正确类型。 +因为数组字面量中所有的值的类型是相同的,Swift 可以推断出 `String[]` 是 `shoppingList` 变量使用的正确类型。 ‌ ### Accessing and Modifying an Array ### 访问和修改数组 @@ -91,7 +91,7 @@ You access and modify an array through its methods and properties, or by using s To find out the number of items in an array, check its read-only `count` property: -可以通过数组的只读属性`count`来获得数组包含的数组项个数。 +可以通过数组的只读属性 `count` 来获得数组包含的数组项个数。 ``` println("The shopping list contains \(shoppingList.count) items.") @@ -101,7 +101,7 @@ println("The shopping list contains \(shoppingList.count) items.") Use the Boolean `isEmpty` property as a shortcut for checking whether the `count` property is equal to `0`: -用布尔值`isEmpty`属性来作为检查`count`属性是否等于`0`的快捷方式。 +用布尔值 `isEmpty` 属性来作为检查 `count` 属性是否等于 `0` 的快捷方式。 ``` if shoppingList.isEmpty { @@ -115,7 +115,7 @@ if shoppingList.isEmpty { You can add a new item to the end of an array by calling the array’s `append` method: -我们可以通过调用数组的`append`方法来插入一个新的数组项到数组的末尾【todo:可以通过调用数组的`append`方法,在数组的末尾插入一个新的数据项】。 +可以通过调用数组的 `append` 方法,在数组的末尾插入一个新的数据项。 ``` shoppingList.append("Flour") @@ -125,7 +125,7 @@ shoppingList.append("Flour") Alternatively, add a new item to the end of an array with the addition assignment operator (`+=`): -或者,可以通过加法赋值运算符(`+=`)来添加新的数组项到数组的末尾【todo:在数组的末尾添加新的数据项】。 +或者,可以通过加法赋值运算符(`+=`)在数组的末尾添加新的数据项。 ``` shoppingList += "Baking Powder" @@ -145,7 +145,7 @@ shoppingList += ["Chocolate Spread", "Cheese", "Butter"] Retrieve a value from the array by using *subscript syntax*, passing the index of the value you want to retrieve within square brackets immediately after the name of the array: -通过*下标语法*从数组中获取某个值,即在数组名之后紧跟由方括号括起来的想要获取的值的索引【todo:即在数组名后紧跟的方括号中传入想要获取的值的索引】: +通过*下标语法*从数组中获取某个值,即在数组名后紧跟的方括号中传入想要获取的值的索引: ``` var firstItem = shoppingList[0] @@ -159,7 +159,7 @@ Note that the first item in the array has an index of `0`, not `1`. Arrays in Sw You can use subscript syntax to change an existing value at a given index: -通过指定的索引,我们可以使用下标语法来修改一个已经存在的值:【todo:使用下标语法可以在给定的索引处改变已存在的值】 +使用下标语法可以在给定的索引处改变已存在的值。 ``` shoppingList[0] = "Six eggs" @@ -169,7 +169,7 @@ shoppingList[0] = "Six eggs" You can also use subscript syntax to change a range of values at once, even if the replacement set of values has a different length than the range you are replacing. The following example replaces `"Chocolate Spread"`, `"Cheese"`, and `"Butter"` with `"Bananas"` and `"Apples"`: -我们还可以通过下标语法一次改变一个范围内的值,即使要替换的值的长度和被替换的值的长度不一致【todo:即使替换的值的集合与被替换的范围的长度不一致】。下面的例子用`"Bananas"` and `"Apples"`替换了`"Chocolate Spread"`, `"Cheese"`, and `"Butter"`: +我们还可以通过下标语法一次改变一个范围内的值,即使替换的值的集合与被替换的范围的长度不一致。下面的例子用 `"Bananas"` and `"Apples"`替换了 `"Chocolate Spread"`, `"Cheese"`, and `"Butter"`: ``` shoppingList[4...6] = ["Bananas", "Apples"] @@ -183,12 +183,12 @@ shoppingList[4...6] = ["Bananas", "Apples"] >注意 ->我们不能使用下标语法插入一个新的数组项到数组的末尾【todo:不能使用下标语法在数组的末尾添加新的数据项】。如果我们试图用一个超过数组边界的下标访问或设置某个数值时,会导致运行时错误。不过,我们可以通过比较索引和数组的`count`属性来判断该索引是否有效。除了count为`0`时(意味着这个数组是空的),数组中最大的有效索引为`count-1`,因为数组的索引是从0开始的。 +>不能使用下标语法在数组的末尾添加新的数据项。如果我们试图用一个超过数组边界的下标访问或设置某个数值时,会导致运行时错误。不过,我们可以通过比较索引和数组的 `count` 属性来判断该索引是否有效。除了 count 为`0`时(意味着这个数组是空的),数组中最大的有效索引为 `count-1`,因为数组的索引是从0开始的。 To insert an item into the array at a specified index, call the array’s `insert(atIndex:)` method: -要在数组的指定索引处插入一个数组项,可以调用数组的`insert(atIndex:)`方法: +要在数组的指定索引处插入一个数组项,可以调用数组的 `insert(atIndex:)` 方法: ``` shoppingList.insert("Maple Syrup", atIndex: 0) @@ -200,11 +200,11 @@ shoppingList.insert("Maple Syrup", atIndex: 0) This call to the `insert` method inserts a new item with a value of `"Maple Syrup"` at the very beginning of the shopping list, indicated by an index of `0`. -上面的例子中,调用了`insert`方法插入了一个值为`“Maple Syrup”`的新数组项到数组的开头,用索引`0`来表示【todo:这个例子调用`insert`方法指定索引为 `0`,在shoppingList的最前面插入了值为`“Maple Syrup”`的新数据项】。 +这个例子调用 `insert` 方法指定索引为 `0`,在 shoppingList 的最前面插入了值为 `“Maple Syrup”` 的新数据项。 Similarly, you remove an item from the array with the `removeAtIndex` method. This method removes the item at the specified index and returns the removed item (although you can ignore the returned value if you do not need it): -类似地,`removeAtIndex`方法可以从数组中移除一个数组项。该方法移除指定索引处的数组项,并返回被移除的数组项(如果不需要,我们可以忽略返回值): +类似地,`removeAtIndex` 方法可以从数组中移除一个数组项。该方法移除指定索引处的数组项,并返回被移除的数组项(如果不需要,我们可以忽略返回值): ``` let mapleSyrup = shoppingList.removeAtIndex(0) @@ -229,7 +229,7 @@ firstItem = shoppingList[0] ``` If you want to remove the final item from an array, use the `removeLast` method rather than the `removeAtIndex `method to avoid the need to query the array’s `count` property. Like the `removeAtIndex` method, `removeLast` returns the removed item: -如果我们想要从数组中移除最后一个数组项,最好使用`removeLast`方法,而不是`removeAtIndex`方法,这样可以避免查询数组的`count`属性。像`removeAtIndex`方法那样,`removeLast`方法也会返回被移除的数组项: +如果我们想要从数组中移除最后一个数组项,最好使用 `removeLast` 方法,而不是 `removeAtIndex` 方法,这样可以避免查询数组的 `count` 属性。像 `removeAtIndex` 方法那样,`removeLast` 方法也会返回被移除的数组项: ``` let apples = shoppingList.removeLast() @@ -246,7 +246,7 @@ let apples = shoppingList.removeLast() ### 遍历数组 You can iterate over the entire set of values in an array with the `for-in` loop: -我们可以使用`for-in`循环来遍历数组中的所有数组项: +我们可以使用 `for-in` 循环来遍历数组中的所有数组项: ``` for item in shoppingList { @@ -260,7 +260,7 @@ for item in shoppingList { ``` If you need the integer index of each item as well as its value, use the global `enumerate` function to iterate over the array instead. The `enumerate` function returns a tuple for each item in the array composed of the index and the value for that item. You can decompose the tuple into temporary constants or variables as part of the iteration: -如果我们除了需要每个数组项的值之外,还需要每个数组项的索引【todo:如果需要每一项的整型索引及对应的值】,那么可以使用全局函数`enumerate`来遍历数组。函数`enumerate`返回由每个数组项的索引和对应的值组成的元组。我们可以把元组分解为临时的常量或者变量来进行遍历。 +如果需要每一项的整型索引及对应的值,那么可以使用全局函数 `enumerate` 来遍历数组。函数 `enumerate` 返回由每个数组项的索引和对应的值组成的元组。我们可以把元组分解为临时的常量或者变量来进行遍历。 ``` for (index, value) in enumerate(shoppingList) { @@ -274,7 +274,7 @@ for (index, value) in enumerate(shoppingList) { ``` For more about the `for-in` loop, see [For Loops](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF). -获取更多关于`for-in`循环的介绍,请参见[For循环](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF)。 +获取更多关于 `for-in` 循环的介绍,请参见 [For循环](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF)。 ### Creating and Initializing an Array @@ -287,10 +287,12 @@ You can create an empty array of a certain type (without setting any initial val var someInts = Int[]() println("someInts is of type Int[] with \(someInts.count) items.") // prints "someInts is of type Int[] with 0 items." + +// 打印出 "someInts is of type Int[] with 0 items." ``` Note that the type of the `someInts` variable is inferred to be `Int[]`, because it is set to the output of an `Int[]` initializer. -注意,变量`someInts`的类型被认为是`Int[]`,因为它的设置自于`Int[]`初始化的输出【todo:因为它设置为`Int[]`初始化器的输出结果】。 +注意,变量 `someInts` 的类型被认为是 `Int[]`,因为它设置为`Int[]`初始化器的输出结果。 Alternatively, if the context already provides type information, such as a function argument or an already-typed variable or constant, you can create an empty array with an empty array literal, which is written as `[]` (an empty pair of square brackets): @@ -309,7 +311,7 @@ someInts = [] ``` Swift’s `Array` type also provides an initializer for creating an array of a certain size with all of its values set to a provided default value. You pass this initializer the number of items to be added to the new array (called `count`) and a default value of the appropriate type (called `repeatedValue`): -Swift`数组`类型还提供了一个构造器【todo:初始化器】来创建指定大小的数组,该数组的数组项的值是默认的【todo:该数组的数据项设置为提供的默认值】。我们传递给构造器新加的数组项的大小(称为`count`),以及适合类型的默认值(称为`repeatedValue`)【todo:我们把新加的数组项的大小(称为`count`)和相应类型的默认值(称为`repeatedValue`)传递给初始化器】。 +Swift `数组`类型还提供了一个初始化器来创建指定大小的数组,该数组的数据项设置为提供的默认值。我们把新加的数组项的大小(称为`count`)和相应类型的默认值(称为`repeatedValue`)传递给初始化器。 ``` var threeDoubles = Double[](count: 3, repeatedValue: 0.0) @@ -319,8 +321,7 @@ var threeDoubles = Double[](count: 3, repeatedValue: 0.0) ``` Thanks to type inference, you don’t need to specify the type to be stored in the array when using this initializer, because it can be inferred from the default value: -感谢类型推导,我们在使用构造器时不需要指定数组中数值的具体类型,因为类型可以从默认值中推导出来: -【todo:多亏有类型推导,使用初始化器时,可以不需要指定数组存储的类型,因为可以从默认值推导类型:】 +多亏有类型推导,使用初始化器时,可以不需要指定数组存储的类型,因为可以从默认值推导类型: ``` var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5) @@ -345,26 +346,26 @@ var sixDoubles = threeDoubles + anotherThreeDoubles A *dictionary* is a container that stores multiple values of the same type. Each value is associated with a unique *key*, which acts as an identifier for that value within the dictionary. Unlike items in an array, items in a dictionary do not have a specified order. You use a dictionary when you need to look up values based on their identifier, in much the same way that a real-world dictionary is used to look up the definition for a particular word. -*字典*是存储多个相同类型数值的容器。每个值和字典中作为该值的唯一标识符的*键*(key)相关联。和数组中的数据项不同,字典中的数据项没有顺序。我们可以使用字典查找基于标识符的数据【todo:可以使用字典根据标识符来查找数据】,就像在现实世界中可以用字典来查找某个特定字词的定义。 +*字典*是存储多个相同类型数值的容器。每个值和字典中作为该值的唯一标识符的*键* (key) 相关联。和数组中的数据项不同,字典中的数据项没有顺序。我们可以使用字典根据标识符来查找数据,就像在现实世界中可以用字典来查找某个特定字词的定义。 Swift dictionaries are specific about the types of keys and values they can store. They differ from Objective-C’s `NSDictionary` and `NSMutableDictionary` classes, which can use any kind of object as their keys and values and do not provide any information about the nature of these objects. In Swift, the type of keys and values that a particular dictionary can store is always made clear, either through an explicit type annotation or through type inference. -Swift字典存储的键和值的类型是确定的。他们和Objective-C的类`NSDictionary`和`NSMutableDictionary`有所不同,这些类可以用任意一种对象作为他们的键和值,且不提供这些对象本质相关的任何信息。在Swift中,某个字典可以存储的键和值的类型是确定的,要么通过显示的类型声明而来,要么通过类型推断而来【todo:可以使用显式类型声明,也可以使用类型推断】。 +Swift 字典存储的键和值的类型是确定的。他们和 Objective-C 的类 `NSDictionary` 和 `NSMutableDictionary` 有所不同,这些类可以用任意一种对象作为他们的键和值,且不提供这些对象本质相关的任何信息。在 Swift 中,某个字典可以存储的键和值的类型是确定的,可以使用显式类型声明,也可以使用类型推断。 Swift’s dictionary type is written as `Dictionary`, where `KeyType` is the type of value that can be used as a dictionary key, and `ValueType` is the type of value that the dictionary stores for those keys. -Swift字典类型写为`Dictionary`,这里的`KeyType`是可以作为字典键的数据类型,`ValueType`是字典中存储的与键相对应的值的类型。 +Swift 字典类型写为 `Dictionary`,这里的 `KeyType` 是可以作为字典键的数据类型,`ValueType` 是字典中存储的与键相对应的值的类型。 The only restriction is that `KeyType` must be *hashable*—that is, it must provide a way to make itself uniquely representable. All of Swift’s basic types (such as `String`, `Int`, `Double`, and `Bool`) are hashable by default, and all of these types can be used as the keys of a dictionary. Enumeration member values without associated values (as described in [Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md)) are also hashable by default. -`KeyType`的唯一限制是它必须是*可哈希的*——也就是说,它必须提供一个方法来使得自己可以被唯一表示【todo:它必须提供一个方法可以唯一代表自己】。所有的Swift基础类型(如`String`、`Int`、 `Double` 和`Bool`)默认都是可哈希的,所有的这些类型都可以被用来作为字典的键。没有关联数值的枚举类型(参见[Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md))也是默认可枚举的【todo:没有对应值的枚举成员数据默认也是可哈希的】。 +`KeyType` 的唯一限制是它必须是*可哈希的*——也就是说,它必须提供一个方法可以唯一代表自己。所有的 Swift 基础类型(如 `String`、`Int`、 `Double` 和`Bool`)默认都是可哈希的,所有的这些类型都可以被用来作为字典的键。没有对应值的枚举成员数据(参见 [Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md))默认也是可哈希的。 ‌ ### Dictionary Literals ### 字典字面量 You can initialize a dictionary with a *dictionary literal*, which has a similar syntax to the array literal seen earlier. A dictionary literal is a shorthand way to write one or more key-value pairs as a `Dictionary` collection. -你可以用*字典字面量*来初始化一个字典,这和之前的数组字面量有着相似的语法。一个字典字面量是一个缩写的方式来表示作为`字典`集合的一个或多个键值对【todo:字典字面量是一个或多个键-值对作为`字典`集合的简写方式】。 +你可以用*字典字面量*来初始化一个字典,这和之前的数组字面量有着相似的语法。字典字面量是一个或多个键-值对作为`字典`集合的简写方式。 A *key-value pair* is a combination of a key and a value. In a dictionary literal, the key and value in each key-value pair are separated by a colon. The key-value pairs are written as a list, separated by commas, surrounded by a pair of square brackets: @@ -394,33 +395,36 @@ The `airports` dictionary is declared as having a type of `Dictionary` is the correct type to use for the `airports` dictionary. -由于字面量中所有的键和值都是相同类型的,因此Swift可以推断出`Dictionary` 是字典`airports`使用的正确类型。 +由于字面量中所有的键和值都是相同类型的,因此 Swift 可以推断出 `Dictionary` 是字典 `airports` 使用的正确类型。 ‌ ### Accessing and Modifying a Dictionary ### 访问和修改字典 You access and modify a dictionary through its methods and properties, or by using subscript syntax. As with an array, you can find out the number of items in a `Dictionary` by checking its read-only `count` property: -我们可以通过字典的方法和属性,或下标语法来访问和修改字典。像数组那样,我们可以通过检查只读属性`count`来获取`字典`中数据项的个数。 +我们可以通过字典的方法和属性,或下标语法来访问和修改字典。像数组那样,我们可以通过检查只读属性 `count` 来获取`字典`中数据项的个数。 ``` println("The dictionary of airports contains \(airports.count) items.") // prints "The dictionary of airports contains 2 items." + +// 打印出 "The dictionary of airports contains 2 items." + ``` You can add a new item to a dictionary with subscript syntax. Use a new key of the appropriate type as the subscript index, and assign a new value of the appropriate type: @@ -435,7 +439,7 @@ airports["LHR"] = "London" You can also use subscript syntax to change the value associated with a particular key: -我们还可以使用下标语法来改变和某个特定键相关联的值【还可以使用下标语法改变某个键对应的值】: +我们还可以使用下标语法改变某个键对应的值: ``` airports["LHR"] = "London Heathrow" @@ -445,21 +449,23 @@ airports["LHR"] = "London Heathrow" ``` As an alternative to subscripting, use a dictionary’s `updateValue(forKey:)` method to set or update the value for a particular key. Like the subscript examples above, the `updateValue(forKey:)` method sets a value for a key if none exists, or updates the value if that key already exists. Unlike a subscript, however, the `updateValue(forKey:)` method returns the old value after performing an update. This enables you to check whether or not an update took place. -字典的`updateValue(forKey:)`方法可作为下标的替代来设置或更新某个特定键对应的值。像上面下标的例子,`updateValue(forKey:)`方法可以设置某个不存在的键的值或者更新某个已有的键的值。和下标不同的是,`updateValue(forKey:)`方法在更新数据后会返回更新前的数值。这使得我们可以检查更新是否成功。 +字典的 `updateValue(forKey:)` 方法可作为下标的替代来设置或更新某个特定键对应的值。像上面下标的例子,`updateValue(forKey:)` 方法可以设置某个不存在的键的值或者更新某个已有的键的值。和下标不同的是,`updateValue(forKey:)` 方法在更新数据后会返回更新前的数值。这使得我们可以检查更新是否成功。 The `updateValue(forKey:)` method returns an optional value of the dictionary’s value type. For a dictionary that stores `String` values, for example, the method returns a value of type `String?`, or “optional `String`”. This optional value contains the old value for that key if one existed before the update, or `nil` if no value existed: -`updateValue(forKey:)`方法返回字典值类型的可选值。举个例子,对于一个储存了`String`数据的字典,这个方法返回了一个`String?类型`或“可选的`String`”类型的数据。如果在更新之前这个键是存在的,则这个可选数据返回更新之前的值,否则返回`nil`。 +`updateValue(forKey:)` 方法返回字典值类型的可选值。举个例子,对于一个储存了 `String` 数据的字典,这个方法返回了一个 `String?类型` 或“可选的 `String`”类型的数据。如果在更新之前这个键是存在的,则这个可选数据返回更新之前的值,否则返回 `nil`。 ``` if let oldValue = airports.updateValue("Dublin International", forKey: "DUB") { println("The old value for DUB was \(oldValue).") } // prints "The old value for DUB was Dublin." + +// 打印出 "The old value for DUB was Dublin." ``` You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type. If the dictionary contains a value for the requested key, the subscript returns an optional value containing the existing value for that key. Otherwise, the subscript returns `nil`: -我们也可以使用下标语法来访问字典中某个特定键对应的值。因为查询某个不存在对应值的键也是有可能的【todo:因为有可能会查询一个没有对应值的键】,字典的下标会返回字典数据类型的可选值。如果字典包含了与要查找的键相对应的值,下标返回的可选值包含那个键对应的值,否则下标返回`nil`。 +我们也可以使用下标语法来访问字典中某个特定键对应的值。因为有可能会查询一个没有对应值的键,字典的下标会返回字典数据类型的可选值。如果字典包含了与要查找的键相对应的值,下标返回的可选值包含那个键对应的值,否则下标返回 `nil`。 ``` if let airportName = airports["DUB"] { @@ -468,10 +474,12 @@ if let airportName = airports["DUB"] { println("That airport is not in the airports dictionary.") } // prints "The name of the airport is Dublin International." + +// 打印出 "The name of the airport is Dublin International." ``` You can use subscript syntax to remove a key-value pair from a dictionary by assigning a value of `nil` for that key: -我们可以使用下标语法设置某个指定键的值为`nil`来从字典中移除该键值对。 +我们可以使用下标语法设置某个指定键的值为 `nil` 来从字典中移除该键值对。 ``` airports["APL"] = "Apple International" @@ -486,7 +494,7 @@ airports["APL"] = nil Alternatively, remove a key-value pair from a dictionary with the `removeValueForKey` method. This method removes the key-value pair if it exists and returns the removed value, or returns `nil` if no value existed: -我们还可以使用`removeValueForKey`方法从字典中移除一个键值对。如果要移除的键对应的值对存在,该方法会移除它们并返回被移除的值,如果对应的值不存在,则返回`nil`。 +我们还可以使用 `removeValueForKey` 方法从字典中移除一个键值对。如果要移除的键对应的值对存在,该方法会移除它们并返回被移除的值,如果对应的值不存在,则返回 `nil`。 ``` if let removedValue = airports.removeValueForKey("DUB") { @@ -494,14 +502,16 @@ if let removedValue = airports.removeValueForKey("DUB") { } else { println("The airports dictionary does not contain a value for DUB.") } -// prints "The removed airport's name is Dublin International. +// prints "The removed airport's name is Dublin International." + +//打印出 "The removed airport's name is Dublin International." ``` ### Iterating Over a Dictionary ### 字典遍历 You can iterate over the key-value pairs in a dictionary with a `for-in` loop. Each item in the dictionary is returned as a (`key, value`) tuple, and you can decompose the tuple’s members into temporary constants or variables as part of the iteration: -我们可以用`for-in`循环遍历一个字典中的键值对。字典中的每个数据项返回相应的(`键, 值`)元组,我们可以把元组分解为临时常量或变量用于遍历: +我们可以用 `for-in` 循环遍历一个字典中的键值对。字典中的每个数据项返回相应的(`键, 值`)元组,我们可以把元组分解为临时常量或变量用于遍历: ``` for (airportCode, airportName) in airports { @@ -512,11 +522,11 @@ for (airportCode, airportName) in airports { ``` For more about the `for-in` loop, see [For Loops](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF). -更多关于`for-in`循环的介绍,请参见[For循环](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF)。 +更多关于 `for-in` 循环的介绍,请参见 [For循环](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF)。 You can also retrieve an iteratable collection of a dictionary’s keys or values by accessing its `keys` and `values` properties: -我们还可以通过字典的`keys`或`values`属性来遍历字典的键或值【todo:可以使用字典的`keys`或`values`属性得到字典的键和值的遍历集合】。 +可以使用字典的 `keys` 或 `values` 属性得到字典的键和值的遍历集合。 ``` for airportCode in airports.keys { @@ -534,8 +544,7 @@ for airportName in airports.values { If you need to use a dictionary’s keys or values with an API that takes an `Array` instance, initialize a new array with the `keys` or `values` property: -如果我们需要使用一个使用字典的键和值,并用`Array`实例作为参数的接口,可以用`keys`或`values`属性来初始化一个新的数组。 -【todo:如果需要使用字典的API 生成键和值的`Array`实例,可以使用`keys`或`values`属性初始化新数组】 +如果需要使用字典的API 生成键和值的 `Array` 实例,可以使用 `keys` 或 `values` 属性初始化新数组。 ``` let airportCodes = Array(airports.keys) @@ -550,22 +559,24 @@ let airportNames = Array(airports.values) >注意 ->Swift字典类型是无序的集合。遍历字典时键、值以及键值对的访问顺序是不确定的。 +>Swift 字典类型是无序的集合。遍历字典时键、值以及键值对的访问顺序是不确定的。 ‌ ### Creating an Empty Dictionary ### 创建空字典 As with arrays, you can create an empty `Dictionary` of a certain type by using initializer syntax: -和数组一样,我们可以使用初始化语法创建一个特定类型的空`字典`。 +和数组一样,我们可以使用初始化语法创建一个特定类型的空 `字典`。 ``` var namesOfIntegers = Dictionary() // namesOfIntegers is an empty Dictionary + +// namesOfIntegers 是一个空字典 ``` This example creates an empty dictionary of type `Int`, `String` to store human-readable names of integer values. Its keys are of type `Int`, and its values are of type `String`. -这个例子创建了`Int`,`String`类型的空字典来存储整型的可读性名称。它的键的类型是`Int`,值的类型是`String`。 +这个例子创建了 `Int`,`String` 类型的空字典来存储整型的可读性名称。它的键的类型是 `Int`,值的类型是 `String`。 If the context already provides type information, create an empty dictionary with an empty dictionary literal, which is written as [`:`] (a colon inside a pair of square brackets): @@ -589,7 +600,7 @@ namesOfIntegers = [:] >注意 ->在后台,Swift数组和字典类型都是由*泛型集合*实现的。更多关于泛型类型和集合的介绍,请参见[Generics](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/22_Generics.md)。 +>在后台,Swift 数组和字典类型都是由*泛型集合*实现的。更多关于泛型类型和集合的介绍,请参见 [Generics](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/22_Generics.md)。 ‌ ## Mutability of Collections @@ -597,7 +608,7 @@ namesOfIntegers = [:] Arrays and dictionaries store multiple values together in a single collection. If you create an array or a dictionary and assign it to a variable, the collection that is created will be *mutable*. This means that you can change (or *mutate*) the size of the collection after it is created by adding more items to the collection, or by removing existing items from the ones it already contains. Conversely, if you assign an array or a dictionary to a constant, that array or dictionary is *immutable*, and its size cannot be changed. -数组和字典在单个集合中存储了多个数据。如果我们创建一个数组或字典并把它声明为变量,这个创建出来的集合是*易变的*。这表示我们可以在创建集合之后通过添加更多的数据项到集合中或从中移除现有的数据项来*改变*它的大小【todo:这意味着我们可以改变集合的大小,在集合中添加更多的数据项,或从中移除已有的数据项】。相反的,如果把一个数组或字典声明为常量,则这个数组或字典是*不可变*的,它的大小是不会变化的。 +数组和字典在单个集合中存储了多个数据。如果我们创建一个数组或字典并把它声明为变量,这个创建出来的集合是*易变的*。这意味着我们可以改变集合的大小,在集合中添加更多的数据项,或从中移除已有的数据项。相反的,如果把一个数组或字典声明为常量,则这个数组或字典是*不可变*的,它的大小是不会变化的。 For dictionaries, immutability also means that you cannot replace the value for an existing key in the dictionary. An immutable dictionary’s contents cannot be changed once they are set. @@ -605,17 +616,17 @@ For dictionaries, immutability also means that you cannot replace the value for Immutability has a slightly different meaning for arrays, however. You are still not allowed to perform any action that has the potential to change the size of an immutable array, but you *are* allowed to set a new value for an existing index in the array. This enables Swift’s `Array` type to provide optimal performance for array operations when the size of an array is fixed. -对数组来说,不可变的意义稍有不同。我们仍不允许改变不可变数组的大小,但是,我们*被*允许改变数组中某个已有索引对应的值。这使得Swift的`Array`类型可以在操作固定大小的数组时提供最佳性能。 +对数组来说,不可变的意义稍有不同。我们仍不允许改变不可变数组的大小,但是,我们*被*允许改变数组中某个已有索引对应的值。这使得 Swift 的 `Array` 类型可以在操作固定大小的数组时提供最佳性能。 The mutability behavior of Swift’s `Array` type also affects how array instances are assigned and modified. For more information, see [Assignment and Copy Behavior for Collection Types](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/09_Classes_and_Structures.md#assignment-and-copy-behavior-for-collection-types). -Swift的`Array`类型的可变性还影响了数组实例是怎么被声明和修改的【todo:Swift的`Array`类型的可变性还会影响数组实例如何赋值和修改】。更多介绍请参见[集合类型的声明和复制](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/09_Classes_and_Structures.md#%E9%9B%86%E5%90%88%E7%9A%84%E8%B5%8B%E5%80%BC%E4%B8%8E%E6%8B%B7%E8%B4%9D)。 +Swift 的 `Array` 类型的可变性还会影响数组实例如何赋值和修改。更多介绍请参见 [集合类型的声明和复制](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/09_Classes_and_Structures.md#%E9%9B%86%E5%90%88%E7%9A%84%E8%B5%8B%E5%80%BC%E4%B8%8E%E6%8B%B7%E8%B4%9D)。 >NOTE >It is good practice to create immutable collections in all cases where the collection’s size does not need to change. Doing so enables the Swift compiler to optimize the performance of the collections you create. >注意 ->当集合的大小不需要改变时,创建一个不可变的集合是比较好的做法。这样做使得Swift编译器优化我们创建的集合的性能【todo:这样做,Swift编译器会优化创建的集合性能】。 +>当集合的大小不需要改变时,创建一个不可变的集合是比较好的做法。这样做,Swift 编译器会优化创建的集合性能。 From edf7a9cbd45ebbf3ea0e6c930c0c497f04b05271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=98=E5=A2=83?= Date: Sun, 13 Jul 2014 12:08:10 +0800 Subject: [PATCH 258/261] =?UTF-8?q?=E5=88=A0=E9=99=A4=E8=8B=B1=E6=96=87?= =?UTF-8?q?=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chapter2/04_Collection_Types.md | 222 +--------------------------- 1 file changed, 7 insertions(+), 215 deletions(-) diff --git a/src/chapter2/04_Collection_Types.md b/src/chapter2/04_Collection_Types.md index 89a9e92..7e2c8d2 100644 --- a/src/chapter2/04_Collection_Types.md +++ b/src/chapter2/04_Collection_Types.md @@ -1,106 +1,67 @@ -# Collection Types # 集合类型 -Swift provides two *collection types*, known as arrays and dictionaries, for storing collections of values. Arrays store ordered lists of values of the same type. Dictionaries store unordered collections of values of the same type, which can be referenced and looked up through a unique identifier (also known as a *key*). - Swift 提供了两种*集合类型* 来存储数据集合,分别是数组(arrays)和字典(dictionaries)。数组用来存储有序的相同类型数据的列表。字典用来存储无序的相同类型数据的集合,这些数据可以通过唯一的标识符(称为*键*)引用和查找。 -Arrays and dictionaries in Swift are always clear about the types of values and keys that they can store. This means that you cannot insert a value of the wrong type into an array or dictionary by mistake. It also means you can be confident about the types of values you will retrieve from an array or dictionary. Swift’s use of explicitly typed collections ensures that your code is always clear about the types of values it can work with and enables you to catch any type mismatches early in your code’s development. - 在Swift中,数组和字典可以存储的键值类型总是明确的。这意味着不会把错误类型的值意外地插入到数组或字典中。这也意味着我们可以清楚的知道从数组或字典中获取的数据类型。Swift 使用显示类型集合,这确保了代码中可以处理的数据类型是明确的,并让我们可以提前发现开发中的任何类型错误。 ->NOTE - ->Swift’s `Array` type exhibits different behavior to other types when assigned to a constant or variable, or when passed to a function or method. For more information, see [Mutability of Collections](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/04_Collection_Types.md#mutability-of-collections) and [Assignment and Copy Behavior for Collection Types](). >注意 >Swift的`Array`类型在赋值给常量、变量或传入函数和方法时与其他类型的行为稍有不同。获取更多信息请参见[Mutability of Collections](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/04_Collection_Types.md#mutability-of-collections)and[AssignmentCopy Behavior for Collection Types]()这两个章节。 -## Arrays ## 数组 -An *array* stores multiple values of the same type in an ordered list. The same value can appear in an array multiple times at different positions. *数组*在一个有序列表中存储了多个相同类型的数据。相同的数据可以多次出现在数组的不同位置。 -Swift arrays are specific about the kinds of values they can store. They differ from Objective-C’s `NSArray` and `NSMutableArray` classes, which can store any kind of object and do not provide any information about the nature of the objects they return. In Swift, the type of values that a particular array can store is always made clear, either through an explicit type annotation, or through type inference, and does not have to be a class type. If you create an array of `Int` values, for example, you can’t insert any value other than `Int` values into that array. Swift arrays are type safe, and are always clear about what they may contain. - Swift 数组可以存储的数据类型是确定的。这与 Objective-C 的类 `NSArray` 和 `NSMutableArray` 不同,这两个类可以存储任何类型的对象,并且不会提供它们返回的对象的任何信息。在 Swift 中,某个数组可以存储的数据类型是确定的,可以使用显式的类型声明,也可以使用类型推断,且不必一定是 class 类型。假如你创建了一个 `Int` 型的数组,那么就不能在这个数组中插入其他任何非 `Int` 型的值。Swift 数组是类型安全的,并且它们可以包含的类型是明确的。 ‌ -### Array Type Shorthand Syntax ### 数组类型简写语法 -The type of a Swift array is written in full as `Array`, where `SomeType` is the type that the array is allowed to store. You can also write the type of an array in shorthand form as `SomeType[]`. Although the two forms are functionally identical, the shorthand form is preferred, and is used throughout this guide when referring to the type of an array. Swift 数组类型的完整写法是 `Array`, 这里的 `SomeType` 指的是数组可以存储的类型。我们也可以把它简写为 `SomeType[]`。尽管这两种形式在功能上完全相同,但更推荐简写形式,且本书中提到数组类型时都会使用这种形式。 ‌ -### Array Literals ### 数组字面量 -You can initialize an array with an *array literal*, which is a shorthand way to write one or more values as an array collection. An array literal is written as a list of values, separated by commas, surrounded by a pair of square brackets: - -你可以用*数组字面量*来初始化数组,这是一个或多个值作为数组集合的简写方式。数组字面量写作一个数值列表,由逗号分隔,被一对方括号括起来: +我们可以用*数组字面量*来初始化数组,这是一个或多个值作为数组集合的简写方式。数组字面量写作一个数值列表,由逗号分隔,被一对方括号括起来: ``` [value 1, value 2, value 3] ``` - -The example below creates an array called `shoppingList` to store `String` values: 下面这个例子创建了一个名为 `shoppingList` 的数组来存储 `String` 类型的数据。 ``` var shoppingList: String[] = ["Eggs", "Milk"] -// shoppingList has been initialized with two initial items // 使用两个初始化项,初始化了shoppingList ``` -The `shoppingList` variable is declared as “an array of `String` values”, written as `String[]`. Because this particular array has specified a value type of `String`, it is *only* allowed to store `String` values. Here, the `shoppingList` array is initialized with two `String` values (`"Eggs" `and `"Milk"`), written within an array literal. - 变量shoppingList声明为“`String` 类型的数组”,写为 `String[]`。由于这个特定数组指定了 `String` 的数据类型,因此它*只能*存储 `String` 类型的数据。这里的 `shoppingList` 数组由两个`String` 值(`"Eggs" `和 `"Milk"`)以数组字面量来初始化。 ->NOTE - ->The `shoppingList` array is declared as a variable (with the `var` introducer) and not a constant (with the `let` introducer) because more items are added to the shopping list in the examples below. - >注意 >数组 `shoppingList` 声明为变量(通过关键字 `var` )而不是常量(通过关键字 `let`),因为在下面的例子中,会有更多的数组项添加到这个购物列表中。 -In this case, the array literal contains two `String `values and nothing else. This matches the type of the `shoppingList` variable’s declaration (an array that can only contain `String` values), and so the assignment of the array literal is permitted as a way to initialize `shoppingList` with two initial items. - 在这个例子中,该数组字面量只包含了两个 `String` 值。这和 `shoppingList` 变量的声明(只能包含 `String` 值的数组)是一致的,因此数组字面量的赋值作为一种方式,可以使用两个初始项初始化`shoppingList`。 -Thanks to Swift’s type inference, you don’t have to write the type of the array if you’re initializing it with an array literal containing values of the same type. The initialization of `shoppingList` could have been written in a shorter form instead: - 多亏了 Swift 的类型推断,如果使用包含相同类型数据的数组字面量,我们不需要写出数组的类型。`shopplingList`的初始化可以简写为: ``` var shoppingList = ["Eggs", "Milk"] ``` -Because all values in the array literal are of the same type, Swift can infer that `String[]` is the correct type to use for the `shoppingList` variable. - 因为数组字面量中所有的值的类型是相同的,Swift 可以推断出 `String[]` 是 `shoppingList` 变量使用的正确类型。 ‌ -### Accessing and Modifying an Array ### 访问和修改数组 -You access and modify an array through its methods and properties, or by using subscript syntax. 我们可以通过数组的方法、属性或使用下标语法来访问和修改数组。 -To find out the number of items in an array, check its read-only `count` property: - 可以通过数组的只读属性 `count` 来获得数组包含的数组项个数。 ``` println("The shopping list contains \(shoppingList.count) items.") -// prints "The shopping list contains 2 items." - +// 打印出 "The shopping list contains 2 items." ``` -Use the Boolean `isEmpty` property as a shortcut for checking whether the `count` property is equal to `0`: - 用布尔值 `isEmpty` 属性来作为检查 `count` 属性是否等于 `0` 的快捷方式。 ``` @@ -109,143 +70,95 @@ if shoppingList.isEmpty { } else { println("The shopping list is not empty.") } -// prints "The shopping list is not empty.” +// 打印出 "The shopping list is not empty.” ``` -You can add a new item to the end of an array by calling the array’s `append` method: - 可以通过调用数组的 `append` 方法,在数组的末尾插入一个新的数据项。 ``` shoppingList.append("Flour") -// shoppingList now contains 3 items, and someone is making pancakes -// shoppingList 现在包含3项 -``` -Alternatively, add a new item to the end of an array with the addition assignment operator (`+=`): +// shoppingList 现在包含3项, 有人在做煎饼 +``` 或者,可以通过加法赋值运算符(`+=`)在数组的末尾添加新的数据项。 ``` shoppingList += "Baking Powder" -// shoppingList now contains 4 items // shoppingList 现在包含4项 ``` -You can also append an array of compatible items with the addition assignment operator (`+=`): - 你还可以通过加法赋值运算符(`+=`)插入一个同类型的数组。 ``` shoppingList += ["Chocolate Spread", "Cheese", "Butter"] -// shoppingList now contains 7 items // shoppingList 现在包含7项 ``` -Retrieve a value from the array by using *subscript syntax*, passing the index of the value you want to retrieve within square brackets immediately after the name of the array: - 通过*下标语法*从数组中获取某个值,即在数组名后紧跟的方括号中传入想要获取的值的索引: ``` var firstItem = shoppingList[0] -// firstItem is equal to "Eggs" // firstItem 等于 "Eggs" ``` -Note that the first item in the array has an index of `0`, not `1`. Arrays in Swift are always zero-indexed. - 注意,数组中第一个数组项的索引为`0`,而不是`1`。Swift数组的索引是从零开始的。 -You can use subscript syntax to change an existing value at a given index: - 使用下标语法可以在给定的索引处改变已存在的值。 ``` shoppingList[0] = "Six eggs" -// the first item in the list is now equal to "Six eggs" rather than "Eggs" // 列表中第一项现在等于 "Six eggs" ,而不是"Eggs" ``` -You can also use subscript syntax to change a range of values at once, even if the replacement set of values has a different length than the range you are replacing. The following example replaces `"Chocolate Spread"`, `"Cheese"`, and `"Butter"` with `"Bananas"` and `"Apples"`: - 我们还可以通过下标语法一次改变一个范围内的值,即使替换的值的集合与被替换的范围的长度不一致。下面的例子用 `"Bananas"` and `"Apples"`替换了 `"Chocolate Spread"`, `"Cheese"`, and `"Butter"`: ``` shoppingList[4...6] = ["Bananas", "Apples"] -// shoppingList now contains 6 items // shoppingList现在包含6项 ``` ->NOTE - ->You can’t use subscript syntax to append a new item to the end of an array. If you try to use subscript syntax to retrieve or set a value for an index that is outside of an array’s existing bounds, you will trigger a runtime error. However, you can check that an index is valid before using it, by comparing it to the array’s `count` property. Except when `count` is `0` (meaning the array is empty), the largest valid index in an array will always be `count - 1`, because arrays are indexed from zero.” - >注意 >不能使用下标语法在数组的末尾添加新的数据项。如果我们试图用一个超过数组边界的下标访问或设置某个数值时,会导致运行时错误。不过,我们可以通过比较索引和数组的 `count` 属性来判断该索引是否有效。除了 count 为`0`时(意味着这个数组是空的),数组中最大的有效索引为 `count-1`,因为数组的索引是从0开始的。 - -To insert an item into the array at a specified index, call the array’s `insert(atIndex:)` method: - 要在数组的指定索引处插入一个数组项,可以调用数组的 `insert(atIndex:)` 方法: ``` shoppingList.insert("Maple Syrup", atIndex: 0) -// shoppingList now contains 7 items -// "Maple Syrup" is now the first item in the list // shoppingList 现在包含7项 // "Maple Syrup" 现在是列表的第一项 ``` -This call to the `insert` method inserts a new item with a value of `"Maple Syrup"` at the very beginning of the shopping list, indicated by an index of `0`. - 这个例子调用 `insert` 方法指定索引为 `0`,在 shoppingList 的最前面插入了值为 `“Maple Syrup”` 的新数据项。 -Similarly, you remove an item from the array with the `removeAtIndex` method. This method removes the item at the specified index and returns the removed item (although you can ignore the returned value if you do not need it): - 类似地,`removeAtIndex` 方法可以从数组中移除一个数组项。该方法移除指定索引处的数组项,并返回被移除的数组项(如果不需要,我们可以忽略返回值): ``` let mapleSyrup = shoppingList.removeAtIndex(0) -// the item that was at index 0 has just been removed -// shoppingList now contains 6 items, and no Maple Syrup -// the mapleSyrup constant is now equal to the removed" Maple Syrup" string - // 索引为0的数据项被移除 // shoppingList 现在包含6项, 不包括 Maple Syrup // mapleSyrup 现在等于被移除的 " Maple Syrup" 字符串 ``` -Any gaps in an array are closed when an item is removed, and so the value at index `0` is once again equal to `"Six eggs"`: - 当一个数组项被移除后数组中的空缺项会被自动填补,因此索引`0`对应的值再次等于`“Six eggs”`: ``` firstItem = shoppingList[0] -// firstItem is now equal to "Six eggs" - // firstItem 现在等于"Six eggs" ``` -If you want to remove the final item from an array, use the `removeLast` method rather than the `removeAtIndex `method to avoid the need to query the array’s `count` property. Like the `removeAtIndex` method, `removeLast` returns the removed item: 如果我们想要从数组中移除最后一个数组项,最好使用 `removeLast` 方法,而不是 `removeAtIndex` 方法,这样可以避免查询数组的 `count` 属性。像 `removeAtIndex` 方法那样,`removeLast` 方法也会返回被移除的数组项: ``` let apples = shoppingList.removeLast() -// the last item in the array has just been removed -// shoppingList now contains 5 items, and no cheese -// the apples constant is now equal to the removed "Apples" string - // 数组中最后一项被移除 // shoppingList 现在包含5项, 不包括cheese // apples 现在等于被移除的"Apples" 字符串 ``` -### Iterating Over an Array ### 遍历数组 -You can iterate over the entire set of values in an array with the `for-in` loop: - 我们可以使用 `for-in` 循环来遍历数组中的所有数组项: ``` @@ -258,8 +171,6 @@ for item in shoppingList { // Baking Powder // Bananas ``` -If you need the integer index of each item as well as its value, use the global `enumerate` function to iterate over the array instead. The `enumerate` function returns a tuple for each item in the array composed of the index and the value for that item. You can decompose the tuple into temporary constants or variables as part of the iteration: - 如果需要每一项的整型索引及对应的值,那么可以使用全局函数 `enumerate` 来遍历数组。函数 `enumerate` 返回由每个数组项的索引和对应的值组成的元组。我们可以把元组分解为临时的常量或者变量来进行遍历。 ``` @@ -272,198 +183,127 @@ for (index, value) in enumerate(shoppingList) { // Item 4: Baking Powder // Item 5: Bananas ``` -For more about the `for-in` loop, see [For Loops](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF). - 获取更多关于 `for-in` 循环的介绍,请参见 [For循环](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF)。 -### Creating and Initializing an Array ### 创建和初始化数组 -You can create an empty array of a certain type (without setting any initial values) using initializer syntax: 我们可以使用初始化语法来创建某一特定类型的空数组(没有设置任何初始值): ``` var someInts = Int[]() println("someInts is of type Int[] with \(someInts.count) items.") -// prints "someInts is of type Int[] with 0 items." - // 打印出 "someInts is of type Int[] with 0 items." ``` -Note that the type of the `someInts` variable is inferred to be `Int[]`, because it is set to the output of an `Int[]` initializer. - 注意,变量 `someInts` 的类型被认为是 `Int[]`,因为它设置为`Int[]`初始化器的输出结果。 -Alternatively, if the context already provides type information, such as a function argument or an already-typed variable or constant, you can create an empty array with an empty array literal, which is written as `[]` (an empty pair of square brackets): - 或者,如果上下文已经提供了类型信息,例如一个函数参数,或一个已经指定类型的变量或常量,我们可以用空数组字面量来创建空数组,写为`[]`(一对空的方括号): ``` someInts.append(3) -// someInts now contains 1 value of type Int - // someInts 现在包含 1 个 Int 值 someInts = [] -// someInts is now an empty array, but is still of type Int[] - // someInts 现在是一个空数组, 但仍然是Int[]类型 ``` -Swift’s `Array` type also provides an initializer for creating an array of a certain size with all of its values set to a provided default value. You pass this initializer the number of items to be added to the new array (called `count`) and a default value of the appropriate type (called `repeatedValue`): Swift `数组`类型还提供了一个初始化器来创建指定大小的数组,该数组的数据项设置为提供的默认值。我们把新加的数组项的大小(称为`count`)和相应类型的默认值(称为`repeatedValue`)传递给初始化器。 ``` var threeDoubles = Double[](count: 3, repeatedValue: 0.0) -// threeDoubles is of type Double[], and equals [0.0, 0.0, 0.0] - // threeDoubles 是 Double[] 类型,等于[0.0, 0.0, 0.0] ``` -Thanks to type inference, you don’t need to specify the type to be stored in the array when using this initializer, because it can be inferred from the default value: - 多亏有类型推导,使用初始化器时,可以不需要指定数组存储的类型,因为可以从默认值推导类型: ``` var anotherThreeDoubles = Array(count: 3, repeatedValue: 2.5) -// anotherThreeDoubles is inferred as Double[], and equals [2.5, 2.5, 2.5] - // anotherThreeDoubles 推导为 Double[] 类型,等于 [2.5, 2.5, 2.5] ``` -Finally, you can create a new array by adding together two existing arrays of compatible type with the addition operator (`+`). The new array’s type is inferred from the type of the two arrays you add together: - 最后,我们可以使用加法操作符(`+`)把两个已经存在的相同类型的数组相加来创建一个新的数组。这个新数组的类型是从两个相加的数组的类型推导出来的: ``` var sixDoubles = threeDoubles + anotherThreeDoubles -// sixDoubles is inferred as Double[], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] - // sixDoubles 推导为Double[]类型, 等于 [0.0, 0.0, 0.0, 2.5, 2.5, 2.5] ``` -## Dictionaries ## 字典 -A *dictionary* is a container that stores multiple values of the same type. Each value is associated with a unique *key*, which acts as an identifier for that value within the dictionary. Unlike items in an array, items in a dictionary do not have a specified order. You use a dictionary when you need to look up values based on their identifier, in much the same way that a real-world dictionary is used to look up the definition for a particular word. - *字典*是存储多个相同类型数值的容器。每个值和字典中作为该值的唯一标识符的*键* (key) 相关联。和数组中的数据项不同,字典中的数据项没有顺序。我们可以使用字典根据标识符来查找数据,就像在现实世界中可以用字典来查找某个特定字词的定义。 -Swift dictionaries are specific about the types of keys and values they can store. They differ from Objective-C’s `NSDictionary` and `NSMutableDictionary` classes, which can use any kind of object as their keys and values and do not provide any information about the nature of these objects. In Swift, the type of keys and values that a particular dictionary can store is always made clear, either through an explicit type annotation or through type inference. - Swift 字典存储的键和值的类型是确定的。他们和 Objective-C 的类 `NSDictionary` 和 `NSMutableDictionary` 有所不同,这些类可以用任意一种对象作为他们的键和值,且不提供这些对象本质相关的任何信息。在 Swift 中,某个字典可以存储的键和值的类型是确定的,可以使用显式类型声明,也可以使用类型推断。 -Swift’s dictionary type is written as `Dictionary`, where `KeyType` is the type of value that can be used as a dictionary key, and `ValueType` is the type of value that the dictionary stores for those keys. - Swift 字典类型写为 `Dictionary`,这里的 `KeyType` 是可以作为字典键的数据类型,`ValueType` 是字典中存储的与键相对应的值的类型。 -The only restriction is that `KeyType` must be *hashable*—that is, it must provide a way to make itself uniquely representable. All of Swift’s basic types (such as `String`, `Int`, `Double`, and `Bool`) are hashable by default, and all of these types can be used as the keys of a dictionary. Enumeration member values without associated values (as described in [Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md)) are also hashable by default. - -`KeyType` 的唯一限制是它必须是*可哈希的*——也就是说,它必须提供一个方法可以唯一代表自己。所有的 Swift 基础类型(如 `String`、`Int`、 `Double` 和`Bool`)默认都是可哈希的,所有的这些类型都可以被用来作为字典的键。没有对应值的枚举成员数据(参见 [Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md))默认也是可哈希的。 +`KeyType` 的唯一限制是它必须是*可哈希的*——也就是说,它必须提供一个方法可以唯一代表自己。所有的 Swift 基础类型(如 `String`、`Int`、 `Double` 和 `Bool`)默认都是可哈希的,所有的这些类型都可以被用来作为字典的键。没有对应值的枚举成员数据(参见 [Enumerations](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/08_Enumerations.md))默认也是可哈希的。 ‌ -### Dictionary Literals ### 字典字面量 -You can initialize a dictionary with a *dictionary literal*, which has a similar syntax to the array literal seen earlier. A dictionary literal is a shorthand way to write one or more key-value pairs as a `Dictionary` collection. 你可以用*字典字面量*来初始化一个字典,这和之前的数组字面量有着相似的语法。字典字面量是一个或多个键-值对作为`字典`集合的简写方式。 -A *key-value pair* is a combination of a key and a value. In a dictionary literal, the key and value in each key-value pair are separated by a colon. The key-value pairs are written as a list, separated by commas, surrounded by a pair of square brackets: - *键-值对*是键和值的组合。在字典字面量中,每个键-值对中的键和值由冒号分隔。键值对的列表,用逗号分隔,由方括号括起来: ``` [key 1: value 1, key 2: value 2, key 3: value 3] ``` -The example below creates a dictionary to store the names of international airports. In this dictionary, the keys are three-letter International Air Transport Association codes, and the values are airport names: - 下面的例子创建了一个字典来储存国际机场的名字。在这个字典中,键是由三个字母组成的国际航空运输协会代码,值是机场的名称: ``` var airports: Dictionary = ["TYO": "Tokyo", "DUB": "Dublin"] ``` -The `airports` dictionary is declared as having a type of `Dictionary`, which means “a `Dictionary` whose keys are of type `String`, and whose values are also of type `String`”. - `airports`字典声明为`Dictionary`类型,即“一个键和值的类型都是`String`类型的字典”。 ->NOTE - ->The `airports` dictionary is declared as a variable (with the `var` introducer), and not a constant (with the `let` introducer), because more airports will be added to the dictionary in the examples below. - >注意 >`airports`字典声明为变量(用关键字`var`),而不是常量(用关键字`let`),因为在下面的例子中,会有更多的机场被添加到这个字典里。 -The `airports` dictionary is initialized with a dictionary literal containing two key-value pairs. The first pair has a key of `"TYO"` and a value of `"Tokyo"`. The second pair has a key of `"DUB"` and a value of `"Dublin"`. - `airports` 字典由包含两对键值对的字典字面量初始化。第一对有键`“TYO”` 和值 `“Tokyo”`。第二对有键 `“DUB”` 和值 `“Dublin”`。 -This dictionary literal contains two `String`: `String` pairs. This matches the type of the `airports` variable declaration (a dictionary with only `String` keys, and only `String` values) and so the assignment of the dictionary literal is permitted as a way to initialize the `airports` dictionary with two initial items. - 这个字典字面量包含两个 `String`:`String` 类型的键值对。这和变量 `airports` 声明(只有 `String` 键和 `String` 值的字典)的类型一致,因此字典字面量的赋值作为一种方法,可以用两个初始项来初始化这个 `airports` 字典。 -As with arrays, you don’t have to write the type of the dictionary if you’re initializing it with a dictionary literal whose keys and values have consistent types. The initialization of `airports` could have been be written in a shorter form instead: - 和数组一样,如用我们用键值类型相同的字典字面量来初始化字典,那么不需要写出它的类型。`airports` 的初始化可以简写为以下形式: ``` var airports = ["TYO": "Tokyo", "DUB": "Dublin"] ``` -Because all keys in the literal are of the same type as each other, and likewise all values are of the same type as each other, Swift can infer that `Dictionary` is the correct type to use for the `airports` dictionary. 由于字面量中所有的键和值都是相同类型的,因此 Swift 可以推断出 `Dictionary` 是字典 `airports` 使用的正确类型。 ‌ -### Accessing and Modifying a Dictionary ### 访问和修改字典 -You access and modify a dictionary through its methods and properties, or by using subscript syntax. As with an array, you can find out the number of items in a `Dictionary` by checking its read-only `count` property: - 我们可以通过字典的方法和属性,或下标语法来访问和修改字典。像数组那样,我们可以通过检查只读属性 `count` 来获取`字典`中数据项的个数。 ``` println("The dictionary of airports contains \(airports.count) items.") -// prints "The dictionary of airports contains 2 items." - // 打印出 "The dictionary of airports contains 2 items." ``` -You can add a new item to a dictionary with subscript syntax. Use a new key of the appropriate type as the subscript index, and assign a new value of the appropriate type: 我们可以通过下标语法给字典添加新的数据项。使用相应类型的键作为下标索引,并赋予相应类型的值: ``` airports["LHR"] = "London" -// the airports dictionary now contains 3 items - // airports 字典现在包含3项 ``` -You can also use subscript syntax to change the value associated with a particular key: - 我们还可以使用下标语法改变某个键对应的值: ``` airports["LHR"] = "London Heathrow" -// the value for "LHR" has been changed to "London Heathrow" - // "LHR" 的值修改为 "London Heathrow" ``` -As an alternative to subscripting, use a dictionary’s `updateValue(forKey:)` method to set or update the value for a particular key. Like the subscript examples above, the `updateValue(forKey:)` method sets a value for a key if none exists, or updates the value if that key already exists. Unlike a subscript, however, the `updateValue(forKey:)` method returns the old value after performing an update. This enables you to check whether or not an update took place. 字典的 `updateValue(forKey:)` 方法可作为下标的替代来设置或更新某个特定键对应的值。像上面下标的例子,`updateValue(forKey:)` 方法可以设置某个不存在的键的值或者更新某个已有的键的值。和下标不同的是,`updateValue(forKey:)` 方法在更新数据后会返回更新前的数值。这使得我们可以检查更新是否成功。 -The `updateValue(forKey:)` method returns an optional value of the dictionary’s value type. For a dictionary that stores `String` values, for example, the method returns a value of type `String?`, or “optional `String`”. This optional value contains the old value for that key if one existed before the update, or `nil` if no value existed: - `updateValue(forKey:)` 方法返回字典值类型的可选值。举个例子,对于一个储存了 `String` 数据的字典,这个方法返回了一个 `String?类型` 或“可选的 `String`”类型的数据。如果在更新之前这个键是存在的,则这个可选数据返回更新之前的值,否则返回 `nil`。 ``` if let oldValue = airports.updateValue("Dublin International", forKey: "DUB") { println("The old value for DUB was \(oldValue).") } -// prints "The old value for DUB was Dublin." - // 打印出 "The old value for DUB was Dublin." ``` -You can also use subscript syntax to retrieve a value from the dictionary for a particular key. Because it is possible to request a key for which no value exists, a dictionary’s subscript returns an optional value of the dictionary’s value type. If the dictionary contains a value for the requested key, the subscript returns an optional value containing the existing value for that key. Otherwise, the subscript returns `nil`: 我们也可以使用下标语法来访问字典中某个特定键对应的值。因为有可能会查询一个没有对应值的键,字典的下标会返回字典数据类型的可选值。如果字典包含了与要查找的键相对应的值,下标返回的可选值包含那个键对应的值,否则下标返回 `nil`。 @@ -473,27 +313,18 @@ if let airportName = airports["DUB"] { } else { println("That airport is not in the airports dictionary.") } -// prints "The name of the airport is Dublin International." - // 打印出 "The name of the airport is Dublin International." ``` -You can use subscript syntax to remove a key-value pair from a dictionary by assigning a value of `nil` for that key: 我们可以使用下标语法设置某个指定键的值为 `nil` 来从字典中移除该键值对。 ``` airports["APL"] = "Apple International" -// "Apple International" is not the real airport for APL, so delete it - // "Apple International" 不是APL的真实机场,所以删除它 airports["APL"] = nil -// APL has now been removed from the dictionary - // APL 已经从字典中移除了 ``` -Alternatively, remove a key-value pair from a dictionary with the `removeValueForKey` method. This method removes the key-value pair if it exists and returns the removed value, or returns `nil` if no value existed: - 我们还可以使用 `removeValueForKey` 方法从字典中移除一个键值对。如果要移除的键对应的值对存在,该方法会移除它们并返回被移除的值,如果对应的值不存在,则返回 `nil`。 ``` @@ -502,15 +333,11 @@ if let removedValue = airports.removeValueForKey("DUB") { } else { println("The airports dictionary does not contain a value for DUB.") } -// prints "The removed airport's name is Dublin International." //打印出 "The removed airport's name is Dublin International." ``` -### Iterating Over a Dictionary ### 字典遍历 -You can iterate over the key-value pairs in a dictionary with a `for-in` loop. Each item in the dictionary is returned as a (`key, value`) tuple, and you can decompose the tuple’s members into temporary constants or variables as part of the iteration: - 我们可以用 `for-in` 循环遍历一个字典中的键值对。字典中的每个数据项返回相应的(`键, 值`)元组,我们可以把元组分解为临时常量或变量用于遍历: ``` @@ -520,12 +347,8 @@ for (airportCode, airportName) in airports { // TYO: Tokyo // LHR: London Heathrow ``` -For more about the `for-in` loop, see [For Loops](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF). - 更多关于 `for-in` 循环的介绍,请参见 [For循环](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/05_Control_Flow.md#for%E5%BE%AA%E7%8E%AF)。 -You can also retrieve an iteratable collection of a dictionary’s keys or values by accessing its `keys` and `values` properties: - 可以使用字典的 `keys` 或 `values` 属性得到字典的键和值的遍历集合。 ``` @@ -542,8 +365,6 @@ for airportName in airports.values { // Airport name: London Heathrow ``` -If you need to use a dictionary’s keys or values with an API that takes an `Array` instance, initialize a new array with the `keys` or `values` property: - 如果需要使用字典的API 生成键和值的 `Array` 实例,可以使用 `keys` 或 `values` 属性初始化新数组。 ``` @@ -553,18 +374,13 @@ let airportCodes = Array(airports.keys) let airportNames = Array(airports.values) // airportNames is ["Tokyo", "London Heathrow"] ``` ->NOTE - ->Swift’s Dictionary type is an unordered collection. The order in which keys, values, and key-value pairs are retrieved when iterating over a dictionary is not specified. >注意 >Swift 字典类型是无序的集合。遍历字典时键、值以及键值对的访问顺序是不确定的。 ‌ -### Creating an Empty Dictionary ### 创建空字典 -As with arrays, you can create an empty `Dictionary` of a certain type by using initializer syntax: 和数组一样,我们可以使用初始化语法创建一个特定类型的空 `字典`。 @@ -574,58 +390,34 @@ var namesOfIntegers = Dictionary() // namesOfIntegers 是一个空字典 ``` -This example creates an empty dictionary of type `Int`, `String` to store human-readable names of integer values. Its keys are of type `Int`, and its values are of type `String`. 这个例子创建了 `Int`,`String` 类型的空字典来存储整型的可读性名称。它的键的类型是 `Int`,值的类型是 `String`。 -If the context already provides type information, create an empty dictionary with an empty dictionary literal, which is written as [`:`] (a colon inside a pair of square brackets): - 如果上下文已经提供了类型信息,可以用空字典字面量来创建空字典,写为[`:`] (中括号中放一个冒号): ``` namesOfIntegers[16] = "sixteen" -// namesOfIntegers now contains 1 key-value pair - // namesOfIntegers 现在包含1个键-值对 namesOfIntegers = [:] -// namesOfIntegers is once again an empty dictionary of type Int, String - // namesOfIntegers再一次成为 Int, String 类型的空字典 ``` ->NOTE - ->Behind the scenes, Swift’s array and dictionary types are implemented as *generic collections*. For more on generic types and collections, see [Generics](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/22_Generics.md). - >注意 >在后台,Swift 数组和字典类型都是由*泛型集合*实现的。更多关于泛型类型和集合的介绍,请参见 [Generics](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/22_Generics.md)。 - ‌ -## Mutability of Collections -## 集合的易变性 -Arrays and dictionaries store multiple values together in a single collection. If you create an array or a dictionary and assign it to a variable, the collection that is created will be *mutable*. This means that you can change (or *mutate*) the size of the collection after it is created by adding more items to the collection, or by removing existing items from the ones it already contains. Conversely, if you assign an array or a dictionary to a constant, that array or dictionary is *immutable*, and its size cannot be changed. +## 集合的易变性 数组和字典在单个集合中存储了多个数据。如果我们创建一个数组或字典并把它声明为变量,这个创建出来的集合是*易变的*。这意味着我们可以改变集合的大小,在集合中添加更多的数据项,或从中移除已有的数据项。相反的,如果把一个数组或字典声明为常量,则这个数组或字典是*不可变*的,它的大小是不会变化的。 -For dictionaries, immutability also means that you cannot replace the value for an existing key in the dictionary. An immutable dictionary’s contents cannot be changed once they are set. - 对字典来说,不可变还意味着我们不能替换字典中某个已有的键对应的值。一个不可变字典的内容一旦设置就不能再改变。 -Immutability has a slightly different meaning for arrays, however. You are still not allowed to perform any action that has the potential to change the size of an immutable array, but you *are* allowed to set a new value for an existing index in the array. This enables Swift’s `Array` type to provide optimal performance for array operations when the size of an array is fixed. - 对数组来说,不可变的意义稍有不同。我们仍不允许改变不可变数组的大小,但是,我们*被*允许改变数组中某个已有索引对应的值。这使得 Swift 的 `Array` 类型可以在操作固定大小的数组时提供最佳性能。 -The mutability behavior of Swift’s `Array` type also affects how array instances are assigned and modified. For more information, see [Assignment and Copy Behavior for Collection Types](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/09_Classes_and_Structures.md#assignment-and-copy-behavior-for-collection-types). - Swift 的 `Array` 类型的可变性还会影响数组实例如何赋值和修改。更多介绍请参见 [集合类型的声明和复制](https://github.com/trans4fun/The-Swift-Programming-Language/blob/master/src/chapter2/09_Classes_and_Structures.md#%E9%9B%86%E5%90%88%E7%9A%84%E8%B5%8B%E5%80%BC%E4%B8%8E%E6%8B%B7%E8%B4%9D)。 ->NOTE - ->It is good practice to create immutable collections in all cases where the collection’s size does not need to change. Doing so enables the Swift compiler to optimize the performance of the collections you create. - >注意 >当集合的大小不需要改变时,创建一个不可变的集合是比较好的做法。这样做,Swift 编译器会优化创建的集合性能。 From 533539b273a856e5f6f6d7366670baf5fe5eaecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=9C=E8=88=9F?= Date: Sun, 13 Jul 2014 21:34:54 +0800 Subject: [PATCH 259/261] Revert "merge upsteam/master" This reverts commit 06306118d57fd9f6f859226e6a752858f82c7108. --- .gitignore | 1 + src/chapter1/01_About_Swift.md | 38 + src/chapter1/02_A_Swift_Tour.md | 211 ++++ src/chapter2/09_Classes_and_Structures.md | 662 +++++++++++ src/chapter2/10_Properties.md | 666 ++++++++++++ src/chapter2/14_Initialization.md | 895 +++++++++++++++ src/chapter2/15_Deinitialization.md | 170 +++ src/chapter2/17_Optional_Chaining.md | 300 +++++ src/chapter2/19_Nested_Types.md | 180 +++ src/chapter2/20_Extensions.md | 397 +++++++ src/chapter2/21_Protocols.md | 943 ++++++++++++++++ src/chapter3/05_Statements.md | 577 ++++++++++ src/chapter3/06_Declarations.md | 1208 +++++++++++++++++++++ src/chapter3/07_Attributes.md | 208 ++++ 14 files changed, 6456 insertions(+) create mode 100644 .gitignore create mode 100644 src/chapter1/01_About_Swift.md create mode 100644 src/chapter1/02_A_Swift_Tour.md create mode 100644 src/chapter2/09_Classes_and_Structures.md create mode 100644 src/chapter2/10_Properties.md create mode 100644 src/chapter2/14_Initialization.md create mode 100644 src/chapter2/15_Deinitialization.md create mode 100644 src/chapter2/17_Optional_Chaining.md create mode 100644 src/chapter2/19_Nested_Types.md create mode 100644 src/chapter2/20_Extensions.md create mode 100644 src/chapter2/21_Protocols.md create mode 100644 src/chapter3/05_Statements.md create mode 100644 src/chapter3/06_Declarations.md create mode 100644 src/chapter3/07_Attributes.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/src/chapter1/01_About_Swift.md b/src/chapter1/01_About_Swift.md new file mode 100644 index 0000000..098b988 --- /dev/null +++ b/src/chapter1/01_About_Swift.md @@ -0,0 +1,38 @@ +# About Swift +# Swift介绍 + +Swift is a new programming language for iOS and OS X apps that builds on the best of C and Objective-C, without the constraints of C compatibility.Swift adopts safe programming patterns and adds modern features to make programming easier, more flexible, and more fun.Swift’s clean slate, backed by the mature and much-loved Cocoa and Cocoa Touch frameworks, is an opportunity to reimagine how software development works. + +Swift是一款为iOS和OS X 应用打造的新式编程语言,它吸取了C语言和Objective-C语言的精华,同时完美兼容C语言。Swift采用了安全编程模式,增加了许多现代语言的特性,使编程工作更加简单,灵活,有趣。一款重新设计的语言,再加上成熟并且深受欢迎的Cocoa框架和Cocoa Touch框架,Swift为软件开发工作带来了无限遐想。 + + +Swift has been years in the making. Apple laid the foundation for Swift by advancing our existing compiler, debugger, and framework infrastructure. We simplified memory management with Automatic Reference Counting (ARC). Our framework stack, built on the solid base of Foundation and Cocoa, has been modernized and standardized throughout. Objective-C itself has evolved to support blocks, collection literals, and modules, enabling framework adoption of modern language technologies without disruption. Thanks to this groundwork, we can now +introduce a new language for the future of Apple software development. + +Swift已经持续研发多年了。苹果公司通过多年对已有编译器,调试器和基础架构的改进经验为Swift奠定了基础。我们通过ARC(Automatic Reference Counting,自动引用计数)简化内存管理。以Cocoa框架作为坚实的基础,我们的框架堆栈已然在各方面都更加的现代化和标准化了。Objective-C在发展过程中支持了块,字面量集合,模块,使框架与现代语言的衔接不至于中断。多亏了它,使我们能够向大家推荐为苹果软件开发的未来而生的编程语言----Swift。 + + +Swift feels familiar to Objective-C developers. It adopts the readability of Objective-C’s named parameters and the power of Objective-C’s dynamic object model. It provides seamless access to existing Cocoa frameworks and mix-and-match interoperability with Objective-C code. Building from this common ground, Swift introduces many new features and unifies the procedural and object-oriented portions of the language. + +Swift对于Object-C开发人员非常友好。它采用了Objective-C的参数命名和动态对象模型。它与现有的Cocoa框架无缝对接并与Objective-C实现了Mix-and-Match(混入内嵌式)互通。基于此,Swift还引入了一些新特性并结合了语言的面向过程和面向对象的功能。 + + +Swift is friendly to new programmers. It is the first industrial-quality systems programming language that is as expressive and enjoyable as a scripting language. It supports playgrounds, an innovative feature that allows programmers to experiment with Swift code and see the results immediately, without the overhead of building and running an app. + +Swift对于新手也是友好的,它是工业级品质的系统编程语言,而且像脚本语言一般生动有趣。它提供了Playground,允许程序开发人员实时预览效果,无需构建和运行整个app。 + + +Swift combines the best in modern language thinking with wisdom from the wider Apple engineering culture. The compiler is optimized for performance, and the language is optimized for development, without compromising on either. It’s designed to scale from “hello, world” to an entire operating system. All this makes Swift a sound future investment for developers and for Apple. + +Swift融入了博大的苹果的工程文化中富有智慧的现代语言思维。从“hello,world”开始到整个语言系统,编译器优化了性能,语言提升了开发效率,无需任何妥协,这一切,让Swift成为了开发者与Apple未来实用的选择。 + + +Swift is a fantastic way to write iOS and OS X apps, and will continue to evolve with new features and capabilities. Our goals for Swift are ambitious. We can’t wait to see what you create with it.” + +Swift是编写iOS和OS X应用的绝美方式,我们会持续引入新特性和新功能。我们对Swift充满了信息。我们已经迫不及待的想看到你用它来做点什么。 + +   +   +   +   + diff --git a/src/chapter1/02_A_Swift_Tour.md b/src/chapter1/02_A_Swift_Tour.md new file mode 100644 index 0000000..b2d2ede --- /dev/null +++ b/src/chapter1/02_A_Swift_Tour.md @@ -0,0 +1,211 @@ +A Swift Tour + +Tradition suggests that the first program in a new language should print the words “Hello, world” on the screen. In Swift, this can be done in a single line: +通常学习一门新语言都会输出一行“Hello,world”.在swift里只需要一行代码 + +“If you have written code in C or Objective-C, this syntax looks familiar to you—in Swift, this line of code is a complete program. You don’t need to import a separate library for functionality like input/output or string handling. Code written at global scope is used as the entry point for the program, so you don’t need a main function. You also don’t need to write semicolons at the end of every statement.” +如果你之前写过C或者Objective-C的代码,你会很熟悉这种语法。在swift里,这一行代码就是一个完整的程序,你不需要再去引入一个完成类似输入输出,字符串处理等操作的类库。在全局范围内编写的代码就是程序的入口,因此你不再需要main函数了,也不需要在每一条语句末尾写分号。 + +“This tour gives you enough information to start writing code in Swift by showing you how to accomplish a variety of programming tasks. Don’t worry if you don’t understand something—everything introduced in this tour is explained in detail in the rest of this book.” +这篇文章会充分向你展示如何用swift完成各种编程任务。不用担心一些细节不太理解,在这本书之后的章节中会详细的为你介绍。 + + +“Simple Values +Use let to make a constant and var to make a variable. The value of a constant doesn’t need to be known at compile time, but you must assign it a value exactly once. This means you can use constants to name a value that you determine once but use in many places.” +简单值 +使用let声明常量,var声明变量。在编译的时候不需要知道常量的值,但是你只能给常量显式地赋值一次。也就是说你可以给常量赋一次值然后在其他一些地方来使用。 + +“A constant or variable must have the same type as the value you want to assign to it. However, you don’t always have to write the type explicitly. Providing a value when you create a constant or variable lets the compiler infer its type. In the example above, the compiler infers that myVariable is an integer because its initial value is a integer.” +不管是常量还是变量必须与其所赋的值类型保持一致。你不一定要把常量或者变量的类型显式地写出来。因为编译器可以根据值来自动推断常量或者变量的类型。如上面的例子,编译器根据myVariable的初始值类型推断出它是一个整型变量。 + +“If the initial value doesn’t provide enough information (or if there is no initial value), specify the type by writing it after the variable, separated by a colon.” +如果初始值没有提供足够的信息或者没有初始值,可以在变量后面写上它的类型,变量和类型用冒号隔开。 + +“Values are never implicitly converted to another type. If you need to convert a value to a different type, explicitly make an instance of the desired type.” +值的类型不会自动转换,如果你需要把一个值转换成另外一种类型,需要强制转换。 + +“There’s an even simpler way to include values in strings: Write the value in parentheses, and write a backslash (\) before the parentheses. For example:” +有一种更简单的把值转换成字符串的方法:把值写在括号里,然后在括号前加一个反斜杠。例如: + +“Create arrays and dictionaries using brackets ([]), and access their elements by writing the index or key in brackets.” +用中括号创建数组和字典,通过中括号里的索引和键来访问集合中的元素。 + +“To create an empty array or dictionary, use the initializer syntax.” +用下面的初始化语法来创建一个空的数组或字典 + +“If type information can be inferred, you can write an empty array as [] and an empty dictionary as [:]—for example, when you set a new value for a variable or pass an argument to a function.” +如果类型可以被推断出来,你可以用[]来创建一个空数组,用[:]来创建一个空字典。例如,当你给一个变量赋值或者给一个函数传参 + +“Control Flow +Use if and switch to make conditionals, and use for-in, for, while, and do-while to make loops. Parentheses around the condition or loop variable are optional. Braces around the body are required.” +流控制 +使用if和switch来进行条件控制,使用for-in、for、while和do-while来进行循环控制。条件和循环变量外面的括号可以省略,但是语句体的大括号是必须的。 + +“In an if statement, the conditional must be a Boolean expression—this means that code such as if score { ... } is an error, not an implicit comparison to zero.” +在if语句里,条件必须是一个Boolean表达式。所以if score { ... }这种写法是错误的,score不会隐式地和0来比较。 + +“You can use if and let together to work with values that might be missing. These values are represented as optionals. An optional value either contains a value or contains nil to indicate that the value is missing. Write a question mark (?) after the type of a value to mark the value as optional.” +你可以一起使用if和let来处理值缺失的情况。有些变量的值是可选的。一个可选的值可能是一个具体的值或者是nil,表示值缺失。在类型后面加一个问号来标记这个变量的值是可选的。 + +“If the optional value is nil, the conditional is false and the code in braces is skipped. Otherwise, the optional value is unwrapped and assigned to the constant after let, which makes the unwrapped value available inside the block of code.” +如果变量的可选值是nil,则判断条件为false,大括号中的代码被略过。如果不为nil,可选值会赋值给let后的常量,并且该常量可以在代码块中使用。 + +“Switches support any kind of data and a wide variety of comparison operations—they aren’t limited to integers and tests for equality.” +Switch支持各种类型的数据以及大量的比较操作-它们不仅限于整数和比较大小。 + +“After executing the code inside the switch case that matched, the program exits from the switch statement. Execution doesn’t continue to the next case, so there is no need to explicitly break out of the switch at the end of each case’s code.” +与switch的case相匹配的代码执行完之后,程序不会继续执行下一个case中的代码,而是会自动退出switch语句,所以不需要在每一个case的代码后面显式的调用break。 + +“You use for-in to iterate over items in a dictionary by providing a pair of names to use for each key-value pair.” +你可以使用for-in来遍历字典,用两个变量来表示每对键值。 + +“Use while to repeat a block of code until a condition changes. The condition of a loop can be at the end instead, ensuring that the loop is run at least once.” +使用while来重复执行一段代码直到条件改变。循环条件也可也在末尾,以保证循环至少可执行一次。 + +“You can keep an index in a loop—either by using .. to make a range of indexes or by writing an explicit initialization, condition, and increment. These two loops do the same thing:” +在循环中可以使用..来表示索引范围或者使用传统的方式。两者是等价的。 + +“Use .. to make a range that omits its upper value, and use ... to make a range that includes both values.” +使用..会忽略范围中的上限值,使用...则不会忽略。 + +“Functions and Closures +Use func to declare a function. Call a function by following its name with a list of arguments in parentheses. Use -> to separate the parameter names and types from the function’s return type.” +函数和闭包 +使用func来声明一个函数。在函数名后的括号里加入参数来调用函数。使用->分隔开函数的参数和函数的返回值类型。 + +“Use a tuple to return multiple values from a function.” +使用元组来返回一组值。 + +“Functions can also take a variable number of arguments, collecting them into an array.” +函数可以有一组可变个数的参数,由array来表示。 + +“Functions can be nested. Nested functions have access to variables that were declared in the outer function. You can use nested functions to organize the code in a function that is long or complex.” +函数可以嵌套,被嵌套的函数可以访问外部函数中声明的变量。你可以使用嵌套函数来重构一段很长很复杂的函数。 + +“Functions are a first-class type. This means that a function can return another function as its value.” +函数是first-class类型,因此它可以作为另一个函数的返回值。 + +“A function can take another function as one of its arguments.” +函数可以作为另一个函数的参数。 + +“Functions are actually a special case of closures. You can write a closure without a name by surrounding code with braces ({}). Use in to separate the arguments and return type from the body.” +函数实际上是一个特殊的闭包。你可以把一段代码写在大括号{}中来表示一个匿名闭包,参数和返回类型与闭包体之间用in来分隔。 + +“You have several options for writing closures more concisely. When a closure’s type is already known, such as the callback for a delegate, you can omit the type of its parameters, its return type, or both. Single statement closures implicitly return the value of their only statement.” +有一些简洁表示闭包的方式。当一个闭包的类型已知,例如作为委托的回调,可以省略它的参数和返回类型。单个语句闭包会把它语句的值当做结果返回。 + +“You can refer to parameters by number instead of by name—this approach is especially useful in very short closures. A closure passed as the last argument to a function can appear immediately after the parentheses.” +你可以使用参数位置替代参数名来引用参数-这个方法特别是在很短的闭包里很好用。闭包作为函数最后一个参数的时候,可以直接跟在小括号后面。 + +“Objects and Classes +Use class followed by the class’s name to create a class. A property declaration in a class is written the same way as a constant or variable declaration, except that it is in the ” +“context of a class. Likewise, method and function declarations are written the same way.” +对象和类 +使用class和类名来创建一个类。类中的属性声明是和常量或者变量的声明方式一样的,唯一的区别是属性声明是在类的上下文之中的。同样的,方法和函数的声明也是一样的。 + +“Create an instance of a class by putting parentheses after the class name. Use dot syntax to access the properties and methods of the instance.” +类名后面跟小括号来创建一个类的实例。使用点语法来访问该实例的属性和方法。 + +“This version of the Shape class is missing something important: an initializer to set up the class when an instance is created. Use init to create one.” +这个版本的Shape类缺少了一个重要的东西:类实例化时候的一个构造器。使用init来创造一个构造器。 + +“Notice how self is used to distinguish the name property from the name argument to the initializer. The arguments to the initializer are passed like a function call when you create an instance of the class. Every property needs a value assigned—either in its declaration (as with numberOfSides) or in the initializer (as with name).” +注意用self来区分name属性和传递给构造器的name参数。像函数调用一样,把参数传递给构造器来创建一个类实例。每一个属性都需要赋值,在属性的声明中(如numberOfSides),或者在构造器中(如name) + +“Use deinit to create a deinitializer if you need to perform some cleanup before the object is deallocated.” +“Subclasses include their superclass name after their class name, separated by a colon. There is no requirement for classes to subclass any standard root class, so you can include or omit a superclass as needed.” +使用deinit来创建一个析构器来执行对象销毁前的清理工作。 +定义子类的时候是在类名后加上父类的名字,中间用冒号隔开。因为类不需要继承任何标准的基类,所以你可以省略父类。 + +“Methods on a subclass that override the superclass’s implementation are marked with override—overriding a method by accident, without override, is detected by the compiler as an error. The compiler also detects methods with override that don’t actually override any method in the superclass.” +子类方法重写父类方法的时候标记为override-这是为了防止意外的重写,如果没有override关键字,编译器会报错。编译器同样会检测在子类标记为override的方法是否真的重写了父类的某个方法。 + +“In addition to simple properties that are stored, properties can have a getter and a setter.” +属性也可以有getter和setter方法。 + +“In the setter for perimeter, the new value has the implicit name newValue. You can provide an explicit name in parentheses after set.” +在setter方法中,新的属性值被隐式地命名为newValue。你可以在set后的括号里显式地给属性值命名。 + +“Notice that the initializer for the EquilateralTriangle class has three different steps: +Setting the value of properties that the subclass declares. +Calling the superclass’s initializer. +Changing the value of properties defined by the ” +“superclass. Any additional setup work that uses methods, getters, or setters can also be done at this point.” +注意创建EquilateralTriangle类的构造器包含三个不同的步骤。 +1.在子类声明的时候设置属性值。 +2.调用父类的构造器。 +3.改变定义在父类中的属性值,还有调用方法,getter和setter方法都可以在这个步骤完成。 + +“If you don’t need to compute the property but still need to provide code that is run before and after setting a new value, use willSet and didSet. For example, the class below ensures that the side length of its triangle is always the same as the side length of its square.” +如果你不需要计算属性,但仍需要在给属性设置新值的前后运行一些代码,使用willSet和didSet。例如,下面的类会确保三角形的边长和方形的边长相等。 + +“Methods on classes have one important difference from functions. Parameter names in functions are used only within the function, but parameters names in methods are also used when you call the method (except for the first parameter). By default, a method has the same name for its parameters when you call it and within the method itself. You can specify a second name, which is used inside the method.” +类中的方法和函数有一个很重要的区别。函数中的参数只会在函数内部使用,但是方法中的参数还可以在方法调用的时候使用(除了第一个参数)。默认情况下,方法调用时候的参数名和方法内部使用的参数名保持一致。在方法内部使用的时候你也可以定义一个不同的名字。 + +“When working with optional values, you can write ? before operations like methods, properties, and subscripting. If the value before the ? is nil, everything after the ? is ignored and the value of the whole expression is nil. Otherwise, the optional value is unwrapped, and everything after the ? acts on the unwrapped value. In both cases, the value of the whole expression is an optional value.” +处理可选值的时候,你可以在?后面跟上方法,属性,子脚本等操作。如果?之前的值是nil,?后面的代码会被忽略,然后整个表达式的值返回nil。否则,?之后的代码会执行。在这两种情况下,整个表达式就是一个可选值。 + +“Enumerations and Structures +Use enum to create an enumeration. Like classes and all other named types, enumerations can have methods associated with them.” +枚举和结构体 +使用enum来创建一个枚举。像类和其他命名类型一样,枚举可以有方法。 + +“In the example above, the raw value type of the enumeration is Int, so you only have to specify the first raw value. The rest of the raw values are assigned in order. You can also use strings or floating-point numbers as the raw type of an enumeration.” +在上面的例子中,枚举的原始值类型是Int,所以你只需要指定第一个值,其余的会按照顺序进行赋值。你同样可以使用字符串和浮点数作为枚举的原始类型。 + +“Use the toRaw and fromRaw functions to convert between the raw value and the enumeration value.” +使用toRaw和fromRaw这两个函数用于在原始值和枚举值之间转换。 + +“The member values of an enumeration are actual values, not just another way of writing their raw values. In fact, in cases where there isn’t a meaningful raw value, you don’t have to provide one.” +枚举的成员值是实际值,并不是原始值的另一种表示方式。实际上,如果原始值没有意义,你就不需要提供。 + +“Notice the two ways that the Hearts member of the ” +“enumeration is referred to above: When assigning a value to the hearts constant, the enumeration member Suit.Hearts is referred to by its full name because the constant doesn’t have an explicit type specified. Inside the switch, the enumeration is referred to by the abbreviated form .Hearts because the value of self is already known to be a suit. You can use the abbreviated form anytime the value’s type is already known.” +注意,有两种方式可以引用Hearts成员:当给hearts常量赋值时,通过Suit.Hearts全名来引用枚举成员,因为常量没有显式指定其类型。在switch语句内部,因为已知self是一个suit,所以可以通过.Hearts这种简写的方式来引用枚举。在已知值类型的情况下你都可以采用简写的方式。 + +“Use struct to create a structure. Structures support many of the same behaviors as classes, including methods and initializers. One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.” +使用struct来创建一个结构体。结构体支持很多和类同样的操作,包括方法和构造器。两者之间最重要的差别是结构体在代码中传递采用的是拷贝的方式,但是类采用的是传递引用的方式。 + +“An instance of an enumeration member can have values associated with the instance. Instances of the same enumeration member can have different values associated with them. You provide the associated values when you create the instance. Associated values and raw values are different: The raw value of an enumeration member is the ”“same for all of its instances, and you provide the raw value when you define the enumeration.” +一个枚举成员的实例可以有对应的实例值。相同枚举成员的实例可以有不同的实例值。当你创建一个实例的时候提供对应的实例值。实例值和原始值是不同的:枚举成员所有的实例的原始值都是相同的,而且你是在定义枚举的时候提供原始值。 + +“For example, consider the case of requesting the sunrise and sunset time from a server. The server either responds with the information or it responds with some error information.” +例如,考虑从服务端获取日出和日落的时间。服务端要么返回正常信息,要么返回错误信息。 + +“Notice how the sunrise and sunset times are extracted from the ServerResponse value as part of matching the value against the switch cases.” +注意,如何从ServerResponse中提去日出和日落时间。 + +Protocols and Extensions +“Use protocol to declare a protocol.” +协议和扩展 +使用protocol来声明一个协议 + +“Classes, enumerations, and structs can all adopt protocols.” +类,枚举,结构体都可以遵循协议 + +“Notice the use of the mutating keyword in the declaration of SimpleStructure to mark a method that modifies the structure. The declaration of SimpleClass doesn’t need any of its methods marked as mutating because methods on a class can always modify the class.” +注意,在SimpleStructure的声明中使用关键字mutating来标记一个会修改结构体的方法。在SimpleClass的声明中不需要用关键字mutating来标记类中的方法,因为类中的方法总是可以修改类。 + +“Use extension to add functionality to an existing type, such as new methods and computed properties. You can use an extension to add protocol conformance to a type that is declared elsewhere, or even to a type that you imported from a library or framework.” +使用扩展给一个已存在的类型增加功能,例如一些新方法和计算过的属性。你可以使用扩展给一个在别处声明的类型增加协议,甚至是给一个从库和框架中引入的类型增加协议。 + +“You can use a protocol name just like any other named type—for example, to create a collection of objects that have different types but that all conform to a single protocol. When you work with values whose type is a protocol type, methods outside the protocol definition are not available.” +你可以像使用其他命名类型一样使用协议名-例如,创建一个具有不同类型但是遵循同一协议的对象集合。当你处理一些协议类型的值的时候,协议定义之外的方法是不可用的。 + +“Even though the variable protocolValue has a runtime type of SimpleClass, the compiler treats it as the given type of ExampleProtocol. This means that you can’t accidentally access methods or properties that the class implements in addition to its protocol conformance.” +虽然变量protocolValue具有一个运行时类型SimpleClass,编译器是把它当做一个协议类型来处理的。这意味着你不能够访问协议没有指定的方法和属性。 + +Generics +“Write a name inside angle brackets to make a generic function or type.” +泛型 +在尖括号中写一个名字来创建一个泛型函数或类型。 + +“You can make generic forms of functions and methods, as well as classes, enumerations, and structures.” +你可以使用泛型来创建函数,方法,类,枚举和结构体。 + +“Use where after the type name to specify a list of ” +“requirements—for example, to require the type to implement a protocol, to require two types to be the same, or to require a class to have a particular superclass.” +在类型名之后使用where来指定一些条件-例如,要求类型遵循某个协议,要求两个类型相同,或者要求一个类有一个特定的父类。 + +“In the simple cases, you can omit where and simply write the protocol or class name after a colon. Writing is the same as writing .” +在简单情况下,你可以省略where,然后在协议和类名之间用冒号隔开。 是等价的。 diff --git a/src/chapter2/09_Classes_and_Structures.md b/src/chapter2/09_Classes_and_Structures.md new file mode 100644 index 0000000..c3a543a --- /dev/null +++ b/src/chapter2/09_Classes_and_Structures.md @@ -0,0 +1,662 @@ +## Classes and Structures +## 类与结构体 + +*Classes* and *structures* are general-purpose, flexible constructs that become the building blocks of your program’s code. You define properties and methods to add functionality to your classes and structures by using exactly the same syntax as for constants, variables, and functions.” + +*类*和*结构体*是通用的、灵活的结构,是您搭建代码的基石。您可以使用和定义常量、变量或函数相同的句法,为类添加属性和方法以增加新的功能。 + +Unlike other programming languages, Swift does not require you to create separate interface and implementation files for custom classes and structures. In Swift, you define a class or a structure in a single file, and the external interface to that class or structure is automatically made available for other code to use. + +与其他编程语言不同,Swift并不强制要求分隔自定义类或结构体的头文件和实现文件。在Swift中,你只需将类或结构体定义在一个文件中,这个类或结构体的外部接口就自动能被其他代码使用。 + +``` +NOTE + +An instance of a class is traditionally known as an object. However, Swift classes and structures are much closer in functionality than in other languages, and much of this chapter describes functionality that can apply to instances of either a class or a structure type. Because of this, the more general term instance is used. +``` + +``` +注意 +类的实例通常被当作为一个对象。但与其他语言相比,Swift中的类和结构体从功能上来说更为相似。本章中介绍的大部分功能,可以适用于任何一个类或者结构体的实例。因此我们将使用一个更加宽泛的词语--实例(instance)来描述类和结构体。 +``` + +### Comparing Classes and Structures +### 比较类和结构体 +Classes and structures in Swift have many things in common. Both can: + +* Define properties to store values +* Define methods to provide functionality +* Define subscripts to provide access to their values using subscript syntax +* Define initializers to set up their initial state +* Be extended to expand their functionality beyond a default implementation +* Conform to protocols to provide standard functionality of a certain kind + +For more information, see [Properties](), [Methods](), [Subscripts](), [Initialization](), [Extensions](), and [Protocols](). + + +在Swift中类和结构体有许多相同之处,它们都有如下功能: + +* 能定义属性以便存储数据 +* 能定义方法以便提供功能 +* ~~定义了下标以便使用下标语法来访问实例的值~~ +* 能定义设定初始状态的初始化方法 +* 能被扩展,使其有默认实现之外的功能 +* 遵从协议(protocol)规则,以便提供~~协议所规定类型的标准功能~~ + +欲了解更多信息,请参见[属性](),[方法](),[下标](),[构造过程](),[扩展]()和[协议]()章节。 + +Classes have additional capabilities that structures do not: + +* Inheritance enables one class to inherit the characteristics of another. +* Type casting enables you to check and interpret the type of a class instance at runtime. +* Deinitializers enable an instance of a class to free up any resources it has assigned. +* Reference counting allows more than one reference to a class instance. + +For more information, see [Inheritance](), [Type Casting](), [Initialization](), and [Automatic Reference Counting](). + +不过类也有一些结构体没有的额外功能: + +* 继承使得一个类能继承来自另一个类的特性。 +* 类型转换可以在运行时检查和解析一个类的实例的类型。 +* 析构方法让类的实例被~~指派给了其他内存~~时能够释放自己的资源。 +* 引用计数允许一个类的实例被多处引用。 + +欲了解更多信息,请参见[继承](),[类型转换](),[构造过程](),[自动引用计数]()章节。 + +``` +NOTE + +Structures are always copied when they are passed around in your code, and do not use reference counting. +``` + +``` +注意: +结构体在代码中被传递时始终是传值,不会涉及到引用计数 + +``` + +‌ +### Definition Syntax +### 定义语法 + +Classes and structures have a similar definition syntax. You introduce classes with the `class` keyword and structures with the `struct` keyword. Both place their entire definition within a pair of braces: + +定义类和结构体的语法相似。定义类以关键词`class`开头,而定义结构体以关键词`struct`开头。类和结构体的所有定义都写在一对大括号内: + +``` +class SomeClass { + // class definition goes here +} +struct SomeStructure { + // structure definition goes here +} +``` + + + +``` +NOTE + +Whenever you define a new class or structure, you effectively define a brand new Swift type. Give types UpperCamelCase names (such as SomeClass and SomeStructure here) to match the capitalization of standard Swift types (such as String, Int, and Bool). Conversely, always give properties and methods lowerCamelCase names (such as frameRate and incrementCount) to differentiate them from type names. +``` + + +``` +注意: + +当你定义一个新的类或者结构体时,你实际上定义了一种新的Swift类型。为了和Swift标准类型(像String,Int,Bool)保持一致,请使用首字母大写的驼峰命名法(例如SomeClass或者SomeStructure)。相反的,为了和类型名区分,属性和方法名建议使用小写驼峰命名法(如frameRate或者incrementCount)。 +``` + +Here’s an example of a structure definition and a class definition: + +下方给出了结构体和类定义的例子: + + +``` +struct Resolution { + var width = 0 + var height = 0 +} +class VideoMode { + var resolution = Resolution() + var interlaced = false + var frameRate = 0.0 + var name: String? +} +``` + +The example above defines a new structure called `Resolution`, to describe a pixel-based display resolution. This structure has two stored properties called `width` and `height`. Stored properties are constants or variables that are bundled up and stored as part of the class or structure. These two properties are inferred to be of type `Int` by setting them to an initial integer value of 0. + +例子定义了一个名叫`Resolution`的新结构体,用来描述一个基于像素的显示方案。这个结构体有两个~~属性~~:`宽`和`高`。~~属性~~是捆绑存储在类和结构体中的变量或常量。这两个属性的类型将被编译器推断为`Int`,并赋予初始值0。 + +The example above also defines a new class called `VideoMode`, to describe a specific video mode for video display. This class has four variable stored properties. The first, `resolution`, is initialized with a new `Resolution` structure instance, which infers a property type of `Resolution`. For the other three properties, new `VideoMode` instances will be initialized with an `interlaced` setting of `false` (meaning “non-interlaced video”), a playback frame rate of `0.0`, and an optional `String` value called `name`. The `name` property is automatically given a default value of `nil`, or “no `name` value”, because it is of an optional type. + +例子中也定义了一个名叫`VideoMode`的新类,用来表示视频显示的模式。VideoMode类中有四个属性。第一个是`resolution`,它在这里被初始化为一个新的`Resolution`结构体实例,而编译器将自动推断分辨率的类型为`Resolution`。除此之外新的`VideoMode`实例还将初始化三个属性,默认为`false`的`interlaced`(意味着这是个“不交错的视频”),默认值为`0.0`表示播放帧速率的`frameRate`,以及一个值可选类型为`String`的`name`。属性`name`将自动赋值为`nil`,或者说`name`无值,因为它的值是可选的。 + +### Class and Structure Instances +### 类和结构体的实例 + +The `Resolution` structure definition and the `VideoMode` class definition only describe what a `Resolution` or `VideoMode` will look like. They themselves do not describe a specific resolution or video mode. To do that, you need to create an instance of the structure or class. + +结构体`Resolution`和类`VideoMode`的定义只是告诉你`Resolution`和`VideoMode`含有什么内容。但他们本身并不描述一个特定的分辨率或者视频模式。要做到这一点,我们要生成一个他们的实例。 + +The syntax for creating instances is very similar for both structures and classes: + +生成结构体实例和生成类实例的语法非常类似: + +``` +let someResolution = Resolution() +let someVideoMode = VideoMode() +``` + +Structures and classes both use initializer syntax for new instances. The simplest form of initializer syntax uses the type name of the class or structure followed by empty parentheses, such as `Resolution()` or `VideoMode()`. This creates a new instance of the class or structure, with any properties initialized to their default values. Class and structure initialization is described in more detail in [Initialization](). + +结构体和类都是用初始化语法来生成新的实例。初始化语法最简单的形式是结构体或类的类型名后加上空括号,例如`Resolution()`和`VideoMode()`。这将创建一个所有的属性都是默认值的结构体或类。类和结构体的初始化在[构造过程]()章节中有更详细的说明。 + +### Accessing Properties +### 属性的访问 +You can access the properties of an instance using *dot syntax*. In dot syntax, you write the property name immediately after the instance name, separated by a period (.), without any spaces: + +你可以使用*点语法*访问实例的属性。使用点语法时,属性名将紧跟在实例名之后,中间以句号(.)隔开: + +``` +println("The width of someResolution is \(someResolution.width)") +// prints "The width of someResolution is 0 +``` + +In this example, `someResolution.width` refers to the `width` property of `someResolution`, and returns its default initial value of `0`. + +在这个例子中,`someResolution.width`表示`someResolution`的`width`属性,且返回默认初始值`0`。 + +You can drill down into sub-properties, such as the `width` property in the `resolution` property of a `VideoMode`: + +你可以继续使用点语法来访问属性的属性,例如`VideoMode`中`resolution`的属性`width`: + +``` +println("The width of someVideoMode is \(someVideoMode.resolution.width)") +// prints "The width of someVideoMode is 0" +``` + +You can also use dot syntax to assign a new value to a variable property: +我们还可以使用点语法来为属性变量赋值: + +``` +someVideoMode.resolution.width = 1280 +println("The width of someVideoMode is now \(someVideoMode.resolution.width)") +// prints "The width of someVideoMode is now 1280" +``` + +``` +NOTE + +Unlike Objective-C, Swift enables you to set sub-properties of a structure property directly. In the last example above, the width property of the resolution property of someVideoMode is set directly, without your needing to set the entire resolution property to a new value. +``` +``` +注意: + +与Objective-C不同,Swift允许直接为结构体的属性的子属性赋值。在上方的例子中,someVideoMode中属性resolution的子属性width被直接赋值了,不再需要给整个resolution属性赋予新值。 +``` +‌ +### Memberwise Initializers for Structure Types +### 结构体带参数的初始化方法 + +All structures have an automatically-generated memberwise initializer, which you can use to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name: + +所有结构体都有一个自动生成的带参数的初始化方法,用于新结构体实例成员属性的初始化。新实例属性的初值会通过变量名传递到带参数的初始化方法里: + +``` +let vga = Resolution(width: 640, height: 480) +``` + +Unlike structures, class instances do not receive a default memberwise initializer. Initializers are described in more detail in [Initialization](). +与结构体不同,类市里没有默认的带参数的初始化方法。对初始化方法的详细说明见[构造过程]()章节。 + +‌ +### Structures and Enumerations Are Value Types +### 结构体和枚举都是值类型 + +A value *type* is a type that is copied when it is assigned to a variable or constant, or when it is passed to a function. +值*类型*的变量在赋值给一个变量、常量或作为参数传给函数时,传递的是该变量值的拷贝。 + +You’ve actually been using value types extensively throughout the previous chapters. In fact, all of the basic types in Swift—integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types, and are implemented as structures behind the scenes. + +实际上在前面章节我们已经广泛使用了值类型。事实上Swift中几乎所有的基本类型---如整数、浮点数、布尔值、字符串、数组和字典,都是值类型,并在底层都以结构体的方式来实现。 + +All structures and enumerations are value types in Swift. This means that any structure and enumeration instances you create—and any value types they have as properties—are always copied when they are passed around in your code. + +Swift中的所有结构体和枚举都是值类型。这意味着你创建的任何一个结构体或枚举的实例,以及他们的属性在代码中被传递的时候都会被复制。 + +Consider this example, which uses the `Resolution` structure from the previous example: + +让我们来看看这个例子,它使用了先前例子中定义的`Resolution`: + +``` +let hd = Resolution(width: 1920, height: 1080) +var cinema = hd +``` + +This example declares a constant called `hd` and sets it to a `Resolution` instance initialized with the width and height of full HD video (`1920` pixels wide by `1080` pixels high). + +例子中声明了一个名叫`hd`的常量,并将它初始化为全高清视频分辨率(宽`1920`长`1080`)的`Resolution`实例。 + +It then declares a variable called `cinema` and sets it to the current value of `hd`. Because `Resolution` is a structure, a copy of the existing instance is made, and this new copy is assigned to `cinema`. Even though `hd` and `cinema` now have the same width and height, they are two completely different instances behind the scenes. +然后例子中声明了一个变量`cinema`,将`hd`的当前值赋给了它。由于`Resolution`是结构体,赋值操作会生成一个新的实例并传递给`cinema`。因此虽然`hd`和`cinema`有相同的宽高,但它们实际上仍是完全不同的实例。 + +Next, the `width` property of `cinema` is amended to be the width of the slightly-wider 2K standard used for digital cinema projection (`2048` pixels wide and `1080` pixels high): + +接下来,将`cinema`的`width`属性改为数字电影中2K宽屏的标准宽度(宽`2048`像素高`1080`像素): + +``` +cinema.width = 2048 +``` + +Checking the `width` property of `cinema` shows that it has indeed changed to be `2048`: + +检查一下`cinema`的`width`属性的确改成了`2048`: + +``` +println("cinema is now \(cinema.width) pixels wide") +// prints "cinema is now 2048 pixels wide" +``` + +However, the `width` property of the original `hd` instance still has the old value of `1920`: +不过,原来的`hd`实例的`width`属性还是旧值`1920`: + +``` +println("hd is still \(hd.width) pixels wide") +// prints "hd is still 1920 pixels wide" +``` + +When `cinema` was given the current value of `hd`, the *values* stored in `hd` were copied into the new `cinema` instance. The end result is two completely separate instances, which just happened to contain the same numeric values. Because they are separate instances, setting the width of `cinema` to `2048` doesn’t affect the width stored in `hd`. + +当使用`hd`给`cinema`赋值时,`hd`存储的*值*被复制了一份并传递给`cinema`实例。结果`hd`和`cinema`成为了仅仅是属性值相同的两个完全无关的实例。所以将`cinema`的`width`属性改为`2048`不会影响`hd`中的`width`值。 + +The same behavior applies to enumerations: +枚举也有相同的特性: + +``` +enum CompassPoint { + case North, South, East, West +} +var currentDirection = CompassPoint.West +let rememberedDirection = currentDirection +currentDirection = .East +if rememberedDirection == .West { + println("The remembered direction is still .West") +} +// prints "The remembered direction is still .West" +``` + +When `rememberedDirection` is assigned the value of `currentDirection`, it is actually set to a copy of that value. + +当`rememberedDirection`赋值为`currentDirection`时,实际上只是赋值了值拷贝而已。 + +Changing the value of `currentDirection` thereafter does not affect the copy of the original value that was stored in `rememberedDirection`. +改变`currentDirection`的值并不会影响存储了原始值副本的`rememberedDirection`。 +‌ +### Classes Are Reference Types +### 类是引用类型 + +Unlike value types, *reference types* are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used instead. + +与值类型不同,在赋值给变量、常量或者传参时,引用类型不会被复制,而是传递与当前值相同的引用。 + +Here’s an example, using the `VideoMode` class defined above: +请看这个例子,例子中使用了上文定义的`VideoMode`: + +``` +let tenEighty = VideoMode() +tenEighty.resolution = hd +tenEighty.interlaced = true +tenEighty.name = "1080i" +tenEighty.frameRate = 25.0 +``` + +This example declares a new constant called `tenEighty` and sets it to refer to a new instance of the `VideoMode` class. The video mode is assigned a copy of the HD resolution of `1920` by `1080` from before. It is set to be interlaced, and is given a name of `"1080i"`. Finally, it is set to a frame rate of `25.0` frames per second. + +例子中声明了一个名为`tenEighty`的新常量,并将它赋值为一个新的`VideoMode`实例。视频模式使用了上文的`hd`值的拷贝,其分辨率为`1920`x`1080`。`tenEighty`的`interlaced`为true,`name`为`1080i`,`frameRate`为`25.0`帧每秒。 + +Next, `tenEighty` is assigned to a new constant, called `alsoTenEighty`, and the frame rate of `alsoTenEighty` is modified: + +然后,一个新常量`alsoTenEighty`被赋值为`tenEighty`,`alsoTenEighty`的帧率做了如下修改: + +``` +let alsoTenEighty = tenEighty +alsoTenEighty.frameRate = 30.0 +``` + +Because classes are reference types, `tenEighty` and `alsoTenEighty` actually both refer to the same `VideoMode` instance. Effectively, they are just two different names for the same single instance. + +因为类是引用类型,`tenEighty`和`alsoTenEighty`都指向了同一个`VideoMode`实例。实际上它们是同一个实例的两个不同的名字而已。 + +Checking the `frameRate` property of `tenEighty` shows that it correctly reports the new frame rate of `30.0` from the underlying `VideoMode` instance: + +接下来我们检查一下`tenEighty`的属性`frameRate`,这能说明`VideoMode`实例的帧率真的变成了新值`30.0`。 + +``` +println("The frameRate property of tenEighty is now \(tenEighty.frameRate)") +// prints "The frameRate property of tenEighty is now 30.0" +``` + +Note that `tenEighty` and `alsoTenEighty` are declared as constants, rather than variables. However, you can still change `tenEighty.frameRate` and `alsoTenEighty.frameRate` because the values of the `tenEighty` and `alsoTenEighty` constants themselves do not actually change. `tenEighty` and `alsoTenEighty` themselves do not “store” the `VideoMode` instance—instead, they both refer to a `VideoMode` instance behind the scenes. It is the `frameRate` property of the underlying `VideoMode` that is changed, not the values of the constant references to that `VideoMode`. + +请注意`tenEighty`和`alsoTenEighty`都被声明成了常量而不是变量。但是因为修改其属性的值并不会改变`tenEighty`和`alsoTenEighty`的值,我们还是可以修改`tenEighty.frameRate`和`alsoTenEighty.frameRate`。`tenEighty`和`alsoTenEighty`并不存储`VideoMode`实例,而是引用一个`VideoMode`实例的地址。改变`frameRate`的值只是改变了引用的`VideoMode`实例的属性,并没有改变引用的`VideoMode`的地址。 +‌ +### Identity Operators +### 身份操作符 + +Because classes are reference types, it is possible for multiple constants and variables to refer to the same single instance of a class behind the scenes. (The same is not true for structures and enumerations, because they are value types and are always copied when they are assigned to a constant or variable, or passed to a function.) + +因为类是引用类型,因此允许多个常量和变量都引用同一个类实例。(结构体和枚举却不是,因为它们是值类型,并且在赋值给变量常量或者传值的时候传递的都是值的拷贝。) + +It can sometimes be useful to find out if two constants or variables refer to exactly the same instance of a class. To enable this, Swift provides two identity operators: + +* Identical to (===) +* Not identical to (!==) + +有时候需要判断两个常量或变量是否指向同一个类实例。Swift提供了两个身份操作符来实现这个功能: + + * 指向同一实例(===) + * 指向不同实例(!==) + +Use these operators to check whether two constants or variables refer to the same single instance: + +以下例子使用了这两个操作符来判断两个常量或变量是否是同一实例: + +``` +if tenEighty === alsoTenEighty { + println("tenEighty and alsoTenEighty refer to the same Resolution instance.") +} +// prints "tenEighty and alsoTenEighty refer to the same Resolution instance." +``` + +Note that “identical to” (represented by three equals signs, or ===) does not mean the same thing as “equal to” (represented by two equals signs, or ==): + +提示:三个等号(===)的身份相等与两个等号(==)的值相等操作符是不一样的。 + +* “Identical to” means that two constants or variables of class type refer to exactly the same class instance. +* “Equal to” means that two instances are considered “equal” or “equivalent” in value, for some appropriate meaning of “equal”, as defined by the type’s designer. + + * 身份相等操作符两端的变量或常量比较的是是否从同一个类实例化而来。 + * 值相等操作符比较的则是两端的值或者对象的内存地址是否相等,这更接近我们平常理解的相等比较。 + +When you define your own custom classes and structures, it is your responsibility to decide what qualifies as two instances being “equal”. The process of defining your own implementations of the “equal to” and “not equal to” operators is described in Equivalence Operators. + +每当你定义一个类或者结构体时,你就有义务对两个实例的“相等”标准作出决断。在[比较运算符](#)中会描述如何去对对相等和不等的比较进行实现。 +‌ +### Pointers +### 指针 + +If you have experience with C, C++, or Objective-C, you may know that these languages use pointers to refer to addresses in memory. A Swift constant or variable that refers to an instance of some reference type is similar to a pointer in C, but is not a direct pointer to an address in memory, and does not require you to write an asterisk (*) to indicate that you are creating a reference. Instead, these references are defined like any other constant or variable in Swift. + +如果你之前有过编写C、C++或者Objective-C的经验,你应该会知道这些语言的指针都是对一个内存中的地址做引用的。一个变量或常量在Swift中与C的指针类似引用一个可以被引用的实例,但它不直接指向内存的某一个地址,也不需要在申明引用的变量名前加上星号(*)。在Swift中除此之外,引用的定义与其他语言相同。 + +## Choosing Between Classes and Structures + +You can use both classes and structures to define custom data types to use as the building blocks of your program’s code. + +在定义时你可以在你的代码中同时使用类和结构体来表示合适的数据类型。 + +However, structure instances are always passed by value, and class instances are always passed by reference. This means that they are suited to different kinds of tasks. As you consider the data constructs and functionality that you need for a project, decide whether each data construct should be defined as a class or as a structure. + +他们拥有不同的特性,结构体实例被赋值时始终传递的是值的拷贝,而类实例则始终传递的是引用。将他们根据项目的实际情况去选择定义出合适的数据是代码构建者应该去仔细斟酌的。 + +As a general guideline, consider creating a structure when one or more of these conditions apply: + +通常来说,符合以下一个或多个条件时应该使用结构体去定义数据: + +* The structure’s primary purpose is to encapsulate a few relatively simple data values. +* It is reasonable to expect that the encapsulated values will be copied rather than referenced when you assign or pass around an instance of that structure. +* Any properties stored by the structure are themselves value types, which would also be expected to be copied rather than referenced. +* The structure does not need to inherit properties or behavior from another existing type. + +* 结构体主要目的时用来将少量相关数据进行封装。 +* 当期望实例在赋值时传递的是封装的值的被拷贝而不是仅仅是引用。 +* 当期望数据结构中的只类型也一同拷贝传值而不是传递引用。 +* 这个数据结构不需要去继承别的类。 + +Examples of good candidates for structures include: + +适合使用结构体的场景: + +* The size of a geometric shape, perhaps encapsulating a width property and a height property, both of type Double. +* A way to refer to ranges within a series, perhaps encapsulating a start property and a length property, both of type Int. +* A point in a 3D coordinate system, perhaps encapsulating x, y and z properties, each of type Double. + +In all other cases, define a class, and create instances of that class to be managed and passed by reference. In practice, this means that most custom data constructs should be classes, not structures. + +* 用来描述几何图形的尺寸,包含了浮点类型的宽和高两个属性。 +* 用来描述一个范围,包含一个整型开始值和一个整型长度。 +* 用来描述一个三维坐标系统,包含双精度的x,y和z三个属性。 + +所有其他情况请定义类并使用类的实例以引用方式传递。实际上大多数情况还是应该用类来作为主要的数据结构承载,结构体仅在必要时。 + +## Assignment and Copy Behavior for Collection Types + +## 集合的赋值与拷贝 + +Swift’s Array and Dictionary types are implemented as structures. However, arrays have slightly different copying behavior from dictionaries and other structures when they are assigned to a constant or variable, and when they are passed to a function or method. + +在Swift中Array和Dictionary类型都是使用结构体实现的。然而当Array被赋值给常量、变量或者当作参数传入一个方法或者函数中时拷贝操作与Dictionary和其他结构体略有不同。 + +The behavior described for Array and Dictionary below is different again from the behavior of NSArray and NSDictionary in Foundation, which are implemented as classes, not structures. NSArray and NSDictionary instances are always assigned and passed around as a reference to an existing instance, rather than as a copy. + +以下Array和Dictionary与Foundation框架中的NSArray和NSDictionary的实现方式是有去别的,后者使用类实现,其实例在传递过程中均以引用形式进行传递而不是拷贝。 + +> NOTE +> +> The descriptions below refer to the “copying” of arrays, dictionaries, strings, and other values. Where copying is mentioned, the behavior you see in your code will always be as if a copy took place. However, Swift only performs an actual copy behind the scenes when it is absolutely necessary to do so. Swift manages all value copying to ensure optimal performance, and you should not avoid assignment to try to preempt this optimization. + +> 提示 +> +> 以下是对于数组,字典,字符串和其它值的拷贝的描述。 在你的代码中出现拷贝引用的地方便会一直时拷贝引用。然而,Swift只在确实有必要发生拷贝行为的场景下才回执行拷贝操作。为了性能的最优,Swift将会在最合适的实际进行拷贝操作,以达到性能最优的目的,而开发者不关心这方面的性能问题也没关系。 + +### Assignment and Copy Behavior for Dictionaries + +### Dictionary的赋值与拷贝 + +Whenever you assign a Dictionary instance to a constant or variable, or pass a Dictionary instance as an argument to a function or method call, the dictionary is copied at the point that the assignment or call takes place. This process is described in Structures and Enumerations Are Value Types. + +只要将一个字典实例进行赋值或者传参操作,就会产生拷贝行为,在[结构体和枚举都是值类型](#)小节中有详细描述过。 + +If the keys and/or values stored in the Dictionary instance are value types (structures or enumerations), they too are copied when the assignment or call takes place. Conversely, if the keys and/or values are reference types (classes or functions), the references are copied, but not the class instances or functions that they refer to. This copy behavior for a dictionary’s keys and values is the same as the copy behavior for a structure’s stored properties when the structure is copied. + +如果字典实例中所储存的键值是结构体或枚举类型,那么赋值的时候也是拷贝赋值。相反,如果键值是引用类型,那么赋值操作只传递会引用,而不是实例本身的拷贝。在结构体中的键值也具有相同特性。 + +The example below defines a dictionary called ages, which stores the names and ages of four people. The ages dictionary is then assigned to a new variable called copiedAges and is copied when this assignment takes place. After the assignment, ages and copiedAges are two separate dictionaries. + +下面的示例定义了一个名为ages的字典实例,存储了四个人的名字和年龄。ages被赋值给了一个名为copiedAges的新变量时字典实例被重新复制了一份。赋值结束后,ages和copiedAges成为两个相互独立的字典实例。 + +``` +var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19] +var copiedAges = ages +``` + +The keys for this dictionary are of type String, and the values are of type Int. Both types are value types in Swift, and so the keys and values are also copied when the dictionary copy takes place. + +这个字典的键是字符串型,值是整型。这两种类型在Swift 中都是值类型,所以当字典被拷贝时,它们也都会被一起拷贝。 + +You can prove that the ages dictionary has been copied by changing an age value in one of the dictionaries and checking the corresponding value in the other. If you set the value for "Peter" in the copiedAges dictionary to 24, the ages dictionary still returns the old value of 23 from before the copy took place: + +我们可以通过改变一个字典中的年龄,然后检查另一个字典中所对应的值,来证明ages字典确实是被拷贝了。如果在copiedAges字典中将Peter的值设为24,那么ages字典中Peter值仍然会返回23: + +``` +copiedAges["Peter"] = 24 +println(ages["Peter"]) +// prints "23" +``` + +### Assignment and Copy Behavior for Arrays +### 数组的赋值与拷贝 + +The assignment and copy behavior for Swift’s Array type is more complex than for its Dictionary type. Array provides C-like performance when you work with an array’s contents and copies an array’s contents only when copying is necessary. + +在Swift 中,数组(Arrays)类型的赋值和拷贝行为要比字典(Dictionary)类型的复杂的多。当操作数组内容时,数组(Array)能提供接近C语言的的性能,并且拷贝行为只有在必要时才会发生。 + +If you assign an Array instance to a constant or variable, or pass an Array instance as an argument to a function or method call, the contents of the array are not copied at the point that the assignment or call takes place. Instead, both arrays share the same sequence of element values. When you modify an element value through one array, the result is observable through the other. + +如果你将一个数组(Arrays)实例赋给一个变量或常量,或者将其作为参数传递给函数或方法,在事件发生时数组的内容不会被拷贝。而且两个数组使用的还是同一套序列。只有当你在一个数组内修改某一元素,修改结果才c会在另一数组显示。 + +For arrays, copying only takes place when you perform an action that has the potential to modify the length of the array. This includes appending, inserting, or removing items, or using a ranged subscript to replace a range of items in the array. If and when array copying does take place, the copy behavior for an array’s contents is the same as for a dictionary’s keys and values, as described in Assignment and Copy Behavior for Dictionaries. + +对数组来说,拷贝行为仅仅当操作有可能修改数组长度时才会发生。这种行为包括了附加(appending),插入(inserting),删除(removing)或者使用范围下标(ranged subscript)去替换这一范围内的元素。只有当数组拷贝确要发生时,数组内容的行为规则与字典中键值的相同,详见[Dictionary的赋值与拷贝](#)。 + +The example below assigns a new array of Int values to a variable called a. This array is also assigned to two further variables called b and c: + +下面的示例将一个整数数组赋给了一个名为a的变量,继而又被赋给了变量b和c: + +``` +var a = [1, 2, 3] +var b = a +var c = a +``` + +You can retrieve the first value in the array with subscript syntax on either a, b, or c: + +我们可以在a,b,c上使用下标语法以得到数组的第一个元素: + +``` +println(a[0]) +// 1 +println(b[0]) +// 1 +println(c[0]) +// 1 +``` + +If you set an item in the array to a new value with subscript syntax, all three of a, b, and c will return the new value. Note that the array is not copied when you set a new value with subscript syntax, because setting a single value with subscript syntax does not have the potential to change the array’s length: + +如果通过下标语法修改数组中某一元素的值,那么a,b,c中的相应值都会发生改变。请注意当你用下标语法修改某一值时,并没有拷贝行为伴随发生,因为下表语法修改值时没有改变数组长度的可能: + +``` +a[0] = 42 +println(a[0]) +// 42 +println(b[0]) +// 42 +println(c[0]) +// 42 +``` + +However, if you append a new item to a, you do modify the array’s length. This prompts Swift to create a new copy of the array at the point that you append the new value. Henceforth, a is a separate, independent copy of the array. + +然而,当你给a附加新元素时,数组的长度发生改变。 Swift 会创建这个数组的一个拷贝。此后,a将会是一个独立拷贝。 + +If you change a value in a after the copy is made, a will return a different value from b and c, which both still reference the original array contents from before the copy took place: + +拷贝发生后,如果再修改a中元素值的话,a将会返回与b,c不同的结果,因为后两者引用的是原来的数组: + +``` +a.append(4) +a[0] = 777 +println(a[0]) +// 777 +println(b[0]) +// 42 +println(c[0]) +// 42 +``` + +#### Ensuring That an Array Is Unique + +#### 确保数组的唯一性 + +It can be useful to ensure that you have a unique copy of an array before performing an action on that array’s contents, or before passing that array to a function or method. You ensure the uniqueness of an array reference by calling the unshare method on a variable of array type. (The unshare method cannot be called on a constant array.) + +在操作一个数组,或将其传递给函数以及方法调用之前是很有必要先确定这个数组是有一个唯一拷贝的。通过在数组变量上调用unshare方法来确定数组引用的唯一性。(当数组赋给常量时,不能调用unshare方法) + +If multiple variables currently refer to the same array, and you call the unshare method on one of those variables, the array is copied, so that the variable has its own independent copy of the array. However, no copying takes place if the variable is already the only reference to the array. + +如果一个数组被多个变量引用,在其中的一个变量上调用unshare方法,则会拷贝此数组,此时这个变量将会有属于它自己的独立数组拷贝。当数组仅被一个变量引用时,则不会有拷贝发生。 + +At the end of the previous example, b and c both reference the same array. Call the unshare method on b to make it become a unique copy: + +在上一个示例的最后,b和c都引用了同一个数组。此时在b上调用unshare方法则会将b变成一个唯一个拷贝: + +``` +b.unshare() +``` + +If you change the first value in b after calling the unshare method, all three arrays will now report a different value: + +在unshare方法调用后再修改b中第一个元素的值,这三个数组(a,b,c)会返回不同的三个值: + +``` +b[0] = -105 +println(a[0]) +// 777 +println(b[0]) +// -105 +println(c[0]) +// 42 +``` + +#### Checking Whether Two Arrays Share the Same Elements + +#### 判定两个数组是否共用相同元素 + +Check whether two arrays or subarrays share the same storage and elements by comparing them with the identity operators (=== and !==). + +我们通过使用恒等运算符(identity operators) (=== 和 !==)来判定两个数组或子数组共用相同的储存空间或元素。 + +The example below uses the “identical to” operator (===) to check whether b and c still share the same array elements: + +下面这个示例使用了“等同(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.") +} +// prints "b and c now refer to two independent sets of array elements." +``` + +Alternatively, use the identity operators to check whether two subarrays share the same elements. The example below compares two identical subarrays from b and confirms that they refer to the same 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.") +} +// prints "These two subarrays share the same elements." +``` + +#### Forcing a Copy of an Array + +#### 强制复制数组 + +Force an explicit copy of an array by calling the array’s copy method. This method performs a shallow copy of the array and returns a new array containing the copied items. + +我们通过调用数组的copy方法进行强制显式复制。这个方法对数组进行了浅拷贝(shallow copy),并且返回一个包含此拷贝数组的新数组。 + +The example below defines an array called names, which stores the names of seven people. A new variable called copiedNames is set to the result of calling the copy method on the names array: + +下面这个示例中定义了一个names数组,其包含了七个人名。还定义了一个copiedNames变量,用以储存在names上调用copy方法所返回的结果: + +``` +var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"] +var copiedNames = names.copy() +``` + +You can prove that the names array has been copied by changing an item in one of the arrays and checking the corresponding item in the other. If you set the first item in the copiedNames array to "Mo" rather than "Mohsen", the names array still returns the old value of "Mohsen" from before the copy took place: + +我们可以通过修改数组中某一个元素,并且检查另一个数组中对应元素的方法来判定names数组确已被复制。如果你将copiedNames中第一个元素从"Mohsen"修改为"Mo",则names数组返回的仍是拷贝发生前的"Mohsen": + +``` +copiedNames[0] = "Mo" +println(names[0]) +// prints "Mohsen" +``` + + +> NOTE +> +> If you simply need to be sure that your reference to an array’s contents is the only reference in existence, call the unshare method, not the copy method. The unshare method does not make a copy of the array unless it is necessary to do so. The copy method always copies the array, even if it is already unshared. + +> 提示: +> +> 如果你仅需要确保你对数组的引用是唯一引用,请调用unshare方法,而不是copy方法。unshare方法只在必要时才会创建数组拷贝。copy方法会在任何时候都创建一个新的拷贝,即使已经标记为唯一。 \ No newline at end of file diff --git a/src/chapter2/10_Properties.md b/src/chapter2/10_Properties.md new file mode 100644 index 0000000..76d3e6a --- /dev/null +++ b/src/chapter2/10_Properties.md @@ -0,0 +1,666 @@ +# Properties +# 属性 + +Properties associate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value. Computed properties are provided by classes, structures, and enumerations. Stored properties are provided only by classes and structures. + +属性将值与特定的类,结构体或者枚举关联起来,存储属性将常量或变量值作为实力的一部分保存起来,而计算属性则用来计算(而非存储)一个值。计算属性可以用于类,结构体和枚举,存储属性只能用于类和结构体。 + + +Stored and computed properties are usually associated with instances of a particular type. However, properties can also be associated with the type itself. Such properties are known as type properties. + +存储和计算属性通常用于特定类型的实例。不过,属性也可以用于类型本身,这样的属性被称为类属性。 + + +In addition, you can define property observers to monitor changes in a property’s value, which you can respond to with custom actions. Property observers can be added to stored properties you define yourself, and also to properties that a subclass inherits from its superclass. + +另外,可以为属性定义监听器,以监听属性值的变化,这样就可以在属性值发生变化时触发自定义操作。可以在定义存储属性的时候为其添加属性监听器,也可以为子类继承父类的属性添加监听器。 + + +## Stored Properties +## 存储属性 + +In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure. Stored properties can be either variable stored properties (introduced by the var keyword) or constant stored properties (introduced by the let keyword). +简单而言,存储属性是一个特定类型实例或结构体中的常量或变量。存储属性可以是变量存储属性(用关键词 `var` 声明),也可以是常量属性(用关键词 `let` 声明)。 + + +You can provide a default value for a stored property as part of its definition, as described in Default Property Values. You can also set and modify the initial value for a stored property during initialization. This is true even for constant stored properties, as described in Modifying Constant Properties During Initialization. + +在定义存储属性时,可以为其指定默认值,详见 Default Property Values 。在存储属性初始化过程中,依然可以设置和修改它的初始值,甚至修改常量存储属性,详见 Modifying Constant Properties During Initialization。 + + +The example below defines a structure called FixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created: + +下面的示例定义了一个名为 `FixedLengthRange` 的结构体,它表示一个整型的范围,其范围长度一旦创建不能改变: + + struct FixedLengthRange { + var firstValue: Int + let length: Int + } + var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3) + // 表示整型值的范围为 0, 1, 2 + rangeOfThreeItems.firstValue = 6 + // 修改 firstValue 后, 表示的整型值的范围为: 6, 7, 8 + +Instances of FixedLengthRange have a variable stored property called firstValue and a constant stored property called length. In the example above, length is initialized when the new range is created and cannot be changed thereafter, because it is a constant property. + +`FixedLengthRange` 的实例包含一个名为 `firstValue` 的变量存储属性和一个名为 `length` 常量存储属性。在上面的示例中, `length` 在 `FixedLengthRange` 实例创建时初始化,并且在此后不能被修改,因为它是一个常量属性。 + + +###Stored Properties of Constant Structure Instances +###存储属性与常量实例 + + +If you create an instance of a structure and assign that instance to a constant, you cannot modify the instance’s properties, even if they were declared as variable properties: + +如果你为一个结构体创建一个实例, 并且把这个实例赋值给一个常量, 那么无论这个实例的属性是否为变量, 其属性都不能被修改。 + + let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) + // this range represents integer values 0, 1, 2, and 3 + // 表示取值范围为 整数的 0, 1, 2, 3 + rangeOfFourItems.firstValue = 6 + // this will report an error, even thought firstValue is a variable property + // 尽管firstValue是变量属性, 对其赋值也会报错 + +Because rangeOfFourItems is declared as a constant (with the let keyword), it is not possible to change its firstValue property, even though firstValue is a variable property. +This behavior is due to structures being value types. When an instance of a value type is marked as a constant, so are all of its properties. + +因为 `rangeOfFourItems`通过`let`关键词声明, 所以是个常量, 故, 无论它的属性是否为变量, 都无法改变它的属性值。 所以, 当一个实例是常量类型, 那么它的所有属性也会变成常量类型。 + + +The same is not true for classes, which are reference types. If you assign an instance of a reference type to a constant, you can still change that instance’s variable properties. + +这种情况对于引用类型(类)并不适用。 如果将某个引用类型的实例赋值给一个常量, 那么依然可以修改该实例的属性。 + +###Lazy Stored Properties +###惰性存储属性 + + +A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the @lazy attribute before its declaration. + +惰性存储属性只有在首次调用时才会进行初始化。 通过在存储属性声明前加上 `@lazy` 来声明一个惰性存储属性。 + +> NOTE +You must always declare a lazy property as a variable (with the var keyword), because its initial value may not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy. + +> 注意 +在声明一个惰性存储属性时, 必须将其定义为变量(通过`var`声明)。 这样做的原因是, 在实例初始化完成前, 可能无法获得惰性属性的初始值。 相反的, 常量属性的初始值必须在实例初始化完成之前赋值,所以常量属性不能被声明为惰性属性。 + +Lazy properties are useful when the initial value for a property is dependent on outside factors whose values are not known until after an instance’s initialization is complete. Lazy properties are also useful when the initial value for a property requires complex or computationally expensive setup that should not be performed unless or until it is needed. + +当某个属性的初始化依赖于其他实例的初始化时,惰性属性是非常有用的。惰性属性在需要复杂计算和耗费时间较长的属性初始化时,也是非常有用的,因为它可以在需要时再进行计算和初始化。 + +The example below uses a lazy stored property to avoid unnecessary initialization of a complex class. This example defines two classes called DataImporter and DataManager, neither of which is shown in full: + +下面这个例子中,演示了在一个复杂类的初始化过程中,如何通过惰性存储属性来避免不必要的初始化。示例中定义了两个类:`DataImporter`, `DataManager`(代码片段)。 + + class DataImporter { + /* + DataImporter is a class to import data from an external file. + The class is assumed to take a non-trivial amount of time to initialize. + + DataImporter 是一个可以从外部文件导入数据的类 + 该类的初始化会消耗很长一段时间 + + */ + var fileName = "data.txt" + // the DataImporter class would provide data importing functionality here + // 这里是DataImporter类导入数据的代码 + } + + class DataManager { + @lazy var importer = DataImporter() + var data = String[]() + // the DataManager class would provide data management functionality here + // DataManager类数据管理功能的代码 + } + + let manager = DataManager() + manager.data += "Some data" + manager.data += "Some more data" + // the DataImporter instance for the importer property has not yet been created + // importer 实例尚未初始化 + + +The DataManager class has a stored property called data, which is initialized with a new, empty array of String values. Although the rest of its functionality is not shown, the purpose of this DataManager class is to manage and provide access to this array of String data. + +`DataManager` 类拥有一个名为 `data` 的存储属性,该属性是一个空的字符串数组。虽然剩余的功能代码没有展示出来,不过 `DataManager` 类的目的是提供管理和访问该字符串数组的功能。 + + +Part of the functionality of the DataManager class is the ability to import data from a file. This functionality is provided by the DataImporter class, which is assumed to take a non-trivial amount of time to initialize. This might be because a DataImporter instance needs to open a file and read its contents into memory when the DataImporter instance is initialized. + +`DataManager`类的一个功能是从文件中导入数据。 该功能由 `DataImporter` 类提供,需要花费很长时间进行初始化。原因是 `DataImporter` 类的实例在初始化的时候需要读取文件并将文件内容写入内存。 + +It is possible for a DataManager instance to manage its data without ever importing data from a file, so there is no need to create a new DataImporter instance when the DataManager itself is created. Instead, it makes more sense to create the DataImporter instance if and when it is first used. + +对于 `DataManager` 类来说,无论是从文件中导入了数据,都不影响它管理自己的数据,所以没必要在它自己初始化的时候就去创建 `DataManager` 实例。更好的做法是,将 `DataImporter` 实例在第一次使用的时候初始化。 + + +Because it is marked with the @lazy attribute, the DataImporter instance for the importer property is only created when the importer property is first accessed, such as when its fileName property is queried: + +因为使用了 `@lazy`,故 `DataImporter` 的实例 `importer` 只会在 `importer`的实例第一次被访问的时候才会初始化,例如访问它的 `fileName` 属性: + +println(manager.importer.fileName) +// the DataImporter instance for the importer property has now been created +//此时, `DataImporter` 的实例 `importer` 才被创建 +// prints "data.txt" + +###Stored Properties and Instance Variables + +###存储属性和实例变量 + + +If you have experience with Objective-C, you may know that it provides two ways to store values and references as part of a class instance. In addition to properties, you can use instance variables as a backing store for the values stored in a property. + +`Object-C`中类的实例对象有两种存储值和引用的方法。除了属性,还可以使用实例变量保存值。 + +Swift unifies these concepts into a single property declaration. A Swift property does not have a corresponding instance variable, and the backing store for a property is not accessed directly. This approach avoids confusion about how the value is accessed in different contexts and simplifies the property’s declaration into a single, definitive statement. All information about the property including its name, type, and memory management characteristics—is defined in a single location as part of the type’s definition. + +在`Swift`中没有实例变量,`Swift` 将这些概念统一为了属性。这样避免了在不同上下文中值的不同访问方式的混淆,并且使属性声明简单明了。所有的属性信息:名称,类型,内存管理特征都包含在类型定义中。 + +##Computed Properties + +##计算属性 + + +In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly. + +除了存储属性外,类,结构体,枚举还可以定义计算属性。计算属性不能存储值,而是通过 `getter` 方法和 `setter` 方法(可选)间接的设置其他属性和值。 + + struct Point { + var x = 0.0, y = 0.0 + } + struct Size { + var width = 0.0, height = 0.0 + } + struct Rect { + var origin = Point() + var size = Size() + var center: Point { + get { + let centerX = origin.x + (size.width / 2) + let centerY = origin.y + (size.height / 2) + return Point(x: centerX, y: centerY) + } + set(newCenter) { + origin.x = newCenter.x - (size.width / 2) + origin.y = newCenter.y - (size.height / 2) + } + } + } + var square = Rect(origin: Point(x: 0.0, y: 0.0), + size: Size(width: 10.0, height: 10.0)) + 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))") + // prints "square.origin is now at (10.0, 10.0)" + // 输出 "square.origin is now at (10.0, 10.0)" + +This example defines three structures for working with geometric shapes: + +这个示例定义了三个结构体来表示一个几何形状: + +Point encapsulates an (x, y) coordinate. +`Point` 封装了坐标(x, y)。 + +Size encapsulates a width and a height. + +`Size` 封装了宽度和高度。 + +Rect defines a rectangle by an origin point and a size. + +`Rect` 用坐标原点和大小定义了一个矩形。 + +The Rect structure also provides a computed property called center. The current center position of a Rect can always be determined from its origin and size, and so you don’t need to store the center point as an explicit Point value. Instead, Rect defines a custom getter and setter for a computed variable called center, to enable you to work with the rectangle’s center as if it were a real stored property. + +`Rect` 结构体提供了一个名为 `center` 的计算属性。矩形的中心点总是可以通过它的原点坐标和大小计算出来,所以你没有必要保存一个确切的矩形中心点的值。这里的 `Rect` 为一个名为 `center` 的计算属性定义了自定义的 `getter` 和 `setter` 方法,以此来设置矩形的中心点。 + +The preceding example creates a new Rect variable called square. The square variable is initialized with an origin point of (0, 0), and a width and height of 10. This square is represented by the blue square in the diagram below. + +例子中接下来创建了一个名为 `square` 的 `Rect` 实例,`point` 初始值为(0,0), `width` 和 `height` 都是10,在下图中用蓝色正方形表示。 + +The square variable’s center property is then accessed through dot syntax (square.center), which causes the getter for center to be called, to retrieve the current property value. Rather than returning an existing value, the getter actually calculates and returns a new Point to represent the center of the square. As can be seen above, the getter correctly returns a center point of (5, 5). + +然后通过点运算符(`square.center`)访问了 `square` 实例的 `center` 属性,此时会触发 `center` 的 `getter` 方法,并返回当前的属性值。和直接返回值不同, `getter` 方法会计算并返回最新的属性值。从上面的代码可以看出, `getter` 方法正确的返回了中心点 `(5, 5)`。 + + +The center property is then set to a new value of (15, 15), which moves the square up and to the right, to the new position shown by the orange square in the diagram below. Setting the center property calls the setter for center, which modifies the x and y values of the stored origin property, and moves the square to its new position. + +接着为 `center` 属性设置了新值 `(15, 15)`,在下图中可以看出 `square` 向右上移动到了一个新的位置(橙色区域)。在设置 `center` 属性时调用了它的 `setter` 方法,修改了 `origin` 的 `x,y`值,并且改变了 `square` 的位置。 + +![Alt text](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/computedProperties_2x.png) + + +###Shorthand Setter Declaration + +###Setter声明简写 + +If a computed property’s setter does not define a name for the new value to be set, a default name of newValue is used. Here’s an alternative version of the Rect structure, which takes advantage of this shorthand notation: + +如果没有给属性的 `setter` 方法的新值指定名称,那么可以使用默认值 `newValue` 。下面是 `Rect` 结构体的简写形式: + + struct AlternativeRect { + var origin = Point() + var size = Size() + var center: Point { + get { + let centerX = origin.x + (size.width / 2) + let centerY = origin.y + (size.height / 2) + return Point(x: centerX, y: centerY) + } + set { + origin.x = newValue.x - (size.width / 2) + origin.y = newValue.y - (size.height / 2) + } + } + } + + +###Read-Only Computed Properties + +###只读计算属性 + +A computed property with a getter but no setter is known as a read-only computed property. A read-only computed property always returns a value, and can be accessed through dot syntax, but cannot be set to a different value. + +只有 `getter` 没有 `setter` 的计算属性是只读计算属性。只读计算属性可以通过点操作符访问,但不能为其设置其他值。 + + +> NOTE + +> You must declare computed properties—including read-only computed properties—as variable properties with the var keyword, because their value is not fixed. The let keyword is only used for constant properties, to indicate that their values cannot be changed once they are set as part of instance initialization. + + +> 注意 + +> 必须使用 `var` 关键词定义计算属性,包括只读计算属性,因为它们的值是可能改变的。 `let` 关键词只用于常量属性,其值在初始化后不可改变。 + +必须使用var关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。 + + +You can simplify the declaration of a read-only computed property by removing the get keyword and its braces: + +只读计算属性的声明可以去掉get关键词和花括号: + + struct Cuboid { + var width = 0.0, height = 0.0, depth = 0.0 + var volume: Double { + return width * height * depth + } + } + + let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0) + println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)") + // prints "the volume of fourByFiveByTwo is 40.0" + // 输出 "the volume of fourByFiveByTwo is 40.0" + +This example defines a new structure called Cuboid, which represents a 3D rectangular box with width, height, and depth properties. This structure also has a read-only computed property called volume, which calculates and returns the current volume of the cuboid. It doesn’t make sense for volume to be settable, because it would be ambiguous as to which values of width, height, and depth should be used for a particular volume value. Nonetheless, it is useful for a Cuboid to provide a read-only computed property to enable external users to discover its current calculated volume. + +这个示例定义了一个名为 `Cuboid` 的结构体,表示一个3D的立方体,有 `width`,`height`,`depth`等属性。它还有一个名为 `volume` 的只读计算属性用来计算并返回 `cuboid` 当前的体积。我们没有必要去设置 `volume` 的值,因为 `volume` 的值可以通过 `width`,`height`,`depth`计算出来。所以比较合适的做法是,提供一个只读计算属性让用户可以获得当前的 `volume` 。 + + +###Property Observers + +###属性观察者 + +Property observers observe and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value. + +属性观察者用来观察并响应属性值的变化。在为属性赋值时,无论新值是否与原值相同,都会触发属性的观察者。 + +You can add property observers to any stored properties you define, apart from lazy stored properties. You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass. Property overriding is described in Overriding. + +可以为除了惰性属性外的其他任何存储属性定义观察者。通过属性重写,可以在子类中为它的父类属性(无论是存储或是计算属性)添加观察者。属性重写在重写一章有详细介绍。 + + +> NOTE +> +> You don’t need to define property observers for non-overridden +> computed properties, because you can observe and respond to changes to +> their value from directly within the computed property’s setter. + +> 注意 +> +> 不需要为非重写计算属性定义观察者,因为你可以直接使用计算属性的`setter`来完成。 + + +You have the option to define either or both of these observers on a property: +* willSet is called just before the value is stored. +* didSet is called immediately after the new value is stored. + +可以通过两种方式为属性定义观察者: +* `willSet` 在值发生改变之前调用 +* `didSet` 在值发生改变之后调用 + + +If you implement a willSet observer, it is passed the new property value as a constant parameter. You can specify a name for this parameter as part of your willSet implementation. If you choose not to write the parameter name and parentheses within your implementation, the parameter will still be made available with a default parameter name of newValue. + +`willSet` 会将新属性值作为常量参数,并且可以为该常量参数指定名称。如果没有为该参数指定名称,那么会使用默认的参数名称 `newValue`。 + + +Similarly, if you implement a didSet observer, it will be passed a constant parameter containing the old property value. You can name the parameter if you wish, or use the default parameter name of oldValue. + +与 `willSet` 类似,`didSet` 会将原属性值作为常量参数。同样可以为参数指定名称或者使用默认值 `oldValue`。 + +> NOTE +> +> willSet and didSet observers are not called when a property is first +> initialized. They are only called when the property’s value is set +> outside of an initialization context. + +> 注意 +> +> `willSet` 和 `didSet` 在属性初始化时不会被调用。 + +Here’s an example of willSet and didSet in action. The example below defines a new class called StepCounter, which tracks the total number of steps that a person takes while walking. This class might be used with input data from a pedometer or other step counter to keep track of a person’s exercise during their daily routine. + +这里有一个使用了 `willSet` 和 `didSet` 的示例。示例中定义了一个名为 `StepCounter` 的类,用来统计当人步行时的总步数,通过使用计步器等装置可以用这个类追踪人在日常工作中的运动量。 + + class StepCounter { + var totalSteps: Int = 0 { + willSet(newTotalSteps) { + println("About to set totalSteps to \(newTotalSteps)") + } + didSet { + if totalSteps > oldValue { + println("Added \(totalSteps - oldValue) steps") + } + } + } + } + let stepCounter = StepCounter() + stepCounter.totalSteps = 200 + // About to set totalSteps to 200 + // Added 200 steps + // 输出 About to set totalSteps to 200 + // 输出 Added 200 steps + stepCounter.totalSteps = 360 + // About to set totalSteps to 360 + // Added 160 steps + // 输出 About to set totalSteps to 360 + // 输出 Added 160 steps + stepCounter.totalSteps = 896 + // About to set totalSteps to 896 + // Added 536 steps + // 输出 About to set totalSteps to 896 + // 输出 Added 536 steps + +The StepCounter class declares a totalSteps property of type Int. This is a stored property with willSet and didSet observers. + +`StepCounter`定义了一个 `int` 类型的属性 `totalSteps`。 `totalSteps` 包含了两个观察者`willSet`和`didSet`。 + + +The willSet and didSet observers for totalSteps are called whenever the property is assigned a new value. This is true even if the new value is the same as the current value. + +当`totalSteps`的值改变时(不论新值是否与原值相同),`willSet` 和 `didSet` 都会被调用。 + + +This example’s willSet observer uses a custom parameter name of newTotalSteps for the upcoming new value. In this example, it simply prints out the value that is about to be set. + +示例中的`willSet`使用了一个名为`newTotalSteps`的参数接收新值。在这个例子中只是简单的将新值输出。 + + +The didSet observer is called after the value of totalSteps is updated. It compares the new value of totalSteps against the old value. If the total number of steps has increased, a message is printed to indicate how many new steps have been taken. The didSet observer does not provide a custom parameter name for the old value, and the default name of oldValue is used instead. + +`didSet`观察者会在`totalSteps`的值被修改后调用。它将`totalSteps`的新值与原值做比较,如果新值大于原值,则会输出新增了多少步。`didSet`观察者没有指定参数名,所以使用默认参数名`oldValue`。 + + +> NOTE +> +> If you assign a value to a property within its own didSet observer, +> the new value that you assign will replace the one that was just set. + + +> 注意 + +> 如果在`didSet`中给属性设置新值,那么新值会替换刚刚设置的值。 + +##Global and Local Variables + +##全局变量和局部变量 + + +The capabilities described above for computing and observing properties are also available to global variables and local variables. Global variables are variables that are defined outside of any function, method, closure, or type context. Local variables are variables that are defined within a function, method, or closure context. + +上面关于属性的计算和观察功能对于全局变量和局部变量同样适用。全局变量定义在所有函数,方法,闭包,类型之外。局部变量定义在函数,方法或闭包内部。 + + +The global and local variables you have encountered in previous chapters have all been stored variables. Stored variables, like stored properties, provide storage for a value of a certain type and allow that value to be set and retrieved. + +在前面的章节中全局和局部变量都是存储变量,类似于存储属性,它为特定类型的值提供存储空间,并允许对其进行读写。 + + +However, you can also define computed variables and define observers for stored variables, in either a global or local scope. Computed variables calculate rather than store a value, and are written in the same way as computed properties. + +另外,还可以在全局或局部作用域中定义计算变量,或者为存储变量定义观察者。计算变量用来计算而非存储一个值,声明方式和计算属性一样。 + + +> NOTE +> +> Global constants and variables are always computed lazily, in a +> similar manner to Lazy Stored Properties. Unlike lazy stored +> properties, global constants and variables do not need to be marked +> with the @lazy attribute. +> +> Local constants and variables are never computed lazily. + + +> 注意 +> +> 和惰性存储属性的方式类似,全局常量和变量总是延迟计算的。不同的是,全局常量和变量不需要使用`@lazy`属性进行声明。 +> +> 局部常量和变量则绝不会延迟计算。 + + +##Type Properties + +##类型属性 + + +Instance properties are properties that belong to an instance of a particular type. Every time you create a new instance of that type, it has its own set of property values, separate from any other instance. + +实例属性属于一个特定类型的实例。每次创建该类型的实例,它都拥有自己独立的一组属性,与其他实例对象无关。 + + +You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties. + +还可以定义属于类型自身的属性。不论该类型有多少实例,这些属性都只有一份。这种属性被称为类型属性。 + + +Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use (like a static constant in C), or a variable property that stores a value that is global to all instances of that type (like a static variable in C). + +类型属性用于定义所有特定的类型实例都可以使用的值,比如所有实例都可以使用同一个常量属性(类似于`C`中的静态常量),或者就像所有的实例都可以使用全局变量属性(类似于`C`中的静态常量)。 + + +For value types (that is, structures and enumerations), you can define stored and computed type properties. For classes, you can define computed type properties only. + +对于值类型(结构和枚举),可以定义存储和计算类型的属性。对于类,则只能定义计算类型的属性。 + + +Stored type properties for value types can be variables or constants. Computed type properties are always declared as variable properties, in the same way as computed instance properties. + +值类型的存储类型属性可以是变量和常量。计算类型属性和计算实例属性相同,通常声明为变量属性。 + +> NOTE +> +> Unlike stored instance properties, you must always give stored type +> properties a default value. This is because the type itself does not +> have an initializer that can assign a value to a stored type property +> at initialization time. + +> 注意 +> +> 与存储实例属性不同,必须为存储类型属性定义默认值。原因是类型本身没有一个可以在初始化时为类型属性赋值的构造器。 + + +###Type Property Syntax + +###类型属性语法 + + +In C and Objective-C, you define static constants and variables associated with a type as global static variables. In Swift, however, type properties are written as part of the type’s definition, within the type’s outer curly braces, and each type property is explicitly scoped to the type it supports. + +在`C`和`Objective-C`中,只能使用全局静态变量来定义依赖于某个属性的变量或常量。但在`Swift`中,类型属性可以作为类型定义的一部分,它的作用域也在类型的范围内。 + + +You define type properties for value types with the static keyword, and type properties for class types with the class keyword. The example below shows the syntax for stored and computed type properties: + +使用`static`关键词定义值类型的类型属性,`class`类型的类型属性用关键词`class`声明。下面的示例演示了存储类型属性和计算类型属性的语法: + + + struct SomeStructure { + static var storedTypeProperty = "Some value." + static var computedTypeProperty: Int { + // return an Int value here + // 这里将返回一个`Int`的值 + } + } + enum SomeEnumeration { + static var storedTypeProperty = "Some value." + static var computedTypeProperty: Int { + // return an Int value here + // 这里将返回一个`Int`的值 + } + } + class SomeClass { + class var computedTypeProperty: Int { + // return an Int value here + // 这里将返回一个`Int`的值 + } + } + + +> NOTE +> +> The computed type property examples above are for read-only computed +> type properties, but you can also define read-write computed type +> properties with the same syntax as for computed instance properties. + +注意 + +上面的计算类型属性的示例都是只读的,仍然可以定义可读写的计算类型属性。 + + +###Querying and Setting Type Properties + +###查询和设置类型属性 + + +Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type. For example: + +就像实例属性,类型属性通过点操作符查询和设置。不过,类型属性的是通过类型自身查询和设置,而非类型的实例: + + println(SomeClass.computedTypeProperty) + // prints "42" + // 输出 "42" + + println(SomeStructure.storedTypeProperty) + // prints "Some value." + // 输出 "Some value." + SomeStructure.storedTypeProperty = "Another value." + println(SomeStructure.storedTypeProperty) + // prints "Another value." + // 输出 "Another value." + +The examples that follow use two stored type properties as part of a structure that models an audio level meter for a number of audio channels. Each channel has an integer audio level between 0 and 10 inclusive. + +下面的示例定义了一个结构体和两个类型属性来为声道音量建模。每一个声道的音量范围是0到10。 + + +The figure below illustrates how two of these audio channels can be combined to model a stereo audio level meter. When a channel’s audio level is 0, none of the lights for that channel are lit. When the audio level is 10, all of the lights for that channel are lit. In this figure, the left channel has a current level of 9, and the right channel has a current level of 7: + +下图演示了如何将两个声道合并为一个立体声道。当某个声道的音量值是0时,所有灯都不会亮。当音量值是10时,所有灯都会亮起。下图中,左侧的音量值为9,右侧的音量值为7: + + +![Alt text](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/staticPropertiesVUMeter_2x.png) + +The audio channels described above are represented by instances of the AudioChannel structure: + +上面的声道通过`AudioChannel`的结构体实例表示如下: + + struct AudioChannel { + static let thresholdLevel = 10 + static var maxInputLevelForAllChannels = 0 + var currentLevel: Int = 0 { + didSet { + if currentLevel > AudioChannel.thresholdLevel { + // cap the new audio level to the threshold level + // 将音量值设置为最大值 + currentLevel = AudioChannel.thresholdLevel + } + if currentLevel > AudioChannel.maxInputLevelForAllChannels { + // store this as the new overall maximum input level + // 将音量值设置为当前值 + AudioChannel.maxInputLevelForAllChannels = currentLevel + } + } + } + } + +The AudioChannel structure defines two stored type properties to support its functionality. The first, thresholdLevel, defines the maximum threshold value an audio level can take. This is a constant value of 10 for all AudioChannel instances. If an audio signal comes in with a higher value than 10, it will be capped to this threshold value (as described below). + +`AudioChannel`定义了两个存储属性。首先,定义了音量最大值`thresholdLevel`,它是一个对所有实例可见的常量值。如果音量大于10,那么就取上限值10。 + + +The second type property is a variable stored property called maxInputLevelForAllChannels. This keeps track of the maximum input value that has been received by any AudioChannel instance. It starts with an initial value of 0. + +第二个类型属性是一个名为`maxInputLevelForAllChannels`的变量存储属性,用来表示所有实例的最大音量值。初始值为0。 + + +The AudioChannel structure also defines a stored instance property called currentLevel, which represents the channel’s current audio level on a scale of 0 to 10. + +`AudioChannel`结构体还定义了一个实例属性`currentLevel`,用来表示当前声道的音量值,取值0到10。 + + +The currentLevel property has a didSet property observer to check the value of currentLevel whenever it is set. This observer performs two checks: + + +`currentLevel`的值在每次设置时都会通过`didSet`进行两种检查: + +* If the new value of currentLevel is greater than the allowed thresholdLevel, the property observer caps currentLevel to thresholdLevel. +* If the new value of currentLevel (after any capping) is higher than any value previously received by any AudioChannel instance, the property observer stores the new currentLevel value in the maxInputLevelForAllChannels static property. + +* 如果`currentLevel`的新值大于允许的最大值`thresholdLevel`,则属性监听器将`currentLevel`设置为`thresholdLevel`。 +* 如果`currentLevel`的新值大于之前所有`AudioChannel`实例的值。那么属性监听器会将新值保存在静态属性`maxInputLevelForAllChannels`中。 + + +> NOTE +> +> In the first of these two checks, the didSet observer sets +> currentLevel to a different value. This does not, however, cause the +> observer to be called again. + +> 注意 +> +> 在第一次检查过程中,`didSet`监听器将`currentLevel`设置为了不同的值,但此时不会再次调用属性监听器。 + + +You can use the AudioChannel structure to create two new audio channels called leftChannel and rightChannel, to represent the audio levels of a stereo sound system: + +可以使用`AudioChannel`创建两个声道实例:`leftChannel`和`rightChannel`: + + var leftChannel = AudioChannel() + var rightChannel = AudioChannel() + +If you set the currentLevel of the left channel to 7, you can see that the maxInputLevelForAllChannels type property is updated to equal 7: + + +如果将`currentLevel`的左声道的值置为7,则可以看到类型属性`maxInputLevelForAllChannels`也更新为了7: + + leftChannel.currentLevel = 7 + println(leftChannel.currentLevel) + // prints "7" + // 输出 "7" + println(AudioChannel.maxInputLevelForAllChannels) + // print "7" + // 输出 "7" + +If you try to set the currentLevel of the right channel to 11, you can see that the right channel’s currentLevel property is capped to the maximum value of 10, and the maxInputLevelForAllChannels type property is updated to equal 10: + +如果想将`currentLevel`的右声道设置为11,你会发现右声道的`currentLevel`值被设置为了10,同时`maxInputLevelForAllChannels` 也更新为10。 + + + rightChannel.currentLevel = 11 + println(rightChannel.currentLevel) + // prints "10" + // 输出 "10" + println(AudioChannel.maxInputLevelForAllChannels) + // prints "10" + // 输出 "10" \ No newline at end of file diff --git a/src/chapter2/14_Initialization.md b/src/chapter2/14_Initialization.md new file mode 100644 index 0000000..d278db2 --- /dev/null +++ b/src/chapter2/14_Initialization.md @@ -0,0 +1,895 @@ +## 问题 + +* `initializer` 的定义?『构造方法』 +* `deinitializer` 的定义?『析构方法』 +* `Stored Properties` 的定义?『属性值』 +* `observers` 的定义?『观察者方法』 +* `external name` 的定义?『外部名称』 +* `local name` 的定义?『内部名称』 +* `constant properties` 的定义?『恒定属性』 +* `Optional Property Types` 的定义?『可选属性类型』 +* `Memberwise` 的定义?『成员式』 +* `Initializer Delegation` 的定义?『构造代理』 +* `designated initializers` 的定义?『指定构造方法』 +* `convenience initializers` 的定义?『便利构造方法』 +* `delegates up` 的定义?『向上委托』 +* `nonetheless` 的定义?『仍然』 + +## 构造过程 (Initialization) + +_构造过程_是准备实例化类、结构或枚举的过程。该过程需要为当前实例化对象的每个属性值设置初始值,并且在其准备好之前执行所需的设置或初始化。 + +> “Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that is required before the new instance is ready to for use.” + +你通过定义_构造方法_来实现构造过程,就好比能够创建特定类型的新实例化对象的特殊方法。与 Objective-C 不同的是,Swift 的构造方法没有返回值。其主要作用是保证一个类的新实例在其首次使用之前能够被正确地初始化。 + +> “You implement this initialization process by defining initializers, which are like special methods that can be called to create a new instance of a particular type. Unlike Objective-C initializers, Swift initializers do not return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they are used for the first time.” + +你也可以为类的实例实现一个_析构方法_,这可以让该实例在被释放前执行任意自定义的清理工作。需要了解更多关于析构方法的信息,请见『析构过程』章节。 + +> “Instances of class types can also implement a deinitializer, which performs any custom cleanup just before an instance of that class is deallocated. For more information about deinitializers, see Deinitialization.” + +### 初始化属性值 (Setting Initial Values for Stored Properties) + +类和结构都_必须_在该类(或结构)的实例被创建时为其属性值设定合适的初始值。属性值不能是一个不确定的状态。 + +> “Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created. Stored properties cannot be left in an indeterminate state.” + +你可以在构造方法中为属性值设定初始值,或者在属性值的定义中指定一个默认值。我们会在接下来的章节中描述这些操作。 + +> “You can set an initial value for a stored property within an initializer, or by assigning a default property value as part of the property’s definition. These actions are described in the following sections.” + +提示: + +> 无论是你为属性值指定默认值,还是通过构造方法设定初始值,该属性值的真实值被直接设定,而不会调用属性值观察者方法。 +> > “When you assign a default value to a stored property, or set its initial value within an initializer, the value of that property is set directly, without calling any property observers.” + +### 构造方法 (Initializers) + +_构造方法_用来创建类的新实例对象。其最简单的形式就是使用 `init` 关键字,类似一个没有参数的实例方法。 + +> “Initializers are called to create a new instance of a particular type. In its simplest form, an initializer is like an instance method with no parameters, written using the init keyword.” + +在接下来的例子中定义了一个叫 `Fahrenheit` 的结构来存储用华氏表示的温度。`Fahrenheit` 结构拥有一个类型为 `Double` 的属性值 `temperature`: + +> “The example below defines a new structure called Fahrenheit to store temperatures expressed in the Fahrenheit scale. The Fahrenheit structure has one stored property, temperature, which is of type Double:” + +``` +struct Fahrenheit { + var temperature: Double + init() { + temperature = 32.0 + } +} +var f = Fahrenheit() +println("The default temperature is \(f.temperature)° Fahrenheit") +// prints "The default temperature is 32.0° Fahrenheit +``` + +该结构只定义了一个不带任何参数的构造方法 `init`,该构造方法为属性值 `temperature` 设定了初始值 `32.0`(在华氏温度中表示水的冰点温度)。 + +> “The structure defines a single initializer, init, with no parameters, which initializes the stored temperature with a value of 32.0 (the freezing point of water when expressed in the Fahrenheit scale).” + +### 默认属性值 (Default Property Values) + +如上所示,你可以在一个构造方法中设定属性值的初始值。另外,你也可以在属性值声明时为其指定_默认值_。 + +> “You can set the initial value of a stored property from within an initializer, as shown above. Alternatively, specify a default property value as part of the property’s declaration. You specify a default property value by assigning an initial value to the property when it is defined.” + +提示: + +> 如果一个属性值总是拥有相同的初始值,请为其提供默认值,而不是在构造方法中设定初始值。虽然结果是一样的,*但默认值将属性值声明和初始化更紧密地绑在一起。这样不仅更简短,也更清晰,能够让你通过默认值来判断该属性值的数据类型。默认值也能让你更容易理解默认构造方法与构造方法继承,我们会在接下来的章节中描述它们。 +> > “If a property always takes the same initial value, provide a default value rather than setting a value within an initializer. The end result is the same, but the default value ties the property’s initialization more closely to its declaration. It makes for shorter, clearer initializers and enables you to infer the type of the property from its default value. The default value also makes it easier for you to take advantage of default initializers and initializer inheritance, as described later in this chapter.” + +你可以将上面的 `Fahrenheit` 结构简单写成在属性 `temperature` 被申明时提供一个默认值: + +>“You can write the Fahrenheit structure from above in a simpler form by providing a default value for its temperature property at the point that the property is declared:” + +``` +struct Fahrenheit { + var temperature = 32.0 +} +``` + +### 自定义构造过程 (Customizing Initialization) + +你可以自定义构造过程中的输入参数和可选属性类型,也可以在构造过程中修改常量,我们会在接下来的章节中描述它们。 + +> “You can customize the initialization process with input parameters and optional property types, or by modifying constant properties during initialization, as described in the following sections.” + +#### 初始化参数 (Initialization Parameters) + +要自定义构造过程,你可以在构造方法的定义中提供_初始化参数_,并定义其类型和名字。初始化参数的作用和语法与函数和方法的参数相同。 + +> “You can provide initialization parameters as part of an initializer’s definition, to define the types and names of values that customize the initialization process. Initialization parameters have the same capabilities and syntax as function and method parameters.” + +在接下来的例子中定义了一个 `Celsius` 的结构来存储用摄氏表示的温度。`Celsius` 结构实现了两个自定义的构造方法,分别是 `init(fromFahrenheit:)` 和 `init(fromKelvin:)`,能够通过不同的温标值分别初始化该结构的实例。 + +> “The following example defines a structure called Celsius, which stores temperatures expressed in the Celsius scale. The Celsius structure implements two custom initializers called init(fromFahrenheit:) and init(fromKelvin:), which initialize a new instance of the structure with a value from a different temperature scale:” + +``` +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 is 100.0 +let freezingPointOfWater = Celsius(fromKelvin: 273.15) +// freezingPointOfWater.temperatureInCelsius is 0.0 +``` + +第一个构造方法拥有一个外部名称为 `fromFahrenheit` 内部名称为 `fahrenheit` 的初始化参数。第二个构造方法拥有一个外部名称为 `fromKelvin` 内部名称为 `kelvin` 的初始化参数。这两个构造方法都将各自的参数转换为摄氏温标值,并保存在属性值 `temperatureInCelsius` 中。 + +> “The first initializer has a single initialization parameter with an external name of fromFahrenheit and a local name of fahrenheit. The second initializer has a single initialization parameter with an external name of fromKelvin and a local name of kelvin. Both initializers convert their single argument into a value in the Celsius scale and store this value in a property called temperatureInCelsius.” + +##### 参数的外部名称和内部名称 (Local and External Parameter Names) + +如同函数和方法的参数一样,初始化参数能同时拥有在构造方法体内使用的内部名称,和构造方法被调用时的外部名称。 + +> “As with function and method parameters, initialization parameters can have both a local name for use within the initializer’s body and an external name for use when calling the initializer.” + +可是,构造方法不像函数和方法那样在其括号前有确定的方法名。因此,初始化参数的类型和名字在明确哪个构造方法被调用时起到了特别重要的作用。正因如此,如果你没有提供外部名称,Swift 会自动为构造方法中的_每个_参数提供外部名称。自动生成的外部名称与内部名称相同,就如你在每个初始化参数前写了 # 符号。 + +> “However, initializers do not have an identifying function name before their parentheses in the way that functions and methods do. Therefore, the names and types of an initializer’s parameters play a particularly important role in identifying which initializer should be called. Because of this, Swift provides an automatic external name for every parameter in an initializer if you don’t provide an external name yourself. This automatic external name is the same as the local name, as if you had written a hash symbol before every initialization parameter.” + +提示: + +> 如果你不想在构造方法的参数中提供外部名称,请将下划线(_)作为申明为该参数的外部名称以复写上面描述中的默认行为。 +> > “If you do not want to provide an external name for a parameter in an initializer, provide an underscore (_) as an explicit external name for that parameter to override the default behavior described above.” + +在接下来的例子中定义了一个 `Color` 的结构,其拥有三个恒定属性 `red`,`green` 和 `blue`。这些属性值在 `0.0` 到 `1.0` 之间,分别用来表示颜色值中的红、绿、蓝数值。 + +> “The following example defines a structure called Color, with three constant properties called red, green, and blue. These properties store a value between 0.0 and 1.0 to indicate the amount of red, green, and blue in the color.” + +`Color` 定义了一个拥有三个 `Double` 类型且参数名合适的构造方法: + +> “Color provides an initializer with three appropriately named parameters of type 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 + } +} +``` + +当你创建 `Color` 实例时,你通过这三种颜色名作为外部名称调用该构造方法: + +> “Whenever you create a new Color instance, you call its initializer using external names for each of the three color components:” + +``` +let magenta = Color(red: 1.0, green: 0.0, blue: 1.0) +``` + +请注意,想不使用外部名称直接调用该构造方法是不可能的。外部名称一旦被定义,在调用时必须使用它,否则会产生编译错误: + +> “Note that it is not possible to call this initializer without using the external names. External names must always be used in an intializer if they are defined, and omitting them is a compile-time error:” + +``` +let veryGreen = Color(0.0, 1.0, 0.0) +// this reports a compile-time error - external names are required +``` + +#### 可选属性类型 (Optional Property Types) + +如果你有一个自定义类型的属性值允许设置为『空值』——可能因为该属性值不能在构造过程中赋值,也可能因为在某些时候允许为『空值』——定义该属性值为_可选_类型。可选类型的属性值会被自动初始化为 `nil`,申明该属性值在构造过程有意设定为『空值』。 + +> “If your custom type has a stored property that is logically allowed to have “no value”—perhaps because its value cannot be set during initialization, or because it is allowed to have “no value” at some later point—declare the property with an optional type. Properties of optional type are automatically initialized with a value of nil, indicating that the property is deliberately intended to have “no value yet” during initialization.” + +在接下来的例子中定义了一个 `SurveyQuestion` 的结构,其拥有一个可选的 `String` 类型属性值 `response`: + +> “The following example defines a class called SurveyQuestion, with an optional String property called 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() +// prints "Do you like cheese?" +cheeseQuestion.response = "Yes, I do like cheese. +``` + +你无法知道一个调查问题的回应直到它被回答了,因此属性值 `response` 被声明为 `String?` 类型,或称 『可选 `String`』。当一个新的 `SurveyQuestion` 实例被初始化时,它会被自动分配默认值 `nil`,表示『空字符串』。 + +> “The response to a survey question cannot be known until it is asked, and so the response property is declared with a type of String?, or “optional String”. It is automatically assigned a default value of nil, meaning “no string yet”, when a new instance of SurveyQuestion is initialized.” + +### 在构造过程中修改恒定属性 (Modifying Constant Properties During Initialization) + +你可以在构造过程中的任意时候修改恒定属性的值,只要在构造过程结束前设定为一个明确的值。 + +> “You can modify the value of a constant property at any point during initialization, as long as it is set to a definite value by the time initialization finishes.” + +提示: + +> 对于类的实例,一个恒定属性值只能在申明它的类初始化期间进行修改。它不能由子类修改。 + +> > “For class instances, a constant property can only be modified during initialization by the class that introduces it. It cannot be modified by a subclass.” + +你可以修改上面的 `SurveyQuestion` 例子,使问题的 `text` 属性使用一个恒定属性而不是一个可变属性,以表明一旦 `SurveyQuestion` 的实例被创建,问题属性便不能改变。即使 `text` 属性现在是一个恒定属性,它仍然可以在类的构造方法中设定: + +> “You can revise the SurveyQuestion example from above to use a constant property rather than a variable property for the text property of the question, to indicate that the question does not change once an instance of SurveyQuestion is created. Even though the text property is now a constant, it can still be set within the class’s initializer:” + +``` +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() +// prints "How about beets?" +beetsQuestion.response = "I also like beets. (But not with cheese.) +``` + +### 默认构造方法 (Default Initializers) + +Swift 为每个结构或基类提供了_默认构造方法_来为它们的所有属性值提供默认值,**?并不提供一个构造方法。默认构造方法简单的创建一个设定了所有属性值为默认值的新实例。 + +> “Swift provides a default initializer for any structure or base class that provides default values for all of its properties and does not provide at least one initializer itself. The default initializer simply creates a new instance with all of its properties set to their default values.” + +在接下来的例子中定义了一个叫 `ShoppingListItem` 的类,其封装了购物清单中一件商品的名字、数量和支付状态: + +> “This example defines a class called ShoppingListItem, which encapsulates the name, quantity, and purchase state of an item in a shopping list:” + +``` +class ShoppingListItem { + var name: String? + var quantity = 1 + var purchased = false +} +var item = ShoppingListItem() +``` + +因为 `ShoppingListItem` 类中所有的属性值都拥有默认值,且这是一个没有父类的基类,`ShoppingListItem` 自动获得了一个默认构造方法,该方法创建一个设定了所有属性值为默认值的新实例。(`name` 属性是一个可选的 `String` 类型属性,因此它自动获得默认值为 `nil`,尽管这个值并没有写在代码中。)上面的例子使用默认构造方法为 `ShoppingListItem` 类创建实例化对象,构造方法语法写作 `ShoppingListItem()` 并将此实例赋值给 `item` 变量。 + +> “Because all properties of the ShoppingListItem class have default values, and because it is a base class with no superclass, ShoppingListItem automatically gains a default initializer implementation that creates a new instance with all of its properties set to their default values. (The name property is an optional String property, and so it automatically receives a default value of nil, even though this value is not written in the code.) The example above uses the default initializer for the ShoppingListItem class to create a new instance of the class with initializer syntax, written as ShoppingListItem(), and assigns this new instance to a variable called item.” + +#### 结构类型的成员式构造方法 (Memberwise Initializers for Structure Types) + +除了上面提到的默认构造方法,如果结构类型为其所有属性值提供了默认值且没有自定义构造方法,那么该结构类型自动接收一个_成员式构造方法_。 + +> “In addition to the default initializers mentioned above, structure types automatically receive a memberwise initializer if they provide default values for all of their stored properties and do not define any of their own custom initializers.” + +成员式构造方法是初始化新结构实例的成员属性的一种简写方式。新实例的属性的初始值可以通过名称传递给成员式构造方法。 + +> “The memberwise initializer is a shorthand way to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name.” + +在接下来的例子中定义了一个叫 `Size` 的结构,其拥有两个属性值分别是 `width` 和 `height`。通过分配了 `0.0` 作为它们的默认值,两个属性均被推断为 `Double` 类型。 + +> “The example below defines a structure called Size with two properties called width and height. Both properties are inferred to be of type Double by assigning a default value of 0.0.” + +由于所有属性值均拥有默认值,`Size` 这个结构自动接受一个成员式构造方法 `init(width:height:)`,你可以通过这个成员式构造方法创建新的 `Size` 实例: + +> “Because both stored properties have a default value, the Size structure automatically receives an init(width:height:) memberwise initializer, which you can use to initialize a new Size instance:” + +``` +struct Size { + var width = 0.0, height = 0.0 +} +let twoByTwo = Size(width: 2.0, height: 2.0) +``` + +### 值类型的构造代理 (Initializer Delegation for Value Types) + +构造方法可以调用其他的构造方法作为实例构造过程的一部分。这个过程称为_构造代理_,其避免了在多个构造方法中的重复代码。“ + +> “Initializers can call other initializers to perform part of an instance’s initialization. This process, known as initializer delegation, avoids duplicating code across multiple initializers.” + +构造代理的工作原理,以及哪些形式的代理是被允许的,针对值类型和类类型是不同的。值类型(结构和枚举)不支持继承,因此他们的构造代理过程比较简单,因为它们只能委托给由它们自己提供的其他构造方法。但是,类类型可以从其他类继承,如『继承』这一章节所描述。这意味着类有更多的责任去确保它们继承了的所有属性值在构造过程中被分配一个合适的值。这些责任将在接下来的『类的继承和初始化』中说明。 + +> “The rules for how initializer delegation works, and for what forms of delegation are allowed, are different for value types and class types. Value types (structures and enumerations) do not support inheritance, and so their initializer delegation process is relatively simple, because they can only delegate to another initializer that they provide themselves. Classes, however, can inherit from other classes, as described in Inheritance. This means that classes have additional responsibilities for ensuring that all stored properties they inherit are assigned a suitable value during initialization. These responsibilities are described in Class Inheritance and Initialization below.” + +对于值类型,当你自定义构造方法时,你使用 `self.init` 来关联同一值类型的其他构造方法。你只能在构造方法中调用 `self.init`。 + +> “For value types, you use self.init to refer to other initializers from the same value type when writing your own custom initializers. You can only call self.init from within an initializer.” + +请注意,如果你为值类型定义一个自定义构造方法,你将不再能够访问该类型的默认构造方法(或成员式构造方法,如果它是一个结构)。这个约束防止一种情况的出现,即你提供了一个更为复杂的构造方法来执行必要的设置,但有人却不小心绕过它使用了自动生成构造方法。 + +> “Note that if you define a custom initializer for a value type, you will no longer have access to the default initializer (or the memberwise structure initializer, if it is a structure) for that type. This constraint prevents a situation in which you provide a more complex initializer that performs additional essential setup is circumvented by someone accidentally using one of the automatic initializers instead.” + +提示: + +> 如果你期望你自定义的值类型能够被默认构造方法和成员式构造方法初始化,并且同时也能够被自定义构造方法初始化,把你的自定义构造方法写在扩展中,而不是该值类型源生实现中的一部分。请参见『扩展』章节了解更多信息。 + +> > “If you want your custom value type to be initializable with the default initializer and memberwise initializer, and also with your own custom initializers, write your custom initializers in an extension rather than as part of the value type’s original implementation. For more information, see Extensions.” + +在接下来的例子中定义了一个叫 `Rect` 的结构来表示一个几何矩形。该例子需要 `Size` 和 `Point` 这两个结构的支持,两个结构均使用 `0.0` 作为它们属性值的默认值: + +> “The following example defines a custom Rect structure to represent a geometric rectangle. The example requires two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties:” + +``` +struct Size { + var width = 0.0, height = 0.0 +} +struct Point { + var x = 0.0, y = 0.0 +} +``` +你可以通过下面三种方式中的一种来初始化 `Rect` 结构: + +* 使用 `origin` 和 `size` 的默认属性值 +* 提供一个特定的原始点和大小 +* 提供一个中心点和大小 + +这些构造过程选项由三个自定义构造方法提供,它们均定义在 `Rect` 结构中: + +> “You can initialize the Rect structure below in one of three ways—by using its default zero-initialized origin and size property values, by providing a specific origin point and size, or by providing a specific center point and size. These initialization options are represented by three custom initializers that are part of the Rect structure’s definition:” + +``` +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)`: + +> “The first Rect initializer, init(), is functionally the same as the default initializer that the structure would have received if it did not have its own custom initializers. This initializer has an empty body, represented by an empty pair of curly braces {}, and does not perfom any initialization. Calling this initializer returns a Rect instance whose origin and size properties are both initialized with the default values of Point(x: 0.0, y: 0.0) and Size(width: 0.0, height: 0.0) from their property definitions:” + +``` +let basicRect = Rect() +// basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0) +``` + +第二个 `Rect` 构造方法 `init(origin:size:)` 在功能上和没有提供自定义构造方法的成员式构造方法相同。该构造方法简单地将 `origin` 和 `size` 参数分配给恰当的属性值: + +> “The second Rect initializer, init(origin:size:), is functionally the same as the memberwise initializer that the structure would have received if it did not have its own custom initializers. This initializer simply assigns the origin and size argument values to the appropriate stored properties:” + +``` +let originRect = Rect(origin: Point(x: 2.0, y: 2.0), + size: Size(width: 5.0, height: 5.0)) +// originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0) +``` + +第三个 `Rect` 构造方法 `init(center:size:)` 稍微复杂一些。它从基于中心点和大小值计算相应的原点开始。然后,它调用(或委托)到 `init(origin:size:)` 构造方法,将新的原点和大小保存到合适的属性中: + +> “The third Rect initializer, init(center:size:), is slightly more complex. It starts by calculating an appropriate origin point based on a center point and a size value. It then calls (or delegates) to the init(origin:size:) initializer, which stores the new origin and size values in the appropriate properties:” + +``` +let centerRect = Rect(center: Point(x: 4.0, y: 4.0), + size: Size(width: 3.0, height: 3.0)) +// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0) +``` + +尽管构造方法 `init(center:size:)` 也能够自己将新的 `origin` 和 `size` 分配给合适的属性。可是,构造方法 `init(center:size:)` 使用已经具有相同功能的构造函数来实现更简单(逻辑清楚)。 + +> “The init(center:size:) initializer could have assigned the new values of origin and size to the appropriate properties itself. However, it is more convenient (and clearer in intent) for the init(center:size:) initializer to take advantage of an existing initializer that already provides exactly that functionality.” + +提示: + +> 如果你想通过不定义 `init()` 和 `init(origin:size:)` 构造方法来替代例子中的方法,请见『扩展』章节。 + +> > “For an alternative way to write this example without defining the init() and init(origin:size:) initializers yourself, see Extensions.” + +### 类的继承与构造过程 + +一个类的所有属性值——包括所有它从父类继承的属性——_必须_在构造过程中分配初始值。 + +> “All of a class’s stored properties—including any properties the class inherits from its superclass—must be assigned an initial value during initialization.” + +Swift 定义了两种类类型的构造方法来保证所有的属性值接收到初始值。它们被称为指定构造方法和便利构造方法。 + +> “Swift defines two kinds of initializers for class types to help ensure all stored properties receive an initial value. These are known as designated initializers and convenience initializers.” + +#### 指定构造方法和便利构造方法 (Designated Initializers and Convenience Initializers) + +_指定构造方法_是类的主要构造方法。一个指定构造方法完全初始化所有该类申明的属性并调用合适的父类构造方法来继续向上追溯构造过程的父类链。 + +> “Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.” + +类往往只有少数指定构造方法,而且只有一个指定构造方法也是很常见的。**?指定构造方法是通过构造过程发生的『漏斗』点,并通过其继续向上追溯构造过程的父类链。 + +> “Classes tend to have very few designated initializers, and it is quite common for a class to have only one. Designated initializers are “funnel” points through which initialization takes place, and through which the initialization process continues up the superclass chain.” + +每个类必须至少拥有一个指定构造方法。在某些情况下,这一要求由从父类继承一个或多个指定构造方法满足,这将在接下来的『自动构造方法继承』中说明。 + +> “Every class must have at least one designated initializer. In some cases, this requirement is satisfied by inheriting one or more designated initializers from a superclass, as described in Automatic Initializer Inheritance below.” + +_便利构造方法_是次要的,是类的辅助构造方法。你可以在同一个类下定义一个便利构造方法来调用指定构造方法,该便利构造方法定义了指定构造方法参数的默认值。你也可以定义一个便利构造方法用于创建特定用例或**?输入值类型的实例。 + +> “Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer’s parameters set to default values. You can also define a convenience initializer to create an instance of that class for a specific use case or input value type.” + +如果你的类不需要便利构造方法,你可以不提供它。每当一个通用构造过程模型的快捷方式能够节省事件或让该类的构造过程的意图更清晰,请使用创建便利构造方法。 + +> “You do not have to provide convenience initializers if your class does not require them. Create convenience initializers whenever a shortcut to a common initialization pattern will save time or make initialization of the class clearer in intent.” + +#### 构造方法链 (Initializer Chaining) + +为了简化指定构造方法和便利构造方法的关系,在构造方法委托调用中 Swift 应用了以下三条规则: + +> “To simplify the relationships between designated and convenience initializers, Swift applies the following three rules for delegation calls between initializers:” + +* __规则一:__指定构造方法只能从其直接父类中调用指定构造方法。 +* __规则二:__便利构造方法只能调用_该类自身_定义的其他构造方法。 +* __规则三:__便利构造方法必须在最终调用一个指定构造方法。 + +> * __Rule 1__ “Designated initializers must call a designated initializer from their immediate superclass.” +> * __Rule 2__ “Convenience initializers must call another initializer available in the same class.” +> * __Rule 3__ “Convenience initializers must ultimately end up calling a designated initializer.” + +一个简单的方法来记住这些: + +* **?指定构造方法必须总是_向上_委托 +* **?便利构造方法必须总是_穿过_委托 + +> “A simple way to remember this is:” +> +> * “Designated initializers must always delegate up.” +> * “Convenience initializers must always delegate across.” + +这些规则如下图所示: + +> “These rules are illustrated in the figure below:” + +**?插图[1] Page 408 + +在这里,父类只有一个指定构造方法和两个便利构造方法。一个便利构造方法调用了其中另一个便利构造方法,而该构造方法调用了唯一那个便利构造方法。这符合上面的规则 2 和 3。该父类自身没有父类,因此不适用规则 1。 + +> “Here, the superclass has a single designated initializer and two convenience initializers. One convenience initializer calls another convenience initializer, which in turn calls the single designated initializer. This satisfies rules 2 and 3 from above. The superclass does not itself have a further superclass, and so rule 1 does not apply.” + +上图中的子类拥有两个指定构造方法和一个便利构造方法。这个便利构造方法必须调用那两个指定构造方法中的一个,因为便利构造方法必须调用其类自身的其他构造方法。这符合上面的规则 2 和 3。该子类中两个指定构造方法都必须调用父类中唯一那个指定构造方法,来符合上面的规则 1。 + +> “The subclass in this figure has two designated initializers and one convenience initializer. The convenience initializer must call one of the two designated initializers, because it can only call another initializer from the same class. This satisfies rules 2 and 3 from above. Both designated initializers must call the single designated initializer from the superclass, to satisfy rule 1 from above.” + +提示: + +> 这些规则并不会影响你的类用户如何_创建_各类的实例。上图中的任何构造方法都能用于创建其所在类的完整实例。这些规则只会影响你如何写这些类的实现。 + +> > “These rules don’t affect how users of your classes create instances of each class. Any initializer in the diagram above can be used to create a fully-initialized instance of the class they belong to. The rules only affect how you write the class’s implementation.” + +下面的图显示了一个更为复杂的 4 个类的层次结构。它表现了指定构造方法如何在类构造过程中用作『漏斗』点,简化了这些类层级间的相互关联。 + +> “The figure below shows a more complex class hierarchy for four classes. It illustrates how the designated initializers in this hierarchy act as “funnel” points for class initialization, simplifying the interrelationships among classes in the chain:” + +**?插图[2] Page 410 + +#### 构造过程的两个阶段 (Two-Phase Initialization) + +在 Swift 中类的构造过程有两个阶段。在第一个阶段,每个属性值被申明它的类分配一个初始值。一旦每个属性值的初始状态被确认,第二阶段便开始,每个类能够在新实例被认为是可以使用之前进一步制定其属性值。 + +> “Class initialization in Swift is a two-phase process. In the first phase, each stored property is assigned an initial value by the class that introduced it. Once the initial state for every stored property has been determined, the second phase begins, and each class is given the opportunity to customize its stored properties further before the new instance is considered ready for use.” + +构造过程的两个阶段使构造过程更安全,同时仍然给予一个类层级中每个类以完全的灵活性。构造过程的两个阶段防止属性值在它们被初始化之前被访问,并防止属性值被另一个构造方法意外地设置为其他值。 + +> “The use of a two-phase initialization process makes initialization safe, while still giving complete flexibility to each class in a class hierarchy. Two-phase initialization prevents property values from being accessed before they are initialized, and prevents property values from being set to a different value by another initializer unexpectedly.” + +提示: + +> Swift 的构造过程的两个阶段和 Objective-C 的构造过程类似。主要的不同之处在第一阶段 Objective-C 分配 0 或 null (如 `0` 或 `nil`) 值给每个属性。Swift 的构造过程更加灵活,因此它可以让你设置自定义初始值,并可以应付 `0` 或 `nil` 不是一个有效默认值的类型。 + +> > “Swift’s two-phase initialization process is similar to initialization in Objective-C. The main difference is that during phase 1, Objective-C assigns zero or null values (such as 0 or nil) to every property. Swift’s initialization flow is more flexible in that it lets you set custom initial values, and can cope with types for which 0 or nil is not a valid default value.” + +Swift 的编译器执行了四个安全检查,来保证构造过程的两个阶段过程中没有错误: + +> “Swift’s compiler performs four helpful safety-checks to make sure that two-phase initialization is completed without error:” + +* __安全检查一:__指定构造方法必须保证其所在类申明的属性在向上委托到父类构造方法前被初始化。 + +> * __Safety Check 1__ “A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.” + +正如上面所提到的,一个对象的内存只会被初始化一次,该对象的所有属性值的初始化状态都是已知的。为了符合这条规范,一个指定构造方法必须保证其所有属性在它脱手给继承链前是已经被初始化了的。 + +> “As mentioned above, the memory for an object is only considered fully initialized once the initial state of all of its stored properties is known. In order for this rule to be satisfied, a designated initializer must make sure that all its own properties are initialized before it hands off up the chain.” + +* __安全检查二:__一个指定构造方法在给继承的属性赋值之前必须向上委托至一个父类的构造方法。如果不是这样,该指定构造方法分配的新值会被父类的构造过程覆盖。 +* __安全检查三:__一个便利构造方法必须在给_任何_属性(包裹其所在类定义的属性)赋值前委托给另一个构造方法。如果不是这样,该便利构造方法分配的新值会被其自身类委托的构造方法覆盖。 +* __安全检查四:__直到构造过程的第一阶段完成前,任何构造方法都不能调用实例方法,不能读取任何实例属性,或引用自身为一个值。 + +> * __Safety Check 2__ “A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property. If it doesn’t, the new value the designated initializer assigns will be overwritten by the superclass as part of its own initialization.” +> * __Safety Check 3__ “A convenience initializer must delegate to another initializer before assigning a value to any property (including properties defined by the same class). If it doesn’t, the new value the convenience initializer assigns will be overwritten by its own class’s designated initializer.” +> * __Safety Check 4__ “An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.” + +在第一阶段完成前,类的实例并不是完全有效的。当在第一阶段结束时,类实例被认为是有效的,属性只能被访问,方法只能被调用,“ + +> “The class instance is not fully valid until the first phase ends. Properties can only be accessed, and methods can only be called, once the class instance is known to be valid at the end of the first phase.” + +下面是构造过程的两个阶段如何基于上面的 4 个安全检查实现的: + +> “Here’s how two-phase initialization plays out, based on the four safety checks above:” + +##### 第一阶段 + +* 一个指定或便利构造方法在一个类中被调用。 +* 该类的一个新实例内存被分配。但内存还未被初始化。 +* 该类的一个指定构造方法确保该类中申明的所有属性值拥有一个值。这些属性值的内存现在被初始化了。 +* 该指定构造方法脱手给父类的构造方法来为它拥有的属性值执行相同的任务。 +* 该过程持续向上追溯继承链,直到到达链条顶端。 +* 一旦达到继承链的顶端,最终的类必须保证其所有的属性值都拥有一个值,然后该实例的内存被认为是完全初始化的,第一阶段结束。 + +> * “A designated or convenience initializer is called on a class.” +> * “Memory for a new instance of that class is allocated. The memory is not yet initialized.” +> * “A designated initializer for that class confirms that all stored properties introduced by that class have a value. The memory for these stored properties is now initialized.” +> * “The designated initializer hands off to a superclass initializer to perform the same task for its own stored properties.” +> * “This continues up the class inheritance chain until the top of the chain is reached.” +> * “Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance’s memory is considered to be fully initialized, and phase 1 is complete.” + +##### 第二阶段 + +* 从继承链的顶端向下工作,继承链中每个指定构造方法都能够进一步自定义该实例。现在构造方法可以访问 `self` 并且能够修改其属性,调用实例方法,等等。 +* 最后,继承链中每个便利构造方法能够自定义该实例,并且使用 `self` 操作。 + +> * “Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access self and can modify its properties, call its instance methods, and so on.” +> * “Finally, any convenience initializers in the chain have the option to customize the instance and to work with self.” + +下图显示了第一阶段在假想的子类和父类中如何寻找构造过程的调用: + +> “Here’s how phase 1 looks for an initialization call for a hypothetical subclass and superclass:” + +**?插图[3] Page 415 + +在这个例子中,构造过程开始于对子类中便利构造方法的调用。该便利构造方法当前还不能修改任何属性。它委托给同一类下的一个指定构造方法。 + +> “In this example, initialization begins with a call to a convenience initializer on the subclass. This convenience initializer cannot yet modify any properties. It delegates across to a designated initializer from the same class.” + +该指定构造方法确保所有子类中的属性都拥有一个值,如安全检查 1。然后它调用了父类的一个指定构造方法来继续向上追溯构造过程。 + +> “The designated initializer makes sure that all of the subclass’s properties have a value, as per safety check 1. It then calls a designated initializer on its superclass to continue the initialization up the chain.” + +父类的指定构造方法确保了父类的所有属性都拥有一个值。在没有往上的父类可以追溯,也不需要进一步的委托。 + +> “The superclass’s designated initializer makes sure that all of the superclass properties have a value. There are no further superclasses to initialize, and so no further delegation is needed.” + +在所有的父类属性都拥有值的时候,内存被认为完全初始化,第一阶段结束。 + +> “As soon as all properties of the superclass have an initial value, its memory is considered fully initialized, and Phase 1 is complete.” + +下图显示了第二阶段如何寻找构造过程的调用: + +> “Here’s how phase 2 looks for the same initialization call:” + +**?插图[4] Page 416 + +父类的指定构造方法已经可以进一步自定义实例(这不是必须的)。 + +> “The superclass’s designated initializer now has an opportunity to customize the instance further (although it does not have to).” + +一旦父类的指定构造方法结束,子类的指定构造方法便可执行额外的自定义操作(同样的,这不是必须的)。 + +> “Once the superclass’s designated initializer is finished, the subclass’s designated initializer can perform additional customization (although again, it does not have to).” + +最后,一旦子类的指定构造方法结束,最早被调用的便利构造方法可以执行额外的自定义操作了。 + +> “Finally, once the subclass’s designated initializer is finished, the convenience initializer that was originally called can perform additional customization.” + +#### 构造方法的继承与重写 (Initializer Inheritance and Overriding) + +与 Objective-C 的子类不同,Swift 的子类会默认继承它们父类的构造方法。Swift 可以防止一种情况:一个简单的父类构造方法被一个更专业的子类自动继承,并用于创建不完整或不正确的子类实例。 + +> “Unlike subclasses in Objective-C, Swift subclasses do not not inherit their superclass initializers by default. Swift’s approach prevents a situation in which a simple initializer from a superclass is automatically inherited by a more specialized subclass and is used to create a new instance of the subclass that is not fully or correctly initialized.” + +如果你希望你的自定义子类能够提供一个多个与父类相同的构造方法——可能在构造过程中需要一些自定义——你可以在你自定义的子类中提供一个相同构造方法的重写来实现。 + +> “If you want your custom subclass to present one or more of the same initializers as its superclass—perhaps to perform some customization during initialization—you can provide an overriding implementation of the same initializer within your custom subclass.” + +如果你重写的构造方法是一个指定构造方法,你可以在你的子类中重写它的实现,并且能够在子类的重写版方法中调用父类父类版方法。 + +> “If the initializer you are overriding is a designated initializer, you can override its implementation in your subclass and call the superclass version of the initializer from within your overriding version.” + +如果你重写的构造方法是一个便利构造方法,你重写的方法必须调用子类自身申明的另一个指定构造方法,正如前面『构造方法链』说明的规则那样。 + +> “If the initializer you are overriding is a convenience initializer, your override must call another designated initializer from its own subclass, as per the rules described above in Initializer Chaining.” + +提示: + +> 与方法、属性和下标不同,当你重写一个构造方法时不需要写 `override` 关键字。 + +> > “Unlike methods, properties, and subscripts, you do not need to write the override keyword when overriding an initializer.” + +#### 自动继承构造方法 (Automatic Initializer Inheritance) + +正如上面所描述的,子类会默认继承它们父类的构造方法。可是,在某些情况下,父类的构造方法会被自动继承。在实践中,**?这意味着​​在许多常见情况下你不需要重写构造方法,并且可以最小影响地继承父类的构造方法,这样做是安全。 + +> “As mentioned above, subclasses do not not inherit their superclass initializers by default. However, superclass initializers are automatically inherited if certain conditions are met. In practice, this means that you do not need to write initializer overrides in many common scenarios, and can inherit your superclass initializers with minimal effort whenever it is safe to do so.” + +假设你为你的子类中申明的任何新属性提供默认值,有下面两个规则要遵守: + +> “Assuming that you provide default values for any new properties you introduce in a subclass, the following two rules apply:” + +* __规则一:__如果你的子类没有定义任何指定构造方法,它会自动继承父类所有的指定构造方法。 +* __规则二:__如果你的子类提供了其父类所有的指定构造方法的实现——或者仅仅如『规则一』所说的继承它们,或者在其自身定义中提供自定义的实现——那么该子类会自动继承父类所有的便利构造方法。 + +> * __Rule 1__ “If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.” +> * __Rule 2__ “If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers.” + +即使你在子类中添加了更多的便利构造方法,这两个规则依然适用。 + +> “These rules apply even if your subclass adds further convenience initializers.” + +提示: + +> 一个子类可以实现一个父类的指定构造方法为子类的一个便利构造方法,这是符合『规则二』的。 + +> > “A subclass can implement a superclass designated initializer as a subclass convenience initializer as part of satisfying rule 2.” + +#### 指定与便利构造方法的语法 (Syntax for Designated and Convenience Initializers) + +类的指定构造方法的编写方法如值类型的构造方法一样简单: + +> “Designated initializers for classes are written in the same way as simple initializers for value types:” + +``` +init(parameters) { + statements +} +``` + +便利构造方法的编写方法也是如此,但必须在 `init` 关键字前面加上 `convenience` 关键字,并以空格分隔: + +> “Convenience initializers are written in the same style, but with the convenience keyword placed before the init keyword, separated by a space:” + +``` +convenience init(parameters) { + statements +} +``` + +#### 指定与便利构造方法的行为 (Designated and Convenience Initializers in Action) + +在接下来的例子显示了指定构造方法,便利构造方法和自动继承的构造方法的行为。这个例子定义了叫 `Food`,`RecipeIngredient` 和 `ShoppingListItem` 三个类的层级关系,并示范了它们之间是如何相互作用的。 + +> “The following example shows designated initializers, convenience initializers, and automatic initializer inheritance in action. This example defines a hierarchy of three classes called Food, RecipeIngredient, and ShoppingListItem, and demonstrates how their initializers interact.” + +该层级中的基类是 `Food`,它是一个仅仅描述了食物名字的简单类。`Food` 类仅有一个 `String` 类型的属性 `name`,并有两个构造方法来创造 `Food` 的实例: + +> “The base class in the hierarchy is called Food, which is a simple class to encapsulate the name of a foodstuff. The Food class introduces a single String property called name and provides two initializers for creating Food instances:” + +``` +class Food { + var name: String + init(name: String) { + self.name = name + } + convenience init() { + self.init(name: "[Unnamed]") + } +} +``` + +下图显示了 `Food` 类的构造方法链: + +> “The figure below shows the initializer chain for the Food class:” + +**?插图[5] Page 421 + +类并没有默认的成员式构造方法,因此 `Food` 类提供了一个仅拥有一个 `name` 参数的指定构造方法。该构造方法可以用来创建指定了名字的 `Food` 实例: + +``` +let namedMeat = Food(name: "Bacon") +// namedMeat's name is "Bacon" +``` + +在 `Food` 类中的 `init(name: String)` 构造方法是一个_指定构造方法_,因为它保证了 `Food` 实例中的所有属性值是完全初始化的。`Food` 并没有父类,因此构造方法 `init(name: String)` 并不需要在其构造过程中调用 `super.init()`。 + +> “The init(name: String) initializer from the Food class is provided as a designated initializer, because it ensures that all stored properties of a new Food instance are fully initialized. The Food class does not have a superclass, and so the init(name: String) initializer does not need to call super.init() to complete its initialization.” + +该 `Food` 类也提供了一个没有参数的_便利构造方法_ `init()`。构造方法 `init()` 通过将赋值为 `[Unnamed]` 的 `name` 参数委托给 `Food` 类的 `init(name: String)`,提供了食物的默认名字: + +> “The Food class also provides a convenience initializer, init(), with no arguments. The init() initializer provides a default placeholder name for a new food by delegating across to the Food class’s init(name: String) with a name value of [Unnamed]:” + +``` +let mysteryMeat = Food() +// mysteryMeat's name is "[Unnamed]" +``` + +该层级中的第二个类是 `Food` 的一个子类,叫做 `RecipeIngredient`。该 `RecipeIngredient` 类创建了一个烹饪食谱的原料模型。它申明了一个 `Int` 类型的属性 `quantity`(从 `Food` 中继承了 `name` 属性)并定义了两个构造方法来创建 `RecipeIngredient` 实例: + +> “The second class in the hierarchy is a subclass of Food called RecipeIngredient. The RecipeIngredient class models an ingredient in a cooking recipe. It introduces an Int property called quantity (in addition to the name property it inherits from Food) and defines two initializers for creating RecipeIngredient instances:” + +``` +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` 类的构造方法链: + +> “The figure below shows the initializer chain for the RecipeIngredient class:” + +**?插图[6] Page 423 + +类 `RecipeIngredient` 拥有唯一一个指定构造方法 `init(name: String, quantity: Int)`,它可以完成新 `RecipeIngredient` 实例的所有属性的填充。该构造方法开始于将传入的 `quantity` 参数赋值给在 `RecipeIngredient` 中申明的新属性 `quantity`。而后,该构造方法向上委托给 `Food` 的构造方法 `init(name: String)`。该过程符合之前『构造过程的两个阶段』章节中的安全检查 1。 + +> “The RecipeIngredient class has a single designated initializer, init(name: String, quantity: Int), which can be used to populate all of the properties of a new RecipeIngredient instance. This initializer starts by assigning the passed quantity argument to the quantity property, which is the only new property introduced by RecipeIngredient. After doing so, the initializer delegates up to the init(name: String) initializer of the Food class. This process satisfies safety check 1 from Two-Phase Initialization above.” + +同时 `RecipeIngredient` 定义了一个便利构造方法 `init(name: String)`,它用于只使用名字来创建 `RecipeIngredient` 实例。该便利构造方法假定了所有没有明确数量的 `RecipeIngredient` 实例的数量为 `1`。该构造方法的定义使创建 `RecipeIngredient` 更加便捷快速,并能够避免创造多个单数量 `RecipeIngredient` 实例时产生的代码冗余。该便利构造方法简单得委托给了其所在类的指定构造方法。 + +> “RecipeIngredient also defines a convenience initializer, init(name: String), which is used to create a RecipeIngredient instance by name alone. This convenience initializer assumes a quantity of 1 for any RecipeIngredient instance that is created without an explicit quantity. The definition of this convenience initializer makes RecipeIngredient instances quicker and more convenient to create, and avoids code duplication when creating several single-quantity RecipeIngredient instances. This convenience initializer simply delegates across to the class’s designated initializer.” + +请注意,`RecipeIngredient` 类提供的便利构造方法 `init(name: String)` 使用了与 `Food` 类中制_指定构造方法_ `init(name: String)` 一样的参数。尽管 `RecipeIngredient` 将其作为便利构造方法,`RecipeIngredient` 仍然提供了其父类所有指定构造方法的实现。因此,`RecipeIngredient` 自动继承了其父类所有的便利构造方法。 + +> “Note that the init(name: String) convenience initializer provided by RecipeIngredient takes the same parameters as the init(name: String) designated initializer from Food. Even though RecipeIngredient provides this initializer as a convenience initializer, RecipeIngredient has nonetheless provided an implementation of all of its superclass’s designated initializers. Therefore, RecipeIngredient automatically inherits all of its superclass’s convenience initializers too.” + +在这个例子中,`RecipeIngredient` 的父类是 `Food`,`Food` 只有一个叫 `init()` 的便利构造方法。因此该构造方法被 `RecipeIngredient` 所继承。继承了的 `init()` 方法和 `Food` 中的一样,只是它委托的是 `RecipeIngredient` 中的 `init(name: String)` 而不是 `Food` 中的。 + +> “In this example, the superclass for RecipeIngredient is Food, which has a single convenience initializer called init(). This initializer is therefore inherited by RecipeIngredient. The inherited version of init() functions in exactly the same way as the Food version, except that it delegates to the RecipeIngredient version of init(name: String) rather than the Food version.” + +这三种构造方法均可以用于创建 `RecipeIngredient` 对象: + +> “All three of these initializers can be used to create new RecipeIngredient instances:” + +``` +let oneMysteryItem = RecipeIngredient() +let oneBacon = RecipeIngredient(name: "Bacon") +let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6) +``` + +第三个并且是最后一个类是 `RecipeIngredient` 的子类,叫做 `ShoppingListItem`。该 `ShoppingListItem` 类创建了一个食谱购物清单的模型。 + +> “The third and final class in the hierarchy is a subclass of RecipeIngredient called ShoppingListItem. The ShoppingListItem class models a recipe ingredient as it appears in a shopping list.” + +购物清单中的所有商品的初始状态都是『未支付』。为了实现它,`ShoppingListItem` 申明了一个默认值为 `false` 的 `Boolean` 的属性 `purchased`。同时,`ShoppingListItem` 也申明了一个计算过的 `description` 属性,它提供了对 `ShoppingListItem` 实例的文本描述: + +> “Every item in the shopping list starts out as “unpurchased”. To represent this fact, ShoppingListItem introduces a Boolean property called purchased, with a default value of false. ShoppingListItem also adds a computed description property, which provides a textual description of a ShoppingListItem instance:” + +``` +class ShoppingListItem: RecipeIngredient { + var purchased = false + var description: String { + var output = "\(quantity) x \(name.lowercaseString)" + output += purchased ? " ✔" : " ✘" + return output + } +} +``` + +提示: + +> `ShoppingListItem` 并没有定义为 `purchased` 提供初始值的构造方法,因为在购物清单中的商品(按这里的模型)的初始状态总是未支付。 + +> > “ShoppingListItem does not define an initializer to provide an initial value for purchased, because items in a shopping list (as modeled here) always start out unpurchased.” + +因为 `ShoppingListItem` 为所有其申明的属性均提供了默认值,并且其自身没有定义任何构造方法。`ShoppingListItem` 自动继承了其父类的所有指定和便利构造方法。 + +> “Because it provides a default value for all of the properties it introduces and does not define any initializers itself, ShoppingListItem automatically inherits all of the designated and convenience initializers from its superclass.” + +下图显示了这三个类的构造方法链的概览: + +> “The figure below shows the overall initializer chain for all three classes:” + +**?插图[7] Page 427 + +这三个继承的构造方法均可以用于创建 `ShoppingListItem` 对象: + +> “You can use all three of the inherited initializers to create a new ShoppingListItem instance:” + +``` +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 ✘ +``` + +至此,一个包含了三个新 `ShoppingListItem` 实例的数组 `breakfastList` 被创建出来。这个数组的类型被推断为 `ShoppingListItem[]`。在该数组被创建后,该数组的第一个 `ShoppingListItem` 实例的名字从 `[Unnamed]` 改变为 `Orange`,并且其被标记为已支付状态。输出数组中每个实例的详细描述,显示出它们的默认状态均被按预期地设置了。 + +> “Here, a new array called breakfastList is created from an array literal containing three new ShoppingListItem instances. The type of the array is inferred to be ShoppingListItem[]. After the array is created, the name of the ShoppingListItem at the start of the array is changed from "[Unnamed]" to "Orange juice" and it is marked as having been purchased. Printing the description of each item in the array shows that their default states have been set as expected.” + +### 通过闭包或方法设置默认属性 (Setting a Default Property Value with a Closure or Function) + +如果一个属性值的默认值需要一些自定义或者设置,你可以使用闭包或者全局方法来为该属性提供自定义默认值。无论该属性所在类的实例何时被初始化,闭包或方法会被调用,并且其返回值会被分配给该属性作为默认值。 + +> “If a stored property’s default value requires some customization or setup, you can use a closure or global function to provide a customized default value for that property. Whenever a new instance of the type that the property belongs to is initialized, the closure or function is called, and its return value is assigned as the property’s default value.” + +这种类型的闭包和方法为该属性创建了一个相同类型的临时值,**?定制的该值是初始状态所期望的,然后返回这个临时值作为该属性的默认值。 + +> “These kinds of closures or functions typically create a temporary value of the same type as the property, tailor that value to represent the desired initial state, and then return that temporary value to be used as the property’s default value.” + +下面是一个如何使用闭包给属性提供默认值的概览: + +> “Here’s a skeleton outline of how a closure can be used to provide a default property value:” + +``` +class SomeClass { + let someProperty: SomeType = { + // create a default value for someProperty inside this closure + // someValue must be of the same type as SomeType + return someValue + }() +} +``` + +请注意,闭包结束的花括号后面紧跟着一堆空的圆括号。这会告诉 Swift 立即执行该闭包。如果你漏掉了圆括号,你会把闭包本身赋值给该属性,而不是这个闭包的返回值。 + +> “Note that the closure’s end curly brace is followed by an empty pair of parentheses. This tells Swift to execute the closure immediately. If you omit these parentheses, you are trying to assign the closure itself to the property, and not the return value of the closure.” + +提示: + +> 如果你使用一个闭包来初始化一个属性,请记住,在该闭包被执行的时候该实例的其他部分还没有被初始化。这意味着你无法在闭包中访问任何其他属性,即使这些属性有默认值也不行。你也不能使用 `self` 属性,或调用任何实例方法。 + +> > “If you use a closure to initialize a property, remember that the rest of the instance has not yet been initialized at the point that the closure is executed. This means that you cannot access any other property values from within your closure, even if those properties have default values. You also cannot use the implicit self property, or call any of the instance’s methods.” + +在接下来的例子中定义了一个叫 `Checkerboard` 的结构,它创建了一个_跳棋_游戏桌面的模型: + +> “The example below defines a structure called Checkerboard, which models a board for the game of Checkers (also known as Draughts):” + +**?插图[8] Page 431 + +_跳棋_游戏在一个黑白相间的 10x10 方格的桌面上进行。为了表示这个游戏桌面,`Checkerboard` 结构有唯一一个属性 `boardColors`,该属性是一个拥有 100 个 `Bool` 值的数组。数组中的 `true` 值表示一个黑色方块,`false` 表示一个白色方块。数组中的第一个对象表示桌面左上角的方块,最后一个对象表示桌面右下角的方块。 + +> “The game of Checkers is played on a ten-by-ten board, with alternating black and white squares. To represent this game board, the Checkerboard structure has a single property called boardColors, which is an array of 100 Bool values. A value of true in the array represents a black square and a value of false represents a white square. The first item in the array represents the top left square on the board and the last item in the array represents the bottom right square on the board.” + +`boardColors` 数组由一个闭包来初始化其颜色值: + +> “The boardColors array is initialized with a closure to set up its color values:” + +``` +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` 中使用。 + +> “Whenever a new Checkerboard instance is created, the closure is executed, and the default value of boardColors is calculated and returned. The closure in the example above calculates and sets the appropriate color for each square on the board in a temporary array called temporaryBoard, and returns this temporary array as the closure’s return value once its setup is complete. The returned array value is stored in boardColors and can be queried with the squareIsBlackAtRow utility function:” + +``` +let board = Checkerboard() +println(board.squareIsBlackAtRow(0, column: 1)) +// prints "true" +println(board.squareIsBlackAtRow(9, column: 9)) +// prints "false" +``` + + + + + diff --git a/src/chapter2/15_Deinitialization.md b/src/chapter2/15_Deinitialization.md new file mode 100644 index 0000000..e265c80 --- /dev/null +++ b/src/chapter2/15_Deinitialization.md @@ -0,0 +1,170 @@ +======= +# 析构过程 (Deinitialization) + +A deinitializer is called immediately before a class instance is deallocated. You write deinitializers with the deinit keyword, similar to how intializers are written with the init keyword. Deinitializers are only available on class types.” + +> 析构函数会在一个类的实例被释放之前被立即调用。用`deinit`关键词来声明析构函数,用`init`来标示类似于初始化的函数。析构函数仅在类中有效。 + +#### How Deinitialization Works + +> #### 析构过程是如何工作的 + +Swift automatically deallocates your instances when they are no longer needed, to free up resources. Swift handles the memory management of instances through automatic reference counting (ARC), as described in Automatic Reference Counting. Typically you don’t need to perform manual clean-up when your instances are deallocated. However, when you are working with your own resources, you might need to perform some additional clean-up yourself. For example, if you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated. + +> Swift 会自动释放不再需要的实例以释放资源。如自动引用计数那一章描述,Swift 通过自动引用计数(ARC)处理实例的内存管理。通常当你的实例被释放时不需要手动地去清理。但是,当使用自己的资源时,你可能需要进行一些额外的清理。例如,如果创建了一个自定义的类来打开一个文件,并写入一些数据,你可能需要在类实例被释放之前关闭该文件。 + + +Class definitions can have at most one deinitializer per class. The deinitializer does not take any parameters and is written without parentheses: + +> 在类的定义中,每个类最多只能有一个析构函数。析构函数不带任何参数,在写法上不带括号: + +```` +deinit { + // 执行析构过程 +} +```` + + +Deinitializers are called automatically, just before instance deallocation takes place. You are not allowed to call a deinitializer yourself. Superclass deinitializers are inherited by their subclasses, and the superclass deinitializer is called automatically at the end of a subclass deinitializer implementation. Superclass deinitializers are always called, even if a subclass does not provide its own deinitializer. + + +> 析构函数会自动在实例释放之前被调用,且不支持手动调用。子类会继承父类的析构函数,在子类析构函数实现的之后,将自动调用父类的析构函数。即便子类没有提供自身的析构函数,其父类的析构函数也总是被调用。 + + +Because an instance is not deallocated until after its deinitializer is called, a deinitializer can access all properties of the instance it is called on and can modify its behavior based on those properties (such as looking up the name of a file that needs to be closed). + +> 因为实例直到实例的析构函数被调用时才会被释放,所以析构函数有权访问所有被调用实例的属性,同时根据那些属性修改其行为(例如查找一个需被关闭文件的名称)。 + + + +#### Deinitializers in Action + +> #### 析构函数操作 + + +Here’s an example of a deinitializer in action. This example defines two new types, Bank and Player, for a simple game. The Bank structure manages a made-up currency, which can never have more than 10,000 coins in circulation. There can only ever be one Bank in the game, and so the Bank is implemented as a structure with static properties and methods to store and manage its current state:” + +> 下面是一个析构函数操作的例子。它是一个简单的游戏,定义了两种新类型,Bank和Player。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) { + coinsInBank += coins + } +} +```` + + +Bank keeps track of the current number of coins it holds with its coinsInBank property. It also offers two methods—vendCoins and receiveCoins—to handle the distribution and collection of coins. + +> Bank根据它的coinsInBank属性来侦听当前存有的货币数。除此之外Bank还提供两个其它方法,分别是receiveCoins和vendCoins,用于处理货币的存取。 + + + +vendCoins checks that there are enough coins in the bank before distributing them. If there are not enough coins, Bank returns a smaller number than the number that was requested (and returns zero if no coins are left in the bank). vendCoins declares numberOfCoinsToVend as a variable parameter, so that the number can be modified within the method’s body without the need to declare a new variable. It returns an integer value to indicate the actual number of coins that were provided. + +> vendCoins方法在 bank 取出货币之前检查是否有足够的量。如果货币不足,Bank则返会所有的剩余量(如果货币量为空则返回 0)。vendCoins方法中将numberOfCoinsToVend声明为一个变量,这样就可以在其它方法中对它进行修改,而无需定义一个新的变量。最终vendCoins方法将为取出的货币返回一个整型值。 + + + +The receiveCoins method simply adds the received number of coins back into the bank’s coin store. + +> 而 receiveCoins 方法更加简单, 将 bank 的货币存量和接收到的货币量相加后再保存回 bank 的货币存量。 + + + +The Player class describes a player in the game. Each player has a certain number of coins stored in their purse at any time. This is represented by the player’s coinsInPurse property: + +> 这里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) + } +} +```` + +Each Player instance is initialized with a starting allowance of a specified number of coins from the bank during initialization, although a Player instance may receive fewer than that number if not enough coins are available. + +> 每一个Player都由一个初始化函数加上指定货币量入参实例化得到,他们将在初始化的过程中从 bank 获得货币。如果 Bank 没有足够的货币存量用于支付,Player 取得的货币量可能会比指定的少。 + + + +The Player class defines a winCoins method, which retrieves a certain number of coins from the bank and adds them to the player’s purse. The Player class also implements a deinitializer, which is called just before a Player instance is deallocated. Here, the deinitializer simply returns all of the player’s coins to the bank: + +> Player类还定义了一个winCoins的方法,该方法可以让player从bank赢取一定数量的硬币存入自己钱包。同时Player类还实现了一个析构函数,它在Player实例释放前一步会被调用。这里的析构函数很简单:将所有player的货币都返还给银行: + + + + +```` +var playerOne: Player? = Player(coins: 100) +println("A new player has joined the game with \(playerOne!.coinsInPurse) coins") +// 打印 "新玩家加入游戏,为其分配100货币" +println("There are now \(Bank.coinsInBank) coins left in the bank") +// 打印 "目前银行货币存量为: 9900" +```` + + +A new Player instance is created, with a request for 100 coins if they are available. This Player instance is stored in an optional Player variable called playerOne. An optional variable is used here, because players can leave the game at any point. The optional lets you track whether there is currently a player in the game. + +> 这里创建了一个新的Player实例,如果银行存量充足他将获取100货币。由于玩家可能随时离开游戏,所以将Player实例存储在一个名为playerOne的可选Player变量中。这样您可以侦听当前是否还有玩家在游戏中。 + + + + + +Because playerOne is an optional, it is qualified with an exclamation mark (!) when its coinsInPurse property is accessed to print its default number of coins, and whenever its winCoins method is called: + +> 因为playerOne是可选的,所以由一个感叹号(!)来作前缀,每当其winCoins方法被调用时,会访问其coinsInPurse属性并打印出他的货币数目。 + + + + + +```` +playerOne!.winCoins(2_000) +println("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins") +// 打印 "PlayerOne 赢取 2000 货币,目前他拥有 2100 个货币" +println("The bank now only has \(Bank.coinsInBank) coins left") +// 打印 "目前银行货币存量为: 7900" +```` + + + + +Here, the player has won 2,000 coins. The player’s purse now contains 2,100 coins, and the bank has only 7,900 coins left. + +> 以上代码运行后,player 赢取了 2,000 货币。他的钱包目前有 2,100 个货币,bank 剩余 7,900 个货币。 + + + +```` +playerOne = nil +println("PlayerOne has left the game") +// 打印 "PlayerOne 离开了游戏" +println("The bank now has \(Bank.coinsInBank) coins") +// 打印 "目前银行货币存量为: 10000" +```` + + +The player has now left the game. This is indicated by setting the optional playerOne variable to nil, meaning “no Player instance.” At the point that this happens, the playerOne variable’s reference to the Player instance is broken. No other properties or variables are still referring to the Player instance, and so it is deallocated in order to free up its memory. Just before this happens, its deinitializer is called automatically, and its coins are returned to the bank. + +> 现在player要离开这个游戏。这将把可选的playerOne变量设置为nil,可以理解为“没有Player实例”的意思。这时playerOne变量对Player实例的引用断开。再没有其它属性或者变量还会引用player实例,为了清空内存,它将被释放掉。析构函数会在这一切发生前自动被触发调用,之后所有的货币将回归到银行,这还真是个游戏。 diff --git a/src/chapter2/17_Optional_Chaining.md b/src/chapter2/17_Optional_Chaining.md new file mode 100644 index 0000000..85642a5 --- /dev/null +++ b/src/chapter2/17_Optional_Chaining.md @@ -0,0 +1,300 @@ +> 翻译:[zearlin](https://github.com/zearlin) + +# 可选链 +----------------- + +可选链(Optional Chaining)是针对当前可能为空值(`nil`)的可选元素的属性,方法及下标调用和查寻的一种处理。 若可选元素为赋值对应的属性,方法或下标都会被成功调用;反之当可选成员为空值(`nil`)时,侧其属性,方法或下标调为会返回空值(`nil`)。多个的查寻可一起链式调用,并当链路的任意一环为nil时链路调用失败。 + +> 注意: +Swift中的可选链与Object-C中空值的方法调用相似,是一种更为全面的实现,适用于所有的类型及支持调用成功与否的判断。 + +## 可选链,强制解析的一种替代方案 + +当你想调用一个属性,方法或下标时通过在可选元素(`optional value`)后添置一个问号(?)来声明一个为可选链,当可选元素为非空时,侧与通过添置感叹号(!)来强解析其值的做法非常相似。主要的区别在于当可选元素为空时可选链会得体地以调用失败结束,而强制解析则会引发一个运行时错误。 + +考虑到可选链空值调用这一情况,可选链的返回值一定为可选值,即使你所查寻的属性,方法或下标返回的并不是是一个可选值。你可以通过返回的可选值来判断可选链的调用是成功的(返回的可选元素有值),还是因为链式中的空值元素而调用失败(返回的可选元素为空)。 + +具体来说,可选链的返回值类型与预期的返回值类型一致,但封装为了一个可选元素。原本返回为整型的属性,在可选链调用中会返回为可选整型(Int?) + +我们将在后续的几个代码片段中解释可选链与强制解析的区别及让你了解如果判断调用成功与否。 + +首先,我们先定义Person与Residence两个类: + +```swift +class Person { + var residence: Residence? +} + +class Residence { + var numberOfRooms = 1 +} +``` + +`Residence`实例拥有一个命名为`numberOfRooms`的整型属性。而`Person`实例有一个可选属性`residence`其类型为`Residence?`。 + +如果你创建一个新的`Person`实例,它的`residence`属性由于是被定义为可选型的,此属性将默认初始化为空。下面的代码中,john的residence属性值为空: + + +```swift +let john = Person() +``` + +如果你在`residence`后添置感叹号(`!`)以强制解析的方式来访问`person`的`residence`的属性`numberOfRooms`时,会引发一个运行时错误,因为`residence`为空无法被解析。 + +```swift +let roomCount = john.residence!.numberOfRooms +//将导致运行时错误 +``` +当`john.residence`为非空及为`roomCount`设一个可理的房间数时以述的代码会被成功调用。然后如上面所演示的,当`residence`为空这段代码就会触发一个运行时错误。 + +可选链提供了访问`numberOfRooms`值的另一种方式。 在这里通过以问号来取代先前的感叹号以可选链的方式调用。 + +```swift +if let roomCount = john.residence?.numberOfRooms { + println("John's residence has \(roomCount) room(s).") +} else { + println("Unable to retrieve the number of rooms.") +} +// 打印 "Unable to retrieve the number of rooms. +``` + +这将告诉Swift将可选的`residence`属于链式中的一环并得到`numberOfRooms`的值当`residence`存在时。 + +因为尝试访问`numberOfRooms`时存在失败的可能,所以可选链返回一个类型为`Int?` 或称之为“可选整型”的值。 当`residence`为空时,这个可选整型也将为空,以表示`numberOfRooms`无法被访问。 + +需要注意一点即使`numberOfRooms`为非可选整型。通来可选链的方式来调用`numberOfRooms`的值查询时返回的类型是`Int?`而不是一个常规的`Int`。 + +我们给`john.residence`分配一个`Residence`实例让它不在为一个空值: + +```swift +john.residence = Residence() +``` + +此时`john.residence`包含了一个真实的`Residence`实例而不再为空了。如果你以先前相同的可选链方式去访问`numberOfRooms`,它将返回一个包含默认值 1 的`Int?`: + +```swift +if let roomCount = john.residence?.numberOfRooms { + println("John's residence has \(roomCount) room(s).") +} else { + println("Unable to retrieve the number of rooms.") +} +// 打印 "John's residence has 1 room(s)"。 +``` + +##定义可选链的模型(实体)类 + +可选链支持多层的属性,方法及下标调用。这一特性让你可以进一步的调用关联类型的复杂模型中的子属性及判断这些子属性对应的属性,方法及下标下否可以访问。 + +在下面的代码片段中为后续的几个例子使用定义了四个实体类,这些类都是基于`Person`和`Residence`模型通过增加`Room`及`Address`类及一些相关的属性,方法及下标进行扩展的。 + +`Person`类还是于先前定义的相同: + +```swift +class Person { + var residence: Residence? +} +``` + +`Residence `类比之前复杂些。这次我们为 `Residence `声明了一个名为 `rooms `的变量,其初始值为 `Room[] `类型的空数值。 + +```swift +class Residence { + var rooms = Room[]() + var numberOfRooms: Int { + return rooms.count + } + subscript(i: Int) -> Room { + return rooms[i] + } + func printNumberOfRooms() { + println("The number of rooms is \(numberOfRooms)") + } + var address: Address? +} +``` +因为在这一版的`Residence`中存储了一个Room实例数组,所以其`numberOfRooms`属性以计算属性的方式实现。计算的`numberOfRooms`属性只是简单的返回了`rooms`数组的`count`属性。 + +为了更便捷的访问它的`rooms`数组,在这一版中`Residence`提供了一个只读下标,一开始我们假设传参的引索是有效的。如果索引是有效的,下标将返回`rooms`数组与请求索引相对应的`room`对象。 + +`Residence`还提供了一个名为`printNumberOfRooms`的方法,用于简单地打印房间数。 + +最后,`Residence`还定义了一个类型为`Address?`的可选属性`address`,对应的`Address`类会在下文中定义。 + +`rooms`数组中用到的`Room`类非常简单只拥有一个`name`属性及对应设置房间名的构造器。 + +```swift +class Room { + let name: String + init(name: String) { self.name = name } +} +``` + +模型中最后的一个类叫`Address`。类中有三个类型为`String?`的可选属性。作为地址信息中的一部分头两个属性`buildingName`及`buildingNumber`是两个可供选择的方式来定位特定的建筑物。 第三个属性,`stree`,则用来保存地址中的街道名称的: + +```swift +class Address { + var buildingName: String? + var buildingNumber: String? + var street: String? + func buildingIdentifier() -> String? { + if buildingName { + return buildingName + } else if buildingNumber { + return buildingNumber + } else { + return nil + } + } +} +``` +`Address`类中还提供了一个名为`buildingIdentifier`的方法,其返回类型为`String?`。 这个方法检查`buildingName`及`buildingName`是否有值,若`buildingName`有值则返回`buildingName`,若非则返回`buildingNumber`的值,如果两者均无则返回空。 + +##以可选链方式的属性调用 + +如先前演示的可选链做为强制解析的一个替代方式,你可以利用可选链来访问可选元素的属性,及检测属性的访问是否能成功,但你不能通过可选链的方式为属性赋值。 + +利用前先写好的类一个新的`Person`实例,并与之前先一样尝试访问它的`numberOfRooms`属性: + +```swift +let john = Person() +if let roomCount = john.residence?.numberOfRooms { + println("John's residence has \(roomCount) room(s).") +} else { + println("Unable to retrieve the number of rooms.") +} +// 打印 "Unable to retrieve the number of rooms。 +``` + +因为`john.residence`为空,所以这个可选链与先前的一样调用失败并没引错误。 + +##以可选链方式的方法调用法 + +你能以可选链的方式去调用一个可选元素的方法,及检测是否方法调用不否成功。即使在方法没有定义返回值的情况下一样可行。 + +`Residence`的`printNumberOfRooms`方法会打印`numberOfRooms`的当前值。方法如下: + +```swift +func printNumberOfRooms(){ + println(“The number of rooms is \(numberOfRooms)”) +} +``` +这个方法没有声明返回值,无返回值函数及方法都会带有一个隐式的返回类型为`Void`(参见Function Without Return Values)。 + +如果你通过可选链的方式去调用一个可选元素的方法,该方法返回的将是`Void?`,而非`Void`,因为通过可选链方式调用的方法返回的均为可选类型。这样让你可以通过一个`If`语句去测试`printNumberOfRooms`方法是否可调用,即使该方法本身没有定义返回值。当`printNumberOfRooms`方法通过可选链调用成功时隐式的返回值为`Void`,否非为空: + +```swift +if john.residence?.printNumberOfRooms() { + println("It was possible to print the number of rooms.") +} else { + println("It was not possible to print the number of rooms.") +} +// 打印 "It was not possible to print the number of rooms."。 +``` + +##以可选链方式的下标调用 + +你可以通过可选链的方式去获取可选元素对应下标的值,及判断下标调用是否成功,然而,你不能在可选链中去设置一个下标的值。 + +> 注意: +当你要通过可选链的试访问对应可选元素的下标时,你应该将问号置于下标所带的括号前,而非后。可选链的问号通常都是紧随表达式中的可选元素后的。 + +下面的例子中我们将通过在`Residence`类中定义的下标去获取`rooms`数组中第一间房间的名称。由于`john.residence`当前为空,所以下标的调用失败。 + +```swift +if let firstRoomName = john.residence?[0].name { + println("The first room name is \(firstRoomName).") +} else { + println("Unable to retrieve the first room name.") +} +// 打印 "Unable to retrieve the first room name."。 +``` + +下标调用时我们将可选链的问号置于`john.residence`后于下标的括号前。因为`john.residence`为可选链需要尝试调用的可选元素。 + +如果我们为`john.residence`创建并分配一个`Residence`实体且其`rooms`属性带一个或多个Room实体,你就可以通过`Residence`的下标在可选链中访问对应的成员了: + +```swift +let johnsHouse = Residence() +johnsHouse.rooms += Room(name: "Living Room") +johnsHouse.rooms += Room(name: "Kitchen") +john.residence = johnsHouse + +if let firstRoomName = john.residence?[0].name { + println("The first room name is \(firstRoomName).") +} else { + println("Unable to retrieve the first room name.") +} +// 打印 "The first room name is Living Room."。 +``` + +##多层链式 + +你可以通过多层链式来访问实体中的属性,方法及下标。多层可选链式调用并不会增加返回值的可选性/形成可选嵌套。 + +也就是说: + +通过可选链得到的值一定为可选类型,无论你想获取的目标值是否为可选。同理一个目标值原为可选元素,不过因为链式的调用而加深变可选性。 + +因此: + +当你想从可选链中得到一个`Int`时,你得到的总会是一个`Int?`类型的值,无论通过多少层的可选链。相同的,原为`Int?`类型的返回值也一样,无论经过多少层得到的还是`Int?`类型。 + +下面的例子中我们将尝试访问从`john`的`residence`属性中的`address`属于获取期其`street`属性的值。这里我们将有两层的可选链调用,链式中的两环`residence`和`address`均为可选类型的属性: + +```swift +if let johnsStreet = john.residence?.address?.street { + println("John's street name is \(johnsStreet).") +} else { + println("Unable to retrieve the address.") +} +// 打印 "Unable to retrieve the address.”。 +``` + +虽然当前的`john.residence`含有一个有效的`Residence`实例。然而`john.residence.address`的还是为空值,所以调用`john.residence?.address?.street`失败了。 + +值得注意在下面的例子中,你将尝试去获得`street`属性的值。 这个属性的类型为`String?`。所以`john.residence?.address?`的返回值也是`String?`,即使经过了两层的可选链路来访问。 + +如果你为`john.street.address`分配一个真实的`Address`实例并为其`street`赋值,你就可以通过多层可用选连的试去访问相关的值。 + +```swift +let johnsAddress = Address() +johnsAddress.buildingName = "The Larches" +johnsAddress.street = "Laurel Street" +john.residence!.address = johnsAddress +``` + +```swift +if let johnsStreet = john.residence?.address?.street { + println("John's street name is \(johnsStreet).") +} else { + println("Unable to retrieve the address.") +} +// 打印 "John's street name is Laurel Street."。 +``` + +注意我们需要通过感叹号来为`jonh.residence.address`赋值。 因为`john.residence`属性是一个可选类型,所以在为`residence`的`address`属性赋值前,我们需要用感叹得到它的实际值先。 + +##返回可选值方法的链式调用 + +先前的例子中我们展示了如果通过可选链路来获取一个可选属性的值。如有需要我们也可以用可选链的方式去调用返回值为可选类型的方法,并也可将其返回值做为链式中的一环。 + +下下面的例子中通过可选链调用了`Address`类的`buildingIdentifier`方法。 这个方法的返回类型为`String?`。 如先前所述,通过可选链调用该方法的最终返回类型也是为`String?`: + +```swift +if let buildingIdentifier = john.residence?.address?.buildingIdentifier() { + println("John's building identifier is \(buildingIdentifier).") +} +// 打印 "John's building identifier is The Larches."。 +``` + +如果你想将该方法的返回值也置于链式中,只需将可选链路的问号置于方法调用的括号后: + +```swift +if let upper = john.residence?.address?.buildingIdentifier()?.uppercaseString { + println("John's uppercase building identifier is \(upper).") +} +// 打印 "John's uppercase building identifier is THE LARCHES."。 +``` + +> 注意: +在上面的例子中,你将可选链的问号置于括后面是因为你想加入链式中的可选元素是`buildingIdentifier`的返回值,而不是该方法本身。 diff --git a/src/chapter2/19_Nested_Types.md b/src/chapter2/19_Nested_Types.md new file mode 100644 index 0000000..6b0805a --- /dev/null +++ b/src/chapter2/19_Nested_Types.md @@ -0,0 +1,180 @@ +* ` Memberwise Initializers for Structure Types` 引自 `Initialization`,中文翻译参考了刘康的`《结构类型的成员式构造方法》` +* `Initializers`: 构造方法 +* `raw Character`: 字符? 原生字符? +* `raw Int`: 整型?原生整型? +* `computed property`: 计算属性? + +> 备注: +> 以下翻译并未遵循英文的第二人称叙事方式,整体使用第一人称讲述嵌套类型。 +> 由于中英文表达的差异,为兼顾译文的流畅性,本人擅自改动了一些原文的语言结构。更正时还请麻烦告知我,鄙人渴望多听取专家意见、希望在翻译的道路上越走越深~ 谢谢~ + + +#Nested Types +#嵌套类型 + +Enumerations are often created to support a specific class or structure’s functionality. Similarly, it can be convenient to define utility classes and structures purely for use within the context of a more complex type. To accomplish this, Swift enables you to define nested types, whereby you nest supporting enumerations, classes, and structures within the definition of the type they support. + +我们常常创建枚举类型来支持特定类或结构体的功能。同样的,枚举类型可以被方便的用于定义工具类(utility classes)和结构体,而这些工具类和结构体仅仅用在更复杂类型的上下文中。为实现这些功能,Swift可以定义嵌套类型,因此我们可以把枚举类型、类、结构体嵌套到支持他们的类型的定义中。 + +To nest a type within another type, write its definition within the outer braces of the type it supports. Types can be nested to as many levels as are required. + +要嵌套一个类型到另一个类型,只需把它的定义写在外层类型的大括号{}内,这个操作有个前提:外层类型支持嵌套内层类型。嵌套类型没有层数限制,想嵌多少层都可以。 + +##Nested Types in Action +##嵌套类型实例 + +The example below defines a structure called `BlackjackCard`, which models a playing card as used in the game of Blackjack. The `BlackJack` structure contains two nested enumeration types called `Suit` and `Rank`. + +下面的例子定义了一个`BlackjackCard`(21点牌)的结构体,来模仿21点出牌。`BlackJack`结构体包含了两个嵌套类型`Suit`和`Rank`。 + +In Blackjack, the Ace cards have a value of either one or eleven. This feature is represented by a structure called Values, which is nested within the Rank enumeration: + +在21点规则中,A牌(Ace)即可算作1点也可算作11点。这一特征用一个嵌套在枚举类型Rank中的结构体Values来代表。 + +``` +struct BlackjackCard { + + // nested Suit enumeration + enum Suit: Character { + case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣" + } + + // nested Rank enumeration + 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.toRaw(), second: nil) + } + } + } + + // BlackjackCard properties and methods + let rank: Rank, suit: Suit + var description: String { + var output = "suit is \(suit.toRaw())," + output += " value is \(rank.values.first)" + if let second = rank.values.second { + output += " or \(second)" + } + return output + } +} + +``` + +``` +struct BlackjackCard { + + // nested Suit enumeration + enum Suit: Character { + case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣" + } + + // nested Rank enumeration + 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.toRaw(), second: nil) + } + } + } + + // BlackjackCard的属性和方法 + let rank: Rank, suit: Suit + var description: String { + var output = "suit is \(suit.toRaw())," + output += " value is \(rank.values.first)" + if let second = rank.values.second { + output += " or \(second)" + } + return output + } +} + +``` + +The `Suit` enumeration describes the four common playing card suits, together with a raw `Character` value to represent their symbol. + +枚举类型`Suit`描述了扑克牌中的4种花色,每一种花色用一个`字符`(Character)代表。 + +The `Rank` enumeration describes the thirteen possible playing card ranks, together with a raw `Int` value to represent their face value. (This raw `Int` value is not used for the Jack, Queen, King, and Ace cards.) + +枚举类型`Rank`描述了相同花色的13张牌,每张牌的面值用一个`整型值`(Int)代表。(这个整型值不用再J、Q、K、A这四张牌上。) + +As mentioned above, the `Rank` enumeration defines a further nested structure of its own, called `Values`. This structure encapsulates the fact that most cards have one value, but the Ace card has two values. The `Values` structure defines two properties to represent this: + +* `first`, of type `Int` +* `second`, of type `Int?`, or “optional `Int`” + +如上所述,枚举类型`Rank`定义了一个内嵌的结构体`Values`。结构体`Values`通过定义两个属性描述了一个实事:大部分牌只有一个面值,而A牌有两个面值。属性如下: + +* `first`, `Int`型 +* `second`, `Int?`型,或者 “optional `Int`” + + +`Rank` also defines a computed property, `values`, which returns an instance of the `Values` structure. This computed property considers the rank of the card and initializes a new `Values` instance with appropriate values based on its rank. It uses special values for `Jack`, `Queen`, `King`, and `Ace`. For the numeric cards, it uses the rank’s raw `Int` value. + +`Rank`还定义了一个返回结构体`Values`实例的计算属性`values`。这个计算属性依据扑克牌的点数,初始化一个基于扑克牌点数推算出正确值的`Values`实例。计算属性`values`赋予J、Q、K和A这四张牌特定的值,赋予其他数字牌rank中定义的原始整型值(raw `Int`)。 + +The `BlackjackCard` structure itself has two properties—`rank` and `suit`. It also defines a computed property called `description`, which uses the values stored in `rank` and `suit` to build a description of the name and value of the card. The `description` property uses optional binding to check whether there is a second value to display, and if so, inserts additional description detail for that second value. + +结构体`BlackjackCard`定义了两个属性`rank`和`suit`,同时还定义了一个计算属性`description`,这个计算属性使用了`rank`和`suit`中存储的值来描述扑克牌的花色和点数。`description`使用可选绑定(optional binding)来判断是否存在第二个值,如果存在,则为第二个值插入额外的描述。 + +Because `BlackjackCard` is a structure with no custom initializers, it has an implicit memberwise initializer, as described in [Memberwise Initializers for Structure Types](). You can use this initializer to initialize a new constant called `theAceOfSpades`: + +因为结构体`BlackjackCard`没有自定义构造方法,所以它有一个默认的成员式构造方法(memberwise initializer),正如[《结构类型的成员式构造方法》]()所描述的。我们可以使用这个构造方法创建一个新的常量(constant)`theAceOfSpades`: + +``` +let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades) +println("theAceOfSpades: \(theAceOfSpades.description)") +// prints "theAceOfSpades: suit is ♠, value is 1 or 11 + +``` + +``` +let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades) +println("theAceOfSpades: \(theAceOfSpades.description)") +// 输出 "theAceOfSpades: suit is ♠, value is 1 or 11 + +``` + +Even though `Rank` and `Suit` are nested within `BlackjackCard`, their type can be inferred from context, and so the initialization of this instance is able to refer to the enumeration members by their member names (`.Ace` and `.Spades`) alone. In the example above, the `description` property correctly reports that the Ace of Spades has a value of `1` or `11`. + +即使`Rank`和`Suit`被嵌套在`BlackjackCard`里,他们依然可以被~~更外层的~~上下文引用。所以构造`BlackjackCard`实例时,可以仅通过成员名称(`.Ace` 和 `.Spades`)来引用枚举类型的成员。上面的例子中,属性`description`如我们所愿,输出了黑桃A的值`1`或`11`。 + +##Referring to Nested Types +##引用嵌套类型 + +To use a nested type outside of its definition context, prefix its name with the name of the type it is nested within: + +外部引用嵌套类型时,仅需在其名称前加上外层类型的名称即可: + +``` +let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw() +// heartsSymbol is "♡" +``` + +For the example above, this enables the names of `Suit`, `Rank`, and `Values` to be kept deliberately short, because their names are naturally qualified by the context in which they are defined. + +正如上例所示,嵌套类型的引用方式可以使`Suit`、`Rank`和`Values`的名字尽可能的简短,因为他们的名字会自然地被所定义的上下文限制。 + diff --git a/src/chapter2/20_Extensions.md b/src/chapter2/20_Extensions.md new file mode 100644 index 0000000..fe6a95a --- /dev/null +++ b/src/chapter2/20_Extensions.md @@ -0,0 +1,397 @@ +# Extensions + +# 扩展(Extensions) + + +Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) + +扩展为已有的类,结构,枚举添加新的功能。其中包括扩展没有代码访问权限的类型(即追溯建模,retroactive modeling)。扩展和 Objective-C 当中的分类(category)很相似。(与 Objective-C 中的分类不同的是,Swift 的扩展没有名字) + +Extensions in Swift can: +- Add computed properties and computed static properties +- Define instance methods and type methods +- Provide new initializers +- Define subscripts +- Define and use new nested types +- Make an existing type conform to a protocol + +Swift 中的扩展可以: +- 增加计算属性和静态计算属性 +- 定义实例方法和类型方法 +- 提供新的构造器 +- 定义下标 +- 定义和使用新的嵌套类型 +- 将已有的类型转换为符合某一个协议 + +> Note +> +> If you define an extension to add new functionality to an existing type, the new functionality will be available on all existing instances of that type, even if they were created before the extension was defined. + + +> 提示 +> +> 如果定义一个扩展用来在已有的类型上增加新的功能,那么新功能会应用在所有已经存在的实例上,即使是在扩展被定义之前实例化的。 + +## Extension Syntax + +## 扩展的语法 + +Declare extensions with the extension keyword: + +使用 ``extension`` 关键字来声明扩展: + +``` +extension SomeType { + // new functionality to add to SomeType goes here +} +``` + +An extension can extend an existing type to make it adopt one or more protocols. Where this is the case, the protocol names are written in exactly the same way as for a class or structure: + +一个扩展可以扩展一个已有的类型,使它能适配一个或多个的协议(protocol)。如果是这种情况的话,协议的命名方式应该与类和结构体的命名方式完全一致。 + +``` +extension SomeType: SomeProtocol, AnotherProtocol { + // implementation of protocol requirements goes here +} +``` + +Adding protocol conformance in this way is described in Adding Protocol Conformance with an Extension. + +这种增加协议一致性(protocol conformance)的方式在 [通过扩展增加协议一致性](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-XID_355) 一文中有记述。 + + +## Computed Properties + +## 计算属性(Computed Properties) + +Extensions can add computed instance properties and computed type properties to existing types. This example adds five computed instance properties to Swift’s built-in Double type, to provide basic support for working with distance units: + +扩展可以为已有的类型增加实例计算属性和类型计算属性。这个例子向 Swift 内建类型 ``Double`` 添加五个实例计算类型,用来提供转换为距离单位的基本功能: + +``` +extension Double { + var km: Double { return self * 1_000.0 } + var m: Double { return self } + var cm: Double { return self / 100.0 } + var mm: Double { return self / 1_000.0 } + var ft: Double { return self / 3.28084 } +} +let oneInch = 25.4.mm +println("One inch is \(oneInch) meters") +// prints "One inch is 0.0254 meters" +let threeFeet = 3.ft +println("Three feet is \(threeFeet) meters") +// prints "Three feet is 0.914399970739201 meters" +``` + +These computed properties express that a Double value should be considered as a certain unit of length. Although they are implemented as computed properties, the names of these properties can be appended to a floating-point literal value with dot syntax, as a way to use that literal value to perform distance conversions. + +这些计算属性表达的是一个 ``Double`` 类型的值是某种长度单位下的值。尽管是计算属性,但他们仍然可以接在一个带有 dot 语法的字面值的后面,用来将字面值转换成距离。 + +In this example, a Double value of 1.0 is considered to represent “one meter”. This is why the m computed property returns self—the expression 1.m is considered to calculate a Double value of 1.0. + +在上述的例子中,``Double`` 类型的 ``1.0`` 代表 “一米” 。这是为什么计算属性 ``m`` 仅仅返回 ``self`` ——表达式 ``1.m`` 最终结果是 ``Double`` 类型的值 ``1.0`` 。 + +Other units require some conversion to be expressed as a value measured in meters. One kilometer is the same as 1,000 meters, so the km computed property multiplies the value by 1_000.00 to convert into a number expressed in meters. Similarly, there are 3.28024 feet in a meter, and so the ft computed property divides the underlying Double value by 3.28024, to convert it from feet to meters. + +其他单位转换为以米为单位的数值需要进行一些转换。1千米等于1,000米,所以计算属性 ``km`` 要把数值转换成以米为单位,需要把值乘以 ''1_000.00''。同样,1英尺等于 ''3.28084'' 米,所以计算属性 ''ft'' 需要把值除以 ''3.28024'' 才能把英尺转换成米。 + +These properties are read-only computed properties, and so they are expressed without the get keyword, for brevity. Their return value is of type Double, and can be used within mathematical calculations wherever a Double is accepted: + +因为这些都是只读的计算属性,所以为了简便起见,不需要关键字 ''keyword'' 进行表示。他们的返回值都是 ``Double`` 类型的,所以可以用在所有可以接受 ``Double`` 类型的数学计算中: + +``` +let aMarathon = 42.km + 195.m +println("A marathon is \(aMarathon) meters long") +// prints "A marathon is 42195.0 meters long" +``` + +> Note +> +> Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties. + + +> 提示 +> +> 扩展可以添加新的计算属性,但是不能添加存储属性,也不能向已有属性添加属性观察器(property observer)。 + + +## Initializers + +## 构造器(Initializers) + +Extensions can add new initializers to existing types. This enables you to extend other types to accept your own custom types as initializer parameters, or to provide additional initialization options that were not included as part of the type’s original implementation. + +扩展能向已有类型添加新的构造器。这允许你用自己定义的类型作为构造器参数扩展其他的类型,或者提供原始实现没有提供的额外的初始化选项 + +Extensions can add new convenience initializers to a class, but they cannot add new designated initializers or deinitializers to a class. Designated initializers and deinitializers must always be provided by the original class implementation. + +扩展能向类添加新的简便构造器,但是不能添加新的指定构造器或者析构器。指定构造器和析构器必须在类的原始实现中提供。 + + +> Note +> +> If you use an extension to add an initializer to a value type that provides default values for all of its stored properties and does not define any custom initializers, you can call the default initializer and memberwise initializer for that value type from within your extension’s initializer. +> This would not be the case if you had written the initializer as part of the value type’s original implementation, as described in Initializer Delegation for Value Types. + + +> 提示 +> +> 如果使用扩展向一个值类型添加构造器,该构造器向所有存储属性提供默认值并且未定义任何其他的自定义构造器,你可以调用默认的构造和成员构造器来为你扩展的构造器当中的值类型赋值。 +> 正如 [构造器对值类型的构造委托](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_281) 一文所说的那样,如果你已经把构造器写成值类型原始实现的一部分,则不符合上述规则。 + +The example below defines a custom Rect structure to represent a geometric rectangle. The example also defines two supporting structures called Size and Point, both of which provide default values of 0.0 for all of their properties: + +在下面的例子里,定义了一个用于描述几何矩形的结构体 ``Rect`` 。同时定义了两个辅助性结构体 ``Size``,``Point``,两个结构体当中的属性默认值都为 ``0.0``: + +``` +struct Size { + var width = 0.0, height = 0.0 +} +struct Point { + var x = 0.0, y = 0.0 +} +struct Rect { + var origin = Point() + var size = Size() +} +``` + +Because the Rect structure provides default values for all of its properties, it receives a default initializer and a memberwise initializer automatically, as described in Default Initializers. These initializers can be used to create new Rect instances: + +因为 结构体 ``Rect`` 为所有的属性都提供了默认值,正如默认构造器一节所说的,它可以自动接受默认构造器和成员构造器。这些构造器可以用来创建新的 ``Rect`` 实例: + +``` +let defaultRect = Rect() +let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), + size: Size(width: 5.0, height: 5.0)) +``` + +You can extend the Rect structure to provide an additional initializer that takes a specific center point and size: + +你可以使用扩展来为结构体 ``Rect`` 额外提供一个以中心点和大小作为参数的构造器: + +``` +extension Rect { + 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) + } +} +``` + +This new initializer starts by calculating an appropriate origin point based on the provided center point and size value. The initializer then calls the structure’s automatic memberwise initializer init(origin:size:), which stores the new origin and size values in the appropriate properties: + +新构造器通过中心点和大小两个参数计算出合适的原点值,然后调用结构体的自动成员构造器 ``init(origin:size:)`` ,把计算出的值存储到合适的属性上: + +``` +let centerRect = Rect(center: Point(x: 4.0, y: 4.0), + size: Size(width: 3.0, height: 3.0)) +// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0) +``` + +> Note +> +> If you provide a new initializer with an extension, you are still responsible for making sure that each instance is fully initialized once the initializer completes. + + +> 提示 +> +> 如果使用扩展来提供新的构造器,那么你仍要确保构造过程中,每一个实例都被完全初始化了。 + + +## Methods + +## 方法(Methods) + +Extensions can add new instance methods and type methods to existing types. The following example adds a new instance method called repetitions to the Int type: + +扩展可以向已有类型添加新的实例方法和类型方法。下面的例子中,向 类型 ``Int`` 中添加了新的实例方法 ``repetitions``: + +``` +extension Int { + func repetitions(task: () -> ()) { + for i in 0..self { + task() + } + } +} +``` + +The repetitions method takes a single argument of type () -> (), which indicates a function that has no parameters and does not return a value. + +``repetitions`` 方法的参数是 ``() -> ()``,说明参数是一个无参数无返回值的函数 + +After defining this extension, you can call the repetitions method on any integer number to perform a task that many number of times: + +扩展被定义之后,你就可以在任何整数上调用 ``repetitions`` 方法,来多次执行某个任务: + +``` +3.repetitions({ + println("Hello!") +}) +// Hello! +// Hello! +// Hello! +``` + +Use trailing closure syntax to make the call more succinct: + +使用尾随闭包(trailing closure)语法可以使调用更简洁: + +``` +3.repetitions { + println("Goodbye!") +} +// Goodbye! +// Goodbye! +// Goodbye! +``` + + +## Mutating Instance Methods + +## 可变实例方法(Mutating Instance Methods) + +Instance methods added with an extension can also modify (or mutate) the instance itself. Structure and enumeration methods that modify self or its properties must mark the instance method as mutating, just like mutating methods from an original implementation. + +通过扩展添加的实例方法也可以修改实例本身。结构体和枚举类型的方法中改变 ``self`` 或者其中的属性,必须标记实例的方法为 ``mutating`` ,就像原始实现中的声明变异方法(mutating method)一样。 + +The example below adds a new mutating method called square to Swift’s Int type, which squares the original value: + +下面的例子为 Swift 中的 ``Int`` 类型添加了一个新的变异方法 ``square``,用来计算原始值的平方: + +``` +extension Int { + mutating func square() { + self = self * self + } +} +var someInt = 3 +someInt.square() +// someInt is now 9 +``` + + +## Subscripts + +## 下标(Subscripts) + +Extensions can add new subscripts to an existing type. This example adds an integer subscript to Swift’s built-in Int type. This subscript [n] returns the decimal digit n places in from the right of the number: + +扩展可以为已有类型添加新的下标。下面的例子为 Swift 中的内建类型 ``Int`` 添加一个整型下标。下标 ``[n]`` 返回 十进制数从右往左第 n 位上的数字: + +- 123456789[0] returns 9 +- 123456789[1] returns 8 + +…and so on: + +……以此类推: + +``` +extension Int { + subscript(digitIndex: Int) -> Int { + var decimalBase = 1 + for _ in 1...digitIndex { + decimalBase *= 10 + } + return (self / decimalBase) % 10 + } +} +746381295[0] +// returns 5 +746381295[1] +// returns 9 +746381295[2] +// returns 2 +746381295[8] +// returns 7 +``` + +If the Int value does not have enough digits for the requested index, the subscript implementation returns 0, as if the number had been padded with zeroes to the left: + +如果该 ``Int`` 值没有足够的位数与请求对应,即下标越界,则下标会返回 ``0`` ,就好像它自动在数字左边补0一样: + +``` +746381295[9] +// returns 0, as if you had requested: +0746381295[9] +``` + + +## Nested Types + +## 嵌套类型(Nested Types) + +Extensions can add new nested types to existing classes, structures and enumerations: + +扩展可以向已有的类,结构体和枚举类型添加新的嵌套类型: + +``` +extension Character { + enum Kind { + case Vowel, Consonant, Other + } + var kind: Kind { + switch String(self).lowercaseString { + case "a", "e", "i", "o", "u": + return .Vowel + case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", + "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z": + return .Consonant + default: + return .Other + } + } +} +``` + +This example adds a new nested enumeration to Character. This enumeration, called Kind, expresses the kind of letter that a particular character represents. Specifically, it expresses whether the character is a vowel or a consonant in a standard Latin script (without taking into account accents or regional variations), or whether it is another kind of character. + +上面的例子为 ``Character`` 添加了新的嵌套枚举。枚举类型的 ``Kind`` 表示一个字符所属的种类。具体来说就是一个字符是拉丁字母的元音,辅音,还是其他种类的字符(不考虑口语和地方变种的情况下)。 + +This example also adds a new computed instance property to Character, called kind, which returns the appropriate Kind enumeration member for that character. + +这个例子中同时也为 ``Character`` 添加了一个新的实例计算属性 ``kind``,用来返回字符对应的枚举成员 ``Kind`` + +The nested enumeration can now be used with Character values: + +现在嵌套枚举可以在 ``Character`` 上面使用了: + +``` +func printLetterKinds(word: String) { + println("'\(word)' is made up of the following kinds of letters:") + for character in word { + switch character.kind { + case .Vowel: + print("vowel ") + case .Consonant: + print("consonant ") + case .Other: + print("other ") + } + } + print("\n") +} +printLetterKinds("Hello") +// 'Hello' is made up of the following kinds of letters: +// consonant vowel consonant consonant vowel +``` + +This function, printLetterKinds, takes an input String value and iterates over its characters. For each character, it considers the kind computed property for that character, and prints an appropriate description of that kind. The printLetterKinds function can then be called to print the kinds of letters in an entire word, as shown here for the word "Hello". + +``printLetterKinds`` 函数迭代 ``String`` 类型的参数的每一个字母。每次迭代都根据当前字母包含的计算属性 ``kind`` 输出对应的类型描述。这样,``printLetterKinds`` 函数就输出了一个单词内所有字母的类型,正如上面例子中的单词 "word" 一样。 + + +> Note +> +> character.kind is already known to be of type Character.Kind. Because of this, all of the Character.Kind member values can be written in shorthand form inside the switch statement, such as .Vowel rather than Character.Kind.Vowel. + + +> 提示 +> +> 因为已知 ``character.kind`` 的类型是 ``Character.Kind``,所以所有 ``Character.Kind`` 的成员值都可以在 ``switch`` 语句中使用简写形式,比如使用 ``.Vowel`` 来代替 ``Character.Kind.Vowel``。 + + diff --git a/src/chapter2/21_Protocols.md b/src/chapter2/21_Protocols.md new file mode 100644 index 0000000..ce4150f --- /dev/null +++ b/src/chapter2/21_Protocols.md @@ -0,0 +1,943 @@ +#Protocols +A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol doesn’t actually provide an implementation for any of these requirements—it only describes what an implementation will look like. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to conform to that protocol. + + +#协议 + +一个协议(protocol)定义了适合特定的任务或功能的方法、属性和其他需求。协议并不提供这些需求的实现,只描述了这个实现应该是怎样的。 + +协议能够被类(class),结构体(structure),枚举(enumeration)适配(adopted),同时,这些类型如果了满足一个协议需求,则被称为遵循(conform to)协议 + +Protocols can require that conforming types have specific instance properties, instance methods, type methods, operators, and subscripts. + +协议可以要求遵循(conforming)的类型有特定的实例属性(instance properties),实例方法(instance methods),类型方法(type methods),操作符(operators)和下标(subscripts)。 + + +##Protocol Syntax +##协议语法 +You define protocols in a very similar way to classes, structures, and enumerations: + +定义协议,与定义类,结构体,枚举的方式非常相似,如下所示: + + protocol SomeProtocol { + // protocol definition goes here + } + +Custom types state that they adopt a particular protocol by placing the protocol’s name after the type’s name, separated by a colon, as part of their definition. Multiple protocols can be listed, and are separated by commas: + +在类型名称后添加协议名称,并以冒号`:`分割,表示自定义类型(Custom types)适配一个特定协议;实现多个协议时,各协议之间用逗号`,`分隔,如下所示: + + struct SomeStructure: FirstProtocol, AnotherProtocol { + // structure definition goes here + } +If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma: + +若某个类有父类,要把父类放在所有其适配的协议之前,且用逗号`,`分割,如下所示: + + class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol { + // class definition goes here + } + +Property Requirements + +##属性要求 + +A protocol can require any conforming type to provide an instance property or type property with a particular name and type. The protocol doesn’t specify whether the property should be a stored property or a computed property—it only specifies the required property name and type. The protocol also specifies whether each property must be gettable or gettable and settable. + +协议可以要求任何遵循(conforming)类型,提供一个特定名称和类型的实例属性(instance property)或类型属性(type property)。协议不指定属性是存储型属性(stored property)还是计算型属性(calculate property)。 +协议同时指定了每个属性是否是可读(gettable)或可读写(gettable and settable) + + +If a protocol requires a property to be gettable and settable, that property requirement cannot be fulfilled by a constant stored property or a read-only computed property. If the protocol only requires a property to be gettable, the requirement can be satisfied by any kind of property, and it is valid for it also to be settable if this is useful for your own code. + +如果协议要求属性可读写(gettable and settable),那常量存储属性(constant stored property)或者只读计算属性(read-only computed property)都无法满足此要求。如果协议只要求属性可读(gettable),那任何类型的属性都满足这个要求,即使这些属性是可写(settable)的。 + +Property requirements are always declared as variable properties, prefixed with the var keyword. Gettable and settable properties are indicated by writing { get set } after their type declaration, and gettable properties are indicated by writing { get }. + +协议里的属性要求,通常都是通过使用`var`关键字来声明的变量属性。 +在类型声明之后用{ get set }表示属性为可读写的。{ get }表示属性为可读的。 + + protocol SomeProtocol { + var mustBeSettable: Int { get set } + var doesNotNeedToBeSettable: Int { get } + } + +Always prefix type property requirements with the class keyword when you define them in a protocol. This is true even though type property requirements are prefixed with the static keyword when implemented by a structure or enumeration: + +当你在一个协议中定义一个某种类型的属性要求,总要前置`class` 关键字。同样某类型属性要求使用`static`关键字前缀,来定义结构体(structure)或枚举类型(enumeration) + +> 这样翻译正确么? + + protocol AnotherProtocol { + class var someTypeProperty: Int { get set } + } + +Here’s an example of a protocol with a single instance property requirement: + +下面是协议的一个例子,这个协议只有一个实例属性(instance property)要求: + + + protocol FullyNamed { + var fullName: String { get } + } + +The FullyNamed protocol defines any kind of thing that has a fully-qualified name. It doesn’t specify what kind of thing it must be—it only specifies that the thing must be able to provide a full name for itself. It specifies this requirement by stating that any FullyNamed type must have a gettable instance property called fullName, which is of type String. + +`FullyNamed`协议可以定义任何需要一个完整`name`的类型(方法,属性或者其他需求)。这个协议并不指定什么,只有一个需求:这个类型本身必须提供一个完整的名称。这个需求通过声明一个`String`类型的实例属性`fullName`,且这个属性必须是可读的(gettable)来指定。 + + + +Here’s an example of a simple structure that adopts and conforms to the FullyNamed protocol: + +下面的例子中,一个简单的结构体适配且遵循`FullyNamed`协议 + + struct Person: FullyNamed { + var fullName: String + } + let john = Person(fullName: "John Appleseed") + // john.fullName is "John Appleseed" + +This example defines a structure called Person, which represents a specific named person. It states that it adopts the FullyNamed protocol as part of the first line of its definition. + +这个例子中定义了一个名为`Person`的结构体,代表一个有名字的人。它在第一行的结构体定义中,声明了其适配`FullyNamed`协议。 + +Each instance of Person has a single stored property called fullName, which is of type String. This matches the single requirement of the FullyNamed protocol, and means that Person has correctly conformed to the protocol. (Swift reports an error at compile-time if a protocol requirement is not fulfilled.) + +每个`Person`实例都有一个单独存储的,`String`类型的属性`fullName`。拥有这个属性代表满足了`FullyNamed`协议的要求,这意味着`Person`遵循协议。(在编译时如果不满足协议要求,swift会报告一个错误)。 + + +Here’s a more complex class, which also adopts and conforms to the FullyNamed protocol: +下面有一个更复杂的类,同样适配且遵循`FullyNamed`协议 + + class Starship: FullyNamed { + var prefix: String? + var name: String + init(name: String, prefix: String? = nil) { + self.name = name + self.prefix = prefix + } + var fullName: String { + return (prefix ? prefix! + " " : "") + name + } + } + var ncc1701 = Starship(name: "Enterprise", prefix: "USS") + // ncc1701.fullName is "USS Enterprise" + +This class implements the fullName property requirement as a computed read-only property for a starship. Each Starship class instance stores a mandatory name and an optional prefix. The fullName property uses the prefix value if it exists, and prepends it to the beginning of name to create a full name for the starship. +这个类提供了`fullName`属性,这个属性是`starship`这个类的一个只读的计算属性。 +每个`starship`类的实例存储一个强制性的名称和一个可选的前缀。当存在前缀时,`fullName`属性会把前缀添加到名称前面,从而创建了一个`starship`的全名。 + + +Method Requirements + +Protocols can require specific instance methods and type methods to be implemented by conforming types. These methods are written as part of the protocol’s definition in exactly the same way as for normal instance and type methods, but without curly braces or a method body. Variadic parameters are allowed, subject to the same rules as for normal methods. + + + +方法需求 + +若某种类型遵循协议,协议可以要求指定特定的实例方法和类型方法。这些方法作为协议定义的一部分,跟通常定义实例与类型方法的途径完全一样,但不需要书写大括号或方法的主体。方法允许含有可变参数,且与通常的方法遵循同样的规则。 + +NOTE + +Protocols use the same syntax as normal methods, but are not allowed to specify default values for method parameters. + +注意 + +协议与通常的方法语法相同,但不允许指定方法中参数的默认值 + +As with type property requirements, you always prefix type method requirements with the class keyword when they are defined in a protocol. This is true even though type method requirements are prefixed with the static keyword when implemented by a structure or enumeration: + + protocol SomeProtocol { + class func someTypeMethod() + } + +当你在一个协议中定义一个某种类型的方法要求,要前置`class` 关键字。同样某类型方法要求使用`static`关键字前缀,来定义结构体(structure)或枚举类型(enumeration) + +The following example defines a protocol with a single instance method requirement: +下面的例子中,定义了一个协议,协议要求一个实例方法。 + + protocol RandomNumberGenerator { + func random() -> Double + } +This protocol, RandomNumberGenerator, requires any conforming type to have an instance method called random, which returns a Double value whenever it is called. (Although it is not specified as part of the protocol, it is assumed that this value will be a number between 0.0 and 1.0 inclusive.) + +`RandomNumberGenerator`,该协议要求任何遵循协议的类型调用一个名为random的实例方法,这个方法无论何时调用,都会返回一个Double类型的值。(这个值在0.0与1.0之间,这一点没有在协议中指出)。 + + +The RandomNumberGenerator protocol does not make any assumptions about how each random number will be generated—it simply requires the generator to provide a standard way to generate a new random number. + +Here’s an implementation of a class that adopts and conforms to the RandomNumberGenerator protocol. This class implements a pseudorandom number generator algorithm known as a linear congruential generator: + + `RandomNumberGenerator`协议不会描述如何建立一个随机数,只需要指定一个随机数生成器,从而提供一种标准的方式来生成一个新随机数。 +   + 下面是一个类的实现,遵循`RandomNumberGenerator`协议。这个类实现了一种伪随机数发生器算法,称为线性同余(linear congruential)发生器: + + + class LinearCongruentialGenerator: RandomNumberGenerator { + var lastRandom = 42.0 + let m = 139968.0 + let a = 3877.0 + let c = 29573.0 + func random() -> Double { + lastRandom = ((lastRandom * a + c) % m) + return lastRandom / m + } + } + let generator = LinearCongruentialGenerator() + println("Here's a random number: \(generator.random())") + // prints "Here's a random number: 0.37464991998171" + println("And another one: \(generator.random())") + // prints "And another one: 0.729023776863283" + +Mutating Method Requirements + +突变方法要求 + +It is sometimes necessary for a method to modify (or mutate) the instance it belongs to. For instance methods on value types (that is, structures and enumerations) you place the mutating keyword before a method’s func keyword to indicate that the method is allowed to modify the instance it belongs to and/or any properties of that instance. This process is described in Modifying Value Types from Within Instance Methods. + +有时,实例的一个方法需要修改(或突变)实例的类型。对值类型(value types)(即结构体和枚举类型)的实例方法中,使用`mutating`关键字,写在方法的函数关键字`fun`前面,来表明实例中该方法允许修改其类型及任何属性。这个过程在 `在实例方法中修改值类型`章节中有详细的描述。 + +If you define a protocol instance method requirement that is intended to mutate instances of any type that adopts the protocol, mark the method with the mutating keyword as part of the protocol’s definition. This enables structures and enumerations to adopt the protocol and satisfy that method requirement. + +如果你定义的协议中,某个实例适配此协议,而实例方法需要改变其类型,协议定义时要在此方法前加上关键字`mutating`。这样可以让结构体及枚举类型适配协议,且满足实例方法的需求。 + +NOTE +注意 + +If you mark a protocol instance method requirement as mutating, you do not need to write the mutating keyword when writing an implementation of that method for a class. The mutating keyword is only used by structures and enumerations. + + +如果你在一个协议中实现的突变方法是为一个类服务的,不需要为其加`上mutating`关键字。 +mutating`关键字只用在结构体与枚举类型中。 +` + +The example below defines a protocol called Togglable, which defines a single instance method requirement called toggle. As its name suggests, the toggle method is intended to toggle or invert the state of any conforming type, typically by modifying a property of that type. + +下面的例子中定义了一个`togglable`协议,包含一个名为`togger`的突变实例方法。正如名称所表达的,适配此协议的某实例中,toggle方法通常会通过改变实例的某个属性,来切换或恢复其类型。 + +The toggle method is marked with the mutating keyword as part of the Togglable protocol definition, to indicate that the method is expected to mutate the state of a conforming instance when it is called: + +`toggle`方法前面加上了`mutating`关键字,作为`Togglabel`协议定义的一部分,则表示一个适配`toggleabel`协议的实例中,这个方法会在调用时改变实例的类型。 + + protocol Togglable { + mutating func toggle() + } + +If you implement the Togglable protocol for a structure or enumeration, that structure or enumeration can conform to the protocol by providing an implementation of the toggle method that is also marked as mutating. + +当你提供的枚举或结构体遵循`Togglable`协议时,需要提供一个带有`mutating`前缀的`toggle`方法。 + + +The example below defines an enumeration called OnOffSwitch. This enumeration toggles between two states, indicated by the enumeration cases On and Off. The enumeration’s toggle implementation is marked as mutating, to match the Togglable protocol’s requirements: + + enum OnOffSwitch: Togglable { + case Off, On + mutating func toggle() { + switch self { + case Off: + self = On + case On: + self = Off + } + } + } + var lightSwitch = OnOffSwitch.Off + lightSwitch.toggle() + // lightSwitch is now equal to .On + +Protocols as Types + +协议类型 + +Protocols do not actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use in your code. + +尽管协议本身并不实现任何功能,但协议可以作为完整的类型来使用。 + +Because it is a type, you can use a protocol in many places where other types are allowed, including: + +你可以把协议类型用在其他类型适用的场景里,比如: + +As a parameter type or return type in a function, method, or initializer + +在函数,方法或构造方法中作为形参类型(parameter type)或返回值类型(return type) + +As the type of a constant, variable, or property + +作为常量、变量或属性这三种类型之一 + +As the type of items in an array, dictionary, or other container + +作为数组,字典或其他容器中的元素类型 + +NOTE +注意 + +Because protocols are types, begin their names with a capital letter (such as FullyNamed and RandomNumberGenerator) to match the names of other types in Swift (such as Int, String, and Double). + +注意: 协议是一种类型,因此协议类型的名称应与Swift中其他类型(Int,Double,String)的写法相同,每一个单字的首字母都采用大写字母(大驼峰写法) + +Here’s an example of a protocol used as a type: + +下面的例子中,协议被当作类型使用: + + class Dice { + let sides: Int + let generator: RandomNumberGenerator + init(sides: Int, generator: RandomNumberGenerator) { + self.sides = sides + self.generator = generator + } + func roll() -> Int { + return Int(generator.random() * Double(sides)) + 1 + } + } + +This example defines a new class called Dice, which represents an n-sided dice for use in a board game. Dice instances have an integer property called sides, which represents how many sides they have, and a property called generator, which provides a random number generator from which to create dice roll values. + +例子中定义了一个`Dice`类,用来表示桌游中的拥有N个面的骰子。`Dice`的实例包含`sides`和`generator`两个属性,前者是整型(integer),用来表示骰子有几个面,后者提供了一个随机数生成器,来表示骰子掷出的值。 + +The generator property is of type RandomNumberGenerator. Therefore, you can set it to an instance of any type that adopts the RandomNumberGenerator protocol. Nothing else is required of the instance you assign to this property, except that the instance must adopt the RandomNumberGenerator protocol. + +`generator`属性的类型为`RandomNumberGenerator`,因此任何类型,若适配`RandomNumberGenerator`协议,其实例都可以赋值给`generator`,除此以外没有其他要求。 + +Dice also has an initializer, to set up its initial state. This initializer has a parameter called generator, which is also of type RandomNumberGenerator. You can pass a value of any conforming type in to this parameter when initializing a new Dice instance. + +`Dice`类也包含一个构造方法,用于设置其初始状态。这个方法包含一个同样是`RandomNumberGenerator`类型的参数`generator`。在构造一个新的`Dice`的实例时,可以传入任何遵循`RandomNumberGenerator`协议的类型作为`generator` + +Dice provides one instance method, roll, which returns an integer value between 1 and the number of sides on the dice. This method calls the generator’s random method to create a new random number between 0.0 and 1.0, and uses this random number to create a dice roll value within the correct range. Because generator is known to adopt RandomNumberGenerator, it is guaranteed to have a random method to call. + +Dice类提供了一个实例方法`roll`,此方法会返回一个整型值,介于1和骰子面的数量之间。这个方法调用`generator`的随机数方法,来创建一在0.0和1.0之间的随机数,并使用这个随机数来确保骰子的滚动值在正确的范围内。因为`generator`适配`RandomNumberGenerator`协议,因此它可以保证有一个`random`方法供调用。 + +Here’s how the Dice class can be used to create a six-sided dice with a LinearCongruentialGenerator instance as its random number generator: + +下面的例子中,展示了如何使用线性同余发生器(LinearCongruentialGenerator)的实例作为随机数生成器,从而创建一个六面的骰子: + + + var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator()) + for _ in 1...5 { + println("Random dice roll is \(d6.roll())") + } + // Random dice roll is 3 + // Random dice roll is 5 + // Random dice roll is 4 + // Random dice roll is 5 + // Random dice roll is 4 + +Delegation +代理 + +Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source. + +代理(Delegation)是一种设计模式,它允许类或结构体将一些他们负责的功能转交(代理)给其他类型的实例。 +委托模式的实现需要定义一个协议,这个协议封装了那些需要被代理的功能,而一个遵循此协议的实例则拥有这些功能 + +The example below defines two protocols for use with dice-based board games: + +下面的例子中定义了两个基于骰子游戏的协议: + + protocol DiceGame { + var dice: Dice { get } + func play() + } + protocol DiceGameDelegate { + func gameDidStart(game: DiceGame) + func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) + func gameDidEnd(game: DiceGame) + } + +The DiceGame protocol is a protocol that can be adopted by any game that involves dice. The DiceGameDelegate protocol can be adopted by any type to track the progress of a DiceGame. + +`DiceGame`协议可以被任意含有骰子的游戏所适配,`DiceGameDelegate`协议可以被任意用来追踪`DiceGame`过程的类型所适配 + +Here’s a version of the Snakes and Ladders game originally introduced in Control Flow. This version is adapted to use a Dice instance for its dice-rolls; to adopt the DiceGame protocol; and to notify a DiceGameDelegate about its progress: + +这里有一个,`Snakes and Ladders`游戏的新版本(之前的版本在流程控制这一节中介绍过)。新版本使用`Dice`类的实例作为掷骰子的需求,并且适配了`DiceGame`协议。同时通知(notify)`DiceGameDelegate`协议,用来记录游戏过程: + + class SnakesAndLadders: DiceGame { + let finalSquare = 25 + let dice = Dice(sides: 6, generator: LinearCongruentialGenerator()) + var square = 0 + var board: Int[] + init() { + board = Int[](count: finalSquare + 1, repeatedValue: 0) + board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 + board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 + } + var delegate: DiceGameDelegate? + func play() { + square = 0 + delegate?.gameDidStart(self) + gameLoop: while square != finalSquare { + let diceRoll = dice.roll() + delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll) + switch square + diceRoll { + case finalSquare: + break gameLoop + case let newSquare where newSquare > finalSquare: + continue gameLoop + default: + square += diceRoll + square += board[square] + } + } + delegate?.gameDidEnd(self) + } + } +For a description of the Snakes and Ladders gameplay, see the Break section of the Control Flow chapter. + +你可以参考流程控制章节中对此游戏的介绍 + +> 译者注 Snakes and Ladders 是蛇梯棋游戏,一种类似大富翁的游戏。 + +This version of the game is wrapped up as a class called SnakesAndLadders, which adopts the DiceGame protocol. It provides a gettable dice property and a play method in order to conform to the protocol. (The dice property is declared as a constant property because it does not need to change after initialization, and the protocol only requires that it is gettable.) + +这个版本的游戏封装为`SnakesAndLadders`类,该类适配`DiceGame`协议。这个类还提供了可读的`dice`属性和`play`方法,从而遵循了`DiceGame`协议。(`dice`属性声明为常量,因为构造之后dice属性就不在改变,且协议只要求`dice`为只读) + + + +The Snakes and Ladders game board setup takes place within the class’s init() initializer. All game logic is moved into the protocol’s play method, which uses the protocol’s required dice property to provide its dice roll values. + +`Snakes And Ladders`游戏通过构造方法(initializer)`init`初始化游戏。所有的游戏逻辑移到了`play`方法中,`play`方法使用协议要求的`dice`属性,来提供骰子掷出的值。 + +Note that the delegate property is defined as an optional DiceGameDelegate, because a delegate isn’t required in order to play the game. Because it is of an optional type, the delegate property is automatically set to an initial value of nil. Thereafter, the game instantiator has the option to set the property to a suitable delegate. + +注意,`delegate`属性并不是游戏运行所必须的,因此`delegate`被定义为`DiceGameDelegate`协议类型的可选属性,`delegate`使用nil作为初始值。此后,游戏实例可以选择将其设置为一个合适的代理。 + + + +DiceGameDelegate provides three methods for tracking the progress of a game. These three methods have been incorporated into the game logic within the play method above, and are called when a new game starts, a new turn begins, or the game ends. + +`DicegameDelegate`协议提供了三个方法来跟踪游戏过程。这三个方法存在于游戏的逻辑中,即上面的play()方法内。分别在游戏开始时,新一轮开始时,游戏结束时被调用。 + + +Because the delegate property is an optional DiceGameDelegate, the play method uses optional chaining each time it calls a method on the delegate. If the delegate property is nil, these delegate calls fail gracefully and without error. If the delegate property is non-nil, the delegate methods are called, and are passed the SnakesAndLadders instance as a parameter. + +因为`delegate`属性是一个遵循`DiceGameDelegate`的可选属性,因此在`play`方法中使用了可选链(optional chaining )来在代理时调用方法。 若`delegate`属性为`nil`, 则`delegate`所调用的方法正常失败(fail gracefully)且不报错。若`delegate`不为`nil`,则方法能够被调用,且作为一个参数传入`SnakesAndLadders`实例中 + +This next example shows a class called DiceGameTracker, which adopts the DiceGameDelegate protocol: + +下一个例子展示了一个名为`DiceGameTracker`的类,适配`DiceGameDelegate`协议。 + + class DiceGameTracker: DiceGameDelegate { + var numberOfTurns = 0 + func gameDidStart(game: DiceGame) { + numberOfTurns = 0 + if game is SnakesAndLadders { + println("Started a new game of Snakes and Ladders") + } + println("The game is using a \(game.dice.sides)-sided dice") + } + func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) { + ++numberOfTurns + println("Rolled a \(diceRoll)") + } + func gameDidEnd(game: DiceGame) { + println("The game lasted for \(numberOfTurns) turns") + } + } + +DiceGameTracker implements all three methods required by DiceGameDelegate. It uses these methods to keep track of the number of turns a game has taken. It resets a numberOfTurns property to zero when the game starts; increments it each time a new turn begins; and prints out the total number of turns once the game has ended. + +DiceGameTracker提供了DiceGameDelegate所要求的三个方法。它使用这三个方法来跟踪游戏进行的轮数。当游戏开始时,将numberOfTurns属性重置为0。每轮开始后递增这个值。当游戏结束时打印游戏进行的总轮数 + +The implementation of gameDidStart shown above uses the game parameter to print some introductory information about the game that is about to be played. The game parameter has a type of DiceGame, not SnakesAndLadders, and so gameDidStart can access and use only methods and properties that are implemented as part of the DiceGame protocol. However, the method is still able to use type casting to query the type of the underlying instance. In this example, it checks whether game is actually an instance of SnakesAndLadders behind the scenes, and prints an appropriate message if so. + +在如上所示的gameDidStart方法的实现中,游戏即将开始时使用了game参数来打印一些介绍性信息。game参数拥有一个DiceGame类型,而不是SnakesAndLadders,所以gameDidStart方法只能访问和使用DiceGame协议中的方法和属性。然而,该方法仍然能够使用类型检查(type casting)查询底层实例的类型。在这个例子中,它在幕后检查游戏是否是SnakesAndLadders的一个实例,当确认后打印一个适当的消息。 + +gameDidStart also accesses the dice property of the passed game parameter. Because game is known to conform to the DiceGame protocol, it is guaranteed to have a dice property, and so the gameDidStart method is able to access and print the dice’s sides property, regardless of what kind of game is being played. + +gameDidStart方法也能够访问dice属性,这个属性存在于被传递为参数的game中。game遵循DiceGame协议,因此被赋予了dice属性,不管运行何种游戏,gameDidStart方法都可以访问且打印骰子的边数。 + + +下面是DiceGameTracker的运行过程: +Here’s how DiceGameTracker looks in action: + + let tracker = DiceGameTracker() + let game = SnakesAndLadders() + game.delegate = tracker + game.play() + // Started a new game of Snakes and Ladders + // The game is using a 6-sided dice + // Rolled a 3 + // Rolled a 5 + // Rolled a 4 + // Rolled a 5 + // The game lasted for 4 turns + +Adding Protocol Conformance with an Extension + +使用扩展添加协议一致性 + +You can extend an existing type to adopt and conform to a new protocol, even if you do not have access to the source code for the existing type. Extensions can add new properties, methods, and subscripts to an existing type, and are therefore able to add any requirements that a protocol may demand. For more about extensions, see Extensions. + +即便不能修改现有类型的代码,你也可以扩展现有类型,从而适配和遵循新协议。扩展(extensions)可以在现有的类型上添加新属性、方法和下标,因此能够满足任何一个协议的需要。更多关于扩展相关的内容,请参考扩展。 + +NOTE +注意 + +Existing instances of a type automatically adopt and conform to a protocol when that conformance is added to the instance’s type in an extension. + +当你使用一个扩展,为一个实例的类型添加上某种对协议的适配后,这个类型已存在的所有实例,都会自动适配与遵循此协议。 + +For example, this protocol, called TextRepresentable, can be implemented by any type that has a way to be represented as text. This might be a description of itself, or a text version of its current state: + +举例来讲,下面的TextRepersentable协议,可以被任何能表现为文字的类型所适配。这有可能是其自身的描述,或是其状态的文字版本。 + + protocol TextRepresentable { + func asText() -> String + } + +The Dice class from earlier can be extended to adopt and conform to TextRepresentable: + +之前的Dice类可以扩展为适配并遵循TextRepresentable协议: + + extension Dice: TextRepresentable { + func asText() -> String { + return "A \(sides)-sided dice" + } + } + +This extension adopts the new protocol in exactly the same way as if Dice had provided it in its original implementation. The protocol name is provided after the type name, separated by a colon, and an implementation of all requirements of the protocol is provided within the extension’s curly braces. + +这个扩展以完全相同的方式适配了新协议,就像骰子提供了最初(适配协议)的实现。协议名称放在类型名称后,用`:`隔开,协议所要求的实现则提供在扩展的花括号内。 + + +Any Dice instance can now be treated as TextRepresentable: + +现在Dice类型的实例可被当作是TextRepresentable类型: + + let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator()) + println(d12.asText()) + // prints "A 12-sided dice" + +Similarly, the SnakesAndLadders game class can be extended to adopt and conform to the TextRepresentable protocol: + +同样,SnakesAndLadders类也可以扩展为适配且遵循TextRepresentable协议: + + extension SnakesAndLadders: TextRepresentable { + func asText() -> String { + return "A game of Snakes and Ladders with \(finalSquare) squares" + } + } + println(game.asText()) + // prints "A game of Snakes and Ladders with 25 squares" + +Declaring Protocol Adoption with an Extension + +通过扩展声明协议适配 + +If a type already conforms to all of the requirements of a protocol, but has not yet stated that it adopts that protocol, you can make it adopt the protocol with an empty extension: + +若一个类型已经遵循了一个协议的所有要求,但未声明此类型适配这个协议,你可以使用一个空的扩展来让其适配协议。 + + struct Hamster { + var name: String + func asText() -> String { + return "A hamster named \(name)" + } + } + extension Hamster: TextRepresentable {} + +Instances of Hamster can now be used wherever TextRepresentable is the required type: + +从现在起,Hamster的实例可以作为TextRepresentable所需要的类型来使用 + + let simonTheHamster = Hamster(name: "Simon") + let somethingTextRepresentable: TextRepresentable = simonTheHamster + println(somethingTextRepresentable.asText()) + // prints "A hamster named Simon" + +NOTE +注意 + +Types do not automatically adopt a protocol just by satisfying its requirements. They must always explicitly declare their adoption of the protocol. + +注意: 即使满足了协议的所有要求,类型也不会自动适配一个协议,因此你必须显式的声明协议适配。 + +Collections of Protocol Type + +集合中的协议类型 + +A protocol can be used as the type to be stored in a collection such as an array or a dictionary, as mentioned in Protocols as Types. This example creates an array of TextRepresentable things: + +协议可以作为集合(数组,字典)内所存储的类型使用,就像之前所讲的一样,协议作为类型使用: + + let things: TextRepresentable[] = [game, d12, simonTheHamster] + +It is now possible to iterate over the items in the array, and print each item’s textual representation: + +如下所示,可以遍历things数组的元素,并打印每个元素的文本(通过asText方法) + + for thing in things { + println(thing.asText()) + } + // A game of Snakes and Ladders with 25 squares + // A 12-sided dice + // A hamster named Simon + +Note that the thing constant is of type TextRepresentable. It is not of type Dice, or DiceGame, or Hamster, even if the actual instance behind the scenes is of one of those types. Nonetheless, because it is of type TextRepresentable, and anything that is TextRepresentable is known to have an asText method, it is safe to call thing.asText each time through the loop. + +注意,thing常量是TextRepresentable类型的。它并非Dice、DiceGame或Hamster类型,即使thing所代表的实例,背后其实是其中一个类型。 +尽管如此,因为thing是TextRepresentable协议类型,此类型都包含asText方法,因此在每次循环中可以安全的调用一次asText方法 + +Protocol Inheritance +协议继承 + +A protocol can inherit one or more other protocols and can add further requirements on top of the requirements it inherits. The syntax for protocol inheritance is similar to the syntax for class inheritance, but with the option to list multiple inherited protocols, separated by commas: + +协议能够继承一或多个其他协议,也可进一步在继承的协议上添加更多的需求。语法与类的继承相似,此外可以用逗号`,`分隔表示继承多个协议 + + protocol InheritingProtocol: SomeProtocol, AnotherProtocol { + // protocol definition goes here + } + +Here’s an example of a protocol that inherits the TextRepresentable protocol from above: +下面的例子中,一个协议继承了之前的TextRepresentable协议: + + protocol PrettyTextRepresentable: TextRepresentable { + func asPrettyText() -> String + } + +This example defines a new protocol, PrettyTextRepresentable, which inherits from TextRepresentable. Anything that adopts PrettyTextRepresentable must satisfy all of the requirements enforced by TextRepresentable, plus the additional requirements enforced by PrettyTextRepresentable. In this example, PrettyTextRepresentable adds a single requirement to provide an instance method called asPrettyText that returns a String. + +这个例子定义了一个新的协议PrettyTextRepresentable,继承自TextRepresentable。若适配PrettyTextRepresentable协议,必须同时满足TextRepresentable协议的需求,且满足由PrettyTextRepresentable添加的额外需求。在这个例子中,PrettyTextRepresentable添加了另一需求,要求提供一个称为asPrettyText的实例方法,用于返回一个字符串。 +The SnakesAndLadders class can be extended to adopt and conform to PrettyTextRepresentable: +可以扩展SnakesAndLadders类,来使之适配且遵循PrettyTextRepresentable协议。 + + extension SnakesAndLadders: PrettyTextRepresentable { + func asPrettyText() -> String { + var output = asText() + ":\n" + for index in 1...finalSquare { + switch board[index] { + case let ladder where ladder > 0: + output += "▲ " + case let snake where snake < 0: + output += "▼ " + default: + output += "○ " + } + } + return output + } + } + +This extension states that it adopts the PrettyTextRepresentable protocol and provides an implementation of the asPrettyText method for the SnakesAndLadders type. Anything that is PrettyTextRepresentable must also be TextRepresentable, and so the asPrettyText implementation starts by calling the asText method from the TextRepresentable protocol to begin an output string. It appends a colon and a line break, and uses this as the start of its pretty text representation. It then iterates through the array of board squares, and appends an emoji representation for each square: + +这个扩展声明其适配PrettyTextRepresentable协议,并提供了SnakesAndLadders类型PrettyText方法的一个实现。任何PrettyTextRepresentable协议也是TextRepresentable的扩展,所以,asPrettyText方法的实现过程是这样的:首先调用来自TextRepresentable协议的asText方法开始输出字符串。方法的输出会附加一个冒号和一个换行符,使用这个作为美化文本输出的开始。然后遍历这个方格板数组中的每一个格子,用一个符号来表示: + +If the square’s value is greater than 0, it is the base of a ladder, and is represented by ▲. +If the square’s value is less than 0, it is the head of a snake, and is represented by ▼. +Otherwise, the square’s value is 0, and it is a “free” square, represented by ○. +The method implementation can now be used to print a pretty text description of any SnakesAndLadders instance: + +当遍历出的元素的值大于0时,表示一个梯子的底部,用`▲`符号表示 +当遍历出的元素的值小于0时,表示一个蛇头,用`▲`符号表示 +当遍历出的元素的值等于0时,表示一个空白方块,用`○`符号表示 + + println(game.asPrettyText()) + // A game of Snakes and Ladders with 25 squares: + // ○ ○ ▲ ○ ○ ▲ ○ ○ ▲ ▲ ○ ○ ○ ▼ ○ ○ ○ ○ ▼ ○ ○ ▼ ○ ▼ ○ + +Protocol Composition +协议合成 + +It can be useful to require a type to conform to multiple protocols at once. You can combine multiple protocols into a single requirement with a protocol composition. Protocol compositions have the form protocol. You can list as many protocols within the pair of angle brackets (<>) as you need, separated by commas. + +有一种很有用的方式,来表示一种适配多个协议的类型。你可以使用协议合成(Protocol Composition)来组合多个协议。 +协议合成的格式为protocal``。你可以在尖括号(`<>`)内列出多个协议,用逗号`,`分隔。 + + + +Here’s an example that combines two protocols called Named and Aged into a single protocol composition requirement on a function parameter: + +下面的例子中,把两个协议Named与Aged组合为一个协议合成,并作为函数的参数使用 + + protocol Named { + var name: String { get } + } + protocol Aged { + var age: Int { get } + } + struct Person: Named, Aged { + var name: String + var age: Int + } + func wishHappyBirthday(celebrator: protocol) { + println("Happy birthday \(celebrator.name) - you're \(celebrator.age)!") + } + let birthdayPerson = Person(name: "Malcolm", age: 21) + wishHappyBirthday(birthdayPerson) + // prints "Happy birthday Malcolm - you're 21!" + + +This example defines a protocol called Named, with a single requirement for a gettable String property called name. It also defines a protocol called Aged, with a single requirement for a gettable Int property called age. Both of these protocols are adopted by a structure called Person. + +这个例子中,定义了一个Named协议,要求一个可读的String类型的属性`name`。同时定义了一个Aged协议,要求一个可读的Int类型的属性`Aged`。两个协议被`Person`结构体所适配。 + +The example also defines a function called wishHappyBirthday, which takes a single parameter called celebrator. The type of this parameter is protocol, which means “any type that conforms to both the Named and Aged protocols.” It doesn’t matter what specific type is passed to the function, as long as it conforms to both of the required protocols. + +这个例子也定义了带有参数`celebrator`的函数`wishHappyBirthday`。参数的类型是`protocol`,表示任何同时遵循Named与Aged协议的类型。不管向函数传递何种参数,只要遵循两个协议即可。 + + +The example then creates a new Person instance called birthdayPerson and passes this new instance to the wishHappyBirthday function. Because Person conforms to both protocols, this is a valid call, and the wishHappyBirthday function is able to print its birthday greeting. + +这个例子也创建了一个`Person`的实例`birthdayPerson`,且将这个实例作为参数传入`wishHappyBirthday`函数。因为Person同时适配 +两个协议,因此函数可以正常调用,并打印一个生日祝福。 + +NOTE +注意 + +Protocol compositions do not define a new, permanent protocol type. Rather, they define a temporary local protocol that has the combined requirements of all protocols in the composition. + +注意: 协议合成并不会生成一个新的协议类型,而是将多个协议合成为一个临时协议。 + +Checking for Protocol Conformance + +协议遵循检查 + +You can use the is and as operators described in Type Casting to check for protocol conformance, and to cast to a specific protocol. Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a type: + +你可以使用类型检查中介绍的`is`,`as`操作符,来检测某类型是否遵循某协议, + +The is operator returns true if an instance conforms to a protocol and returns false if it does not. +The as? version of the downcast operator returns an optional value of the protocol’s type, and this value is nil if the instance does not conform to that protocol. +The as version of the downcast operator forces the downcast to the protocol type and triggers a runtime error if the downcast does not succeed. + +is操作符用于检查实例是否遵循某个协议,若不遵循则返回`false`。 +as?根据协议类型返回一个可选值,当实例遵循协议时,返回该协议类型;否则返回nil +as操作符可以对协议类型进行强制向下转型。若若换失败则会报一个运行时错误。 + +> 译者注: 向下转型就是把基类转换到继承类,向上转型就是把继承类转换为基类。 + +This example defines a protocol called HasArea, with a single property requirement of a gettable Double property called area: + +下面的例子定义了协议HasArea,需要一个可读的Double类型的属性area。 + + @objc protocol HasArea { + var area: Double { get } + } + +NOTE +注意 +You can check for protocol conformance only if your protocol is marked with the @objc attribute, as seen for the HasArea protocol above. This attribute indicates that the protocol should be exposed to Objective-C code and is described in Using Swift with Cocoa and Objective-C. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to be able to check for protocol conformance. + +注意: 只有用`@objc`属性标注的协议,才可以做协议遵循检查。这个属性表示协议会暴露给Objective-C的代码,可以参考Using Siwft with Cocoa and Objectivei-c。即使你不打算与 Objective-C进行交互,当你需要进行协议遵循检查时,也要在协议前面添加`@objc`. + +Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to check for conformance, you will be able to apply that protocol only to class types. + +还要注意一点,`@objc`协议只适用于类,不能用于结构体或枚举。因此只有协议被应用在类上,才能使用`@objc`检查协议的遵循。 + +Here are two classes, Circle and Country, both of which conform to the HasArea protocol: + +下面两个类`Circle`与`Country`都遵循`HasArea`协议 + + class Circle: HasArea { + let pi = 3.1415927 + var radius: Double + var area: Double { return pi * radius * radius } + init(radius: Double) { self.radius = radius } + } + class Country: HasArea { + var area: Double + init(area: Double) { self.area = area } + } + +The Circle class implements the area property requirement as a computed property, based on a stored radius property. The Country class implements the area requirement directly as a stored property. Both classes correctly conform to the HasArea protocol. + +`Circle`类把`area`属性实现为基于存储属性 `radius`的计算属性, `Country`类则把`area`属性直接实现为存储型属性。这两个类都遵循`haxArea`协议。 + + +Here’s a class called Animal, which does not conform to the HasArea protocol: + +这个例子中`Animal`类不遵循`HasArea`协议: + + class Animal { + var legs: Int + init(legs: Int) { self.legs = legs } + } + +The Circle, Country and Animal classes do not have a shared base class. Nonetheless, they are all classes, and so instances of all three types can be used to initialize an array that stores values of type AnyObject: +`Circle`类,`Country`类,`Animal`类并没有一个相同的基类,可以采用`AnyObject`类型的数组来承载他们构造后的实例: + + let objects: AnyObject[] = [ + Circle(radius: 2.0), + Country(area: 243_610), + Animal(legs: 4) + ] +The objects array is initialized with an array literal containing a Circle instance with a radius of 2 units; a Country instance initialized with the surface area of the United Kingdom in square kilometers; and an Animal instance with four legs. + +The objects array can now be iterated, and each object in the array can be checked to see if it conforms to the HasArea protocol: + +objects数组使用数组字面量(array literal)初始化,数组包含一个`radius`为2的`Circle` 实例,aear属性等于英国面积的`Country`实例和一个`legs`属性为4的`Animal`实例。 + +现在objects数组可以被迭代,且可以对迭代出的每一个元素进行检查,看其是否遵循了`HasArea`协议: + + for object in objects { + if let objectWithArea = object as? HasArea { + println("Area is \(objectWithArea.area)") + } else { + println("Something that doesn't have an area") + } + } + // Area is 12.5663708 + // Area is 243610.0 + // Something that doesn't have an area + +Whenever an object in the array conforms to the HasArea protocol, the optional value returned by the as? operator is unwrapped with optional binding into a constant called objectWithArea. The objectWithArea constant is known to be of type HasArea, and so its area property can be accessed and printed in a type-safe way. + +Note that the underlying objects are not changed by the casting process. They continue to be a Circle, a Country and an Animal. However, at the point that they are stored in the objectWithArea constant, they are only known to be of type HasArea, and so only their area property can be accessed. + +迭代出的元素使用可选绑定(optional binding)将其绑定到`objectWithArea`常量上,使用as?操作符判断其是否遵循`HasArea`协议。`objectWithArea`常量是遵循HasArea协议类型的实例,因此其`area`属性是可以被访问和打印的。 + +`objects`数组中元素的类型并不会因为向下转型而改变,它们仍然是`Circle`,`Country`,`Animal`类型。然而,当它们被存储到`objectWithArea`常量后,只会被认为是`HasArea`类型,因此只有`area`属性能够被访问。 +Optional Protocol Requirements + +可选的协议要求 + +You can define optional requirements for protocols, These requirements do not have to be implemented by types that conform to the protocol. Optional requirements are prefixed by the @optional keyword as part of the protocol’s definition. + +您可以定义可选的协议要求,这些要求不需要类型实现符合协议。可选要求使用`@optional`关键字,作为协议的定义的一部分。 + +An optional protocol requirement can be called with optional chaining, to account for the possibility that the requirement was not implemented by a type that conforms to the protocol. For information on optional chaining, see Optional Chaining. + +You check for an implementation of an optional requirement by writing a question mark after the name of the requirement when it is called, such as someOptionalMethod?(someArgument). Optional property requirements, and optional method requirements that return a value, will always return an optional value of the appropriate type when they are accessed or called, to reflect the fact that the optional requirement may not have been implemented. + +可选协议要求通过可选链(optional chaining)进行调用,为一个类型实现不遵循协议预留可能,详细内容可以参考可选链章节。 + +你可以在实现名称后加上?来检查该实现,比如`someOptionalMethod?(someArgument)`。可选方法需求和可选属性要求,在调用或访问时都会返回一个可选值(optional value),当可选的要求可能没有被实施时,这个值也会反映出来。 + + + +NOTE + +Optional protocol requirements can only be specified if your protocol is marked with the @objc attribute. Even if you are not interoperating with Objective-C, you need to mark your protocols with the @objc attribute if you want to specify optional requirements. + +注意: 可选协议要求只能在含有`@objc`前缀的协议中指定。即使你不准备与Objective-c进行交互,当你要指定可选协议需求时,也需要添加这个前缀。 + +Note also that @objc protocols can be adopted only by classes, and not by structures or enumerations. If you mark your protocol as @objc in order to specify optional requirements, you will only be able to apply that protocol to class types. + +还要注意,`@objc`协议只适用于类,不能用于结构体或枚举。因此只有协议被应用在类上,才能通过`@objc`指定可选协议要求。 + +The following example defines an integer-counting class called Counter, which uses an external data source to provide its increment amount. This data source is defined by the CounterDataSource protocol, which has two optional requirements: + +下面的例子定义了一个计数器类`Counter`,它使用一个外部数据源提供其增量。这个数据源是`CounterDataSource`定义的协议,它有两个可选的要求: + + @objc protocol CounterDataSource { + @optional func incrementForCount(count: Int) -> Int + @optional var fixedIncrement: Int { get } + } + +The CounterDataSource protocol defines an optional method requirement called incrementForCount and an optional property requirement called fixedIncrement. These requirements define two different ways for data sources to provide an appropriate increment amount for a Counter instance. + +`CounterDataSource`协议定义了一个可选的方法要求incrementForCount和一个可选的属性要求`fixedIncrement` 。这些要求定义了两种不同的方式的数据源,来给Counter实例提供一个适当的增量。 + + +NOTE +注意 +Strictly speaking, you can write a custom class that conforms to CounterDataSource without implementing either protocol requirement. They are both optional, after all. Although technically allowed, this wouldn’t make for a very good data source. + +严格来讲,你可以实现一个类来适配协议`CounterDataSource`,而不去实现协议中的两个要求,因为`CounterDataSource`中的属性和方法要求都是可选的。尽管这样写是可以的,但这并不是一个好的数据源的实现。 + +The Counter class, defined below, has an optional dataSource property of type CounterDataSource?: +Counter类含有`CounterDataSource?`类型的可选属性`dataSource`,如下所示: + + @objc class Counter { + var count = 0 + var dataSource: CounterDataSource? + func increment() { + if let amount = dataSource?.incrementForCount?(count) { + count += amount + } else if let amount = dataSource?.fixedIncrement? { + count += amount + } + } + } +The Counter class stores its current value in a variable property called count. The Counter class also defines a method called increment, which increments the count property every time the method is called. + +`Counter`类通过`count`属性来存储当前值,`increment`方法在每次调用后增加`count`的值。 + + +The increment method first tries to retrieve an increment amount by looking for an implementation of the incrementForCount method on its data source. The increment method uses optional chaining to try to call incrementForCount, and passes the current count value as the method’s single argument. + +`increment`方法首先通过可选链调用`incrementForCount`方法内数据源的实现,从而获取增量,并将当前的`count`值作为参数传入方法 + + + +Note two levels of optional chaining at play here. Firstly, it is possible that dataSource may be nil, and so dataSource has a question mark after its name to indicate that incrementForCount should only be called if dataSource is non-nil. Secondly, even if dataSource does exist, there is no guarantee that it implements incrementForCount, because it is an optional requirement. This is why incrementForCount is also written with a question mark after its name. + +注意,这里有两级可选链。首先,`dataSource`可能为`nil`,所以`dataSource`后使用问好,表明只有在`dataSource`不为`nil`时才调用`incrementForCount`方法。其次,即使`dataSource`存在,也不能保证它实现了`incrementForCount`方法,因为这是一个可选的要求。这就是为什么`incrementForCount`的名字后面也跟着一个问号。 + +Because the call to incrementForCount can fail for either of these two reasons, the call returns an optional Int value. This is true even though incrementForCount is defined as returning a non-optional Int value in the definition of CounterDataSource. + +以上原因表明,即使`CounterDataSource`协议中`incrementForCount`方法被定义为返回一个非可选的Int类型的值,在调用`incrementForCount`方法后,也会返回一个Int类型的可选值。 + +After calling incrementForCount, the optional Int that it returns is unwrapped into a constant called amount, using optional binding. If the optional Int does contain a value—that is, if the delegate and method both exist, and the method returned a value—the unwrapped amount is added onto the stored count property, and incrementation is complete. + +当调用完incrementForCount方法后,返回的可选值通过可选绑定,赋值给常量`amont`。 +如果可选值包含值-代表如果代理和方法都存在,方法返回了值-`amount`会赋给存储属性`count`,这个增量过程就完成了。 + +If it is not possible to retrieve a value from the incrementForCount method—either because dataSource is nil, or because the data source does not implement incrementForCount—then the increment method tries to retrieve a value from the data source’s fixedIncrement property instead. The fixedIncrement property is also an optional requirement, and so its name is also written using optional chaining with a question mark on the end, to indicate that the attempt to access the property’s value can fail. As before, the returned value is an optional Int value, even though fixedIncrement is defined as a non-optional Int property as part of the CounterDataSource protocol definition. + +如果不能从incrementForCount方法获取到值 -可能`dataSource`为`nil`,或dataSource没有实现`incrementForCount方法`-increment方法会尝试从数据源中获取fixedIncrement属性的值来代替。`fixedIncrement`属性也是一个可选的要求,所以它也使用可选链,以一个问号结束,表明试图访问属性的值时可以失败。和之前一样,即使`CounterDataSource`协议中,`fixedIncrement`属性被定义为返回一个非可选的Int类型的值,返回值也是一个可选的Int类型的值。 + +Here’s a simple CounterDataSource implementation where the data source returns a constant value of 3 every time it is queried. It does this by implementing the optional fixedIncrement property requirement: + +这里有一个简单的CounterDataSource的实现,通过实现了可选属性fixedIncrement,每次查询都会返回一个常量3。 + + class ThreeSource: CounterDataSource { + let fixedIncrement = 3 + } + +You can use an instance of ThreeSource as the data source for a new Counter instance: + +你可以使用ThreeSource的实例作为Counter实例的数据源: + + var counter = Counter() + counter.dataSource = ThreeSource() + for _ in 1...4 { + counter.increment() + println(counter.count) + } + // 3 + // 6 + // 9 + // 12 + +The code above creates a new Counter instance; sets its data source to be a new ThreeSource instance; and calls the counter’s increment method four times. As expected, the counter’s count property increases by three each time increment is called. + +上面的代码创建了一个新的Counter实例,同时把数据源设置为ThreeSource的实例,之后调用了四次计数器的increment方法。正如我们所期望的,increment方法调用一次,计数器的count属性会增加3。 + +Here’s a more complex data source called TowardsZeroSource, which makes a Counter instance count up or down towards zero from its current count value: +这里有一个更加复杂的数据源例子`TowardsZeroSource`,使计数器实例会从当前计数值向上或向下计数,直到零: + + class TowardsZeroSource: CounterDataSource { + func incrementForCount(count: Int) -> Int { + if count == 0 { + return 0 + } else if count < 0 { + return 1 + } else { + return -1 + } + } + } +The TowardsZeroSource class implements the optional incrementForCount method from the CounterDataSource protocol and uses the count argument value to work out which direction to count in. If count is already zero, the method returns 0 to indicate that no further counting should take place. + +You can use an instance of TowardsZeroSource with the existing Counter instance to count from -4 to zero. Once the counter reaches zero, no more counting takes place: + +`TowardsZeroSource`类实现了`CounterDataSource`协议中可选的`incrementForCount`方法,使用`count`参数值来决定计数方向。如果`count`已经是零,方法返回0,表明不会有进一步计算了。 +   + 你可以在`Counter`实例中使用`TowardsZeroSource`实例,从-4计数至零。一旦计数器达到零就不会在计数了: + + counter.count = -4 + counter.dataSource = TowardsZeroSource() + for _ in 1...5 { + counter.increment() + println(counter.count) + } + // -3 + // -2 + // -1 + // 0 + // 0 diff --git a/src/chapter3/05_Statements.md b/src/chapter3/05_Statements.md new file mode 100644 index 0000000..8d982e9 --- /dev/null +++ b/src/chapter3/05_Statements.md @@ -0,0 +1,577 @@ +> 翻译:玩家 + + +#Statements# +--------- +# 语句章节 # +---------- + +本页包含内容 + - [循环语句](#loop_statements) + - [分支语句](#branch_statements) + - [带标签的语句](#labeled_statement) + - [控制传递语句](#control_transfer_statements) + +In Swift, there are two kinds of statements: simple statements and control flow statements. Simple statements are the most common and consist of either an expression or a declaration. Control flow statements are used to control the flow of execution in a program. There are three types of control flow statements in Swift: loop statements, branch statements, and control transfer statements. + +swift和其他语言一样,语句可大致分为简单语句和控制流语句,控制流语句也可分为循环语句:用来重复的执行代码块;分支语句:用来执行满足特定条件的代码块;控制语句用来决定代码的执行顺序。后续会详细阐述各控制流语句的使用。 + +Loop statements allow a block of code to be executed repeatedly, branch statements allow a certain block of code to be executed only when certain conditions are met, and control transfer statements provide a way to alter the order in which code is executed. Each type of control flow statement is described in detail below. + +A semicolon (;) can optionally appear after any statement and is used to separate multiple statements if they appear on the same line. + +和javascript类似,在一行语句的结束尾可以不添加分号(;),但是如果一行有多个独立语句必须要添加。在语法上讲,在语句末尾是否添加分好都是可以的,但是从团队协助以及减少错误方面来讲,最好统一加上,一般而言大公司的svn服务器上都会添加一个钩子,用来减少出错的可能,所以最好还是养成添加的习惯。 + +> statement -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression);opt +> statement -> [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration);opt +> statement -> [loop-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement);opt +> statement -> [branch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/branch-statement);opt +> statement -> [labeled-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/branch-statement) +> statement -> [control-transfer-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/control-transfer-statement);opt +> statement -> [statement statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/control-transfer-statement);opt + + + --------- + + +> 语句语法 +> *语句* → [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) **;** _可选_ +> *语句* → [*声明*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) **;** _可选_ +> *语句* → [*循环语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement) **;** _可选_ +> *语句* → [*分支语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/branch-statement) **;** _可选_ +> *语句* → [*标记语句(Labeled Statement)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/labeled-statement) +> *语句* → [*控制转移语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/control-transfer-statement) **;** _可选_ +> *多条语句(Statements)* → [*语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement) [*多条语句(Statements)*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) _可选_ + + + +##Loop Statements## +##循环语句## + +Loop statements allow a block of code to be executed repeatedly, depending on the conditions specified in the loop. Swift has four loop statements: a for statement, a for-in statement, a while statement, and a do-while statement. + +Control flow in a loop statement can be changed by a break statement and a continue statement and is discussed in Break Statement and Continue Statement below. + +> loop-statement -> [for-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-statement) +> loop-statement -> [for-in-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-in-statement) +> loop-statement -> [while-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-statement) +> loop-statement -> [do-while-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/do-while-statement) + +各个编程语言从语法上讲,基本的变量,语句都是类似的,swift循环语句也提供四种方式来循环语句:`for`语句 `for in`语句 `while`语句 `do-shile`语句 +通过`break`和`continue`可以改变循环语句的控制流,和其他语言类似,具体可参考break和continue + +> 循环语句语法 +> *循环语句* → [*for语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-statement) +> *循环语句* → [*for-in语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-in-statement) +> *循环语句* → [*while语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-statement) +> *循环语句* → [*do-while语句*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/do-while-statement) + + +##For Statement## +##for语句## + +A for statement allows a block of code to be executed repeatedly while incrementing a counter, as long as a condition remains true. + +A for statement has the following form: + + for initialization; condition; increment { + statements + } + +`for`语句可以重复的执行一端代码,并且可以递增一个计数器 +`for`语句的形式如下 + + for `initialzation`; `condition`; `increment` { + `statements` + } + +The semicolons between the initialization, condition, and increment are required. The braces around the statements in the body of the loop are also required. + +A for statement is executed as follows: + +The initialization is evaluated only once. It is typically used to declare and initialize any variables that are needed for the remainder of the loop. +The condition expression is evaluated. +If true, the program executes the statements, and execution continues to step 3. If false, the program does not execute the statements or the increment expression, and the program is finished executing the for statement. +The increment expression is evaluated, and execution returns to step 2. +Variables defined within the initialization are valid only within the scope of the for statement itself. + +The value of the condition expression must have a type that conforms to the LogicValue protocol. + +> for-statement -> for [for-init](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init);[expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt; [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) +> for-statement -> for ([for-init](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init)opt;[expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt; [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) +> for-init -> [variable-declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/variable-declaration) | [expression-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression-list) + + +`initialzation` `condition`和`increment`之间的分号 不可少,`{`也不可少 + + 1. `initialzation`只是被执行一次,通常用于声明和初始化在接下来循环中需要的变量 + 2. `condition`:如果为真(`true`)`statements`将会执行,进行第3步,如果为`false`则`statements`和`increment`都不会被执行,for至此执行完毕 + 3. 计算`increment`表达式,然后转到第2步。 + +定义在`initialzation`中的变量仅在`for`语句的作用域以内有效。`condition`表达式的值的类型必须遵循LogicValue协议。 + +> For 循环语法 +> *for语句* → for [*for初始条件*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ [*代码块*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) +> for语句 → for [*for初始条件*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/for-init) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ **;** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) _可选_ **)** [*代码块*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) +> *for初始条件* → [*变量声明*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/variable-declaration) | [*表达式列表*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression-list) + + +##For-In Statement## +##For-In 语句## + +A for-in statement allows a block of code to be executed once for each item in a collection (or any type) that conforms to the Sequence protocol. + +A for-in statement has the following form: + + for item in collection { + statements + } + +`for-in`语句允许在重复执行代码块的同时,迭代集合(或遵循Sequence协议的任意类型)中的每一项。 + +`for-in`语句的形式如下: + + for `item` in `collection` { + `statements` + } + +The generate method is called on the collection expression to obtain a value of a generator type—that is, a type that conforms to the Generator protocol. The program begins executing a loop by calling the next method on the stream. If the value returned is not None, it is assigned to the item pattern, the program executes the statements, and then continues execution at the beginning of the loop. Otherwise, the program does not perform assignment or execute the statements, and it is finished executing the for-in statement + +> GRAMMAR OF A FOR-IN STATEMENT +> for-in-statement -> for [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) in [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) + +`for-in`语句在循环开始前会调用`collection`表达式的`generate`方法来获取一个生成器类型(这是一个遵循Generator协议的类型)的值。接下来循环开始,调用`collection`表达式的`next`方法。如果其返回值不是`None`,它将会被赋给`item`,然后执行`statements`,执行完毕后回到循环开始处;否则,将不会赋值给`item`也不会执行`statements`,`for-in`至此执行完毕。这和`javascript`中的`for in`语句是一样的,可以理解为循环`collection`,如果有key的取出,去执行接下来的`statements` + +`For-In`循环语法 +> *for-in语句* → **for** [*模式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) **in** [*表达式*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) [*代码块*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) + + +##While Statement## +##While语句## + +A while statement allows a block of code to be executed repeatedly, as long as a condition remains true. + +A while statement has the following form: + + while condition { + statements + } + +`while`语句允许重复执行代码块 +`while`语句的形式如下: + + while `condition` { + `statements` + } + +A while statement is executed as follows: + + 1. The condition is evaluated. +If true, execution continues to step 2. If false, the program is finished executing the while statement. + 2. The program executes the statements, and execution returns to step 1. + +Because the value of the condition is evaluated before the statements are executed, the statements in a while statement can be executed zero or more times. + +The value of the condition must have a type that conforms to the LogicValue protocol. The condition can also be an optional binding declaration, as discussed in [Optional Bindind](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_432) + +> GRAMMAR OF A WHILE STATEMENT +> while-statement -> whild [while-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-condition) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) +> while-condition -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) | [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) + + +`while`语句的执行流程为判断`condition`,如果为真(`true`),这会执行`statements`,否则`while`语句执行到此结束 +由于`condition`的值在`statements`执行前就已计算出,因此`while`语句中的`statements`可能会被执行若干次,也可能不会被执行。 +`condition`表达式的值的类型必须遵循LogicValue协议。同时,`condition`表达式也可以使用可选绑定,请参考可选绑定待添加链接。 + +> While 循环语法 +> *while语句* → **while** [*while-condition*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-condition) [*code-block*](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) +> *while条件* → [*expression*](..\chapter3\04_Expressions.html#expression) | [*declaration*](..\chapter3\05_Declarations.html#declaration) + + +##Do-While Statement## +##Do-While 语句## + +A do-while statement allows a block of code to be executed one or more times, as long as a condition remains true. + +A do-while statement has the following form: + + do { + statements + } while condition + +`do-while`语句允许代码块被执行一次或多次。 +`do-while`语句的形式如下: + + do { + `statements` + } while `condition` + +A do-while statement is executed as follows: + + 1. The program executes the statements, and execution continues to step 2 + 2. The condition is evaluated.If true, execution returns to step 1. If false, the program is finished executing the do-while statement. + +`do-while`语句的执行流程如下: + + 1. 执行`statements`,完后钻到2 + 2. 计算condition表达式,如果返回(`true`)继续回到1新一轮执行,否则`do-while`至此执行完毕 + +Because the value of the condition is evaluated after the statements are executed, the statements in a do-while statement are executed at least once. + +The value of the condition must have a type that conforms to the LogicValue protocol. The condition can also be an optional binding declaration, as discussed in [Optional Binding](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_432) + + 由于`condition`是在`statements`执行之后才会计算,因此可见,相比较`while`而言,`do-while`至少会执行一次 +`condition`表达式的值的类型必须遵循`LogicValue`协议。同时,`condition`表达式也可以使用可选绑定,请参考可选绑定。 +> do-while-statement→ do [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) while [while-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/while-condition) + + + +##Branch Statements## +##分支语句## + +Branch statements allow the program to execute certain parts of code depending on the value of one or more conditions. The values of the conditions specified in a branch statement control how the program branches and, therefore, what block of code is executed. Swift has two branch statements: an if statement and a switch statement. + +Control flow in a switch statement can be changed by a break statement and is discussed in Break Statement below + +> GRAMMAR OF A BRANCH STAREMENT +> branch-statement -> [if-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) +> brach-statement -> [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) + +通过一个或者多个条件的值,来决定语句允许程序执行指定部分的代码,swift和其他语言类似提供了`if`语句和`switch`语句 +`switch`语句中的控制流可以用`break`语句修改,请参考[Break](http://chinaz.com/swift/chapter3/10_Statements.html#break_statement) 语句。 +>branch-statement → [if-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) +>branch-statement → [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) + + +##If Statement## +##if语句## + +An if statement is used for executing code based on the evaluation of one or more conditions. + +There are two basic forms of an if statement. In each form, the opening and closing braces are required. + +The first form allows code to be executed only when a condition is true and has the following form: + + if condition { + statements + } + +通过一个或多个条件的值来决定执行哪一块的代码,if语句主要有三种使用方式,但无乱哪种方式都需要添加`{`和`}` +第一种形式是当且仅当条件为真时执行代码,像下面这样: + + if `condition` { + `statements` + } + +The second form of an if statement provides an additional else clause (introduced by the else keyword) and is used for executing one part of code when the condition is true and another part code when the same condition is false. When a single else clause is present, an if statement has the following form: + + + if condition { + statements to execute if condition is true + } else { + statements to execute if condition is false + } + +The else clause of an if statement can contain another if statement to test more than one condition. An if statement chained together in this way has the following form: + + if condition 1 { + statements to execute if condition 1 is true + } else if condition 2 { + statements to execute if condition 2 is true + } else { + statements to execute if both conditions are false + } + + +第二种形式是在第一种形式的基础上添加else语句,当只有一个else语句时,像下面这样: + + if `condition` { + `statements to execute if condition is true` + } else { + `statements to execute if condition is false` + } + +第三种则是else中又需要进行判断,即有多种判断情况: + + if `condition 1` { + `statements to execute if condition 1 is true` + } else if `condition 2` { + `statements to execute if condition 2 is true` + } + else { + `statements to execute if both conditions are false` + } + +The value of any condition in an if statement must have a type that conforms to the LogicValue protocol. The condition can also be an optional binding declaration, as discussed in[Option Binding](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_432) + +> GRAMMAR OF AN IF STATEMENT +> if-statement -> if [if-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-condition) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) [else-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/else-clause) opt +> if-condition -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) | [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) +> else-clause -> else [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) | else [if-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) + + +`if`语句中条件的值的类型必须遵循`LogicValue`协议。同时,条件也可以使用可选绑定,请参考可选绑定`待添加链接` +>if-statement → if [if-condition](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-condition) [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-condition) [else-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/else-clause) opt + +>if-condition → [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) | [declaration](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/declaration) + +>else-clause → else [code-block](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/swift/grammar/code-block) | else [if-statement opt](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/if-statement) + + +##Switch Statement## +##Switch 语句## + +A switch statement allows certain blocks of code to be executed depending on the value of a control expression. +A switch statement has the following form: + + switch control expression { + case pattern 1: + statements + case pattern 2 where condition: + statements + case pattern 3 where condition, + pattern 4 where condition: + statements + default: + statements + } + +取决于`switch~语句的控制表达式(control expression),`switch`语句将决定执行哪一块代码。 + +switch语句的形式如下: + + switch `control expression` { + case `pattern 1`: + `statements` + case `pattern 2` where `condition`: + `statements` + case `pattern 3` where `condition`, + `pattern 4` where `condition`: + `statements` + default: + `statements` + } +The control expression of the switch statement is evaluated and then compared with the patterns specified in each case. If a match is found, the program executes the statements listed within the scope of that case. The scope of each case can’t be empty. As a result, you must include at least one statement following the colon (:) of each case label. Use a single break statement if you don’t intend to execute any code in the body of a matched case. + +`switch`语句的表达式`control expression`会首选被计算,然后与下面的每个`case`的模式进行匹配,如果匹配成功,程序将会执行对应`case`中的`statements`,需要注意的是每个case不能为空,也就是说在case中至少有一条语句,如果在相应case中不想执行代码,只需要在程序中写个`break`即可 + + +The values of expressions your code can branch on is very flexible. For instance, in addition to the values of scalar types, such as integers and characters, your code can branch on the values of any type, including floating-point numbers, strings, tuples, instances of custom classes, and optionals. The value of the control expression can even be matched to the value of a case in an enumeration and checked for inclusion in a specified range of values. For examples of how to use these various types of values in switch statements, see Switch in the Control Flow chapter. + +A switch case can optionally contain a guard expression after each pattern. A guard expression is introduced by the keyword where followed by an expression, and is used to provide an additional condition before a pattern in a case is considered matched to the control expression. If a guard expression is present, the statements within the relevant case are executed only if the value of the control expression matches one of the patterns of the case and the guard expression evaluates to true. For instance, a control expression matches the case in the example below only if it is a tuple that contains two elements of the same value, such as (1, 1). + +case let (x, y) where x == y: + +可以用作控制表达式的值是什么灵活的,除了标量类型(scalartypes,如`Int`、`Character`)之外,你还可以使用其他任何类型的值,包括浮点数,字符串,远组,自定义类的实例以及可选(`optional`)类型,甚至是枚举类型中的成员和指定的范围(`range`)等。关于在`switch`语句中使用这些类型,请参考控制流章节的Switch. + +你可以在模式后端添加一个保护作用的表达式(guard expression),构成是这样的:关键字`where`后面跟着一个作为额外测试条件的表达式,因此当且仅当表达式匹配的一个case的某个模式在保护作用的表达式为真时,对应case中的`statements`才会被执行,在下面例子中,控制表达式只会匹配含有两个相等元素的元组 + + case let (x, y) where x == y: + } + + +As the above example shows, patterns in a case can also bind constants using the keyword let (they can also bind variables using the keyword var). These constants (or variables) can then be referenced in a corresponding guard expression and throughout the rest of the code within the scope of the case. That said, if the case contains multiple patterns that match the control expression, none of those patterns can contain constant or variable bindings. + + +正如上面的例子,也可以在模式中使用let(或var)语句来绑定常量(或变量)。这些常量(或变量)可以在其对应的起保护作用的表达式和其对应的case块里的代码中引用。但是,如果case中有多个模式匹配控制表达式,那么这些模式都不能绑定常量(或变量)。 + +A switch statement can also include a default case, introduced by the keyword default. The code within a default case is executed only if no other cases match the control expression. A switch statement can include only one default case, which must appear at the end of the switch statement. + +Although the actual execution order of pattern-matching operations, and in particular the evaluation order of patterns in cases, is unspecified, pattern matching in a switch statement behaves as if the evaluation is performed in source order—that is, the order in which they appear in source code. As a result, if multiple cases contain patterns that evaluate to the same value, and thus can match the value of the control expression, the program executes only the code within the first matching case in source order. + +switch语句也可以包含默认(default)块,只有其它case块都无法匹配控制表达式时,默认块中的代码才会被执行。一个switch语句只能有一个默认块,而且必须在switch语句的最后面。 + +尽管模式匹配操作的实际执行顺序,并且计算顺序是不可知的,但是Swift规定能够了swift中的语句中的模式匹配顺序和书写源码的顺序保持一致。因此,当多个模式含有相通的值并且能够匹配控制表达式时,程序只会执行源码中第一个匹配`case`中的代码 + +##Switch Statements Must Be Exhaustive## +##Switch 语句必须是完备的## + +In Swift, every possible value of the control expression’s type must match the value of at least one pattern of a case. When this simply isn’t feasible (for instance, when the control expression’s type is Int), you can include a default case to satisfy the requirement + +`switch`语句中包含多个`case`,每个`case`都是`switch`的一个分支,由`switch`来决定执行哪一个分支代码,`switch`语句必须是完整的,也就是值必须与`case`中的某一个对应,可以通过`default`来指定默认就不符合`case`条件时执行的代码块,并且这个`default`分支必须在最后。 + +##Execution Does Not Fall Through Cases Implicitly## +##不存在隐式的贯穿(fall through)## + +After the code within a matched case has finished executing, the program exits from the switch statement. Program execution does not continue or “fall through” to the next case or default case. That said, if you want execution to continue from one case to the next, explicitly include a fallthrough statement, which simply consists of the keyword fallthrough, in the case from which you want execution to continue. For more information about the fallthrough statement, see Fallthrough Statement below + +> switch-statement -> switch [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) {[switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt} +> switch-cases -> [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-case) [switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt +> switch-case -> [case-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) +> switch-case [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label): | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label): +> case-label -> case [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list): +> case-item-list -> [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause) opt | [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause)opt , [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list) +> default-label -> default +> guard-clause -> where [guard-expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-expression) +> guard-expression -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) + +当匹配的`case`代码在执行完毕后,程序会终止`switch`语句,而不会继续执行下一个`case`语句,这就意味着,如果你想执行下一个case块,需要显式地在你需要的case块里使用fallthrough语句。关于fallthrough语句的更多信息,请参考Fallthrough 语句。 + +> switch-statement -> switch [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) {[switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt} +> switch-cases -> [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-case) [switch-cases](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-cases) opt +> switch-case -> [case-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label) [statements](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statements) +> switch-case [switch-case](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-label): | [default-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/default-label): +> case-label -> case [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list): +> case-item-list -> [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause) opt | [pattern](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Patterns.html#//apple_ref/swift/grammar/pattern) [guard-clause](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-clause)opt , [case-item-list](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/case-item-list) +> default-label -> default +> guard-clause -> where [guard-expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/guard-expression) +> guard-expression -> [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression) + + +##Labeled Statement## +##带标签的语句## + +You can prefix a loop statement or a switch statement with a statement label, which consists of the name of the label followed immediately by a colon (:). Use statement labels with break and continue statements to be explicit about how you want to change control flow in a loop statement or a switch statement, as discussed in Break Statement and Continue Statement below. + +你可以在循环语句和`switch`语句前面加上标签,它由标签名和`:`组成,在`break`和`continue`后面跟上标签名可以显式的在循环语句和switch语句中更改控制流,把控制权传递给指定标签标记的语句。关于这两条语句用法,请参考[Break](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-XID_976) 语句和[Continue](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/doc/uid/TP40014097-CH33-XID_976) 语句 + +The scope of a labeled statement is the entire statement following the statement label. You can nest labeled statements, but the name of each statement label must be unique. + +For more information and to see examples of how to use statement labels, see Labeled Statements in the Control Flow chapter + +> labeld-statement -> [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [loop-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement) | [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) +> statement-label -> [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name): +> label-name -> [identifier](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier) + + + +标签的作用域是该标签所标记的语句之后的所有语句。你可以不使用带标签的语句,但只要使用它,标签名就必唯一。 + +关于使用带标签的语句的例子,请参考控制流一章的带标签的语句 + +> labeld-statement -> [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [loop-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/loop-statement) | [statement-label](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/statement-label) [switch-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/switch-statement) +> statement-label -> [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name): +> label-name -> [identifier](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html#//apple_ref/swift/grammar/identifier) + + +##Control Transfer Statements## +##控制传递语句## + +Control transfer statements can change the order in which code in your program is executed by unconditionally transferring program control from one piece of code to another. Swift has four control transfer statements: a break statement, a continue statement, a fallthrough statement, and a return statement. + +> control-transfer-statement -> [break-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/break-statement) +> control-transfer-statement -> [continue-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/continue-statement) +> continue-statement -> [fallthrougth-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/fallthrough-statement) +> continue-statement -> [return-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/return-statement) + +能够无条件的把控制权从一片代码传递到另一片代码,控制传递语句能够改变代码的执行顺序,Swift 提供四种类型的控制传递语句: `break`语句,`continue`语句,`fallthrough`语句和`return`语句 + +> control-transfer-statement -> [break-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/break-statement) +> control-transfer-statement -> [continue-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/continue-statement) +> continue-statement -> [fallthrougth-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/fallthrough-statement) +> continue-statement -> [return-statement](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/return-statement) + +##Break Statement## +##break语句## +A break statement ends program execution of a loop or a switch statement. A break statement can consist of only the keyword break, or it can consist of the keyword break followed by the name of a statement label, as shown below. + + break + break label name + +`break`用于终止循环或是`switch`语句,用break语句时,可以只写break这个关键词,也可以在break后面跟上标签名(label name),像下面这样: + + break + break label name + +When a break statement is followed by the name of a statement label, it ends program execution of the loop or switch statement named by that label. + +When a break statement is not followed by the name of a statement label, it ends program execution of the switch statement or the innermost enclosing loop statement in which it occurs. + +当`break`后面带有标签名时,可用于终止这个标签标记的循环或`switch`语句的执行 + +而当只有`break`关键词时,则会终止`switch`语句或上下文中包含`break` +的最内层的循环的执行 + +In both cases, program control is then transferred to the first line of code following the enclosing loop or switch statement, if any. + +For examples of how to use a break statement, see Break and Labeled Statements in the Control Flow chapter. + +> break-statement -> break [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name) opt + +在这两种情况下,控制权都会被传递给循环或switch语句外面的第一行语句 + +关于使用break语句的例子,请参考控制流一章的Break和带标签的语句 + +> break-statement -> break [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name) opt + +##Continue Statement## +##Continue 语句## +A continue statement ends program execution of the current iteration of a loop statement but does not stop execution of the loop statement. A continue statement can consist of only the keyword continue, or it can consist of the keyword continue followed by the name of a statement label, as shown below. + + continue + continue label name + +continue语句用于终止循环中当前迭代的执行,但不会终止该循环的执行。使用continue语句时,和break一样,可以只写continue这个关键词,也可以在continue后面跟上标签名(label name),像下面这样: + + continue + continue label name + +When a continue statement is followed by the name of a statement label, it ends program execution of the current iteration of the loop statement named by that label. + +When a continue statement is not followed by the name of a statement label, it ends program execution of the current iteration of the innermost enclosing loop statement in which it occurs. + +当continue语句后面带标签名时,可用于终止由这个标签标记的循环中当前迭代的执行 + +而当只写break时,可用于终止上下文中包含continue语句的最内层循环中当前迭代的执行 + +In both cases, program control is then transferred to the condition of the enclosing loop statement. + +In a for statement, the increment expression is still evaluated after the continue statement is executed, because the increment expression is evaluated after the execution of the loop’s body. + +For examples of how to use a continue statement, see Continue and Labeled Statements in the Control Flow chapter + +> continue-statement -> continue [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name)opt + +在这两种情况下,控制权都会被传递给循环外面的第一行语句。 + +在for语句中,continue语句执行后,increment表达式还是会被计算,这是因为每次循环体执行完毕后increment表达式都会被计算。 + +关于使用continue语句的例子,请参考控制流一章的Continue和带标签的语句 + +> continue-statement -> continue [label-name](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Statements.html#//apple_ref/swift/grammar/label-name)opt + + +##Fallthrough Statement## +##Fallthrough 语句## + +A fallthrough statement consists of the fallthrough keyword and occurs only in a case block of a switch statement. A fallthrough statement causes program execution to continue from one case in a switch statement to the next case. Program execution continues to the next case even if the patterns of the case label do not match the value of the switch statement’s control expression. + +A fallthrough statement can appear anywhere inside a switch statement, not just as the last statement of a case block, but it can’t be used in the final case block. It also cannot transfer control into a case block whose pattern contains value binding patterns. + +`fallthrough`语句用于在`switch`语句中传递控制权。`fallthrough`语句会把控制权从`switch`语句中的一个`case`无条件的传递给下一个case,即使下一个`case`的值与`switch`语句的控制表达式的值不匹配 + +For an example of how to use a fallthrough statement in a switch statement, see Control Transfer Statements in the Control Flow chapter. + +> fallthrough-statement -> fallthrough + +关于在switch语句中使用fallthrough语句的例子,请参考控制流一章的控制传递语句 + +> fallthrough-statement -> fallthrough + +##Return Statement## +##Return 语句## + +A return statement occurs only in the body of a function or method definition and causes program execution to return to the calling function or method. Program execution continues at the point immediately following the function or method call. + +A return statement can consist of only the keyword return, or it can consist of the keyword return followed by an expression, as shown below. + + return + return expression + +`return`用于在函数或是方法中,将控制权传递给调用者,接着程序将会从调用者的位置继续的往下执行 +使用return语句时,可以只写return这个关键词,也可以在return后面跟上表达式,像下面这样 + + return + return `expression` + +When a return statement is followed by an expression, the value of the expression is returned to the calling function or method. If the value of the expression does not match the value of the return type declared in the function or method declaration, the expression’s value is converted to the return type before it is returned to the calling function or method. + +当`return`后面跟有表达式时,会把表达式的值返回给调用者,如果表达式值的类型与调用者期望的类型不匹配,swift会在返回表达式的值之前把表达式值的类型转为调用者期望的类型 + +When a return statement is not followed by an expression, it can be used only to return from a function or method that does not return a value (that is, when the return type of the function or method is Void or ()). + +> return-statement -> return [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt + +而当只写return时,仅仅是将控制权从该函数或方法传递给调用者,而不返回一个值。(这就是说,该函数或方法的返回类型为Void或()) + +> return-statement -> return [expression](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Expressions.html#//apple_ref/swift/grammar/expression)opt diff --git a/src/chapter3/06_Declarations.md b/src/chapter3/06_Declarations.md new file mode 100644 index 0000000..85e263f --- /dev/null +++ b/src/chapter3/06_Declarations.md @@ -0,0 +1,1208 @@ +# 声明 +A declaration introduces a new name or construct into your program. For example, you use declarations to introduce functions and methods, variables and constants, and to define new, named enumeration, structure, class, and protocol types. You can also use a declaration to extend the the behavior of an existing named type and to import symbols into your program that are declared elsewhere. + +声明将新的名字或者结构引入到程序中。例如,使用声明可以引入函数、方法、变量和常量;可以定义新的,命名的枚举类型,结构,类和协议类型。也可以使用声明来扩展已存在命名类型的行为,在程序中引入在其它地方声明的符号。 + +In Swift, most declarations are also definitions in the sense that they are implemented or initialized at the same time they are declared. That said, because protocols don’t implement their members, most protocol members are declarations only. For convenience and because the distinction isn’t that important in Swift, the term declaration covers both declarations and definitions. + +在Swift中,大多数声明在某种意义上也是定义,可以在声明的同时实现和初始化他们。也就是说,因为协议并不会实现他们的成员,所以大多数协议成员仅仅是声明。为了方便,由于这个不同在Swift里不是那么重要,因此术语declaration同时包含了声明和定义。 + +>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 + +## 模块范围 + +The module scope defines the code that’s visible to other code in Swift source files that are part of the same module. The top-level code in a Swift source file consists of zero or more statements, declarations, and expressions. Variables, constants, and other named declarations that are declared at the top-level of a source file are visible to code in every source file that is part of the same module。 + +模块范围定义了对模块中其它Swift源文件可见的代码。在Swift源文件中顶层的代码由0或多个语句、声明和表达式组成。在源文件的顶层声明的变量、常量和其它命名的声明对同一模块的其它源文件代码都是可见的。 + +>GRAMMAR OF A TOP-LEVEL DECLARATION + +>top-level-declaration → statements­opt + +Code Blocks + +代码块 + +A code block is used by a variety of declarations and control structures to group statements together. It has the following form: + +通过代码块把不同的声明和控制结构语句分组,有如下的形式: + + { + `statements` + } + +The statements inside a code block include declarations, expressions, and other kinds of statements and are executed in order of their appearance in source code. + +在代码块里的语句包括声明,表达式,和其它类型的语句,按照在源代码里出现的顺序执行。 + +>GRAMMAR OF A CODE BLOCK +>code-block → {­statements­opt­} + +##Import Declaration + +## Import 声明 + +An import declaration lets you access symbols that are declared outside the current file. The basic form imports the entire module; it consists of the import keyword followed by a module name: + + +import声明可以让你访问当前文件之外声明的符号。基本的形式是引入整个模块。由import关键字后面跟着一个模块名进行声明。 + + + import module + +Providing more detail limits which symbols are imported—you can specify a specific submodule or a specific declaration within a module or submodule. When this detailed form is used, only the imported symbol (and not the module that declares it) is made available in the current scope. + +如果提供更多的细节限制,还可以明确限制引入一个具体的子模块或者模块子模块里的一个具体的声明。如果采用这种形式的声明,只有被引入的符号(而不是声明它的模块)可以在当前范围里被访问到。 + + 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 + +##Constant Declaration + +##常量声明 + +A constant declaration introduces a constant named value into your program. Constant declarations are declared using the keyword let and have the following form: + +常量声明引入一个不变的命名值到程序中。常量声明使用关键字let,采用如下的形式: + + let constant name: type = expression + +A constant declaration defines an immutable binding between the constant name and the value of the initializer expression; after the value of a constant is set, it cannot be changed. That said, if a constant is initialized with a class object, the object itself can change, but the binding between the constant name and the object it refers to can’t. + +常量声明在常量名和初始化表达式的值之间定义了一个不可变的绑定;在值被设置之后,它就不能改变了。也就是说,如果常量用一个class对象实例化,对象本身可以改变,但是在常量名和对象之间的绑定是不会改变的。 + +When a constant is declared at global scope, it must be initialized with a value. When a constant declaration occurs in the context of a class or structure declaration, it is considered a constant property. Constant declarations are not computed properties and therefore do not have getters or setters. + +如果一个常量在全局范围里声明,它就必须有一个初始值。当一个常量在类或者结构声明中声明,它会被认为是一个常量属性。常量声明不是计算型属性,因此没有getters和setters方法。 + +If the constant name of a constant declaration is a tuple pattern, the name of each item in the tuple is bound to the corresponding value in the initializer expression. + +如果一个常量声明的名字是一个元组,元组中的每一项在初始化表达式里都会绑定到相应的值。 + + let (firstNumber, secondNumber) = (10, 42) + +In this example, firstNumber is a named constant for the value 10, and secondNumber is a named constant for the value 42. Both constants can now be used independently: + +在这个例子,firstNumer是一个命名常量,值是10。secondNumber是一个命名常量,值是4。这两个常量现在都可以独立的使用。 + + println("The first number is \(firstNumber).") + // prints "The first number is 10." + println("The second number is \(secondNumber).") + // prints "The second number is 42." + +The type annotation (: type) is optional in a constant declaration when the type of the constant name can be inferred, as described in Type Inference. + +如Type Inference里描述的一样,如果常量名的类型可以被推断出来,类型标识(:type)是可选的。 + +To declare a static constant property, mark the declaration with the static keyword. Static properties are discussed in Type Properties. + +为了声明一个静态的常量属性,使用关键字static来标记声明。静态属性会在Type Proerties里讨论。 + +For more information about constants and for guidance about when to use them, see Constants and Variables and Stored Properties + +想获得更多关于常量的信息或者想在使用中获得帮助,请查看常量和变量和存储属性(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 + + +##Variable Declaration + +##变量声明 + +A variable declaration introduces a variable named value into your program and is declared using the keyword var. + +变量声明会引入一个可变的命名值到程序中,使用关键字var进行声明。 + +Variable declarations have several forms that declare different kinds of named, mutable values, including stored and computed variables and properties, stored variable and property observers, and static variable properties. The appropriate form to use depends on the scope at which the variable is declared and the kind of variable you intend to declare. + +变量声明有好几种不同的形式来声明不同类型的命名的,可变的值,包括存储型和计算型的变量和属性,存储型变量和属性观察者,还有静态的变量属性。要使用哪种适合的形式取决于变量声明的范围和你打算声明的变量种类。 + +>注意: + + +You can override a property in a subclass by prefixing the subclass’s property declaration with the override keyword, as described in Overriding. + +通过在子类中的属性声明的前面使用override,可以在子类中重写一个属性。 + + +##Stored Variables and Stored Variable Properties + +##存储型变量和存储型变量属性 + +The following form declares a stored variable or stored variable property: + +下面的形式声明了一个存储型变量或存储型的变量属性 + + var variable name: type = expression + +You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class or structure declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, it is referred to as a stored variable. When it is declared in the context of a class or structure declaration, it is referred to as a stored variable property. + +你可以在全局范围、函数的局部范围或者类或结构声明的上下文环境里定义变量声明。如果这种形式的变量声明在全局范围或者函数局部范围里声明,它指的就是存储型变量。如果是在类或者结构声明的环境里声明的,它就是指的存储型变量属性。 + +The initializer expression can’t be present in a protocol declaration, but in all other contexts, the initializer expression is optional. That said, if no initializer expression is present, the variable declaration must include an explicit type annotation (: type). + +初始化表达式不能在协议声明里出现,但是可以出现在其它所有的上下文环境里。初始化表达式是可选的。也就是说,如果没有初始化表达式存在,变量声明必须包括一个显式的类型表示(:type)。 + +As with constant declarations, if the variable name is a tuple pattern, the name of each item in the tuple is bound to the corresponding value in the initializer expression. + +和常量声明一样,如果变量名字是一个元组,元组中每一项的名字都会被绑定到初始化表达式的对应的值。 + + +As their names suggest, the value of a stored variable or a stored variable property is stored in memory. + +顾名思义,存储型变量或者存储型属性的值是存储在内存中的。 + +##Computed Variables and Computed Properties + +##计算型变量和计算型属性 + +The following form declares a computed variable or computed property: + +下面的形式声明了一个计算型变量或者计算型属性 + + var variable name: type { + get { + statements + } + set(setter name) { + statements + } + } +You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class, structure, enumeration, or extension declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, it is referred to as a computed variable. When it is declared in the context of a class, structure, or extension declaration, it is referred to as a computed property. + +可以在全局范围,局部范围,或者类、结构、枚举或者扩展声明里定义这种形式的声明。如果这类型是的变量声明在全局范围或者函数的局部范围声明的,它指的是计算型变量。如果它在类,结构或者扩展声明里声明的,它指的就是计算型属性。 + + +The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly, as described in Read-Only Computed Properties. But if you provide a setter clause, you must also provide a getter clause. + +getter用于读取值,setter用于写入值。setter子句是可选的,仅仅getter方法是必须的,你可以把两者都忽略,只是简单的直接返回请求值,如在Read-Only Comuted Properties描述的一样。但是如果你提供一个setter子句,你也必须要提供一个getter子句。 + +The setter name and enclosing parentheses is optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is newValue, as described in Shorthand Setter Declaration. + +setter名字和封闭的括号是可选的。如果你提供了一个setter名字。如果你提供一个setter名字,它会被作为setter的参数的名称。如果你美欧提供setter名称,setter缺省的参数名是newvalue,如在Shorthand Setter Declaration描述的那样. + +Unlike stored named values and stored variable properties, the value of a computed named value or a computed property is not stored in memory. + +不像存储型命名值和存储型变量属性,计算型命名值或者计算型属性的值不会存储到内存中。 + +For more information and to see examples of computed properties, see Computed Properties. + +获得更多信息和如何使用属性监视器的例子,请查看属性监视器(prpperty observers)一节。 + +##Stored Variable Observers and Property Observers + +##存储型变量监视器和属性监视器 + +You can also declare a stored variable or property with willSet and didSet observers. A stored variable or property declared with observers has the following form: + +也可以使用willset和didset监视器声明一个存储型的变量或者属性。用监视器声明的存储型变量或者属性有以下的形式: + + var variable name: type = expression { + willSet(setter name) { + statements + } + didSet(setter name) { + statements + } + } + +You define this form of a variable declaration at global scope, the local scope of a function, or in the context of a class or structure declaration. When a variable declaration of this form is declared at global scope or the local scope of a function, the observers are referred to as stored variable observers. When it is declared in the context of a class or structure declaration, the observers are referred to as property observers. + +可以在全局范围,函数的局部返回,或类,结构的上下文环境里声明这种形式的变量。当这种类型是在在全局范围或者函数的局部范围里声明的时候,监视器会被作为存储型变量监视器。当在类或者结构声明中声明的时候,监视器会被作为属性监视器。 + +You can add property observers to any stored property. You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass, as described in Overriding Property Observers. + +可以为任何存储型属性增加监视器。也可以为继承的属性通过使用子类覆盖增加属性监视器(无论是存储型的或是计算型的),就像Overriding PropertyOververs里描述的一样。 + +The initializer expression is optional in the context of a class or structure declaration, but required elsewhere. The type annotation is required in all variable declarations that include observers, regardless of the context in which they are declared. + +在类或者结构声明里,初始化表达式是可选的。但是在其它所有地方是必须的。类型标识在所有变量声明里是必须的,包括监视器,无论他们声明的环境。 + +The willSet and didSet observers provide a way to observe (and to respond appropriately) when the value of a variable or property is being set. The observers are not called when the variable or property is first initialized. Instead, they are called only when the value is set outside of an initialization context. + +willset 和 didset 监视器提供了一种方式来观察(适当的响应)什么时候变量或者属性的值被设置。监视器在变量或属性在第一次初始化的时候不会被调用,仅仅在初始化环境的外边设置的时候会被调用。 + +A willSet observer is called just before the value of the variable or property is set. The new value is passed to the willSet observer as a constant, and therefore it can’t be changed in the implementation of the willSet clause. The didSet observer is called immediately after the new value is set. In contrast to the willSet observer, the old value of the variable or property is passed to the didSet observer in case you still need access to it. That said, if you assign a value to a variable or property within its own didSet observer clause, that new value that you assign will replace the one that was just set and passed to the willSet observer. + +willset监视器只是在变量或是属性值被设置的时候调用。新值会被作为常量传递给willset语句,因此在willset子句实现的时候不能改变。didSet监视器在新值被设置的时候会立即被调用。与willset监视器相比,变量或属性的旧值会传给didSet监视器,以应对万一需要访问它 + +The setter name and enclosing parentheses in the willSet and didSet clauses are optional. If you provide setter names, they are used as the parameter names to the willSet and didSet observers. If you do not provide setter names, the default parameter name to the willSet observer is newValue and the default parameter name to the didSet observer is oldValue. + +在willset和didset语句里 setter名字和括号是可选的。如果你提供你不提供setter名字,willset 缺省的参数名是newValue好缺省的参数名是oldValue. + +The didSet clause is optional when you provide a willSet clause. Likewise, the willSet clause is optional when you provide a didSet clause. + +如果你提供一个willset语句,didset语句是可选的。同样的,如果你提供一个didset 语句,willset语句是可选的 + +For more information and to see an example of how to use property observers, see Property Observers. + +获得更多信息,查看如何使用属性监视器的例子,请查看属性监视器(prpperty observers)一节。 + +##Class and Static Variable Properties + +##类和静态变量属性 + +To declare a class computed property, mark the declaration with the class keyword. To declare a static variable property, mark the declaration with the static keyword. Class and static properties are discussed in Type Properties. + +要声明一个类的计算型属性,要用关键字class标记声明。声明静态的变量属性,用关键字static标记。类和静态属性在Type属性里有讨论。 + +>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-bloc + + +##Type Alias Declaration + +##类型的别名声明 + +A type alias declaration introduces a named alias of an existing type into your program. Type alias declarations begin with the keyword typealias and have the following form: + +类型别名声明引入了存在类型的名字到程序中,以关键字typelias开头,采用如下的形式: + + typealias name = existing type + +After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. The existing type can be a named type or a compound type. Type aliases do not create new types; they simply allow a name to refer to an existing type. + +在声明一个类型别名后,那个别名可以使用在你的程序的的任何有那个类型的地方使用了。存在的类型可能是命名类型或是复合类型。类型 别名不是创造新类型,它们只是简单的把名字指向一个存在的类型。 + +See also Protocol Associated Type Declaration. + +也可以参看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 + +##Function Declaration + +##函数声明 + +A :newTerm`function declaration` introduces a function or method into your program. A function declared in the context of class, structure, enumeration, or protocol is referred to as a method. Function declarations are declared using the keyword func and have the following form: + +新术语”函数声明“引入了一个函数或者方法到程序中。在类,结构,枚举或者协议里声明的函数会被当做方法。函数声明使用关键字func,采用以下的形式。 + + func function name(parameters) -> return type { + statements + } + +If the function has a return type of Void, the return type can be omitted as follows: + +如果函数的返回类型是void,返回类型可像下面这样忽略: + +func function name(parameters) { + statements +} + +The type of each parameter must be included—it can’t be inferred. By default, the parameters to a function are constants. Write var in front of a parameter’s name to make it a variable, scoping any changes made to the variable just to the function body, or write inout to make those changes also apply to the argument that was passed in the caller’s scope. For a discussion of in-out parameters, see In-Out Parameters. + +必须包含每个参数的类型-参数类型不能通过推断。默认情况下,函数的参数是常量。在参数名的前面写一个var会让它成为一个变量,对变量的做的任何变化只会在函数内有效,或者用inout使的这些改变可以在调用域内生效。 + +Functions can return multiple values using a tuple type as the return type of the function. + +函数可以使用元组类型作为函数的返回类型来返回多个值。 + +A function definition can appear inside another function declaration. This kind of function is known as a nested function. For a discussion of nested functions, see Nested Functions. + +函数定义可以出现在另一个函数声明之内。这种函数叫做嵌入函数。对于嵌入函数的讨论,请参见Nested Function。 + +Parameter Names + +Function parameters are a comma separated list where each parameter has one of several forms. The order of arguments in a function call must match the order of parameters in the function’s declaration. The simplest entry in a parameter list has the following form: + +函数参数是一个逗号分隔的列表,每个参数可以有好几种形式。函数调用的时候参数的顺序必须匹配函数声明的参数顺序。在参数列表里最简单的输入形式: + + parameter name: parameter type + + +For function parameters, the parameter name is used within the function body, but is not used when calling the function. For method parameters, the parameter name is used as within the function body, and is also used as a label for the argument when calling the method. The name of a method’s first parameter is used only within the function body, like the parameter of a function. For example: + +对于函数参数,参数名字在函数体内部使用,但是在调用函数的时候不会使用。对于方法参数,参数名可以在函数体使用,在调用方法时也可以作为参数的标签使用。函数的一个参数名字仅仅在函数内使用,就像函数的参数。例如 + + + func f(x: Int, y: String) -> String { + return y + String(x) + } + f(7, "hello") // x and y have no name + + class C { + func f(x: Int, y: String) -> String { + return y + String(x) + } + } + let c = C() + c.f(7, y: "hello") // x没有名称,y有名称 + + +You can override the default behavior for how parameter names are used with one of the following forms: + +可以重写参数名字使用的默认行为,采用如下的形式: + + + external parameter name local parameter name: parameter type + #parameter name: parameter type + _ local parameter name: parameter type + + +A second name before the local parameter name gives the parameter an external name, which can be different than the local parameter name. The external parameter name must be used when the function is called. The corresponding argument must have the external name in function or method calls. + +本地参数名前的第二个名字给参数了一个外部的名字,这个不同于本地的参数名。外部的参数名必须在函数调用的时候调用。相应的参数必须在函数或者方法调用时有外部名字。 + +A hash symbol (#) before a parameter name indicates that the name should be used as both an external and a local parameter name. It has the same meaning as writing the local parameter name twice. The corresponding argument must have this name in function or method calls. + +参数名前的#显示了名字应该同时被作为外部和本地参数使用。它和写入本地参数名两次有同样的意义。相应的参数在函数或者参数调用时必须有这个名字。 + +An underscore (_) before a local parameter name gives that parameter no name to be used in function calls. The corresponding argument must have no name in function or method calls. + +本地参数名前面的下划线在函数调用的时候让参数可以没有名字。相应的参数在函数或者方法调用的时候没有名字。 + +##Special Kinds of Parameters + +##特殊类型的参数 + +Parameters can be ignored, take a variable number of values, and provide default values using the following forms: + +参数可以忽略,需要不同数量的值,会提供默认值,使用如下的形式: + + + _ : <#parameter type#. + parameter name: parameter type... + parameter name: parameter type = default argument value + + +A parameter named with an underscore (_) is explicitly ignored an can’t be accessed within the body of the function. + +带有下划线的参数会显式的被忽略,在函数内部不能被访问到。 + +A parameter with a base type name followed immediately by three dots (...) is understood as a variadic parameter. A function can have at most one variadic parameter, which must be its last parameter. A variadic parameter is treated as an array that contains elements of the base type name. For instance, the variadic parameter Int... is treated as Int[]. For an example that uses a variadic parameter, see Variadic Parameters. + +基本类型名的参数,如果紧跟着三个点(...),被理解为是可变参数。一个函数最多可以有一个可变参数,且必须是最后一个参数。可变参数被作包含基本类型的元素数组。举例来讲,可变参数int...被看做是int[]。 查看可变参数的使用例子,详见可变参数(variadic parameters)一节。 + +A parameter with an equals sign (=) and an expression after its type is understood to have a default value of the given expression. If the parameter is omitted when calling the function, the default value is used instead. If the parameter is not omitted, it must have its name in the function call. For example, f() and f(x: 7) are both valid calls to a function with a single default parameter named x, but f(7) is invalid because it provides a value without a name. + +带有等号(=)的参数和它的类型后面的表达式会被当作给定表达式的默认类型。如果参数在调用函数的时候被忽略,默认值会被使用。例如,对于带有单个默认的的参数名x的函数,f()和f(x:7)都是有效的调用,但是f(7)是有效的,因为它提供了没有名字的值。 + +Special Kinds of Methods on an enumeration or a structure that modify self must be marked with the mutating keyword at the start of the function declaration. + +会修改self的枚举类型或者结构上的方法,必须在函数声明的开始标记为mutating关键字 + +Methods that override a superclass method must be marked with the override keyword at the start of the function declaration. It is an error to override a method without the override keyword or to use the overridekeyword on a method that doesn’t override a superclass method. + +重写超类方法的方法必须在函数声明的开头override关键词标记。没有override就重写方法会产生错误或者使用override在没有重载超类的方法 + +Methods associated with a type rather than an instance of a type must be marked with the static attribute for enumerations and structures or the class attribute for classes. + +与type相关而不是类型实例相关的方法必须使用使用static属性来标记枚举、结构或者类的class属性。 + +##Curried Functions and Methods + +##科里化函数和方法 + +Curried functions and methods have the following form: + +科里化函数和方法有以下的形式: + + + func function name(parameters)(parameters) -> return type { + statements + } + +以这种形式定义的函数的返回值是另一个函数。举例来说,下面的两个声明时等价的: + + func addTwoNumbers(a: Int)(b: Int) -> Int { + return a + b + } + func addTwoNumbers(a: Int) -> (Int -> Int) { + func addTheSecondNumber(b: Int) -> Int { + return a + b + } + return addTheSecondNumber + } + + addTwoNumbers(4)(5) // Returns 9 + +多级柯里化应用如下 + +>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­: + +A function declared this way is understood as a function whose return type is another function. For example, the following two declarations are equivalent: + +用这种方式声明的函数会被当做一个函数,它的返回类型是另外一个函数。例如,下面2个声明是一样的: + + +##Enumeration Declaration + +##枚举声明 + +An enumeration declaration introduces a named enumeration type into your program. + +枚举声明引入了名叫枚举的类型程序中。 + + +Enumeration declarations have two basic forms and are declared using the keyword enum. The body of an enumeration declared using either form contains zero or more values—called enumeration cases—and any number of declarations, including computed properties, instance methods, static methods, initializers, type aliases, and even other enumeration, structure, and class declarations. Enumeration declarations can’t contain destructor or protocol declarations. + +枚举声明有2种基本的形式,使用关键字enum声明。一个枚举类型的的主体会使用这2种形式之一,包含0或多个值-被称作枚举类型。还有任何数量的声明,包括计算型的属性,实例方法,静态方法,初始化,类型别名,和其它的枚举、结构和类声明。枚举声明不能包含析构或者协议声明。 + +Unlike classes and structures, enumeration types do not have an implicitly provided default initializer; all initializers must be declared explicitly. Initializers can delegate to other initializers in the enumeration, but the initialization process is complete only after an initializer assigns one of the enumeration cases to self. + +不像类或者结构,枚举类型没有一个默认的初始化,但是初始化过程仅仅在初始化赋值给枚举类型的一个给self的时候。 + +Like structures but unlike classes, enumerations are value types; instances of an enumeration are copied when assigned to variables or constants, or when passed as arguments to a function call. For information about value types, see Structures and Enumerations Are Value Types. + +类似结构但是不像类,枚举是值类型;一个枚举实例在赋值给变量或者常量的时候会被复制,或者在传递参数给函数调用的的时候。 + +You can extend the behavior of an enumeration type with an extension declaration, as discussed in Extension Declaration. + + +可以使用extension声明扩展枚举类型的行为,如果Extension Declaration Enumerations with Cases of Any Type描述的那样。 + +The following form declares an enumeration type that contains enumeration cases of any type: + +下面的形式声明了一个枚举类型,包含了所有类型的枚举。 + + + enum enumeration name { + case enumeration case 1 + case enumeration case 2(associated value types) + } + + + +Enumerations declared in this form are sometimes called discriminated unions in other programming languages. + +用这种形式声明的枚举在其它语言里有时候被叫做discriminated unions + +In this form, each case block consists of the keyword case followed by one or more enumeration cases, separated by commas. The name of each case must be unique. Each case can also specify that it stores values of a given type. These types are specified in the associated value types tuple, immediately following the name of the case. For more information and to see examples of cases with associated value types, seeAssociated Values. + +用这种方式,每个cast块由关键字case组成,case后跟着一个或者多个逗号分隔的枚举case。每个case的名字必须是唯一的。每个case也能够确定它存储一个给定类型的值。这些类型用关联值类型元组来设置,后面紧跟着case的名字。获取更多信息,或关联值类型的的例子,请看Assiciated Values Enumerations with Raw Cases Values + +The following form declares an enumeration type that contains enumeration cases of the same basic type: + +下面的形式声明了一种枚举类型,包含同样基本类型的枚举case + + + enum enumeration name: raw value type { + case enumeration case 1 = raw value 1 + case enumeration case 2 = raw value 2 + } + + + +In this form, each case block consists of the keyword case, followed by one or more enumeration cases, separated by commas. Unlike the cases in the first form, each case has an underlying value, called a raw value, of the same basic type. The type of these values is specified in the raw value type and must represent a literal integer, floating-point number, character, or string. + +通过这种形式,每种caes块是由关键字case后面跟着一个或者多个由多个逗号分隔的枚举case。不像第一种形式的case,每个case有一个underlying值,叫做原生值。这些值的类型在rsw值的类型设置,必须表示一个字面量整数,浮点数,字符和字符串。 + +Each case must have a unique name and be assigned a unique raw value. If the raw value type is specified as Int and you don’t assign a value to the cases explicitly, they are implicitly assigned the values 0, 1, 2, and so on. Each unassigned case of type Int is implicitly assigned a raw value that is automatically incremented from the raw value of the previous case. + +每个case必须有一个唯一的名字,然后被赋值为一个单独的原生值。如果原生值用Int设置,你不需要要显式的赋值,他们可以默认的赋值1,1,2等等。每个没有赋值的Int类型会被赋值为原生类型,可以自动的从之前的case的原生值递增。 + + + enum ExampleEnum: Int { + case A, B, C = 5, D + } + + +In the above example, the value of ExampleEnum.A is 0 and the value of ExampleEnum.B is 1. And because the value of ExampleEnum.C is explicitly set to 5, the value of ExampleEnum.D is automatically incremented from 5 and is therefore 6. + +在上面的例子中,ExampleEnum。A的值是o.ExampleEnum.B值是1。因为ExampleEnum.C是显式的设置为5,ExampleEnumd.D的值会从5自动的增加,所以是6. + +The raw value of an enumeration case can be accessed by calling its toRaw method, as inExampleEnum.B.toRaw(). You can also use a raw value to find a corresponding case, if there is one, by calling the fromRaw method, which returns an optional case. For more information and to see examples of cases with raw value types, see Raw Values. + +枚举类型的原生值可以通过toRaw方法访问,比如ExampleEnum.B.toRaw()。你也可以使用一个原生值来找到对应的case通过调用fromRaw方法。 + +##Accessing Enumeration Cases + +##访问枚举case + +To reference the case of an enumeration type, use dot (.) syntax, as in EnumerationType.EnumerationCase. When the enumeration type can be inferred from context, you can omit it (the dot is still required), as described in Enumeration Syntax and Implicit Member Expression. + +和EnumerationType.EnumerationCase一样,可以使用语法.来引用一个enumeration类型的case,就像inEnumeration Syntax and Implicit Member Expression所描述的。 + +To check the values of enumeration cases, use a switch statement, as shown in Matching Enumeration Values with a Switch Statement. The enumeration type is pattern-matched against the enumeration case patterns in the case blocks of the switch statement, as described in Enumeration Case Pattern. + +使用switch语句来检验枚举事件的值,如使用switch语句匹配枚举值(Matching Enumeration Values with a Switch Statement)一节描述的那样。 + +>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­ + +##Structure Declaration + +##结构声明 + +A structure declaration introduces a named structure type into your program. Structure declarations are declared using the keyword struct and have the following form: + +结构声明引入了命名的类型到程序中。结构声明使用关键字struct,采用如下的形式: + + struct structure name: adopted protocols { + declarations + } + + +The body of a structure contains zero or more declarations. These declarations can include both stored and computed properties, static properties, instance methods, static methods, initializers, type aliases, and even other structure, class, and enumeration declarations. Structure declarations can’t contain destructor or protocol declarations. For a discussion and several examples of structures that include various kinds of declarations, see Classes and Structures. + +结构体包含0或者更多的声明。这个声明能包括存储型和计算型的属性,静态属性,示例方法,静态方法,构造器,类型别名,甚至其它结构,类和枚举声明。结构声明不能包含析构或者协议声明。在Classes and Structures里,包括好几种了不同类型的声明的结构例子。 + +Structure types can adopt any number of protocols, but can’t inherit from classes, enumerations, or other structures. + +结构类型可以采用任何数量的协议,但是不能从classes,枚举或者它结构继承。 + +There are three ways create an instance of a previously declared structure: + +有3种方式创建过去声明过的示例结构的示例。 + + +- Call one of the initializers declared within the structure, as described in Initializers. + 就像Initializers描述的,调用结构里的一个初始器之一。 + +- If no initializers are declared, call the structure’s memberwise initializer, as described in Memberwise Initializers for Structure Types. + 如果没有初始器被声明,就可以调用结构区的成员 + +- If no initializers are declared, and all properties of the structure declaration were given initial values, call the structure’s default initializer, as described in Default Initializers. + 如果没有初始化器被声明,结构所有其他声明的属性就会被给予初始化的值,调用结构的某人初始化器,正如Default Initializers .描述的那样。 + + + +The process of initializing a structure’s declared properties is described in Initialization. + +初始化一个结构的声明的属性的过程在Initialization描述。 + +Properties of a structure instance can be accessed using dot (.) syntax, as described in Accessing Properties. + +一个结构实例的属性使用通过.语来访问。 + +Structures are value types; instances of a structure are copied when assigned to variables or constants, or when passed as arguments to a function call. For information about value types, see Structures and Enumerations Are Value Types. + +结构是值类型;一个结构的实例在赋值给变量或者常量或者在传递参数给函数调用的时候采用复制的形式。关于值类型的信息,请参看Structures and Enumerations Are Value Types. + +You can extend the behavior of a structure type with an extension declaration, as discussed in Extension Declaration. + +你可以用一个扩展声明来扩展结构类型的行为,正如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­} + +##Class Declaration + +##类声明 + + +A class declaration introduces a named class type into your program. Class declarations are declared using the keyword class and have the following form: + +类型声明引入了命名的类型到程序中。类声明使用关键字class声明,采用下面的形式: + + + class class name: superclass, adopted protocols { + declarations + } + + +The body of a class contains zero or more declarations. These declarations can include both stored and computed properties, instance methods, class methods, initializers, a single destructor method, type aliases, and even other class, structure, and enumeration declarations. Class declarations can’t contain protocol declarations. For a discussion and several examples of classes that include various kinds of declarations, see Classes and Structures. + +一个class的主题会包含0或多个声明。这些声明可以包括存储型和计算型的属性,实例方法,类方法,构造器,单个析构函数,类型 别名,和甚至其它的class,结构,枚举声明。类声明不能包括协议声明。详细讨论和例子请看 Classes and Structures + +A class type can inherit from only one parent class, its superclass, but can adopt any number of protocols. The superclass appears first in the type-inheritance-clause, followed by any adopted protocols. +一个class类只能从一个父类中继承,但是可以有多个协议。超类首先出现在类型继承语句中,后面跟着采用的协议。 + +As discussed in Initializer Declaration, classes can have designated and convenience initializers. When you declare either kind of initializer, you can require any subclass to override it by marking the initializer with therequired attribute. The designated initializer of a class must initialize all of the class’s declared properties and it must do so before calling any of its superclass’s designated initializers. + +正如在初始化声明讨论的一样,类可以有指定和便利的构造器。当你声明某种构造器时,可以使用required属性要求所有子类重写。这个特定的构造器必须初始化类的所有声明的属性。在调用任何超类的特定的构造器时都必须这么做。 + +A class can override properties, methods, and initializers of its superclass. Overridden methods and properties must be marked with the override keyword. + +类可以重写它超类的属性,方法和构造器。重写的方法和属性必须都使用override来标记。 + +Although properties and methods declared in the superclass are inherited by the current class, designated initializers declared in the superclass are not. That said, if the current class overrides all of the superclass’s designated initializers, it inherits the superclass’s convenience initializers. Swift classes do not inherit from a universal base class. + +尽管在子类中声明的属性和方法可以被当前的类继承,但是在超类中指定的构造器却不可以。也就是说,如果当前类重写了超类的所有指定的构造器,它就会继续超类的便利构造器。Swift类不会从通用的基类中继承。 + +There are two ways create an instance of a previously declared class: + +有两种方式创建过去声明的类的实例: + +- Call one of the initializers declared within the class, as described in Initializers. + 在类的内部调用声明的初始化器。 +- If no initializers are declared, and all properties of the class declaration were given initial values, call the class’s default initializer, as described in Default Initializers. + 如果没有声明的初始化器,类声明的素有属性会有一个初始化值,是通过调用类的默认的初始化器来完成的。正如Default Initializers描述的。 + + + +Access properties of a class instance with dot (.) syntax, as described in Accessing Properties. + +使用.语法访问类的属性,如Accessing Properties描述的一样。 + + +Classes are reference types; instances of a class are referred to, rather than copied, when assigned to variables or constants, or when passed as arguments to a function call. For information about reference types, see Structures and Enumerations Are Value Types. + +类是引用类型;在被赋值给变量或常量的时候,或者当被作为参数传递给函数调用的时候,类的实例会被引用而不是被复制。更多信息,参考Structures and Enumerations Are Value Types.。 + + +You can extend the behavior of a class type with an extension declaration, as discussed in Extension Declaration. + +可以使用extension声明来扩展类的行为,如Extension Desclaration描述的那样. + + + > 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­} + +##Protocol Declaration + +##协议声明 + +A protocol declaration introduces a named protocol type into your program. Protocol declarations are declared using the keyword protocol and have the following form: + +协议声明引入命名的协议类型到程序中,用关键字protocol来声明,有如下的形式: + + + protocol protocol name: inherited protocols { + protocol member declarations + } + +The body of a protocol contains zero or more protocol member declarations, which describe the conformance requirements that any type adopting the protocol must fulfill. In particular, a protocol can declare that conforming types must implement certain properties, methods, initializers, and subscripts. Protocols can also declare special kinds of type aliases, called associated types, that can specify relationships among the various declarations of the protocol. The protocol member declarations are discussed in detail below. + +协议的主体包含0或多个协议成员声明,它描述了任何实现它的协议都必须满足的一致性要求。特别是,一致性的协议必须实现某个属性,方法,构造器,和附属脚本。协议也能声明特殊种类的类型别名,被、称作关联类型,设置协议里的不同声明的关系。下面会对协议成员声明会做详细的讨论 + +Protocol types can inherit from any number of other protocols. When a protocol type inherits from other protocols, the set of requirements from those other protocols are aggregated, and any type that inherits from the current protocol must conform to all those requirements. For an example of how to use protocol inheritance, see Protocol Inheritance. + +协议类型可以继承任意数量的其它协议。如果一个协议类型从其它协议继承时任何从当前协议继承的类型都必须和从那些协议中的要求集合一致。如何使用协议继承,请查看Protocol Inheritance. + + +NOTE +注意 + +You can also aggregate the conformance requirements of multiple protocols using protocol composition types, as described in Protocol Composition Type and Protocol Composition. + +你也可以使用协议符合类型聚合多个协议的一致性要求。 + +You can add protocol conformance to a previously declared type by adopting the protocol in an extension declaration of that type. In the extension, you must implement all of the adopted protocol’s requirements. If the type already implements all of the requirements, you can leave the body of the extension declaration empty. + +你可以增加协议conformance到任何一个过去声明的类型通过在那个类型的extendsion中声明。在这个扩展里,你必须实现所有使用的协议的需求。如果那个类型已经实现了所有的要求,扩展声明的主题可以是空的。 + +By default, types that conform to a protocol must implement all properties, methods, and subscripts declared in the protocol. That said, you can mark these protocol member declarations with the optional attribute to specify that their implementation by a conforming type is optional. The optional attribute can be applied only to protocols that are marked with the objc attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. For more information about how to use the optionalattribute and for guidance about how to access optional protocol members—for example, when you’re not sure whether a conforming type implements them—see Optional Protocol Requirements. + +默认情况下,与协议一致的类型必须实现所有的属性,方法,和声明的附属脚本。也就是说,你可以用opaional属性来标记协议成员,表示他们的实现是可选的。option属性仅仅能被应用到objc标记的属性。结构,仅仅class类型能采纳和玉包含可选的成员变量的协议一致。对于如何访问可选的协议成员-例如,如果你不确定一个一致性类型是否要实现-查看一下 Optional Protocol Requirements. + +To restrict the adoption of a protocol to class types only, mark the entire protocol declaration with theclass_protocol attribute. Any protocol that inherits from a protocol marked with the class_protocol attribute can likewise be adopted only by a class type. + +为了限制协议的的只应用到某个class type,用 class_protocol属性标记整个协议声明。任何从标记class_protocol 协议继承的协议可以只被class类型采纳。 + +NOTE +注意 + +If a protocol is already marked with the objc attribute, the class_protocol attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the class_protocol attribute explicitly. + +如果协议已经用objc标记过了,class_protocol会隐式的应用到那个协议;没有必要显式的用class_protocol标记协议。 + +Protocols are named types, and thus they can appear in all the same places in your code as other named types, as discussed in Protocols as Types. However, you can’t construct an instance of a protocol, because protocols do not actually provide the implementations for the requirements they specify. + +协议是命名类型,因此在你的代码里它们可以像其它命名类型一样出现在左右同样的地方,如在协议里的类型一样。不管怎么样,你不能构造协议的实例,因为协议实际上不能提供它们 + +You can use protocols to declare which methods a delegate of a class or structure should implement, as described in Delegation. +你可以使用协议来声明类或者结构应该实现那个方法,如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 Property Declaration + +##协议属性声明 + +Protocols declare that conforming types must implement a property by including a protocol property declaration in the body of the protocol declaration. Protocol property declarations have a special form of a variable declaration: + +协议声明一致性类型必须通过在协议声明体里包括一个协议属性声明来实现属性。协议属性声明有一个特殊形式的变量声明: + + var property name: type { get set } + +As with other protocol member declarations, these property declarations declare only the getter and setter requirements for types that conform to the protocol. As a result, you don’t implement the getter or setter directly in the protocol in which it is declared. + +与其它协议成员声明一样,这些属性声明只声明了与协议一致的类型的getter和setter要求。结果,你不能在它声明的协议里实现getter货setter + +The getter and setter requirements can be satisfied by a conforming type in a variety of ways. If a property declaration includes both the get and set keywords, a conforming type can implement it with a stored variable property or a computed property that is both readable and writeable (that is, one that implements both a getter and a setter). However, that property declaration can’t be implemented as a constant property or a read-only computed property. If a property declaration includes only the get keyword, it can be implemented as any kind of property. For examples of conforming types that implement the property requirements of a protocol, see Property Requirements. + +getter和setter要求可以通过一致性类型以各种方式满足。如果属性声明包含get和set关键词,一致性类型就可以用可读写(实现了getter和setter)的存储型变量属性或计算型属性,但是属性不能以常量属性或只读计算型属性实现。如果属性声明仅仅包含get关键词的话,它可以作为任意类型的属性被实现。比如说实现了协议的属性要求的一致性类型,参见属性要求。 + +See also Variable Declaration. + +更多参见变量声明 + +GRAMMAR OF A PROTOCOL PROPERTY DECLARATION + +protocol-property-declaration → variable-declaration-head­variable-name­type-annotation­getter-setter-keyword-block­ + + +##Protocol Method Declaration + +##协议方法声明 + +Protocols declare that conforming types must implement a method by including a protocol method declaration in the body of the protocol declaration. Protocol method declarations have the same form as function declarations, with two exceptions: They don’t include a function body, and you can’t provide any default parameter values as part of the function declaration. For examples of conforming types that implement the method requirements of a protocol, see Method Requirements. + +协议声明一致性类型必须在协议声明体里通过包括一个协议方法声明来实现方法。协议方法声明与函数声明有同样的形式,只有2点例外:他们不需要包括函数体,你不能提供任何某人参数值作为函数声明的一部分。 + + +To declare a class or static method requirement in a protocol declaration, mark the method declaration with the class keyword. Classes that implement this method also declare the method with the class keyword. Structures that implement it must declare the method with the static keyword instead. If you’re implementing the method in an extension, use the class keyword if you’re extending a class and the static keyword if you’re extending a structure. + +在协议声明里,为了声明一个类或者静态方法要求,使用class关键字来标记方法声明。实现这个方法的类也用class来声明方法。实现它的结构必须用static进行声明。如果你在extension里实现,如果你扩展class使用class,如果是结构使用static + + +>GRAMMAR OF A PROTOCOL METHOD DECLARATION + +>protocol-method-declaration → function-head­function-name­generic-parameter-clause­opt­function-signature­ + +##Protocol Initializer Declaration + +##协议构造器声明 + +Protocols declare that conforming types must implement an initializer by including a protocol initializer declaration in the body of the protocol declaration. Protocol initializer declarations have the same form as initializer declarations, except they don’t include the initializer’s body. + +协议声明了一致性类型必须在协议声明的主体里通过引入一个协议构造器声明来实现一个构造器。协议构造器声明除了不包含构造器体外,和构造器声明有着相同的形式. + +See also Initializer Declaration. + +更多请参阅构造器声明。 + +>GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION + +>protocol-initializer-declaration → initializer-head­generic-parameter-clause­opt­parameter-clause­ + + +##Protocol Subscript Declaration + +Protocols declare that conforming types must implement a subscript by including a protocol subscript declaration in the body of the protocol declaration. Protocol property declarations have a special form of a subscript declaration: + +协议声明了一致性类型必须在协议声明的主体里通过引入一个协议附属脚本声明来实现一个附属脚本。协议属性声明对附属脚本声明有一个特殊附属脚本声明形式: + +>subscript (parameters) -> return type { get set } + + +Subscript declarations only declare the minimum getter and setter implementation requirements for types that conform to the protocol. If the subscript declaration includes both the get and set keywords, a conforming type must implement both a getter and a setter clause. If the subscript declaration includes only the get keyword, a conforming type must implement at least a getter clause and optionally can implement a setter clause. +See also Subscript Declaration. + +附属脚本声明只为和协议一致的类型声明了必需的最小数量的的getter和setter。如果附属脚本声明包含get和set关键字, 一致的类型也必须有一个getter和setter语句。如果附属脚本声明值包含get关键字,一致的类型必须至少包含一个 getter语句,可以选择是否包含setter语句。 + +>GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION + +>protocol-subscript-declaration → subscript-head­subscript-result­getter-setter-keyword-block­ + +##Protocol Associated Type Declaration + +##协议关联类型声明 + +Protocols declare associated types using the keyword typealias. An associated type provides an alias for a type that is used as part of a protocol’s declaration. Accosiated types are similiar to type paramters in generic parameter clauses, but they’re associated with Self in the protocol in which they’re declared. In that context, Self refers to the eventual type that conforms to the protocol. For more information and examples, see Associated Types. + +协议用关键字typealias声明关联类型。关联类型为类型提供了一个别名,这个被用作协议声明的一部分。关联类型与在通用参数子句的类型参数相似,但是他们与声明他们的协议中的self相似。在那个环境下,self指的是时间类型。 + +See also Type Alias Declaration. + +也可以参看 Type Alias Declaration. + +>GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION + +>protocol-associated-type-declaration → typealias-head­type-inheritance-clause­opt­typealias-assignment­op + + +##Initializer Declaration + +##构造器声明 + +An initializer declaration introduces an initializer for a class, structure, or enumeration into your program. Initializer declarations are declared using the keyword init and have two basic forms. + +构造器声明引入了类的构造器器到程序中。初始化声明使用关键字init声明,有两种基本形式: + +Structure, enumeration, and class types can have any number of initializers, but the rules and associated behavior for class initializers are different. Unlike structures and enumerations, classes have two kinds of initializers: designated initializers and convenience initializers, as described in Initialization. + +结构,枚举和类类型可以有很多构造器,但是类构造器的规则和关联行为是不同的。不像结构和枚举类型。类有两种构造器:指定的和便利的构造器器。 + +The following form declares initializers for structures, enumerations, and designated initializers of classes: + +下面的形式声明了结构,枚举和类指定的构造器 + + init(parameters) { + statements + } + + +A designated initializer of a class initializes all of the class’s properties directly. It can’t call any other initializers of the same class, and if the class has a superclass, it must call one of the superclass’s designated initializers. If the class inherits any properties from its superclass, one of the superclass’s designated initializers must be called before any of these properties can be set or modified in the current class. + +类的指定构造器将类的所有属性直接初始化。如果类有超类,它不能调用该类的其它构造器,它只能调用超类的一个 指定构造器。如果该类从它的超类处继承了任何属性,这些属性在当前类内被赋值或修饰时,必须带调用一个超类的 指定构造器。 + +Designated initializers can be declared in the context of a class declaration only and therefore can’t be added to a class using an extension declaration. + +指定构造器可以在类声明的上下文中声明,因此它不能用扩展声明的方法被加入到一个类中。 + +Initializers in structures and enumerations can call other declared initializers to delegate part or all of the initialization process. + +结构体和枚举的构造器可以调用其它的已声明的构造器,来委托部分或全部初始化过程。 + +To declare convenience initializers for a class, prefix the initializer declaration with the context-sensitive keyword convenience. + +以关键字convenience来声明一个类的便利构造器: + + convenience init(parameters) { + statements + } + + +Convenience initializers can delegate the initialization process to another convenience initializer or to one of the class’s designated initializers. That said, the initialization processes must end with a call to a designated initializer that ultimately initializes the class’s properties. Convenience initializers can’t call a superclass’s initializers. + +便利构造器可以将初始化过程委托给另一个便利构造器或类的一个指定构造器。这意味着,类的初始化过程必须 以一个将所有类属性完全初始化的指定构造器的调用作为结束。便利构造器不能调用超类的构造器。 + +You can mark designated and convenience initializers with the required attribute to require that every subclass implement the initializer. Because designated initializers are not inherited by subclasses, they must be implemented directly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or overrides the designated initializers with convenience initializers). Unlike methods, properties, and subscripts, you don’t need to mark overridden initializers with the override keyword. + +你可以使用requierd关键字,将便利构造器和指定构造器标记为每个子类的构造器都必须拥有的。因为指定构造器 不被子类继承,他们必须被立即执行。当子类直接执行所有超类的指定构造器(或使用便利构造器重写指定构造器)时, 必需的便利构造器可以被隐式的执行,亦可以被继承。不像方法,附属脚本那样,你不需要为这些重写的构造器标注 overrride关键字。 + +To see examples of initializers in various type declarations, see Initialization. + +查看更多关于不同声明方法的构造器的例子,参阅构造过程一节。 + +>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­ + +A deinitializer declaration declares a deinitializer for a class type. Deinitializers take no parameters and have the following form: + +析构声明在类中声明了一个析构器。析构器不需要参数,遵循如下的格式: + + deinit { + statements + } + + +A deinitializer is called automatically when there are no longer any references to a class object, just before the class object is deallocated. A deinitializer can be declared only in the body of a class declaration—but not in an extension of a class—and each class can have at most one. + +当类中没有对任何其它对象的引用时,在类对象释放之前,析构器会自动的被调用。析构器只能在类的声明体内、而不能在 类的扩展内声明,每个类最多只能有一个析构器声明。 + +A subclass inherits its superclass’s deinitializer, which is implicitly called just before the subclass object is deallocated. The subclass object is not deallocated until all deinitializers in its inheritance chain have finished executing. + +子类继承了它的超类的析构器,在子类帝乡将要被释放时会被隐式的调用。子类在所有析构器被执行完毕前不会被释放。 + +Deinitializers are not called directly. + +析构器不会被直接调用。 + +For an example of how to use a deinitializer in a class declaration, see Deinitialization. +如何使用类声明中的析构器,请查看Deinitialization + +>GRAMMAR OF A DEINITIALIZER DECLARATION + +>deinitializer-declaration → attributes­opt­deinit­code-block + +##Extension Declaration +##扩展声明 + +An extension declaration allows you to extend the behavior of existing class, structure, and enumeration types. Extension declarations begin with the keyword extension and have the following form: + +扩展声明用于扩展一个已存在的类,结构体,枚举的行为。扩展声明以关键字extension开始,有如下的形式: + + + extension type: adopted protocols { + declarations + } + + + +The body of an extension declaration contains zero or more declarations. These declarations can include computed properties, computed static properties, instance methods, static and class methods, initializers, subscript declarations, and even class, structure, and enumeration declarations. Extension declarations can’t contain destructor or protocol declarations, store properties, property observers, or other extension declarations. For a discussion and several examples of extensions that include various kinds of declarations, see Extensions. + +扩展声明体包括零个或多个声明。这些声明可以包括计算型属性,计算型静态属性,实例方法,静态和类方法,构造器,附属脚本声明,甚至其它类,结构和枚举声明。扩展声明不能包含析构器,协议声明,存储型属性,属性监测器或其它的扩展属性。详细讨论和查看包含多种扩展声明的实例,参见Extensions一节。 + +Extension declarations can add protocol conformance to an existing class, structure, and enumeration type in the adopted protocols. Extension declarations can’t add class inheritance to an existing class, and therefore the type-inheritance-clause in an extension declaration contains only a list of protocols. + +扩展声明可以向存在的类,结构体,枚举添加一致的协议。扩展声明不能向一个类中添加类的继承,因此type-inheritance-clause只包含协议的列表。 + + +Properties, methods, and initializers of an existing type can’t be overridden in an extension of that type. +现存类型的属性,方法,构造器不能被它们的扩展重写。 + +Extension declarations can contain initializer declarations. That said, if the type you’re extending is defined in another module, an initializer declaration must delegate to an initializer already defined in that module to ensure members of that type are properly initialized. +扩展声明可以包含构造器声明,这意味着,如果你扩展的类型在其他模块中定义,构造器声明必须委托另一个在 那个模块里声明的构造器来恰当的初始化。 + +>GRAMMAR OF AN EXTENSION DECLARATION + +>extension-declaration → extension­type-identifier­type-inheritance-clause­opt­extension-body­ +>extension-body → {­declarations­opt­}­ + + +##Subscript Declaration + +##附属脚本声明 + +A subscript declaration allows you to add subscripting support for objects of a particular type and are typically used to provide a convenient syntax for accessing the elements in a collection, list, or sequence. Subscript declarations are declared using the keyword subscript and have the following form: + +附属脚本声明用于向特定类型的对象添加附属脚本支持,通常为访问集合,列表和序列的元素提供便利的语法。使用关键字subscript,声明形式如下: + + +> subscript (`parameter`) -> (return type){ + get{ + `statements` + } + set(`setter name`){ + `statements` + } +} + + +Subscript declarations can appear only in the context of a class, structure, enumeration, extension, or protocol declaration. + +附属脚本声明只能出现在类,结构,枚举类型,扩展或协议声明的上下文中。 + +The parameters specify one or more indexes used to access elements of the corresponding type in a subscript expression (for example, the i in the expression object[i]). Although the indexes used to access the elements can be of any type, each parameter must include a type annotation to specify the type of each index. The return type specifies the type of the element being accessed. + +参数(parameters)指定了一个或多个用于在相应类型的附属脚本表达式中访问元素的索引(例如,表达式object[i]中的i)。尽管用于访问元素的索引可以是任意类型,但是每个参数必须包含一个类型标注来指定每种索引的类型。返回类型(return type)指定被访问的元素的类型。 + + +As with computed properties, subscript declarations support reading and writing the value of the accessed elements. The getter is used to read the value, and the setter is used to write the value. The setter clause is optional, and when only a getter is needed, you can omit both clauses and simply return the requested value directly. That said, if you provide a setter clause, you must also provide a getter clause. + +和计算型属性一样,附属脚本声明支持对访问元素的读写。getter用于读取,setter用于写入。setter子句是可选的,当仅需要一个getter子句时,可以将二者都忽略,直接返回请求的值即可。也就是说,如果提供了setter子句,getter子句也必须要有。 + +The setter name and enclosing parentheses are optional. If you provide a setter name, it is used as the name of the parameter to the setter. If you do not provide a setter name, the default parameter name to the setter is value. That type of the setter name must be the same as the return type. + +setter的名字和封闭的括号是可选的。如果提供了setter名称,它会被setter的参数名。如果没有提供setter名称,那么传给setter的参数的名称默认是value。setter名称的类型必须与返回类型(return type)的类型相同。 + +You can overload a subscript declaration in the type in which it is declared, as long as the parameters or the return type differ from the one you’re overloading. You can also override a subscript declaration inherited from a superclass. When you do so, you must mark the overridden subscript declaration with the override keyword. + +在附属脚本声明的类型中,可以重载附属脚本,只要参数(parameters)或返回类型(return type) 与先前的不同即可。如果这样做的话,必须使用override关键字声明那个被覆盖的附属脚本。 + +You can also declare subscripts in the context of a protocol declaration, as described in Protocol Subscript Declaration. +在协议声明的上下文中,也声明附属脚本,正如Protocol Subscript Declaration描述的一样。 + +For more information about subscripting and to see examples of subscript declarations, see Subscripts。. + +获取更多关于附属脚本的信息和例子,请参看Subscripts。 + +>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­ + +##Operator Declaration + +##运算符声明 + +An operator declaration introduces a new infix, prefix, or postfix operator into your program and is declared using the contextual keyword operator. + +运算符声明引入了新的中缀,前缀或后缀运算到程序中,使用上下文关键字operator声明。 + +You can declare operators of three different fixities: infix, prefix, and postfix. The fixity of an operator specifies the relative position of an operator to its operands. + +可以声明3种不同的缀:中缀、前缀和后缀。一个运算符的缀规定了一个它相对于它的操作数的相对位置。 + +There are three basic forms of an operator declaration, one for each fixity. The fixity of the operator is specified by including the contextual keyword infix, prefix, or postfix between operator and the name of the operator. In each form, the name of the operator can contain only the operator characters defined in Operators. + +运算符声明有三种基本形式,每种缀性各一种。运算符的缀性通过在operator和运算符之间添加上下文关键字infix,prefix或postfix来指定。对于每种形式,运算符的名字只能包含Operators中定义的运算符字符。 + +The following form declares a new infix operator: + +下面这种形式声明了一个新的中缀运算符: + +> operator infix `operator name`{ + precedence `precedence level` + associativity `associativity` + } + + +An infix operator is a binary operator that is written between its two operands, such as the familiar addition operator (+) in the expression 1 + 2. + +中缀运算符是二元运算符,置于两个操作数之间,比如我们熟悉的表达式1 + 2 中的加法运算符(+)。 + +Infix operators can optionally specify a precedence, associativity, or both. + +中缀运算符可以指定优先级,结合性,或两者同时指定。 + +The precedence of an operator specifies how tightly an operator binds to its operands in the absence of grouping parentheses. You specify the precedence of an operator by writing the contextual keyword precedence followed by the precedence level. The precedence level can be any whole number (decimal integer) from 0 to 255; unlike decimal integer literals, it can’t contain any underscore characters. Although the precedence level is a specific number, it is significant only relative to another operator. That is, when two operators compete with each other for their operands, such as in the expression 2 + 3 * 5, the operator with the higher precedence level binds more tightly to its operands. + +运算符的优先级指定了在没有分组括号的情况下,运算符与它的操作数绑定的紧密程度。可以使用上下文关键字precedence和优先等级一起来指定一个运算符的优先级。优先级可以是0到255之间的任何一个数字(十进制整数);与十进制整数字面量不同的是,它不可以包含任何下划线字符。尽管优先级是一个特定的数字,但它仅用作与另一个运算符比较(大小)。也就是说,一个操作数可以同时被两个运算符使用时,例如2 + 3 * 5,优先级更高的运算符将优先与操作数绑定。 + +The associativity of an operator specifies how a sequence of operators with the same precedence level are grouped together in the absence of grouping parentheses. You specify the associativity of an operator by writing the contextual keyword associativity followed by the associativity, which is one of the contextual keywords left, right, or none. Operators that are left-associative group left-to-right. For example, the subtraction operator (-) is left-associative, and therefore the expression 4 - 5 - 6 is grouped as (4 - 5) - 6 and evaluates to -7. Operators that are right-associative group right-to-left, and operators that are specified with an associativity of none don’t associate at all. Nonassociative operators of the same precedence level can’t appear adjacent to each to other. For example, 1 < 2 < 3 is not a valid expression. + +运算符的结合性明确了,没有分组的括号包围的情况下,优先级相同的运算符以何种顺序被分组的。使用上下文关键字associativity和结合性(associativity)一起来指定一个运算符的结合性,其中结合性的值是上下文关键字left,right或none之一。左结合运算符以从左到右的形式分组。例如,减法运算符(-)具有左结合性,因此表达式4 - 5 - 6以(4 - 5) - 6的形式分组,其结果为-7。 右结合运算符以从右到左的形式分组,对于设置为none的非结合运算符,它们不以任何形式分组。具有相同优先级的非结合运算符,不可以互相邻接。例如,1 < 2 < 3 就是一个无效的表达式 + +Infix operators that are declared without specifying a precedence or associativity are initialized with a precedence level of 100 and an associativity of none. + +如果再声明时不指定任何优先级或结合性,中缀运算符的优先级会被初始化为100,结合性被初始化为none。 + +The following form declares a new prefix operator: + +下面的形式声明了一个新的前缀运算符: + +> operator prefix `operator name`{} + + +A prefix operator is a unary operator that is written immediately before its operand, such as the prefix increment operator (++) is in the expression ++i. + +前缀运算符一元运算符,紧跟在操作数之前,比如表达式 ++i 中的前缀递增运算符(++)。 + +Prefix operators declarations don’t specify a precedence level. Prefix operators are nonassociative. + +前缀缀运算符的声明中不指定优先级。前缀运算符是非结合的。 + +The following form declares a new postfix operator: + +下面的形式声明了一个新的后缀运算符: + + +> operator postfix `operator name`{} + + + +A postfix operator is a unary operator that is written immediately after its operand, such as the postfix increment operator (++) is in the expression i++. + +后缀运算符一元运算符,紧跟在操作数之前,比如表达式 i++ 中的前后缀递增运算符(++)。 + +As with prefix operators, postfix operator declarations don’t specify a precedence level. Postfix operators are nonassociative. + +与前缀运算符一样,后缀运算符声明不会指定优先级。后缀运算符也是非结合性的。 + +After declaring a new operator, you implement it by declaring a function that has the same name as the operator. To see an example of how to create and implement a new operator, see Custom Operators. + +在声明了一个新的运算符之后,要声明一个和运算符同名的函数来实现它。如何创建和实现新的操作符,请看Custom Operators。 + + + +>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 + diff --git a/src/chapter3/07_Attributes.md b/src/chapter3/07_Attributes.md new file mode 100644 index 0000000..b285b60 --- /dev/null +++ b/src/chapter3/07_Attributes.md @@ -0,0 +1,208 @@ +# Attributes + +# 特性 + +*Attributes* provide more information about a declaration or type. There are two kinds of attributes in Swift, those that apply to declarations and those that apply to types. For instance, the `required` attribute—when applied to a designated or convenience initializer declaration of a class—indicates that every subclass must implement that initializer. And the `noreturn` attribute—when applied to a function or method type—indicates that the function or method doesn’t return to its caller. + +*特性* 为声明和类型提供了更多的信息。在Swift中有两种类型的特性,一种用于修饰声明,另一种用于修饰类型。比如,`required`特性——当被用来修饰一个类的预设构造函数声明或者便利构造函数声明时——表明其所有的子类都必须实现这个构造函数。`noreturn`特性——当修饰函数或者方法类型时——表明这个函数或者方法不会返回任何值给其调用者。 + +You specify an attribute by writing the `@` symbol followed by the attribute’s name and any arguments that the attribute accepts: + +``` + @attribute name + @attribute name(attribute arguments) +``` + +你可以通过`@`符号以及紧随其后的特性名称和该特性可以接受的参数来使用特性。 + +``` + @attribute name + @attribute name(attribute arguments) +``` + +Some declaration attributes accept arguments that specify more information about the attribute and how it applies to a particular declaration. These *attribute arguments* are enclosed in parentheses, and their format is defined by the attribute they belong to. + +有些声明特性可以通过给定参数来补充该特性相关的更多信息,并说明该特性将如何应用于这个声明中。这些`特性参数`写在小括号里面,他们的具体格式需要根据他们所属的特性来确定。 + +## Declaration Attributes + +## 声明特性 + +You can apply a declaration attribute to declarations only. However, you can also apply the `noreturn` attribute to a function or method *type*. + +声明特性只能描述声明。不过你还是可以使用`noreturn`特性来描述函数或者方法*类型*。 + +`assignment` +> Apply this attribute to functions that overload a compound assignment operator. Functions that overload a compound assignment operator must mark their initial input parameter as `inout`. For an example of how to use the assignment attribute, see [Compound Assignment Operators](#). + +`assignment` +> 这个特性用于描述重载了复合赋值运算符的函数。一个重载了复合赋值运算符的函数必须将它的初始化输入参数标记为`inout`.关于如何使用assigment特性请查看[符合赋值运算符](#)中的一个例子。 + +`class_protocol` +> Apply this attribute to a protocol to indicate that the protocol can be adopted by class types only. + +> If you apply the `objc` attribute to a protocol, the `class_protocol` attribute is implicitly applied to that protocol; there’s no need to mark the protocol with the `class_protocol` attribute explicitly. + +`class_protocol` +> 这个特性用于描述协议,它表明被修饰的协议只能被类使用[//todo adopted]。 + +> 如果一个协议已经添加了`objc`特性,那么`class_protocol`特性就已经被隐形地添加在这个协议上了,不需要再显性地添加一次。 + +`exported` +> Apply this attribute to an import declaration to export the imported module, submodule, or declaration from the current module. If another module imports the current module, that other module can access the items exported by the current module. + +`exported` +> 这个特性被用于修饰导入声明。当一个导入声明具有该特性时,所有通过该声明导入的的模块,子模块或者声明都可以被导出。如果另一个模块导入了这个模块,那么那个模块可以访问所有被这个模块导出的项。 + +`final` +> Apply this attribute to a class or to a property, method, or subscript member of a class. It’s applied to a class to indicate that the class can’t be subclassed. It’s applied to a property, method, or subscript of a class to indicate that that class member can’t be overridden in any subclass. + +`final` +> 这个特性用于描述类或者类的属性、方法、或者下标上。如若一个类具有该特性,则表明这个类不能被继承。如果一个类的属性、方法或者下标具有该特性,则表明这个类的成员不能被任何子类覆盖。 + +`lazy` +> Apply this attribute to a stored variable property of a class or structure to indicate that the property’s initial value is calculated and stored at most once, when the property is first accessed. For an example of how to use the `lazy` attribute, see [Lazy Stored Properties](#). + +`lazy` +> 如果一个类或者结构体的存储变量属性具有该特性,则这个属性的初始值最多只被计算和存储一次,且这一次的计算和存储发生在第一次被访问时。查看[懒惰存储属性](#)中给出的关于如何使用`lazy`的例子。 + +`noreturn` +> Apply this attribute to a function or method declaration to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. You can mark a function or method type with this attribute to indicate that the function or method doesn’t return to its caller. + +> You can override a function or method that is not marked with the `noreturn` attribute with a function or method that is. That said, you can’t override a function or method that is marked with the `noreturn` attribute with a function or method that is not. Similar rules apply when you implement a protocol method in a conforming type. + +`noreturn` +> 可以通过将这个特性应用在函数或者方法声明中来指定这个函数或者方法,`T`,是`@noreturn T`类型。你可以通过使用这个特性来标记函数或者方法,借此来表明这个函数或者方法不返回任何值给它的调用者。 + +> 你可以使用一个标记了这个特性的函数或者方法来覆盖一个没有标记过这个特性的函数或者方法,但是反过来不行。同样的,当你要实现一个协议方法时,也需要遵循这个规则。 + +`NSCopying` +> Apply this attribute to a stored variable property of a class. This attribute causes the property’s setter to be synthesized with a *copy* of the property’s value—returned by the `copyWithZone` method—instead of the value of the property itself. The type of the property must conform to the `NSCopying` protocol. + +> The `NSCopying` attribute behaves in a way similar to the Objective-C `copy` property attribute. + +`NSCopying` +> 这个特性用于修饰一个类的储存变量属性。该特性将使得这个类的属性的setter方法与这个属性的返回值的*副本*合成——通过`copyWithZone`方法进行返回——而不是这个属性值本身。这个属性值的类型必须遵循`NSCopying`协议。 + +> `NSCopying`特性与Objective-C中的`copy`属性特性类似。 + +`NSManaged` +> Apply this attribute to a stored variable property of a class that inherits from `NSManagedObject` to indicate that the storage and implementation of the property are provided dynamically by Core Data at runtime based on the associated entity description. + +`NSManaged` +> 这个特性用于修饰继承了`NSManagedObject`的类的成员,通过该特性来表明这个成员的存储和实现由Core Data在运行时根据相关实体描述来动态地提供。 + +`objc` +> Apply this attribute to any declaration that can be represented in Objective-C—for example, non-nested classes, protocols, properties and methods (including getters and setters) of classes and protocols, initializers, deinitializers, and subscripts. The `objc` attribute tells the compiler that a declaration is available to use in Objective-C code. + +> If you apply the `objc` attribute to a class or protocol, it’s implicitly applied to the members of that class or protocol. The compiler also implicitly adds the `objc` attribute to a class that inherits from another class marked with the `objc` attribute. Protocols marked with the `objc` attribute can’t inherit from protocols that aren’t. + +> The `objc` attribute optionally accepts a single attribute argument, which consists of an identifier. Use this attribute when you want to expose a different name to Objective-C for the entity the `objc` attribute applies to. You can use this argument to name classes, protocols, methods, getters, setters, and initializers. The example below exposes the getter for the enabled property of the `ExampleClass` to Objective-C code as `isEnabled` rather than just as the name of the property itself. + +``` + @objc + class ExampleClass { + var enabled: Bool { + @objc(isEnabled) get { + // Return the appropriate value + } + } + } +``` + +`objc` +> 这个特性用于描述任何可以在Objective-C中表示的声明,如非嵌套类,协议,类和协议的属性和方法(包括getter和setter),构造函数,析构函数和下标。`objc`特性告诉编译器该声明可以在Objective-C的代码中被使用。 + +> 如果一个类或者协议具有`objc`特性,那么这个类或者协议的所有成员都将隐形地具有`objc`特性。编译器甚至会隐形地添加`objc`特性给具有`objc`特性的类的子类。被标记`objc`特性的协议不能继承没有被标记`objc`特性的协议。 + +> `objc`特性可选地接收一个标识符作为参数。你就可以使用这个特性参数让被标记的对象对Objective-C暴露一个不一样的名字。你可以使用这个参数来重新命名类,协议,方法,getter,setter和构造函数。下面的例子通过给定特性参数使得类`ExampleClass`的enabled这个属性以`isEnabled`这个名字暴露给Objective-C. + +``` + @objc + class ExampleClass { + var enabled: Bool { + @objc(isEnabled) get { + // 返回合适的值 + } + } + } +``` + +`optional` +> Apply this attribute to a protocol’s property, method, or subscript members to indicate that a conforming type isn’t required to implement those members. + +> You can apply the `optional` attribute only to protocols that are marked with the `objc` attribute. As a result, only class types can adopt and conform to a protocol that contains optional member requirements. For more information about how to use the `optional` attribute and for guidance about how to access optional protocol members—for example, when you’re not sure whether a conforming type implements them—see [Optional Protocol Requirements](#). + +`optional` + +> 这个特性用于描述协议的属性,方法和下标,以此来表明遵循了该协议的类型,只需要可选地实现这些被标记的成员。 + +> 这个特性只能被用于描述具有`objc`特性的协议。也就是说,只有类才能接受和遵循一个具有optional特性成员的协议。更多关于如何使用`optional`特性,以及对于一个遵循了具有`optional`特性的协议的类型,在无法明确它实现了哪些可选成员的情况下,如何正确地读取其可选成员的问题,请参考[可选协议要求](#)。 + +`required` +> Apply this attribute to a designated or convenience initializer of a class to indicate that every subclass must implement that initializer. + +> Required designated initializers must be implemented explicitly. Required convenience initializers can be either implemented explicitly or inherited when the subclass directly implements all of the superclass’s designated initializers (or when the subclass overrides the designated initializers with convenience initializers). + +`required` +> 通过为一个类的预设构造函数或者便利构造函数添加该特性来表明这个类的每一个子类都必须实现这个构造函数。 + +> 具有该特性的预设构造函数必须被显性地实现。具有该特性的便利构造函数可以被显性地实现,或者当子类直接实现了所有父类的预设构造函数时(或者子类使用便利构造函数重写了预设构造函数),可以直接继承这个便利构造函数。 + +### Declaration Attributes Used by Interface Builder + +## 在Interface Builder中使用声明特性 + +Interface Builder attributes are declaration attributes used by Interface Builder to synchronize with Xcode. Swift provides the following Interface Builder attributes: `IBAction`, `IBDesignable`, `IBInspectable`, and `IBOutlet`. These attributes are conceptually the same as their Objective-C counterparts. + +Interface Builder特性是Interface Builder用来和Xcode同步的声明特性。Swift提供了以下几种Interface Builder特性: `IBAction`,`IBDesignable`,`IBInspectable`和`IBOutlet`。这些特性在概念上和Objective-C中对应的特性是一样的。 + +You apply the `IBOutlet` and `IBInspectable` attributes to property declarations of a class. You apply the `IBAction` attribute to method declarations of a class and the `IBDesignable` attribute to class declarations. + +`IBOutlet`和`IBInspectable`特性用于描述类的属性声明,`IBAction`特性用于描述类的方法声明而`IBDesignable`用于描述类的声明。 + +## Type Attributes + +## 类型特性 + +You can apply type attributes to types only. However, you can also apply the `noreturn` attribute to a function or method *declaration*. + +类型特性只能描述类型。尽管如此,你还是可以使用`noreturn`特性去修饰函数和方法的声明。 + +`auto_closure` +> This attribute is used to delay the evaluation of an expression by automatically wrapping that expression in a closure with no arguments. Apply this attribute to a function or method type that takes no arguments and that returns the type of the expression. For an example of how to use the `auto_closure` attribute, see [Function Type](#). + +`auto_closure` +> 这个特性通过自动地将表达式包裹在一个没有参数的闭包中来延迟表达式的求值。将该特性用于描述不带任何参数的函数和方法,而这些函数和方法返回表达式的类型。关于如何使用`auto_closure`特性,参考[函数类型](#)中的例子。 + +`noreturn` +> Apply this attribute to the type of a function or method to indicate that the function or method doesn’t return to its caller. You can also mark a function or method declaration with this attribute to indicate that the corresponding type of that function or method, `T`, is `@noreturn T`. + +`noreturn` +> 使用这个特性来描述函数或者方法,以此表明该函数或者方法不返回任何值给它的调用者。你也可以使用这个特性来标记函数或者方法声明,借此来表明这个函数或者方法,`T`,是`@noreturn T`类型。 + +## GRAMMAR OF AN ATTRIBUTE + +## 特性语法总结 + +> attribute → @attribute-nameattribute-argument-clauseopt + +> attribute-name → identifier + +> attribute-argument-clause → (balanced-tokensopt) + +> attributes → attributeattributesopt + +> balanced-tokens → balanced-tokenbalanced-tokensopt + +> balanced-token → (balanced-tokensopt) + +> balanced-token → [balanced-tokensopt] + +> balanced-token → {balanced-tokensopt} + +> balanced-token → Any identifier, keyword, literal, or operator + +> balanced-token → Any punctuation except (, ), [, ], {, or } + + From 4c630290867fe99b42753e115ba0ccd795919002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=9C=E8=88=9F?= Date: Sun, 13 Jul 2014 22:02:36 +0800 Subject: [PATCH 260/261] delete english part --- src/chapter2/10_Properties.md | 257 +--------------------------------- 1 file changed, 5 insertions(+), 252 deletions(-) diff --git a/src/chapter2/10_Properties.md b/src/chapter2/10_Properties.md index 76d3e6a..21d6e8f 100644 --- a/src/chapter2/10_Properties.md +++ b/src/chapter2/10_Properties.md @@ -1,34 +1,17 @@ -# Properties # 属性 -Properties associate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value. Computed properties are provided by classes, structures, and enumerations. Stored properties are provided only by classes and structures. - 属性将值与特定的类,结构体或者枚举关联起来,存储属性将常量或变量值作为实力的一部分保存起来,而计算属性则用来计算(而非存储)一个值。计算属性可以用于类,结构体和枚举,存储属性只能用于类和结构体。 - -Stored and computed properties are usually associated with instances of a particular type. However, properties can also be associated with the type itself. Such properties are known as type properties. - 存储和计算属性通常用于特定类型的实例。不过,属性也可以用于类型本身,这样的属性被称为类属性。 - -In addition, you can define property observers to monitor changes in a property’s value, which you can respond to with custom actions. Property observers can be added to stored properties you define yourself, and also to properties that a subclass inherits from its superclass. - 另外,可以为属性定义监听器,以监听属性值的变化,这样就可以在属性值发生变化时触发自定义操作。可以在定义存储属性的时候为其添加属性监听器,也可以为子类继承父类的属性添加监听器。 -## Stored Properties ## 存储属性 -In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure. Stored properties can be either variable stored properties (introduced by the var keyword) or constant stored properties (introduced by the let keyword). 简单而言,存储属性是一个特定类型实例或结构体中的常量或变量。存储属性可以是变量存储属性(用关键词 `var` 声明),也可以是常量属性(用关键词 `let` 声明)。 - -You can provide a default value for a stored property as part of its definition, as described in Default Property Values. You can also set and modify the initial value for a stored property during initialization. This is true even for constant stored properties, as described in Modifying Constant Properties During Initialization. - -在定义存储属性时,可以为其指定默认值,详见 Default Property Values 。在存储属性初始化过程中,依然可以设置和修改它的初始值,甚至修改常量存储属性,详见 Modifying Constant Properties During Initialization。 - - -The example below defines a structure called FixedLengthRange, which describes a range of integers whose range length cannot be changed once it is created: +在定义存储属性时,可以为其指定默认值,详见 《构造过程 - 默认属性值》。在存储属性初始化过程中,依然可以设置和修改它的初始值,甚至修改常量存储属性,详见 《构造过程 - 在构造过程中修改恒定属性》。 下面的示例定义了一个名为 `FixedLengthRange` 的结构体,它表示一个整型的范围,其范围长度一旦创建不能改变: @@ -41,17 +24,11 @@ The example below defines a structure called FixedLengthRange, which describes a rangeOfThreeItems.firstValue = 6 // 修改 firstValue 后, 表示的整型值的范围为: 6, 7, 8 -Instances of FixedLengthRange have a variable stored property called firstValue and a constant stored property called length. In the example above, length is initialized when the new range is created and cannot be changed thereafter, because it is a constant property. - `FixedLengthRange` 的实例包含一个名为 `firstValue` 的变量存储属性和一个名为 `length` 常量存储属性。在上面的示例中, `length` 在 `FixedLengthRange` 实例创建时初始化,并且在此后不能被修改,因为它是一个常量属性。 -###Stored Properties of Constant Structure Instances ###存储属性与常量实例 - -If you create an instance of a structure and assign that instance to a constant, you cannot modify the instance’s properties, even if they were declared as variable properties: - 如果你为一个结构体创建一个实例, 并且把这个实例赋值给一个常量, 那么无论这个实例的属性是否为变量, 其属性都不能被修改。 let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4) @@ -61,36 +38,19 @@ If you create an instance of a structure and assign that instance to a constant, // this will report an error, even thought firstValue is a variable property // 尽管firstValue是变量属性, 对其赋值也会报错 -Because rangeOfFourItems is declared as a constant (with the let keyword), it is not possible to change its firstValue property, even though firstValue is a variable property. -This behavior is due to structures being value types. When an instance of a value type is marked as a constant, so are all of its properties. - 因为 `rangeOfFourItems`通过`let`关键词声明, 所以是个常量, 故, 无论它的属性是否为变量, 都无法改变它的属性值。 所以, 当一个实例是常量类型, 那么它的所有属性也会变成常量类型。 - -The same is not true for classes, which are reference types. If you assign an instance of a reference type to a constant, you can still change that instance’s variable properties. - 这种情况对于引用类型(类)并不适用。 如果将某个引用类型的实例赋值给一个常量, 那么依然可以修改该实例的属性。 -###Lazy Stored Properties ###惰性存储属性 - -A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the @lazy attribute before its declaration. - 惰性存储属性只有在首次调用时才会进行初始化。 通过在存储属性声明前加上 `@lazy` 来声明一个惰性存储属性。 -> NOTE -You must always declare a lazy property as a variable (with the var keyword), because its initial value may not be retrieved until after instance initialization completes. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy. - > 注意 在声明一个惰性存储属性时, 必须将其定义为变量(通过`var`声明)。 这样做的原因是, 在实例初始化完成前, 可能无法获得惰性属性的初始值。 相反的, 常量属性的初始值必须在实例初始化完成之前赋值,所以常量属性不能被声明为惰性属性。 -Lazy properties are useful when the initial value for a property is dependent on outside factors whose values are not known until after an instance’s initialization is complete. Lazy properties are also useful when the initial value for a property requires complex or computationally expensive setup that should not be performed unless or until it is needed. - 当某个属性的初始化依赖于其他实例的初始化时,惰性属性是非常有用的。惰性属性在需要复杂计算和耗费时间较长的属性初始化时,也是非常有用的,因为它可以在需要时再进行计算和初始化。 -The example below uses a lazy stored property to avoid unnecessary initialization of a complex class. This example defines two classes called DataImporter and DataManager, neither of which is shown in full: - 下面这个例子中,演示了在一个复杂类的初始化过程中,如何通过惰性存储属性来避免不必要的初始化。示例中定义了两个类:`DataImporter`, `DataManager`(代码片段)。 class DataImporter { @@ -120,23 +80,12 @@ The example below uses a lazy stored property to avoid unnecessary initializatio // the DataImporter instance for the importer property has not yet been created // importer 实例尚未初始化 - -The DataManager class has a stored property called data, which is initialized with a new, empty array of String values. Although the rest of its functionality is not shown, the purpose of this DataManager class is to manage and provide access to this array of String data. - `DataManager` 类拥有一个名为 `data` 的存储属性,该属性是一个空的字符串数组。虽然剩余的功能代码没有展示出来,不过 `DataManager` 类的目的是提供管理和访问该字符串数组的功能。 - -Part of the functionality of the DataManager class is the ability to import data from a file. This functionality is provided by the DataImporter class, which is assumed to take a non-trivial amount of time to initialize. This might be because a DataImporter instance needs to open a file and read its contents into memory when the DataImporter instance is initialized. - `DataManager`类的一个功能是从文件中导入数据。 该功能由 `DataImporter` 类提供,需要花费很长时间进行初始化。原因是 `DataImporter` 类的实例在初始化的时候需要读取文件并将文件内容写入内存。 -It is possible for a DataManager instance to manage its data without ever importing data from a file, so there is no need to create a new DataImporter instance when the DataManager itself is created. Instead, it makes more sense to create the DataImporter instance if and when it is first used. - 对于 `DataManager` 类来说,无论是从文件中导入了数据,都不影响它管理自己的数据,所以没必要在它自己初始化的时候就去创建 `DataManager` 实例。更好的做法是,将 `DataImporter` 实例在第一次使用的时候初始化。 - -Because it is marked with the @lazy attribute, the DataImporter instance for the importer property is only created when the importer property is first accessed, such as when its fileName property is queried: - 因为使用了 `@lazy`,故 `DataImporter` 的实例 `importer` 只会在 `importer`的实例第一次被访问的时候才会初始化,例如访问它的 `fileName` 属性: println(manager.importer.fileName) @@ -144,26 +93,14 @@ println(manager.importer.fileName) //此时, `DataImporter` 的实例 `importer` 才被创建 // prints "data.txt" -###Stored Properties and Instance Variables - ###存储属性和实例变量 - -If you have experience with Objective-C, you may know that it provides two ways to store values and references as part of a class instance. In addition to properties, you can use instance variables as a backing store for the values stored in a property. - `Object-C`中类的实例对象有两种存储值和引用的方法。除了属性,还可以使用实例变量保存值。 -Swift unifies these concepts into a single property declaration. A Swift property does not have a corresponding instance variable, and the backing store for a property is not accessed directly. This approach avoids confusion about how the value is accessed in different contexts and simplifies the property’s declaration into a single, definitive statement. All information about the property including its name, type, and memory management characteristics—is defined in a single location as part of the type’s definition. - 在`Swift`中没有实例变量,`Swift` 将这些概念统一为了属性。这样避免了在不同上下文中值的不同访问方式的混淆,并且使属性声明简单明了。所有的属性信息:名称,类型,内存管理特征都包含在类型定义中。 -##Computed Properties - ##计算属性 - -In addition to stored properties, classes, structures, and enumerations can define computed properties, which do not actually store a value. Instead, they provide a getter and an optional setter to retrieve and set other properties and values indirectly. - 除了存储属性外,类,结构体,枚举还可以定义计算属性。计算属性不能存储值,而是通过 `getter` 方法和 `setter` 方法(可选)间接的设置其他属性和值。 struct Point { @@ -195,47 +132,27 @@ In addition to stored properties, classes, structures, and enumerations can defi // prints "square.origin is now at (10.0, 10.0)" // 输出 "square.origin is now at (10.0, 10.0)" -This example defines three structures for working with geometric shapes: - 这个示例定义了三个结构体来表示一个几何形状: -Point encapsulates an (x, y) coordinate. `Point` 封装了坐标(x, y)。 -Size encapsulates a width and a height. - `Size` 封装了宽度和高度。 -Rect defines a rectangle by an origin point and a size. - `Rect` 用坐标原点和大小定义了一个矩形。 -The Rect structure also provides a computed property called center. The current center position of a Rect can always be determined from its origin and size, and so you don’t need to store the center point as an explicit Point value. Instead, Rect defines a custom getter and setter for a computed variable called center, to enable you to work with the rectangle’s center as if it were a real stored property. - `Rect` 结构体提供了一个名为 `center` 的计算属性。矩形的中心点总是可以通过它的原点坐标和大小计算出来,所以你没有必要保存一个确切的矩形中心点的值。这里的 `Rect` 为一个名为 `center` 的计算属性定义了自定义的 `getter` 和 `setter` 方法,以此来设置矩形的中心点。 -The preceding example creates a new Rect variable called square. The square variable is initialized with an origin point of (0, 0), and a width and height of 10. This square is represented by the blue square in the diagram below. - 例子中接下来创建了一个名为 `square` 的 `Rect` 实例,`point` 初始值为(0,0), `width` 和 `height` 都是10,在下图中用蓝色正方形表示。 -The square variable’s center property is then accessed through dot syntax (square.center), which causes the getter for center to be called, to retrieve the current property value. Rather than returning an existing value, the getter actually calculates and returns a new Point to represent the center of the square. As can be seen above, the getter correctly returns a center point of (5, 5). - 然后通过点运算符(`square.center`)访问了 `square` 实例的 `center` 属性,此时会触发 `center` 的 `getter` 方法,并返回当前的属性值。和直接返回值不同, `getter` 方法会计算并返回最新的属性值。从上面的代码可以看出, `getter` 方法正确的返回了中心点 `(5, 5)`。 - -The center property is then set to a new value of (15, 15), which moves the square up and to the right, to the new position shown by the orange square in the diagram below. Setting the center property calls the setter for center, which modifies the x and y values of the stored origin property, and moves the square to its new position. - 接着为 `center` 属性设置了新值 `(15, 15)`,在下图中可以看出 `square` 向右上移动到了一个新的位置(橙色区域)。在设置 `center` 属性时调用了它的 `setter` 方法,修改了 `origin` 的 `x,y`值,并且改变了 `square` 的位置。 ![Alt text](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/computedProperties_2x.png) -###Shorthand Setter Declaration - ###Setter声明简写 -If a computed property’s setter does not define a name for the new value to be set, a default name of newValue is used. Here’s an alternative version of the Rect structure, which takes advantage of this shorthand notation: - 如果没有给属性的 `setter` 方法的新值指定名称,那么可以使用默认值 `newValue` 。下面是 `Rect` 结构体的简写形式: struct AlternativeRect { @@ -255,29 +172,16 @@ If a computed property’s setter does not define a name for the new value to be } -###Read-Only Computed Properties - ###只读计算属性 -A computed property with a getter but no setter is known as a read-only computed property. A read-only computed property always returns a value, and can be accessed through dot syntax, but cannot be set to a different value. - 只有 `getter` 没有 `setter` 的计算属性是只读计算属性。只读计算属性可以通过点操作符访问,但不能为其设置其他值。 - -> NOTE - -> You must declare computed properties—including read-only computed properties—as variable properties with the var keyword, because their value is not fixed. The let keyword is only used for constant properties, to indicate that their values cannot be changed once they are set as part of instance initialization. - - > 注意 > 必须使用 `var` 关键词定义计算属性,包括只读计算属性,因为它们的值是可能改变的。 `let` 关键词只用于常量属性,其值在初始化后不可改变。 必须使用var关键字定义计算属性,包括只读计算属性,因为他们的值不是固定的。let关键字只用来声明常量属性,表示初始化后再也无法修改的值。 - -You can simplify the declaration of a read-only computed property by removing the get keyword and its braces: - 只读计算属性的声明可以去掉get关键词和花括号: struct Cuboid { @@ -292,65 +196,30 @@ You can simplify the declaration of a read-only computed property by removing th // prints "the volume of fourByFiveByTwo is 40.0" // 输出 "the volume of fourByFiveByTwo is 40.0" -This example defines a new structure called Cuboid, which represents a 3D rectangular box with width, height, and depth properties. This structure also has a read-only computed property called volume, which calculates and returns the current volume of the cuboid. It doesn’t make sense for volume to be settable, because it would be ambiguous as to which values of width, height, and depth should be used for a particular volume value. Nonetheless, it is useful for a Cuboid to provide a read-only computed property to enable external users to discover its current calculated volume. - 这个示例定义了一个名为 `Cuboid` 的结构体,表示一个3D的立方体,有 `width`,`height`,`depth`等属性。它还有一个名为 `volume` 的只读计算属性用来计算并返回 `cuboid` 当前的体积。我们没有必要去设置 `volume` 的值,因为 `volume` 的值可以通过 `width`,`height`,`depth`计算出来。所以比较合适的做法是,提供一个只读计算属性让用户可以获得当前的 `volume` 。 - -###Property Observers - ###属性观察者 -Property observers observe and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value. - 属性观察者用来观察并响应属性值的变化。在为属性赋值时,无论新值是否与原值相同,都会触发属性的观察者。 -You can add property observers to any stored properties you define, apart from lazy stored properties. You can also add property observers to any inherited property (whether stored or computed) by overriding the property within a subclass. Property overriding is described in Overriding. - -可以为除了惰性属性外的其他任何存储属性定义观察者。通过属性重写,可以在子类中为它的父类属性(无论是存储或是计算属性)添加观察者。属性重写在重写一章有详细介绍。 - - -> NOTE -> -> You don’t need to define property observers for non-overridden -> computed properties, because you can observe and respond to changes to -> their value from directly within the computed property’s setter. +可以为除了惰性属性外的其他任何存储属性定义观察者。通过属性重写,可以在子类中为它的父类属性(无论是存储或是计算属性)添加观察者。属性重写在《构造过程 - 构造方法的继承与重写》一章中有详细介绍。 > 注意 > > 不需要为非重写计算属性定义观察者,因为你可以直接使用计算属性的`setter`来完成。 - -You have the option to define either or both of these observers on a property: -* willSet is called just before the value is stored. -* didSet is called immediately after the new value is stored. - 可以通过两种方式为属性定义观察者: * `willSet` 在值发生改变之前调用 * `didSet` 在值发生改变之后调用 - -If you implement a willSet observer, it is passed the new property value as a constant parameter. You can specify a name for this parameter as part of your willSet implementation. If you choose not to write the parameter name and parentheses within your implementation, the parameter will still be made available with a default parameter name of newValue. - `willSet` 会将新属性值作为常量参数,并且可以为该常量参数指定名称。如果没有为该参数指定名称,那么会使用默认的参数名称 `newValue`。 - -Similarly, if you implement a didSet observer, it will be passed a constant parameter containing the old property value. You can name the parameter if you wish, or use the default parameter name of oldValue. - 与 `willSet` 类似,`didSet` 会将原属性值作为常量参数。同样可以为参数指定名称或者使用默认值 `oldValue`。 -> NOTE -> -> willSet and didSet observers are not called when a property is first -> initialized. They are only called when the property’s value is set -> outside of an initialization context. - > 注意 > > `willSet` 和 `didSet` 在属性初始化时不会被调用。 -Here’s an example of willSet and didSet in action. The example below defines a new class called StepCounter, which tracks the total number of steps that a person takes while walking. This class might be used with input data from a pedometer or other step counter to keep track of a person’s exercise during their daily routine. - 这里有一个使用了 `willSet` 和 `didSet` 的示例。示例中定义了一个名为 `StepCounter` 的类,用来统计当人步行时的总步数,通过使用计步器等装置可以用这个类追踪人在日常工作中的运动量。 class StepCounter { @@ -382,66 +251,27 @@ Here’s an example of willSet and didSet in action. The example below defines a // 输出 About to set totalSteps to 896 // 输出 Added 536 steps -The StepCounter class declares a totalSteps property of type Int. This is a stored property with willSet and didSet observers. - `StepCounter`定义了一个 `int` 类型的属性 `totalSteps`。 `totalSteps` 包含了两个观察者`willSet`和`didSet`。 - -The willSet and didSet observers for totalSteps are called whenever the property is assigned a new value. This is true even if the new value is the same as the current value. - 当`totalSteps`的值改变时(不论新值是否与原值相同),`willSet` 和 `didSet` 都会被调用。 - -This example’s willSet observer uses a custom parameter name of newTotalSteps for the upcoming new value. In this example, it simply prints out the value that is about to be set. - 示例中的`willSet`使用了一个名为`newTotalSteps`的参数接收新值。在这个例子中只是简单的将新值输出。 - -The didSet observer is called after the value of totalSteps is updated. It compares the new value of totalSteps against the old value. If the total number of steps has increased, a message is printed to indicate how many new steps have been taken. The didSet observer does not provide a custom parameter name for the old value, and the default name of oldValue is used instead. - `didSet`观察者会在`totalSteps`的值被修改后调用。它将`totalSteps`的新值与原值做比较,如果新值大于原值,则会输出新增了多少步。`didSet`观察者没有指定参数名,所以使用默认参数名`oldValue`。 - -> NOTE -> -> If you assign a value to a property within its own didSet observer, -> the new value that you assign will replace the one that was just set. - - > 注意 > 如果在`didSet`中给属性设置新值,那么新值会替换刚刚设置的值。 -##Global and Local Variables ##全局变量和局部变量 - -The capabilities described above for computing and observing properties are also available to global variables and local variables. Global variables are variables that are defined outside of any function, method, closure, or type context. Local variables are variables that are defined within a function, method, or closure context. - 上面关于属性的计算和观察功能对于全局变量和局部变量同样适用。全局变量定义在所有函数,方法,闭包,类型之外。局部变量定义在函数,方法或闭包内部。 - -The global and local variables you have encountered in previous chapters have all been stored variables. Stored variables, like stored properties, provide storage for a value of a certain type and allow that value to be set and retrieved. - 在前面的章节中全局和局部变量都是存储变量,类似于存储属性,它为特定类型的值提供存储空间,并允许对其进行读写。 - -However, you can also define computed variables and define observers for stored variables, in either a global or local scope. Computed variables calculate rather than store a value, and are written in the same way as computed properties. - 另外,还可以在全局或局部作用域中定义计算变量,或者为存储变量定义观察者。计算变量用来计算而非存储一个值,声明方式和计算属性一样。 - -> NOTE -> -> Global constants and variables are always computed lazily, in a -> similar manner to Lazy Stored Properties. Unlike lazy stored -> properties, global constants and variables do not need to be marked -> with the @lazy attribute. -> -> Local constants and variables are never computed lazily. - - > 注意 > > 和惰性存储属性的方式类似,全局常量和变量总是延迟计算的。不同的是,全局常量和变量不需要使用`@lazy`属性进行声明。 @@ -449,59 +279,27 @@ However, you can also define computed variables and define observers for stored > 局部常量和变量则绝不会延迟计算。 -##Type Properties - ##类型属性 - -Instance properties are properties that belong to an instance of a particular type. Every time you create a new instance of that type, it has its own set of property values, separate from any other instance. - 实例属性属于一个特定类型的实例。每次创建该类型的实例,它都拥有自己独立的一组属性,与其他实例对象无关。 - -You can also define properties that belong to the type itself, not to any one instance of that type. There will only ever be one copy of these properties, no matter how many instances of that type you create. These kinds of properties are called type properties. - 还可以定义属于类型自身的属性。不论该类型有多少实例,这些属性都只有一份。这种属性被称为类型属性。 - -Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use (like a static constant in C), or a variable property that stores a value that is global to all instances of that type (like a static variable in C). - 类型属性用于定义所有特定的类型实例都可以使用的值,比如所有实例都可以使用同一个常量属性(类似于`C`中的静态常量),或者就像所有的实例都可以使用全局变量属性(类似于`C`中的静态常量)。 - -For value types (that is, structures and enumerations), you can define stored and computed type properties. For classes, you can define computed type properties only. - 对于值类型(结构和枚举),可以定义存储和计算类型的属性。对于类,则只能定义计算类型的属性。 - -Stored type properties for value types can be variables or constants. Computed type properties are always declared as variable properties, in the same way as computed instance properties. - 值类型的存储类型属性可以是变量和常量。计算类型属性和计算实例属性相同,通常声明为变量属性。 -> NOTE -> -> Unlike stored instance properties, you must always give stored type -> properties a default value. This is because the type itself does not -> have an initializer that can assign a value to a stored type property -> at initialization time. - > 注意 > > 与存储实例属性不同,必须为存储类型属性定义默认值。原因是类型本身没有一个可以在初始化时为类型属性赋值的构造器。 -###Type Property Syntax - ###类型属性语法 - -In C and Objective-C, you define static constants and variables associated with a type as global static variables. In Swift, however, type properties are written as part of the type’s definition, within the type’s outer curly braces, and each type property is explicitly scoped to the type it supports. - 在`C`和`Objective-C`中,只能使用全局静态变量来定义依赖于某个属性的变量或常量。但在`Swift`中,类型属性可以作为类型定义的一部分,它的作用域也在类型的范围内。 - -You define type properties for value types with the static keyword, and type properties for class types with the class keyword. The example below shows the syntax for stored and computed type properties: - 使用`static`关键词定义值类型的类型属性,`class`类型的类型属性用关键词`class`声明。下面的示例演示了存储类型属性和计算类型属性的语法: @@ -527,24 +325,14 @@ You define type properties for value types with the static keyword, and type pro } -> NOTE -> -> The computed type property examples above are for read-only computed -> type properties, but you can also define read-write computed type -> properties with the same syntax as for computed instance properties. - -注意 - -上面的计算类型属性的示例都是只读的,仍然可以定义可读写的计算类型属性。 - +> 注意 +> +> 上面的计算类型属性的示例都是只读的,仍然可以定义可读写的计算类型属性。 -###Querying and Setting Type Properties ###查询和设置类型属性 -Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type. For example: - 就像实例属性,类型属性通过点操作符查询和设置。不过,类型属性的是通过类型自身查询和设置,而非类型的实例: println(SomeClass.computedTypeProperty) @@ -559,20 +347,13 @@ Type properties are queried and set with dot syntax, just like instance properti // prints "Another value." // 输出 "Another value." -The examples that follow use two stored type properties as part of a structure that models an audio level meter for a number of audio channels. Each channel has an integer audio level between 0 and 10 inclusive. 下面的示例定义了一个结构体和两个类型属性来为声道音量建模。每一个声道的音量范围是0到10。 - -The figure below illustrates how two of these audio channels can be combined to model a stereo audio level meter. When a channel’s audio level is 0, none of the lights for that channel are lit. When the audio level is 10, all of the lights for that channel are lit. In this figure, the left channel has a current level of 9, and the right channel has a current level of 7: - 下图演示了如何将两个声道合并为一个立体声道。当某个声道的音量值是0时,所有灯都不会亮。当音量值是10时,所有灯都会亮起。下图中,左侧的音量值为9,右侧的音量值为7: - ![Alt text](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Art/staticPropertiesVUMeter_2x.png) -The audio channels described above are represented by instances of the AudioChannel structure: - 上面的声道通过`AudioChannel`的结构体实例表示如下: struct AudioChannel { @@ -594,54 +375,28 @@ The audio channels described above are represented by instances of the AudioChan } } -The AudioChannel structure defines two stored type properties to support its functionality. The first, thresholdLevel, defines the maximum threshold value an audio level can take. This is a constant value of 10 for all AudioChannel instances. If an audio signal comes in with a higher value than 10, it will be capped to this threshold value (as described below). `AudioChannel`定义了两个存储属性。首先,定义了音量最大值`thresholdLevel`,它是一个对所有实例可见的常量值。如果音量大于10,那么就取上限值10。 - -The second type property is a variable stored property called maxInputLevelForAllChannels. This keeps track of the maximum input value that has been received by any AudioChannel instance. It starts with an initial value of 0. - 第二个类型属性是一个名为`maxInputLevelForAllChannels`的变量存储属性,用来表示所有实例的最大音量值。初始值为0。 - -The AudioChannel structure also defines a stored instance property called currentLevel, which represents the channel’s current audio level on a scale of 0 to 10. - `AudioChannel`结构体还定义了一个实例属性`currentLevel`,用来表示当前声道的音量值,取值0到10。 - -The currentLevel property has a didSet property observer to check the value of currentLevel whenever it is set. This observer performs two checks: - - `currentLevel`的值在每次设置时都会通过`didSet`进行两种检查: -* If the new value of currentLevel is greater than the allowed thresholdLevel, the property observer caps currentLevel to thresholdLevel. -* If the new value of currentLevel (after any capping) is higher than any value previously received by any AudioChannel instance, the property observer stores the new currentLevel value in the maxInputLevelForAllChannels static property. - * 如果`currentLevel`的新值大于允许的最大值`thresholdLevel`,则属性监听器将`currentLevel`设置为`thresholdLevel`。 * 如果`currentLevel`的新值大于之前所有`AudioChannel`实例的值。那么属性监听器会将新值保存在静态属性`maxInputLevelForAllChannels`中。 -> NOTE -> -> In the first of these two checks, the didSet observer sets -> currentLevel to a different value. This does not, however, cause the -> observer to be called again. - > 注意 > > 在第一次检查过程中,`didSet`监听器将`currentLevel`设置为了不同的值,但此时不会再次调用属性监听器。 - -You can use the AudioChannel structure to create two new audio channels called leftChannel and rightChannel, to represent the audio levels of a stereo sound system: - 可以使用`AudioChannel`创建两个声道实例:`leftChannel`和`rightChannel`: var leftChannel = AudioChannel() var rightChannel = AudioChannel() -If you set the currentLevel of the left channel to 7, you can see that the maxInputLevelForAllChannels type property is updated to equal 7: - - 如果将`currentLevel`的左声道的值置为7,则可以看到类型属性`maxInputLevelForAllChannels`也更新为了7: leftChannel.currentLevel = 7 @@ -652,8 +407,6 @@ If you set the currentLevel of the left channel to 7, you can see that the maxIn // print "7" // 输出 "7" -If you try to set the currentLevel of the right channel to 11, you can see that the right channel’s currentLevel property is capped to the maximum value of 10, and the maxInputLevelForAllChannels type property is updated to equal 10: - 如果想将`currentLevel`的右声道设置为11,你会发现右声道的`currentLevel`值被设置为了10,同时`maxInputLevelForAllChannels` 也更新为10。 From 7e5fd45d2208796e9a0665af86aae8805b83e65c Mon Sep 17 00:00:00 2001 From: sleeeeeep Date: Mon, 14 Jul 2014 16:59:34 +0800 Subject: [PATCH 261/261] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c7f366a..a2f9d4d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ The Swift Programming Language 中文化项目 * 基础部分 [已完成 by 琼雪] [review by 栖邀] * 基本操作符 [已完成 by 冰浠] [review by 姜天意] * 字符串和字符 [已完成 by 筱谷] [review by 尘境] - * 集合类型 [已完成 by 尘境] + * 集合类型 [已完成 by 尘境] [review by 紫溪] * 控制流 [已完成 by 墨昕] * 函数 [已完成 by 紫溪] [review by 飞长] * 闭包 [已完成 by 闻西] [review by 米尔]