# Swift 可选

> 原文： [https://www.programiz.com/swift-programming/optionals](https://www.programiz.com/swift-programming/optionals)

#### 在本文中，您将学习可选，其用例以及 Swift 中的可选处理。

在上一篇文章中，我们了解了 Swift 中可用的不同数据类型，并且还注意到这些类型声明的变量或常量包含默认值。

**示例：**

```swift
let someValue = Int()
print(someValue)

```

运行该程序时，输出为：

```swift
0
```

但是，Swift 中还有另一种称为 Optional 的数据类型，其默认值为空值（`nil`）。 如果希望变量或常量中不包含任何值，则可以使用可选。 可选类型可以包含一个值或不存在一个值（空值）。

从技术上讲，您可以认为它是可选的鞋盒。 鞋盒中可能装有鞋，也可能没有。 因此，从包装箱中取出鞋子时，您应该事先知道。

* * *

## 如何声明 Optional？

通过将`!`或`?`附加到`Type`，您可以简单地将数据类型表示为 Optional。 如果一个可选参数中包含一个值，则返回值为`Optional<Value>`，否则返回`nil`。

### 示例 1：如何在 Swift 中声明一个可选的？

```swift
var someValue:Int?
var someAnotherValue:Int!
print(someValue)
print(someAnotherValue) 
```

When you run the program, the output will be:

```swift
nil
nil
```

在上面的程序中，我们使用`?`和`!`初始化了一个可选类型。 两种方法都可以创建可选的方法，但是有一个主要的不同，我们将在下面进行探讨。

声明一个可选的 Int 意味着该变量将具有整数值或无值。 由于没有为变量分配任何值，因此您可以在屏幕上看到两个`print`语句输出`nil`。

* * *

### 示例 2：从可选项分配和访问值

```swift
let someValue:Int? = 5
print(someValue)
print(someValue!) 
```

When you run the program, the output will be:

```swift
Optional(5)
5 
```

在上面的程序中，我们声明了`Int`类型的可选内容，并在其中分配了值 5。

如您所见，将可选选项打印为`print(someValue)`不会给您`5`而是`Optional(5)`。 它具有上述形式：`Optional<Value>`。 为了从中访问`<Value>`，我们需要一种称为**展开**的机制。

您可以通过在变量/常量的末尾附加`!`字符来展开可选字符，如下一行`print(someValue!)`所示。 `print(someValue!)`打开包装，并在屏幕上输出`5`。

但是，请记住，仅当确定在访问可选选项时肯定具有值时，才应使用这种解包机制。

* * *

### 示例 3：显式声明一个未包装的可选

您还可以通过以下方式创建解包后的可选内容：

```swift
let someValue:Int! = 5
print(someValue) 
```

When you run the program, the output will be:

```swift
5
```

在上面的程序中，`Int!`创建一个未包装的可选内容，当您访问它时，它会自动对值进行包装，因此您不必每次都附加`!`字符。

请确保在使用这些可选选项时，变量在访问它时始终需要有一个值。 如果不这样做，将会导致致命的错误崩溃。

* * *

### 示例 4：访问 null 的未包装可选对象时发生致命错误

```swift
var someValue:Int!
var unwrappedValue:Int = someValue //crashes due to this line 
```

当您运行该程序时，您会因**致命错误而崩溃：在解开可选值**时意外发现 nil，因为代码`unwrappedValue:Int = someValue`试图将可选 `someValue` 中的值赋给变量 `unwrappedValue` 。

但是， `somevalue` 是包含`nil`值的`Optional`类型。 尝试将 nil 值分配给变量 `unwrappedValue` （这不是可选的）会导致崩溃。

有多种处理此情况的技术，下面将进行说明。

* * *

## 可选处理

为了使用可选值，需要将其解包。 使用可选值的更好方法是通过条件展开而不是使用`!`运算符强制展开。

这是因为有条件的展开询问**检查此变量是否具有值？** 。 如果是，请提供该值，否则将处理 nil 情况。

相反，强制展开表示**该变量在使用时确实有一个值**。 因此，当您强制解开一个 nil 的变量时，您的程序将在解开可选异常并抛出的同时抛出**意外发现的 nil。 下面说明了一些用于条件展开的技术：**

### 1\. If 语句

您可以使用 if 语句，然后将可选参数与 nil 进行比较，以找出可选参数是否包含值。 您可以在 if 语句中使用比较运算符“等于”运算符（`==`）或“不等于”运算符（`!=`）。

#### 示例 5：if else 语句的可选处理

```swift
var someValue:Int?
var someAnotherValue:Int! = 0

if someValue != nil {
	print("It has some value \(someValue!)")
} else {
	print("doesn't contain value")
}

if someAnotherValue != nil {
	print("It has some value \(someAnotherValue!)")
} else {
	print("doesn't contain value")
} 
```

When you run the program, the output will be:

```swift
doesn't contain value
It has some value 0 
```

在上面的程序中，如果可选值包含值，则执行 if 语句内的代码，否则执行 else 块内的语句。 使用此技术进行可选处理的主要缺点是，您仍然需要使用`!`运算符从可选值中解包该值。

* * *

### 2.可选绑定（如果允许）

可选绑定可帮助您找出可选值是否包含值。 如果可选值包含一个值，则该值可用作临时常量或变量。 因此，可以将可选绑定与 if 语句一起使用，以检查可选内部的值，并在单个操作中将该值提取到常量或变量中。

#### 示例 5：使用 if let 语句的可选处理

```swift
var someValue:Int?
var someAnotherValue:Int! = 0

if let temp = someValue {
	print("It has some value \(temp)") 
} else {
	print("doesn't contain value")
}

if let temp = someAnotherValue {
	print("It has some value \(temp)")
} else {
	print("doesn't contain value")      
} 
```

When you run the program, the output will be:

```swift
doesn't contain value
It has some value 0 
```

在上面的程序中，如果可选语句包含一个值，则执行 if 语句中的代码。 否则，else 块将被执行。 `if-let`语句还自动展开该值，并将展开后的值放入 `temp` 常量中。 该技术的主要优势在于，尽管可以确定某个可选项包含一个值，但您无需强行解开该值。

* * *

### 3.保护声明

您可以使用 guard 处理 Swift 中的可选项。 如果您不知道什么警卫，请不要担心。 现在，仅将警卫视为没有 if 阻止的`if-else`条件。 如果条件失败，则执行 else 语句。 如果不是，则执行下一条语句。 有关更多详细信息，请参见 [Swift Guard](/swift-programming/guard-statement "Swift guard statement") 。

#### 示例 6：使用防护罩的可选处理

```swift
func testFunction() {
	let someValue:Int? = 5
	guard let temp = someValue else {
		return
	}
	print("It has some value \(temp)")
}

testFunction() 
```

When you run the program, the output will be:

```swift
It has some value 5
```

在上述程序中，防护包含一个条件，即可选的 `someValue` 是否包含值。 如果它包含一个值，则`guard-let`语句将自动解包该值，并将解包后的值放入 `temp` 常量中。 否则，else 块将被执行，它将返回到调用函数。 由于可选内容包含一个值，因此将调用`print`函数。

* * *

### 4.无商定算子

在 Swift 中，您还可以使用 nil-coalescing 运算符检查可选变量是否包含值。 定义为`(a ?? b)`。 它解开可选的 `a` 并返回它（如果它包含一个值），或者如果 `a` 为零，则返回默认值 `b` 。

#### 示例 7：使用 nil-coalescing 运算符的可选处理

```swift
var someValue:Int!
let defaultValue = 5
let unwrappedValue:Int = someValue ?? defaultValue
print(unwrappedValue) 
```

When you run the program, the output will be:

```swift
5
```

在上面的程序中，变量 `someValue` 定义为可选，并且包含 `nil` 值。 nil 合并运算符无法解开可选内容，因此返回 `defaultValue` 。 因此，语句`print(unwrappedValue)`在控制台中输出 5。

```swift
var someValue:Int? = 10
let defaultValue = 5
let unwrappedValue:Int = someValue ?? defaultValue
print(unwrappedValue) 
```

When you run the program, the output will be:

```swift
10
```

但是，在上述程序中，可选变量 `someValue` 初始化为值 10。因此，nil 合并运算符成功地从 `someValue` 中解包了该值。 因此，语句`someValue ?? defaultValue`返回 10，并且语句`print(unwrappedValue)`在控制台中输出 10。