# 常量和变量以及基本类型\_2

## 1. 元组类型

**元组**（tuples）把多个值组合成一个复合值。元组内的值可以是任意类型，并不要求是相同类型。

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


// 可以在声明时指定其中元素的名字
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”


// 你可以在定义元组的时候给单个元素命名：

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

```

作为函数返回值时，元组非常有用。相比于objc，使用元组可以返回多个返回值

> 当遇到一些相关值的简单分组时，元组是很有用的。元组不适合用来创建复杂的数据结构。如果你的数据结构比较复杂，不要使用元组，用类或结构体去建模。

## 2. 可选类型

使用**可选类型**（optionals）来处理值可能缺失的情况。可选类型表示两种可能： 或者有值， 你可以解析可选类型访问这个值， 或者根本没有值(nil)。

```c++

let a : Int? = 12  // Int? 可选类型，可以赋为nil，表示没有值

a = nil

```

> Int类型和Int?可选类型并不是同一种类型了

### 2.1 nil

在Objc中, nil代表的是一个空指针，表示某个变量不指向任何对象

在Swift中, nil 不是指针——它是一个确定的值，用来表示值缺失

### 2.2 强制解析

可选类型的对象往往不能直接使用，需要转化为对应的非可选类型。

![](https://pic.existorlive.cn/%E6%88%AA%E5%B1%8F2020-11-02%20%E4%B8%8B%E5%8D%881.57.21.png)

这里**在对象名字后加一个！将可选类型强制解析为对应的非可选类型**

```swift
let a : Int? = 11

if a != nil {
    print(a! + 1)
}

```

> 使用 ! 来获取一个不存在的可选值会导致运行时错误。使用 ! 来强制解析值之前，一定要确定可选包含一个非 nil 的值。

### 2.3 可选绑定

使用**可选绑定**（optional binding）来判断可选类型是否包含值，如果包含就把值赋给一个临时常量或者变量。

通过`while`，`if`和`guard`判断可选类型是否有值

```swift

let a : Int? = 11

// if 语句的句中（body）中才能获取到值
if let b = a {
    print(b + 1)
}


// guard 语句外且在语句后才能获取到值
guard let b = a else {
    return
}
print(b+1)
```

### 2.4 隐式解析可选类型

有时候在程序架构中，第一次被赋值之后，可以确定一个可选类型总会有值。在这种情况下，每次都要判断和解析可选值是非常低效的，因为可以确定它总会有值。

当确定一个可选类型有值后，可以将可选类型赋予给**隐式解析可选类型**。在使用**隐式解析可选类型**的对象时，会自动解析为对应的非可选类型，而不需要手动强制解析。

```swift
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // 需要感叹号来获取值

let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString  // 不需要感叹号 可以自动的隐式解析
```

> **隐式解析可选类型** 必须要保证有值，否则在隐式解析时会报错。

> **隐式解析可选类型** 仍然是可选类型，只是可以自动解析

***

## 3. 错误处理

```swift

// 函数
func makeASandwich() throws {
    // 这个函数有可能抛出错误
}

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

```

## 4. 断言和先决条件

**断言**和**先决条件**是在运行时所做的检查。你可以用他们来检查在执行后续代码之前是否一个必要的条件已经被满足了。

如果**断言**或者**先决条件**中的布尔条件评估的结果为 true（真），则代码像往常一样继续执行。**如果布尔条件评估结果为 false（假），程序的当前状态是无效的，则代码执行结束，应用程序中止**。

> 断言和先决条件并不是用来处理可以恢复的或者可预期的错误。因为一个断言失败表明了程序正处于一个无效的状态，没有办法去捕获一个失败的断言。

**断言仅在调试环境运行，而先决条件则在调试环境和生产环境中运行**

### 4.1 断言

Swift标准库提供了断言函数 `assert(_:_:file:line:)` 和 `assertionFailure(_:file:line:)`

```swift

let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// 因为 age < 0，所以断言会触发


if age > 10 {
    print("You can ride the roller-coaster or the ferris wheel.")
} else if age > 0 {
    print("You can ride the ferris wheel.")
} else {
    // 代码已经检查了条件,直接触发断言失败
    assertionFailure("A person's age can't be less than zero.")
}

```

### 4.2 先决条件

先决条件同样提供了`precondition(_:_:file:line:)` 和`·preconditionFailure(_:file:line:)`

```swift
// 在一个下标的实现里...
precondition(index > 0, "Index must be greater than zero.")
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gitbook.existorlive.cn/kai-fa-yu-yan-xue-xi/swift/1.-ji-chu-bu-fen/2.-chang-liang-he-bian-liang-yi-ji-ji-ben-lei-xing-2.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
