Merge pull request #312 from huangqiaobo/develop

2.5控制流的Continue部分代码
This commit is contained in:
梁杰
2014-09-10 14:02:02 +08:00
6 changed files with 118 additions and 150 deletions

View File

@ -568,7 +568,7 @@ for character in puzzleInput {
case "a", "e", "i", "o", "u", " ":
continue
default:
puzzleOutput += character
puzzleOutput.append(character)
}
}
println(puzzleOutput)

View File

@ -349,8 +349,12 @@ arithmeticMean(3, 8, 19)
```swift
func alignRight(var string: String, count: Int, pad: Character) -> String {
let amountToPad = count - countElements(string)
if amountToPad < 1 {
return string
}
let padString = String(pad)
for _ in 1...amountToPad {
string = pad + string
string = padString + string
}
return string
}

View File

@ -76,7 +76,7 @@ var reversed = sorted(names, backwards)
如果第一个字符串 (`s1`) 大于第二个字符串 (`s2`)`backwards`函数返回`true`,表示在新的数组中`s1`应该出现在`s2`前。
对于字符串中的字符来说,“大于” 表示 “按照字母顺序较晚出现”。
这意味着字母`"B"`大于字母`"A"`,字符串`"Tom"`大于字符串`"Tim"`
其将进行字母逆序排序,`"Barry"`将会排在`"Alex"`
其将进行字母逆序排序,`"Barry"`将会排在`"Alex"`
然而,这是一个相当冗长的方式,本质上只是写了一个单表达式函数 (a > b)。
在下面的例子中,利用闭合表达式语法可以更好的构造一个内联排序闭包。

View File

@ -103,7 +103,7 @@ println("The width of someResolution is \(someResolution.width)")
在上面的例子中,`someResolution.width`引用`someResolution``width`属性,返回`width`的初始值`0`
你也可以访问子属性,如`VideoMode``Resolution`属性的`width`属性:
你也可以访问子属性,如`VideoMode``Resolution`属性的`width`属性:
```swift
println("The width of someVideoMode is \(someVideoMode.resolution.width)")
@ -126,7 +126,7 @@ println("The width of someVideoMode is now \(someVideoMode.resolution.width)")
所有结构体都有一个自动生成的成员逐一构造器,用于初始化新结构体实例中成员的属性。新实例中各个属性的初始值可以通过属性的名称传递到成员逐一构造器之中:
```swift
let vga = resolution(width:640, height: 480)
let vga = Resolution(width:640, height: 480)
```
与结构体不同,类实例没有默认的成员逐一构造器。[构造过程](14_Initialization.html)章节会对构造器进行更详细的讨论。

View File

@ -61,7 +61,7 @@ rangeOfFourItems.firstValue = 6
<a name="lazy_stored_properties"></a>
### 延迟存储属性
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用`@lazy`来标示一个延迟存储属性。
延迟存储属性是指当第一次被调用的时候才会计算其初始值的属性。在属性声明前使用`lazy`来标示一个延迟存储属性。
> 注意:
> 必须将延迟存储属性声明成变量(使用`var`关键字),因为属性的值在实例构造完成之前可能无法得到。而常量属性在构造过程完成之前必须要有初始值,因此无法声明成延迟属性。
@ -81,14 +81,14 @@ class DataImporter {
}
class DataManager {
@lazy var importer = DataImporter()
var data = String[]()
lazy var importer = DataImporter()
var data = [String]()
// 这是提供数据管理功能
}
let manager = DataManager()
manager.data += "Some data"
manager.data += "Some more data"
manager.data.append("Some data")
manager.data.append("Some more data")
// DataImporter 实例的 importer 属性还没有被创建
```
@ -98,7 +98,7 @@ manager.data += "Some more data"
`DataManager`也可能不从文件中导入数据。所以当`DataManager`的实例被创建时,没必要创建一个`DataImporter`的实例,更明智的是当用到`DataImporter`的时候才去创建它。
由于使用了`@lazy``importer`属性只有在第一次被访问的时候才被创建。比如访问它的属性`fileName`时:
由于使用了`lazy``importer`属性只有在第一次被访问的时候才被创建。比如访问它的属性`fileName`时:
```swift
println(manager.importer.fileName)
@ -109,7 +109,7 @@ println(manager.importer.fileName)
<a name="stored_properties_and_instance_variables"></a>
### 存储属性和实例变量
如果您有过 Objective-C 经验应该知道Objective-C为类实例存储值和引提供两种方法。对于属性来说也可以使用实例变量作为属性值的后端存储。
如果您有过 Objective-C 经验应该知道Objective-C为类实例存储值和引提供两种方法。对于属性来说,也可以使用实例变量作为属性值的后端存储。
Swift 编程语言中把这些理论统一用属性来实现。Swift 中的属性没有对应的实例变量,属性的后端存储也无法直接访问。这就避免了不同场景下访问方式的困扰,同时也将属性的定义简化成一个语句。
一个类型中属性的全部信息——包括命名、类型和内存管理特征——都在唯一一个地方(类型定义中)定义。
@ -285,7 +285,7 @@ stepCounter.totalSteps = 896
另外,在全局或局部范围都可以定义计算型变量和为存储型变量定义观察器,计算型变量跟计算属性一样,返回一个计算的值而不是存储值,声明格式也完全一样。
> 注意:
> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`@lazy`特性。
> 全局的常量或变量都是延迟计算的,跟[延迟存储属性](#lazy_stored_properties)相似,不同的地方在于,全局的常量或变量不需要标记`lazy`特性。
> 局部范围的常量或变量不会延迟计算。
<a name="type_properties"></a>

View File

@ -25,44 +25,34 @@
> 注意:
Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。
下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了两个对所有车辆都通用的属性(`numberOfWheels``maxPassengers`)。这些属性`description`方法中使用,这个方法返回一个`String`类型的,对车辆特征的描述
下面的例子定义了一个叫`Vehicle`的基类。这个基类声明了一个名为`currentSpeed `默认值是0.0的存储属性(属性类型推断为`Double `)。`currentSpeed `属性的值被一个`String` 类型的只读计算型属性`description`使用,用来创建车辆的描述
`Vehicle`基类也定义了一个名为`makeNoise`的方法。这个方法实际上不为`Vehicle`实例做任何事,但之后将会被`Vehicle`的子类定制
```swift
class Vehicle {
var numberOfWheels: Int
var maxPassengers: Int
func description() -> String {
return "\(numberOfWheels) wheels; up to \(maxPassengers) passengers"
}
init() {
numberOfWheels = 0
maxPassengers = 1
}
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {
// 什么也不做-因为车辆不一定会有噪音
}
}
```
`Vehicle`类定义了*构造器initializer*来设置属性的值。构造器会在[构造过程](../chapter2/_14Initialization.html)一节中详细介绍,这里我们做一下简单介绍,以便于讲解子类中继承来的属性如何被修改。
构造器用于创建某个类型的一个新实例。尽管构造器并不是方法,但在语法上,两者很相似。构造器的工作是准备新实例以供使用,并确保实例中的所有属性都拥有有效的初始化值。
构造器的最简单形式就像一个没有参数的实例方法,使用`init`关键字:
```swift
init() {
// 执行构造过程
}
您可以用初始化语法创建一个`Vehicle `的新实例,即 `TypeName`后面跟一个空括号:
```swift
let someVehicle = Vehicle()
```
现在已经创建了一个`Vehicle`的新实例,你可以访问它的`description`属性来打印车辆的当前速度。
```swift
println("Vehicle: \(someVehicle.description)")
// Vehicle: traveling at 0.0 miles per hour
```
如果要创建一个`Vehicle`类的新实例,使用*构造器*语法调用上面的初始化器,即类名后面跟一个空的小括号:
```swift
let someVehicle = Vehicle()
```
这个`Vehicle`类的构造器为任意的一辆车设置一些初始化属性值(`numberOfWheels = 0 ``maxPassengers = 1`)。
`Vehicle`类定义了车辆的共同特性,但这个类本身并没太大用处。为了使它更为实用,你需要进一步细化它来描述更具体的车辆。
<a name="subclassing"></a>
## 子类生成Subclassing
@ -83,56 +73,50 @@ class SomeClass: SomeSuperclass {
“定义一个新的类叫`Bicycle `,它继承了`Vehicle`的特性”;
```swift
class Bicycle: Vehicle {
init() {
super.init()
numberOfWheels = 2
}
}
```
preview
`Bicycle``Vehicle`的子类,`Vehicle``Bicycle`的超类。新的`Bicycle`类自动获得`Vehicle`类的特性,比如 `maxPassengers``numberOfWheels`属性。你可以在子类中定制这些特性,或添加新的特性来更好地描述`Bicycle`类。
`Bicycle`类定义了一个构造器来设置它定制的特性自行车只有2个轮子`Bicycle`的构造器调用了它父类`Vehicle`的构造器 `super.init()`,以此确保在`Bicycle`类试图修改那些继承来的属性前`Vehicle`类已经初始化过它们了。
> 注意:
不像 Objective-C在 Swift 中,初始化器默认是不继承的,见[初始化器的继承与重写](../chapter2/_14Initialization.html#initializer_inheritance_and_ overriding)
`Vehicle`类中`maxPassengers`的默认值对自行车来说已经是正确的,因此在`Bicycle`的构造器中并没有改变它。而`numberOfWheels`原来的值对自行车来说是不正确的,因此在初始化器中将它更改为 2。
`Bicycle`不仅可以继承`Vehicle`的属性,还可以继承它的方法。如果你创建了一个`Bicycle`类的实例,你就可以调用它继承来的`description`方法,并且可以看到,它输出的属性值已经发生了变化:
```swift
let bicycle = Bicycle()
println("Bicycle: \(bicycle.description())")
// Bicycle: 2 wheels; up to 1 passengers
```
子类还可以继续被其它类继承:
```swift
class Tandem: Bicycle {
init() {
super.init()
maxPassengers = 2
}
class Bicycle: Vehicle {
var hasBasket = false
}
```
上面的例子创建了`Bicycle`的一个子类双人自行车tandem`Tandem``Bicycle`继承了两个属性,而这两个属性是`Bicycle``Vehicle`继承而来的。`Tandem`并不修改轮子的数量,因为它仍是一辆自行车,有 2 个轮子。但它需要修改`maxPassengers`的值,因为双人自行车可以坐两个人
> 注意:
子类只允许修改从超类继承来的变量属性,而不能修改继承来的常量属性。
创建一个`Tandem`类的实例,打印它的描述,即可看到它的属性已被更新:
```swift
let tandem = Tandem()
println("Tandem: \(tandem.description())")
// Tandem: 2 wheels; up to 2 passengers
新的`Bicycle`类自动获得`Vehicle`类的所有特性,比如 `currentSpeed ``description`属性,还有它的`makeNoise`方法
除了它所继承的特性,`Bicycle`类还定义了一个默认值为`false`的存储型属性`hasBasket`(属性推断为`Bool`)。
默认情况下,你创建任何新的`Bicycle`实例将不会有一个篮子,创建该实例之后,你可以为特定的`Bicycle`实例设置`hasBasket `属性为`ture`
```swift
let bicycle = Bicycle()
bicycle.hasBasket = true
```
你还可以修改`Bicycle `实例所继承的`currentSpeed `属性,和查询实例所继承的`description `属性:
```swift
bicycle.currentSpeed = 15.0
println("Bicycle: \(bicycle.description)")
// Bicycle: traveling at 15.0 miles per hour
```
注意,`Tandem`类也继承了`description`方法。一个类的实例方法会被这个类的所有子类继承。
子类还可以继续被其它类继承,下面的示例为`Bicycle `创建了一个名为`Tandem `(双人自行车)的子类:
```swift
class Tandem: Bicycle {
var currentNumberOfPassengers = 0
}
```
`Tandem``Bicycle`继承了所有的属性与方法,这又使它同时继承了`Vehicle`的所有属性与方法。`Tandem`也增加了一个新的叫做`currentNumberOfPassengers`的存储型属性默认值为0。
如果你创建了一个`Tandem`的实例,你可以使用它所有的新属性和继承的属性,还能查询从`Vehicle`继承来的只读属性`description `
```swift
let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
println("Tandem: \(tandem.description)")
// Tandem: traveling at 22.0 miles per hour
```
<a name="overriding"></a>
## 重写Overriding
@ -157,35 +141,22 @@ println("Tandem: \(tandem.description())")
在子类中,你可以重写继承来的实例方法或类方法,提供一个定制或替代的方法实现。
下面的例子定义了`Vehicle`的一个新的子类,叫`Car`,它重写了从`Vehicle`类继承来的`description`方法:
下面的例子定义了`Vehicle`的一个新的子类,叫`Train `,它重写了从`Vehicle`类继承来的`makeNoise `方法:
```swift
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"
}
class Train: Vehicle {
override func makeNoise() {
println("Choo Choo")
}
}
```
`Car`声明了一个新的存储型属性`speed`,它是`Double`类型的,默认值是`0.0`表示“时速是0英里”。`Car`有自己的初始化器它将乘客的最大数量设为5轮子数量设为4。
`Car`重写了继承来的`description`方法,它的声明与`Vehicle`中的`description`方法一致,声明前面加上了`override`关键字。
`Car`中的`description`方法并非完全自定义,而是通过`super.description`使用了超类`Vehicle`中的`description`方法,然后再追加一些额外的信息,比如汽车的当前速度。
如果你创建一个`Car`的新实例,并打印`description`方法的输出,你就会发现描述信息已经发生了改变:
如果你创建一个`Train `的新实例,并调用了它的`makeNoise `方法,你就会发现`Train `版本的方法被调用:
```swift
let car = Car()
println("Car: \(car.description())")
// Car: 4 wheels; up to 5 passengers; traveling at 0.0 mph
let train = Train()
train.makeNoise()
// prints "Choo Choo"
```
### 重写属性
@ -199,32 +170,29 @@ println("Car: \(car.description())")
你可以将一个继承来的只读属性重写为一个读写属性,只需要你在重写版本的属性里提供 getter 和 setter 即可。但是,你不可以将一个继承来的读写属性重写为一个只读属性。
> 注意:
如果你在重写属性中提供了 setter那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接返回`super.someProperty`来返回继承来的值。正如下面的`SpeedLimitedCar`的例子所示
如果你在重写属性中提供了 setter那么你也一定要提供 getter。如果你不想在重写版本中的 getter 里修改继承来的属性值,你可以直接通过`super.someProperty`来返回继承来的值,其中`someProperty`是你要重写的属性的名字
以下的例子定义了一个新类,叫`SpeedLimitedCar`,它是`Car`的子类。类`SpeedLimitedCar`表示安装了限速装置的车它的最高速度只能达到40mph。你可以通过重写继承来的`speed`属性来实现这个速度限制
以下的例子定义了一个新类,叫`Car`,它是`Vehicle `的子类。这个类引入了一个新的存储型属性叫做`gear `默认为整数1。`Car`重写继承`Vehicle `的description属性提供自定义的包含当前档位的描述
```swift
class SpeedLimitedCar: Car {
override var speed: Double {
get {
return super.speed
}
set {
super.speed = min(newValue, 40.0)
}
}
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + " in gear \(gear)"
}
}
```
当你设置一个`SpeedLimitedCar`实例的`speed`属性时属性setter的实现会去检查新值与限制值40mph的大小它会将超类的`speed`设置为`newValue``40.0`中较小的那个。这两个值哪个较小由`min`函数决定它是Swift标准库中的一个全局函数。`min`函数接收两个或更多的数,返回其中最小的那个
如果你尝试将`SpeedLimitedCar`实例`speed`属性设置为一个大于40mph的数然后打印`description`函数的输出你会发现速度被限制在40mph
```
重写的`description `属性,首先要调用`super.description`返回`Vehicle`类的`description`属性。之后,`Car `类版本的`description`在末尾增加了一些额外的文本来提供关于当前档位的信息
如果你创建了`Car `实例并且设置了它的`gear``currentSpeed`属性,你可以看到它的`description`返回了`Car`中定义的`description`
```swift
let limitedCar = SpeedLimitedCar()
limitedCar.speed = 60.0
println("SpeedLimitedCar: \(limitedCar.description())")
// SpeedLimitedCar: 4 wheels; up to 5 passengers; traveling at 40.0 mph
let car = Car()
car.currentSpeed = 25.0
car.gear = 3
println("Car: \(car.description)")
// Car: traveling at 25.0 miles per hour in gear 3
```
#### 重写属性观察器Property Observer
@ -234,37 +202,33 @@ println("SpeedLimitedCar: \(limitedCar.description())")
> 注意:
你不可以为继承来的常量存储型属性或继承来的只读计算型属性添加属性观察器。这些属性的值是不可以被设置的,所以,为它们提供`willSet``didSet`实现是不恰当。此外还要注意,你不可以同时提供重写的 setter 和重写的属性观察器。如果你想观察属性值的变化,并且你已经为那个属性提供了定制的 setter那么你在 setter 中就可以观察到任何值变化了。
下面的例子定义了一个新类叫`AutomaticCar`,它是`Car`的子类。`AutomaticCar`表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位`AutomaticCar`也提供了定制的`description`方法,可以输出当前挡位。
下面的例子定义了一个新类叫`AutomaticCar`,它是`Car`的子类。`AutomaticCar`表示自动挡汽车,它可以根据当前的速度自动选择合适的挡位:
```swift
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)"
}
class AutomaticCar: Car {
override var currentSpeed: Double {
didSet {
gear = Int(currentSpeed / 10.0) + 1
}
}
}
```
当你设置`AutomaticCar``speed`属性,属性的`didSet`观察器就会自动地设置`gear`属性为新的速度选择一个合适的挡位。具体来说就是属性观察器将新的速度值除以10然后向下取得最接近的整数值最后加1来得到档位`gear`的值。例如速度为10.0时挡位为1速度为35.0时挡位为4
当你设置`AutomaticCar``currentSpeed `属性,属性的`didSet`观察器就会自动地设置`gear`属性为新的速度选择一个合适的挡位。具体来说就是属性观察器将新的速度值除以10然后向下取得最接近的整数值最后加1来得到档位`gear`的值。例如速度为10.0时挡位为1速度为35.0时挡位为4
```swift
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
let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
println("AutomaticCar: \(automatic.description)")
// AutomaticCar: traveling at 35.0 miles per hour in gear 4
```
<a name="preventing_overrides"></a>
## 防止重写
你可以通过把方法,属性或下标脚本标记为*`final`*来防止它们被重写,只需要在声明关键字前加上`@final`特性即可。(例如:`@final var`, `@final func`, `@final class func`, 以及 `@final subscript`
你可以通过把方法,属性或下标脚本标记为*`final`*来防止它们被重写,只需要在声明关键字前加上`@final`特性即可。(例如:`final var`, `final func`, `final class func`, 以及 `final subscript`
如果你重写了`final`方法,属性或下标脚本,在编译时会报错。在扩展中,你添加到类里的方法,属性或下标脚本也可以在扩展的定义里标记为 final。
你可以通过在关键字`class`前添加`@final`特性(`@final class`)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。
你可以通过在关键字`class`前添加`final`特性(`final class`)来将整个类标记为 final 的,这样的类是不可被继承的,否则会报编译错误。