From 68352bf6d3edd537a2c51626065b4d553c0a5377 Mon Sep 17 00:00:00 2001 From: zac1st Date: Fri, 13 Jun 2014 13:19:44 +1000 Subject: [PATCH] add highlight to chapter 1.2 add swift highlight --- source/chapter1/02_a_swift_tour.md | 82 +++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/source/chapter1/02_a_swift_tour.md b/source/chapter1/02_a_swift_tour.md index 7c528860..256a5fb3 100644 --- a/source/chapter1/02_a_swift_tour.md +++ b/source/chapter1/02_a_swift_tour.md @@ -67,10 +67,12 @@ 有一种更简单的把值转换成字符串的方法:把值写到括号中,并且在括号之前写一个反斜杠。例如: +```swift let apples = 3 let oranges = 5 let appleSummary = "I have \(apples) apples." let fruitSummary = "I have \(apples + oranges) pieces of fruit." +``` > 练习: > @@ -78,29 +80,38 @@ 使用方括号`[]`来创建数组和字典,并使用下标或者键(key)来访问元素。 +```swift var shoppingList = ["catfish", "water", "tulips", "blue paint"] shoppingList[1] = "bottle of water" +``` +```swift var occupations = [ "Malcolm": "Captain", "Kaylee": "Mechanic", ] occupations["Jayne"] = "Public Relations" +``` 要创建一个空数组或者字典,使用初始化语法。 +```swift let emptyArray = String[]() let emptyDictionary = Dictionary() +``` 如果类型信息可以被推断出来,你可以用`[]`和`[:]`来创建空数组和空字典——就像你声明变量或者给函数传参数的时候一样。 +```swift shoppingList = [] // 去逛街并买点东西 +``` ## 控制流 使用`if`和`switch`来进行条件操作,使用`for-in`、`for`、`while`和`do-while`来进行循环。包裹条件和循环变量括号可以省略,但是语句体的大括号是必须的。 +```swift let individualScores = [75, 43, 103, 87, 12] var teamScore = 0 for score in individualScores { @@ -111,11 +122,13 @@ } } teamScore +``` 在`if`语句中,条件必须是一个布尔表达式——这意味着像`if score { ... }`这样的代码将报错,而不会隐形地与 0 做对比。 你可以一起使用`if`和`let`来处理值缺失的情况。有些变量的值是可选的。一个可选的值可能是一个具体的值或者是`nil`,表示值缺失。在类型后面加一个问号来标记这个变量的值是可选的。 +```swift var optionalString: String? = "Hello" optionalString == nil @@ -124,6 +137,7 @@ if let name = optionalName { greeting = "Hello, \(name)" } +``` > 练习: > @@ -133,6 +147,7 @@ `switch`支持任意类型的数据以及各种比较操作——不仅仅是整数以及测试相等。 +```swift let vegetable = "red pepper" switch vegetable { case "celery": @@ -144,6 +159,7 @@ default: let vegetableComment = "Everything tastes good in soup." } +``` > 练习: > @@ -153,6 +169,7 @@ 你可以使用`for-in`来遍历字典,需要两个变量来表示每个键值对。 +```swift let interestingNumbers = [ "Prime": [2, 3, 5, 7, 11, 13], "Fibonacci": [1, 1, 2, 3, 5, 8], @@ -167,6 +184,7 @@ } } largest +``` > 练习: > @@ -174,6 +192,7 @@ 使用`while`来重复运行一段代码直到不满足条件。循环条件可以在开头也可以在结尾。 +```swift var n = 2 while n < 100 { n = n * 2 @@ -185,9 +204,11 @@ m = m * 2 } while m < 100 m +``` 你可以在循环中使用`..`来表示范围,也可以使用传统的写法,两者是等价的: +```swift var firstForLoop = 0 for i in 0..3 { firstForLoop += i @@ -199,6 +220,7 @@ secondForLoop += 1 } secondForLoop +``` 使用`..`创建的范围不包含上界,如果想包含的话需要使用`...`。 @@ -207,10 +229,12 @@ 使用`func`来声明一个函数,使用名字和参数来调用函数。使用`->`来指定函数返回值。 +```swift func greet(name: String, day: String) -> String { return "Hello \(name), today is \(day)." } greet("Bob", "Tuesday") +``` > 练习: > @@ -218,13 +242,16 @@ 使用一个元组来返回多个值。 +```swift func getGasPrices() -> (Double, Double, Double) { return (3.59, 3.69, 3.79) } getGasPrices() +``` 函数的参数数量是可变的,用一个数组来获取它们: +```swift func sumOf(numbers: Int...) -> Int { var sum = 0 for number in numbers { @@ -234,6 +261,7 @@ } sumOf() sumOf(42, 597, 12) +``` > 练习: > @@ -241,6 +269,7 @@ 函数可以嵌套。被嵌套的函数可以访问外侧函数的变量,你可以使用嵌套函数来重构一个太长或者太复杂的函数。 +```swift func returnFifteen() -> Int { var y = 10 func add() { @@ -250,9 +279,11 @@ return y } returnFifteen() +``` -函数是一等公民,这意味着函数可以作为另一个函数的返回值。 +函数是第一等类型,这意味着函数可以作为另一个函数的返回值。 +```swift func makeIncrementer() -> (Int -> Int) { func addOne(number: Int) -> Int { return 1 + number @@ -261,9 +292,11 @@ } var increment = makeIncrementer() increment(7) +``` 函数也可以当做参数传入另一个函数。 +```swift func hasAnyMatches(list: Int[], condition: Int -> Bool) -> Bool { for item in list { if condition(item) { @@ -277,14 +310,17 @@ } var numbers = [20, 19, 7, 12] hasAnyMatches(numbers, lessThanTen) +``` 函数实际上是一种特殊的闭包,你可以使用`{}`来创建一个匿名闭包。使用`in`将参数和返回值类型声明与闭包函数体进行分离。 +```swift numbers.map({ (number: Int) -> Int in let result = 3 * number return result }) +``` > 练习: > @@ -292,23 +328,29 @@ 有很多种创建闭包的方法。如果一个闭包的类型已知,比如作为一个回调函数,你可以忽略参数的类型和返回值。单个语句闭包会把它语句的值当做结果返回。 +```swift numbers.map({ number in 3 * number }) +``` 你可以通过参数位置而不是参数名字来引用参数——这个方法在非常短的闭包中非常有用。当一个闭包作为最后一个参数传给一个函数的时候,它可以直接跟在括号后面。 +```swift sort([1, 5, 3, 12, 2]) { $0 > $1 } +``` ## 对象和类 使用`class`和类名来创建一个类。类中属性的声明和常量、变量声明一样,唯一的区别就是它们的上下文是类。同样,方法和函数声明也一样。 +```swift class Shape { var numberOfSides = 0 func simpleDescription() -> String { return "A shape with \(numberOfSides) sides." } } +``` > 练习: > @@ -316,12 +358,15 @@ 要创建一个类的实例,在类名后面加上括号。使用点语法来访问实例的属性和方法。 +```swift var shape = Shape() shape.numberOfSides = 7 var shapeDescription = shape.simpleDescription() +``` 这个版本的`Shape`类缺少了一些重要的东西:一个构造函数来初始化类实例。使用`init`来创建一个构造器。 +```swift class NamedShape { var numberOfSides: Int = 0 var name: String @@ -334,6 +379,7 @@ return "A shape with \(numberOfSides) sides." } } +``` 注意`self`被用来区别实例变量。当你创建实例的时候,像传入函数参数一样给类传入构造器的参数。每个属性都需要赋值——无论是通过声明(就像`numberOfSides`)还是通过构造器(就像`name`)。 @@ -343,6 +389,7 @@ 子类如果要重写父类的方法的话,需要用`override`标记——如果没有添加`override`就重写父类方法的话编译器会报错。编译器同样会检测`override`标记的方法是否确实在父类中。 +```swift class Square: NamedShape { var sideLength: Double @@ -363,6 +410,7 @@ let test = Square(sideLength: 5.2, name: "my test square") test.area() test.simpleDescription() +``` > 练习: > @@ -370,6 +418,7 @@ 属性可以有 getter 和 setter 。 +```swift class EquilateralTriangle: NamedShape { var sideLength: Double = 0.0 @@ -396,6 +445,7 @@ triangle.perimeter triangle.perimeter = 9.9 triangle.sideLength +``` 在`perimeter`的 setter 中,新值的名字是`newValue`。你可以在`set`之后显式的设置一个名字。 @@ -409,6 +459,7 @@ 比如,下面的类确保三角形的边长总是和正方形的边长相同。 +```swift class TriangleAndSquare { var triangle: EquilateralTriangle { willSet { @@ -430,9 +481,11 @@ triangleAndSquare.triangle.sideLength triangleAndSquare.square = Square(sideLength: 50, name: "larger square") triangleAndSquare.triangle.sideLength +``` 类中的方法和一般的函数有一个重要的区别,函数的参数名只在函数内部使用,但是方法的参数名需要在调用的时候显式说明(除了第一个参数)。默认情况下,方法的参数名和它在方法内部的名字一样,不过你也可以定义第二个名字,这个名字被用在方法内部。 +```swift class Counter { var count: Int = 0 func incrementBy(amount: Int, numberOfTimes times: Int) { @@ -441,17 +494,21 @@ } var counter = Counter() counter.incrementBy(2, numberOfTimes: 7) +``` 处理变量的可选值时,你可以在操作(比如方法、属性和子脚本)之前加`?`。如果`?`之前的值是`nil`,`?`后面的东西都会被忽略,并且整个表达式返回`nil`。否则,`?`之后的东西都会被运行。在这两种情况下,整个表达式的值也是一个可选值。 +```swift let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") let sideLength = optionalSquare?.sideLength +``` ## 枚举和结构体 使用`enum`来创建一个枚举。就像类和其他所有命名类型一样,枚举可以包含方法。 +```swift enum Rank: Int { case Ace = 1 case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten @@ -473,6 +530,7 @@ } let ace = Rank.Ace let aceRawValue = ace.toRaw() +``` > 练习: > @@ -482,12 +540,15 @@ 使用`toRaw`和`fromRaw`函数来在原始值和枚举值之间进行转换。 +```swift if let convertedRank = Rank.fromRaw(3) { let threeDescription = convertedRank.simpleDescription() } +``` 枚举的成员值是实际值,并不是原始值的另一种表达方法。实际上,如果原始值没有意义,你不需要设置。 +```swift enum Suit { case Spades, Hearts, Diamonds, Clubs func simpleDescription() -> String { @@ -506,6 +567,7 @@ } let hearts = Suit.Hearts let heartsDescription = hearts.simpleDescription() +``` > 练习: > @@ -516,6 +578,7 @@ 使用`struct`来创建一个结构体。结构体和类有很多相同的地方,比如方法和构造器。它们之间最大的一个区别就是 结构体是传值,类是传引用。 +```swift struct Card { var rank: Rank var suit: Suit @@ -526,6 +589,7 @@ } let threeOfSpades = Card(rank: .Three, suit: .Spades) let threeOfSpadesDescription = threeOfSpades.simpleDescription() +``` > 练习: > @@ -535,6 +599,7 @@ 例如,考虑从服务器获取日出和日落的时间。服务器会返回正常结果或者错误信息。 +```swift enum ServerResponse { case Result(String, String) case Error(String) @@ -549,6 +614,7 @@ case let .Error(error): let serverResponse = "Failure... \(error)" } +``` > 练习: > @@ -561,13 +627,16 @@ 使用`protocol`来声明一个接口。 +```swift protocol ExampleProtocol { var simpleDescription: String { get } mutating func adjust() } +``` 类、枚举和结构体都可以实现接口。 +```swift class SimpleClass: ExampleProtocol { var simpleDescription: String = "A very simple class." var anotherProperty: Int = 69105 @@ -588,6 +657,7 @@ var b = SimpleStructure() b.adjust() let bDescription = b.simpleDescription +``` > 练习: > @@ -597,6 +667,7 @@ 使用`extension`来为现有的类型添加功能,比如添加一个计算属性的方法。你可以使用扩展来给任意类型添加协议,甚至是你从外部库或者框架中导入的类型。 +```swift extension Int: ExampleProtocol { var simpleDescription: String { return "The number \(self)" @@ -606,6 +677,7 @@ } } 7.simpleDescription +``` > 练习: > @@ -613,9 +685,11 @@ 你可以像使用其他命名类型一样使用接口名——例如,创建一个有不同类型但是都实现一个接口的对象集合。当你处理类型是接口的值时,接口外定义的方法不可用。 +```swift let protocolValue: ExampleProtocol = a protocolValue.simpleDescription // protocolValue.anotherProperty // Uncomment to see the error +``` 即使`protocolValue`变量运行时的类型是`simpleClass`,编译器会把它的类型当做`ExampleProtocol`。这表示你不能调用类在它实现的接口之外实现的方法或者属性。 @@ -624,6 +698,7 @@ 在尖括号里写一个名字来创建一个泛型函数或者类型。 +```swift func repeat(item: ItemType, times: Int) -> ItemType[] { var result = ItemType[]() for i in 0..times { @@ -632,9 +707,11 @@ return result } repeat("knock", 4) +``` 你也可以创建泛型类、枚举和结构体。 +```swift // Reimplement the Swift standard library's optional type enum OptionalValue { case None @@ -642,9 +719,11 @@ } var possibleInteger: OptionalValue = .None possibleInteger = .Some(100) +``` 在类型名后面使用`where`来指定一个需求列表——例如,要限定实现一个协议的类型,需要限定两个类型要相同,或者限定一个类必须有一个特定的父类。 +```swift func anyCommonElements (lhs: T, rhs: U) -> Bool { for lhsItem in lhs { for rhsItem in rhs { @@ -656,6 +735,7 @@ return false } anyCommonElements([1, 2, 3], [3]) +``` > 练习: >