一、简单值

1.使用 let 来声明常量,使用 var 来声明变量。 let常量只能被赋值一次。let和var被赋值时就声明了类型。

let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70



2.值永远不会被隐式转换为其他类型。如果你需要把一个值转换成其他类型,请显式转换。


let label = "The width is"
let width = 94
let widthLabel = label + String(width)



3.有一种更简单的把值转换成字符串的方法:把值写到括号中,并且在括号之前写一个反斜杠。例如:


let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."

4.使用方括号 [] 来创建数组和字典,并使用下标或者键(key)来访问元素。最后一个元素后面允许有个逗号。

var shoppingList = ["catfish", "water", "tulips", "blue paint"]
shoppingList[1] = "bottle of water"
var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"



5.要创建一个空数组或者字典,使用初始化语法。

let emptyArray = [String]()
 let emptyDictionary = [String: Float]()



6.如果类型信息可以被推断出来,你可以用 [] 和 [:] 来创建空数组和空字典——就像你声明变量或者给函数传参 数的时候一样。


shoppingList = []
 occupations = [:]



二、元组

        元组(tuples)把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。


1.下面这个例子中, (404, "Not Found") 是一个描述 HTTP 状态码(HTTP status code)的元组。HTTP 状态码是 当你请求网页的时候 web 服务器返回的一个特殊值。如果你请求的网页不存在就会返回一个 404 Not Found 状 态码。

let http404Error = (404, "Not Found") 
// http404Error 的类型是 (Int, String),值是 (404, "Not Found")



2.(404, "Not Found") 元组把一个 Int 值和一个 String 值组合起来表示 HTTP 状态码的两个部分:一个数字 和一个人类可读的描述。这个元组可以被描述为“一个类型为 (Int, String) 的元组”。 你可以把任意顺序的类型组合成一个元组,这个元组可以包含所有类型。只要你想,你可以创建一个类型为 (In t, Int, Int) 或者 (String, Bool) 或者其他任何你想要的组合的元组。 你可以将一个元组的内容分解(decompose)成单独的常量和变量,然后你就可以正常使用它们了:

let (statusCode, statusMessage) = http404Error 
 print("The status code is \(statusCode)") 
// 输出 "The status code is 404"
 print("The status message is \(statusMessage)") 
// 输出 "The status message is Not Found"



3.如果你只需要一部分元组值,分解的时候可以把要忽略的部分用下划线( _ )标记:


let (justTheStatusCode, _) = http404Error 
print("The status code is \(justTheStatusCode)") 
// 输出 "The status code is 404"



4.此外,你还可以通过下标来访问元组中的单个元素,下标从零开始:

print("The status code is \(http404Error.0)")
 // 输出 "The status code is 404" 
print("The status message is \(http404Error.1)") 
// 输出 "The status message is Not Found"



5.你可以在定义元组的时候给单个元素命名:

let http200Status = (statusCode: 200, description: "OK")



6.给元组中的元素命名后,你可以通过名字来获取这些元素的值:

print("The status code is \(http200Status.statusCode)") 
// 输出 "The status code is 200" 
print("The status message is \(http200Status.description)") 
// 输出 "The status message is OK"

        作为函数返回值时,元组非常有用。一个用来获取网页的函数可能会返回一个 (Int, String) 元组来描述是否 获取成功。和只能返回一个类型的值比较起来,一个包含两个不同类型值的元组可以让函数的返回信息更有用。


三、可选类型

1.你可以给可选变量赋值为 nil 来表示它没有值:

var serverResponseCode: Int? = 404
// serverResponseCode 包含一个可选的 Int 值 404
serverResponseCode = nil
// serverResponseCode 现在不包含值



2.如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为 nil :

var surveyAnswer: String? 
// surveyAnswer 被自动设置为 nil
注意:
Swift 的 nil 和 Objective-C 中的 nil 并不一样。在 Objective-C 中, nil 是一个指向不存在对象的指 针。在 Swift 中, nil 不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设 置为 nil ,不只是对象类型。

3.if 语句以及强制解析
如果可选类型有值,它将不等于 nil : 

if convertedNumber != nil {
     print("convertedNumber contains some integer value.")
}
// 输出 "convertedNumber contains some integer value."

当你确定可选类型确实包含值之后,你可以在可选的名字后面加一个感叹号( ! )来获取值。这个惊叹号表 示“我知道这个可选有值,请使用它。”这被称为可选值的强制解析(forced unwrapping):


if convertedNumber != nil {
     print("convertedNumber has an integer value of \(convertedNumber!).")
}
// 输出 "convertedNumber has an integer value of 123."



4.可选绑定


if let actualNumber = Int(possibleNumber) {
     print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
 } else {
     print("\'\(possibleNumber)\' could not be converted to an integer")
}
// 输出 "'123' has an integer value of 123" 
使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。



5.隐式解析可选类型


把想要用作可选的类型 的后面的问号( String? )改成感叹号( String! )来声明一个隐式解析可选类型。 一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用 解析来获取可选值。


下面的例子展示了可选类型 String 和隐式解析可选类型 String 之间的区别:

let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要感叹号来获取值 
let assumedString: String! = "An implicitly unwrapped optional string." let implicitString: String = assumedString // 不需要感叹号 
注意:
如果一个变量之后可能变成 nil 的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否 是 nil 的话,请使用普通可选类型。




三、错误处理

func makeASandwich() throws {
     // ...
} 
 do {
     try makeASandwich()
     eatASandwich()
 } catch SandwichError.outOfCleanDishes {
     washDishes()
 } catch SandwichError.missingIngredients(let ingredients) {
     buyGroceries(ingredients)
}

在此例中,makeASandwich()(做一个三明治)函数会抛出一个错误消息如果没有干净的盘子或者某个原料缺 失。因为makeASandwich() 抛出错误,函数调用被包裹在try表达式中。将函数包裹在一个do 语句中,任 何被抛出的错误会被传播到提供的 catch从句中。


如果没有错误被抛出,eatASandwich()函数会被调用。如果一个匹配SandwichError.outOfCleanDishes 的错误被抛出,washDishes()函数会被调用。如果一个匹配SandwichError.missingIngredients的错误被抛出, buyGroceries(_:)函数会被调用,并且使用 catch 所捕捉到的关联值[String] 作为参数。




四、基本运算符

1.赋值运算符

如果赋值的右边是一个多元组,它的元素可以马上被分解成多个常量或变量:

let (x, y) = (1, 2)
// 现在 x 等于 1,y 等于 2 
2.算数运算符
加法运算符也可用于 String 的拼接: 
 "hello, " + "world" // 等于 "hello, world" 
 -9 % 4 // 等于 -1


一元负号运算符
数值的正负号可以使用前缀 - (即一元负号符)来切换:

let three = 3
let minusThree = -three // minusThree 等于 -3
let plusThree = -minusThree // plusThree 等于 3, 或 "负负3"

一元负号符( - )写在操作数之前,中间没有空格。


一元正号运算符


一元正号符( + )不做任何改变地返回操作数的值:


let minusSix = -6 
let alsoMinusSix = +minusSix // alsoMinusSix 等于 -6



3.组合赋值运算符


var a = 1

a += 2
// a 现在是 3

表达式 a += 2 是 a = a + 2 的简写,一个组合加运算就是把加法运算和赋值运算组合成进一个运算符里,同 时完成两个运算任务。


注意:
复合赋值运算没有返回值, let b = a += 2 这类代码是错误。



4.比较运算符

当元组中的值可以比较时,你也可以使用这些运算符来比较它们的大小。例如,因为 Int 和 String 类型的值 可以比较,所以类型为 (Int, String) 的元组也可以被比较。相反, Bool 不能被比较,也意味着存有布尔类 型的元组不能被比较。

(1, "zebra") < (2, "apple")
(3, "apple") < (3, "bird")
(4, "dog") == (4, "dog")
// true,因为 1 小于 2
// true,因为 3 等于 3,但是 apple 小于 bird // true,因为 4 等于 4,dog 等于 dog

在上面的例子中,你可以看到,在第一行中从左到右的比较行为。因为 1 小于 2 ,所以 (1, "zebra") 小于 (2, "apple") ,不管元组剩下的值如何。所以 "zebra" 小于 "apple" 没有任何影响,因为元组的比较已经被第一个元 素决定了。不过,当元组的第一个元素相同时候,第二个元素将会用作比较-第二行和第三行代码就发生了这样的 比较。


注意:
Swift 标准库只能比较七个以内元素的元组比较函数。如果你的元组元素超过七个时,你需要自己实现比较运算 符。



5.三目运算符


三目运算提供有效率且便捷的方式来表达二选一的选择。需要注意的事,过度使用三目运算符会使简洁的代码变
的难懂。我们应避免在一个组合语句中使用多个三目运算符


6.空合运算符

空合运算符( a ?? b )将对可选类型 a 进行空判断,如果 a 包含一个值就进行解封,否则就返回一个默认
值 b 。表达式 a 必须是 Optional 类型。默认值 b 的类型必须要和 a 存储值的类型保持一致。
空合运算符是对以下代码的简短表达方法:

a != nil ? a! : b



7.区间运算符


闭区间运算符(a...b )定义一个包含从 a到 b(包括 a和 b)的所有值的区间。
半开区间运算符( a..<b)定义一个从a 到b 但不包括b 的区间。

8.逻辑运算符

•逻辑非( !a )
•逻辑与( a && b)
•逻辑或( a || b)


五、字符串和字符

1.初始化空字符串

var emptyString = "" // 空字符串字面量 
var anotherEmptyString = String() // 初始化方法
// 两个字符串均为空并等价。

您可以通过检查其 Bool 类型的 isEmpty 属性来判断该字符串是否为空:


if emptyString.isEmpty {
    print("Nothing to see here")
}
// 打印输出:"Nothing to see here"



2.字符串可变性


您可以通过将一个特定字符串分配给一个变量来对其进行修改,或者分配给一个常量来保证其不会被修改:


var variableString = "Horse"
variableString += " and carriage"
// variableString 现在为 "Horse and carriage" 
let constantString = "Highlander"
constantString += " and another Highlander"
// 这会报告一个编译错误 (compile-time error) - 常量字符串不可以被修改。



3.字符串是值类型


Swift 的 String 类型是值类型。 如果您创建了一个新的字符串,那么当其进行常量、变量赋值操作,或在函数/ 方法中传递时,会进行值拷贝。



4.使用字符


您可通过 for-in 循环来遍历字符串中的 characters 属性来获取每一个字符的值:

for character in "Dog!?".characters {
    print(character)
}
// D
// o
// g
// !
// ?



5.连接字符串和字符


字符串可以通过加法运算符( + )相加在一起(或称“连接”)创建一个新的字符串:

let string1 = "hello"

let string2 = " there"

var welcome = string1 + string2 
// welcome 现在等于 "hello there"

您也可以通过加法赋值运算符 ( += ) 将一个字符串添加到一个已经存在字符串变量上:


var instruction = "look over"

instruction += string2

// instruction 现在等于 "look over there"

您可以用 append() 方法将一个字符附加到一个字符串变量的尾部:


let exclamationMark: Character = "!" 
welcome.append(exclamationMark)

// welcome 现在等于 "hello there!"



6.字符串插值


let multiplier = 3

let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
 // message 是 "3 times 2.5 is 7.5"

在上面的例子中, multiplier 作为 \(multiplier) 被插入到一个字符串常量量中。 当创建字符串执行插值计算 时此占位符会被替换为 multiplier 实际的值。



7.计算字符数量
如果想要获得一个字符串中 Character 值的数量,可以使用字符串的 characters 属性的 count 属性:

let unusualMenagerie = "Koala ?, Snail ?, Penguin ?, Dromedary ?" 
print("unusualMenagerie has \(unusualMenagerie.characters.count) characters") 
// 打印输出 "unusualMenagerie has 40 characters"



8.访问和修改字符串


使用 startIndex属性可以获取一个 String的第一个 Character的索引。使用 endIndex属性可以获取最后一个 Character 的后一个位置的索引。因此, endIndex属性不能作为一个字符串的有效下标。如果 String是空串, startIndex 和endIndex 是相等的。


通过调用 String 的 index(before:) 或 index(after:) 方法,可以立即得到前面或后面的一个索引。您还 可以通过调用 index(_:offsetBy:) 方法来获取对应偏移量的索引,这种方式可以避免多次调用 index(befor e:) 或 index(after:) 方法。


let greeting = "Guten Tag!"
 greeting[greeting.startIndex]
 // G
 greeting[greeting.index(before: greeting.endIndex)]
 // !
 greeting[greeting.index(after: greeting.startIndex)]
 // u
 let index = greeting.index(greeting.startIndex, offsetBy: 7)
 greeting[index]
 // a

试图获取越界索引对应的 Character ,将引发一个运行时错误。


greeting[greeting.endIndex] // error
greeting.index(after: endIndex) // error

使用 characters 属性的 indices 属性会创建一个包含全部索引的范围(Range),用来在一个字符串中访问单 个字符。


for index in greeting.characters.indices {
    print("\(greeting[index]) ", terminator: "")
}
// 打印输出 "G u t e n T a g ! "

调用 insert(_:at:) 方法可以在一个字符串的指定索引插入一个字符,调用 insert(contentsOf:at:) 方法可 以在一个字符串的指定索引插入一个段字符串。


var welcome = "hello"

welcome.insert("!", at: welcome.endIndex) // welcome 变量现在等于 "hello!" 
welcome.insert(contentsOf:" there".characters, at: welcome.index(before: welcome.endIndex)) 
// welcome 变量现在等于 "hello there!"

调用 remove(at:) 方法可以在一个字符串的指定索引删除一个字符,调用 removeSubrange(_:) 方法可以在一 个字符串的指定索引删除一个子字符串。


welcome.remove(at: welcome.index(before: welcome.endIndex))
 // welcome 现在等于 "hello there" 
let range = welcome.index(welcome.endIndex, offsetBy: -6)..<welcome.endIndex welcome.removeSubrange(range)

// welcome 现在等于 "hello"



9.比较字符串


字符串/字符相等


字符串/字符可以用等于操作符( == )和不等于操作符( != )


let quotation = "We're a lot alike, you and I."
let sameQuotation = "We're a lot alike, you and I."
if quotation == sameQuotation {
    print("These two strings are considered equal")
}
// 打印输出 "These two strings are considered equal"

前缀/后缀相等


通过调用字符串的 hasPrefix(_:) / hasSuffix(_:) 方法来检查字符串是否拥有特定前缀/后缀,两个方法均接收一 个 String 类型的参数,并返回一个布尔值。


if scene.hasPrefix("Act 1 ") { }
  if scene.hasSuffix("Capulet's mansion") {   }