Swift Study 1.1  类型

元组
元组（tuples）把多个值组合成一个复合值。元组内的值可以使任意类型，并不要求是相同类型。
 
下面这个例子中，(404, "Not Found")是一个描述 HTTP 状态码（HTTP status code）的元组。HTTP 状态码是当你请求网页的时候 web 服务器返回的一个特殊值。如果你请求的网页不存在就会返回一个404 Not Found状态码。
let http404Error = (404, "Not Found") 
// http404Error 的类型是 (Int, String)，值是 (404, "Not Found") 
(404, "Not Found")元组把一个Int值和一个String值组合起来表示 HTTP 状态码的两个部分：一个数字和一个人类可读的描述。这个元组可以被描述为“一个类型为(Int, String)的元组”。
 
你可以把任意顺序的类型组合成一个元组，这个元组可以包含所有类型。只要你想，你可以创建一个类型为(Int, Int, Int)或者(String, Bool)或者其他任何你想要的组合的元组。
 
你可以将一个元组的内容分解（decompose）成单独的常量和变量，然后你就可以正常使用它们了：
let (statusCode, statusMessage) = http404Error 
println("The status code is \(statusCode)") 
// 输出 "The status code is 404" 
println("The status message is \(statusMessage)") 
// 输出 "The status message is Not Found" 
如果你只需要一部分元组值，分解的时候可以把要忽略的部分用下划线（_）标记：
let (justTheStatusCode, _) = http404Error 
println("The status code is \(justTheStatusCode)") 
// 输出 "The status code is 404" 
此外，你还可以通过下标来访问元组中的单个元素，下标从零开始：
println("The status code is \(http404Error.0)") 
// 输出 "The status code is 404" 
println("The status message is \(http404Error.1)") 
// 输出 "The status message is Not Found" 
你可以在定义元组的时候给单个元素命名：
let http200Status = (statusCode: 200, description: "OK") 
给元组中的元素命名后，你可以通过名字来获取这些元素的值：
println("The status code is \(http200Status.statusCode)") 
// 输出 "The status code is 200" 
println("The status message is \(http200Status.description)") 
// 输出 "The status message is OK" 
作为函数返回值时，元组非常有用。一个用来获取网页的函数可能会返回一个(Int, String)元组来描述是否获取成功。和只能返回一个类型的值比较起来，一个包含两个不同类型值的元组可以让函数的返回信息更有用。请参考[函数参数与返回值(06_Functions.html#Function_Parameters_and_Return_Values)。
 
注意：元组在临时组织值的时候很有用，但是并不适合创建复杂的数据结构。如果你的数据结构并不是临时使用，请使用类或者结构体而不是元组。请参考类和结构体。
 
可选
使用可选（optionals）来处理值可能缺失的情况。可选表示：
 
-有值，等于 x
 
或者
 
没有值
 
注意：C 和 Objective-C 中并没有可选这个概念。最接近的是 Objective-C 中的一个特性，一个方法要不返回一个对象要不返回nil，nil表示“缺少一个合法的对象”。然而，这只对对象起作用——对于结构体，基本的 C 类型或者枚举类型不起作用。对于这些类型，Objective-C 方法一般会返回一个特殊值（比如NSNotFound）来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而，Swift 的可选可以让你暗示任意类型的值缺失，并不需要一个特殊值。
 
来看一个例子。Swift 的String类型有一个叫做toInt的方法，作用是将一个String值转换成一个Int值。然而，并不是所有的字符串都可以转换成一个整数。字符串"123"可以被转换成数字123，但是字符串"hello, world"不行。
 
下面的例子使用toInt方法来尝试将一个String转换成Int：
let possibleNumber = "123" 
let convertedNumber = possibleNumber.toInt() 
// convertedNumber 被推测为类型 "Int?"， 或者类型 "optional Int" 
因为toInt方法可能会失败，所以它返回一个可选的（optional）Int，而不是一个Int。一个可选的Int被写作Int?而不是Int。问号暗示包含的值是可选，也就是说可能包含Int值也可能不包含值。（不能包含其他任何值比如Bool值或者String值。只能是Int或者什么都没有。）
 
if 语句以及强制解析
你可以使用if语句来判断一个可选是否包含值。如果可选有值，结果是true；如果没有值，结果是false。
 
当你确定可选包确实含值之后，你可以在可选的名字后面加一个感叹号(!)来获取值。这个惊叹号表示“我知道这个可选有值，请使用它。”这被称为可选值的强制解析（forced unwrapping）：
if convertedNumber { 
    println("\(possibleNumber) has an integer value of \(convertedNumber!)") 
} else { 
    println("\(possibleNumber) could not be converted to an integer") 
} 
// 输出 "123 has an integer value of 123" 
更多关于if语句的内容，请参考控制流。
 
注意：使用!来获取一个不存在的可选值会导致运行时错误。使用!来强制解析值之前，一定要确定可选包含一个非nil的值。
 
可选绑定
使用可选绑定（optional binding）来判断可选是否包含值，如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if和while语句中来对可选的值进行判断并把值赋给一个常量或者变量。if和while语句，请参考控制流。
 
像下面这样在if语句中写一个可选绑定：
if let constantName = someOptional { 
    statements 
} 
你可以像上面这样使用可选绑定来重写possibleNumber这个例子：
if let actualNumber = possibleNumber.toInt() { 
    println("\(possibleNumber) has an integer value of \(actualNumber)") 
} else { 
    println("\(possibleNumber) could not be converted to an integer") 
} 
// 输出 "123 has an integer value of 123" 
这段代码可以被理解为：
 
“如果possibleNumber.toInt返回的可选Int包含一个值，创建一个叫做actualNumber的新常量并将可选包含的值赋给它。”
 
如果转换成功，actualNumber常量可以在if语句的第一个分支中使用。它已经被可选包含的值初始化过，所以不需要再使用!后缀来获取它的值。在这个例子中，actualNumber只被用来输出转换结果。
 
你可以在可选绑定中使用常量和变量。如果你想在if语句的第一个分支中操作actualNumber的值，你可以改成if var actualNumber，这样可选包含的值就会被赋给一个变量而非常量。
 
nil
你可以给可选变量赋值为nil来表示它没有值：
var serverResponseCode: Int? = 404 
// serverResponseCode 包含一个可选的 Int 值 404 
serverResponseCode = nil 
// serverResponseCode 现在不包含值 
注意：nil不能用于非可选的常量和变量。如果你的代码中有常量或者变量需要处理值缺失的情况，请把它们声明成对应的可选类型。
 
如果你声明一个可选常量或者变量但是没有赋值，它们会自动被设置为nil：
var surveyAnswer: String? 
// surveyAnswer 被自动设置为 nil 
注意：Swift 的nil和 Objective-C 中的nil并不一样。在 Objective-C 中，nil是一个指向不存在对象的指针。在 Swift 中，nil不是指针——它是一个确定的值，用来表示值缺失。任何类型的可选都可以被设置为nil，不只是对象类型。
 
隐式解析可选
如上所述，可选暗示了常量或者变量可以“没有值”。可选可以通过if语句来判断是否有值，如果有值的话可以通过可选绑定来解析值。
 
有时候在程序架构中，第一次被赋值之后，可以确定一个可选总会有值。在这种情况下，每次都要判断和解析可选值是非常低效的，因为可以确定它总会有值。
 
这种类型的可选被定义为隐式解析可选（implicitly unwrapped optionals）。把想要用作可选的类型的后面的问号（String?）改成感叹号（String!）来声明一个隐式解析可选。
 
当可选被第一次赋值之后就可以确定之后一直有值的时候，隐式解析可选非常有用。隐式解析可选主要被用在 Swift 中类的构造过程中，请参考类实例之间的循环强引用。
 
一个隐式解析可选其实就是一个普通的可选，但是可以被当做非可选来使用，并不需要每次都使用解析来获取可选值。下面的例子展示了可选String和隐式解析可选String之间的区别：
let possibleString: String? = "An optional string." 
println(possibleString!) // 需要惊叹号来获取值 
// 输出 "An optional string." 
 
let assumedString: String! = "An implicitly unwrapped optional string." 
println(assumedString)  // 不需要感叹号 
// 输出 "An implicitly unwrapped optional string." 
你可以把隐式解析可选当做一个可以自动解析的可选。你要做的只是声明的时候把感叹号放到类型的结尾，而不是每次取值的可选名字的结尾。
 
注意：如果你在隐式解析可选没有值的时候尝试取值，会触发运行时错误。和你在没有值的普通可选后面加一个惊叹号一样。
 
你仍然可以把隐式解析可选当做普通可选来判断它是否包含值：
if assumedString { 
    println(assumedString) 
} 
// 输出 "An implicitly unwrapped optional string." 
你也可以在可选绑定中使用隐式解析可选来检查并解析它的值：
if let definiteString = assumedString { 
    println(definiteString) 
} 
// 输出 "An implicitly unwrapped optional string." 
注意：如果一个变量之后可能变成nil的话请不要使用隐式解析可选。如果你需要在变量的生命周期中判断是否是nil的话，请使用普通可选类型。
 
断言
可选可以让你判断值是否存在，你可以在代码中优雅地处理值缺失的情况。然而，在某些情况下，如果值缺失或者值并不满足特定的条件，你的代码可能并不需要继续执行。这时，你可以在你的代码中触发一个断言（assertion）来结束代码运行并通过调试来找到值缺失的原因。
 
使用断言进行调试
断言会在运行时判断一个逻辑条件是否为true。从字面意思来说，断言“断言”一个条件是否为真。你可以使用断言来保证在运行其他代码之前，某些重要的条件已经被满足。如果条件判断为true，代码运行会继续进行；如果条件判断为false，代码运行停止，你的应用被终止。
 
如果你的代码在调试环境下触发了一个断言，比如你在 Xcode 中构建并运行一个应用，你可以清楚地看到不合法的状态发生在哪里并检查断言被触发时你的应用的状态。此外，断言允许你附加一条调试信息。
 
你可以使用全局assert函数来写一个断言。向assert函数传入一个结果为true或者false的表达式以及一条信息，当表达式为false的时候这条信息会被显示：
let age = -3 
assert(age >= 0, "A person's age cannot be less than zero") 
// 因为 age < 0，所以断言会触发 
在这个例子中，只有age >= 0为true的时候代码运行才会继续，也就是说，当age的值非负的时候。如果age的值是负数，就像代码中那样，age >= 0为false，断言被触发，结束应用。
 
断言信息不能使用字符串插值。断言信息可以省略，就像这样：
assert(age >= 0) 
 
何时使用断言
当条件可能为假时使用断言，但是最终一定要保证条件为真，这样你的代码才能继续运行。断言的适用情景：
 
- 整数的附属脚本索引被传入一个自定义附属脚本实现，但是下标索引值可能太小或者太大。
- 需要给函数传入一个值，但是非法的值可能导致函数不能正常执行。
- 一个可选值现在是nil，但是后面的代码运行需要一个非nil值。
 
请参考附属脚本和函数。
 
注意：断言可能导致你的应用终止运行，所以你应当仔细设计你的代码来让非法条件不会出现。然而，在你的应用发布之前，有时候非法条件可能出现，这时使用断言可以快速发现问题。