Optional Binding (可选项绑定)
You useoptional bindingto find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used withifandwhilestatements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action.ifandwhilestatements are described in more detail inControl Flow.
使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if和while语句中,这条语句不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值赋给一个常量或者变量。if和while语句,请参考控制流。
Write an optional binding for anifstatement as follows:
像下面这样在if语句中写一个可选绑定:
if let constantName=someOptional {
statements
}
You can rewrite thepossibleNumberexample from theOptionalssection to use optional binding rather than forced unwrapping:
你可以像上面这样使用可选绑定来重写possibleNumber这个例子:
if let actualNumber=Int(possibleNumber) {
print("\"\(possibleNumber)\" has an integer value of\(actualNumber)")
} else {
print("\"\(possibleNumber)\" could not be converted to an integer")
}
// Prints ""123" has an integer value of 123"
This code can be read as:
这段代码可以被理解为:
“If the optionalIntreturned byInt(possibleNumber)contains a value, set a new constant calledactualNumberto the value contained in the optional.”
“如果Int(possibleNumber)返回的可选Int包含一个值,创建一个叫做actualNumber的新常量并将可选包含的值赋给它。”
If the conversion is successful, theactualNumberconstant becomes available for use within the first branch of theifstatement. It has already been initialized with the value containedwithinthe optional, and so there is no need to use the!suffix to access its value. In this example,actualNumberis simply used to print the result of the conversion.
如果转换成功,actualNumber常量可以在if语句的第一个分支中使用。它已经被可选类型包含的值初始化过,所以不需要再使用!后缀来获取它的值。在这个例子中,actualNumber只被用来输出转换结果。
You can use both constants and variables with optional binding. If you wanted to manipulate the value ofactualNumberwithin the first branch of theifstatement, you could writeif var actualNumberinstead, and the value contained within the optional would be made available as a variable rather than a constant.
你可以在可选绑定中使用常量和变量。如果你想在if语句的第一个分支中操作actualNumber的值,你可以改成if var actualNumber,这样可选类型包含的值就会被赋给一个变量而非常量。
You can include as many optional bindings and Boolean conditions in a singleifstatement as you need to, separated by commas. If any of the values in the optional bindings arenilor any Boolean condition evaluates tofalse, the wholeifstatement’s condition is considered to befalse. The followingifstatements are equivalent:
你可以包含多个可选绑定或多个布尔条件在一个if语句中,只要使用逗号分开就行。只要有任意一个可选绑定的值为nil,或者任意一个布尔条件为false,则整个if条件判断为false,这时你就需要使用嵌套if条件语句来处理,如下所示:
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
// 输出 "4 < 42 < 100"
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
// 输出 "4 < 42 < 100"
Note (注意)
Constants and variables created with optional binding in anifstatement are available only within the body of theifstatement. In contrast, the constants and variables created with aguardstatement are available in the lines of code that follow theguardstatement, as described inEarly Exit.
在if条件语句中使用常量和变量来创建一个可选绑定,仅在if语句的句中(body)中才能获取到值。相反,在guard语句中使用常量和变量来创建一个可选绑定,仅在guard语句外且在语句后才能获取到值,请参考提前退出。
Implicitly Unwrapped Optionals (隐式解析可选类型)
As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with anifstatement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist.
如上所述,可选类型暗示了常量或者变量可以“没有值”。可选可以通过if语句来判断是否有值,如果有值的话可以通过可选绑定来解析值。
Sometimes it is clear from a program’s structure that an optional willalwayshave a value, after that value is first set. In these cases, it is useful to remove the need to check and unwrap the optional’s value every time it is accessed, because it can be safely assumed to have a value all of the time.
有时候在程序架构中,第一次被赋值之后,可以确定一个可选类型_总会_有值。在这种情况下,每次都要判断和解析可选值是非常低效的,因为可以确定它总会有值。
These kinds of optionals are defined asimplicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional.
这种类型的可选状态被定义为隐式解析可选类型(implicitly unwrapped optionals)。把想要用作可选的类型的后面的问号(String?)改成感叹号(String!)来声明一个隐式解析可选类型。
Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described inUnowned References and Implicitly Unwrapped Optional Properties.
当可选类型被第一次赋值之后就可以确定之后一直有值的时候,隐式解析可选类型非常有用。隐式解析可选类型主要被用在 Swift 中类的构造过程中,请参考无主引用以及隐式解析可选属性。
An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it is accessed. The following example shows the difference in behavior between an optional string and an implicitly unwrapped optional string when accessing their wrapped value as an explicitString:
一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用解析来获取可选值。下面的例子展示了可选类型String和隐式解析可选类型String之间的区别:
let possibleString:String? ="An optional string."
let forcedString:String=possibleString!// requires an exclamation mark
// 需要感叹号来获取值
let assumedString:String! ="An implicitly unwrapped optional string."
let implicitString:String=assumedString// no need for an exclamation mark
// 不需要感叹号
You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used. Rather than placing an exclamation mark after the optional’s name each time you use it, you place an exclamation mark after the optional’s type when you declare it.
你可以把隐式解析可选类型当做一个可以自动解析的可选类型。你要做的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。
Note
If an implicitly unwrapped optional isniland you try to access its wrapped value, you’ll trigger a runtime error. The result is exactly the same as if you place an exclamation mark after a normal optional that does not contain a value.
如果你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个惊叹号一样。
You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value:
你仍然可以把隐式解析可选类型当做普通可选类型来判断它是否包含值:
if assumedString!=nil{
print(assumedString)
}
// Prints "An implicitly unwrapped optional string."
You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement:
你也可以在可选绑定中使用隐式解析可选类型来检查并解析它的值:
if let definiteString=assumedString{
print(definiteString)
}
// Prints "An implicitly unwrapped optional string."
Note
Do not use an implicitly unwrapped optional when there is a possibility of a variable becomingnilat a later point. Always use a normal optional type if you need to check for anilvalue during the lifetime of a variable.
如果一个变量之后可能变成nil的话请不要使用隐式解析可选类型。如果你需要在变量的生命周期中判断是否是nil的话,请使用普通可选类型。
Error Handling (错误处理)
You use error handlingto respond to error conditions your program may encounter during execution.
你可以使用错误处理(error handling)来应对程序执行中可能会遇到的错误条件。
In contrast to optionals, which can use the presence or absence of a value to communicate success or failure of a function, error handling allows you to determine the underlying cause of failure, and, if necessary, propagate the error to another part of your program.
与可选项相反,错误处理可以使用值的存在或不存在来传达函数的成功或失败, 错误处理允许您确定失败的根本原因,并且如果需要,将错误传播到程序的另一部分。
When a function encounters an error condition, it throws an error. That function’s caller can then catch the error and respond appropriately.
当函数遇到错误条件时,它会抛出错误。那个函数的调用者然后可以捕获错误并适当地作出响应。
func canThrowAnError()throws {
// this function may or may not throw an error
}
A function indicates that it can throw an error by including thethrowskeyword in its declaration. When you call a function that can throw an error, you prepend thetrykeyword to the expression.
函数表明它可以通过在其声明中加上抛出错误关键字来抛出错误。当你调用一个可以抛出错误的函数时,你需要在表达式前面加上前缀。
Swift automatically propagates errors out of their current scope until they are handled by acatchclause.
Swift自动将错误传播到当前范围之外,直到它们被一个catch子句处理。
do{
trycanThrowAnError()
// no error was thrown
} catch {
// an error was thrown
}
A do statement creates a new containing scope, which allows errors to be propagated to one or morecatchclauses.
一个do语句创建了一个新的包含作用域,使得错误能被传播到一个或多个catch从句。
Here’s an example of how error handling can be used to respond to different error conditions:
这里有一个错误处理如何用来应对不同错误条件的例子。
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(letingredients) {
buyGroceries(ingredients)
}
In this example, themakeASandwich()function will throw an error if no clean dishes are available or if any ingredients are missing. BecausemakeASandwich()can throw an error, the function call is wrapped in atryexpression. By wrapping the function call in adostatement, any errors that are thrown will be propagated to the provided catchclauses.
在此例中,makeASandwich()(做一个三明治)函数会抛出一个错误消息如果没有干净的盘子或者某个原料缺失。因为makeASandwich()抛出错误,函数调用被包裹在try表达式中。将函数包裹在一个do语句中,任何被抛出的错误会被传播到提供的catch从句中。
If no error is thrown, theeatASandwich()function is called. If an error is thrown and it matches theSandwichError.outOfCleanDishescase, then thewashDishes()function will be called. If an error is thrown and it matches theSandwichError.missingIngredientscase, then thebuyGroceries(_:)function is called with the associated[String]value captured by thecatchpattern.
如果没有错误被抛出,eatASandwich()函数会被调用。如果一个匹配SandwichError.outOfCleanDishes的错误被抛出,washDishes()函数会被调用。如果一个匹配SandwichError.missingIngredients的错误被抛出,buyGroceries(_:)函数会被调用,并且使用catch所捕捉到的关联值[String]作为参数。
Throwing, catching, and propagating errors is covered in greater detail inError Handling.
抛出,捕捉,以及传播错误会在错误处理章节详细说明。
Assertions (断言)
In some cases, it is simply not possible for your code to continue execution if a particular condition is not satisfied. In these situations, you can trigger anassertionin your code to end code execution and to provide an opportunity to debug the cause of the absent or invalid value.
可选类型可以让你判断值是否存在,你可以在代码中优雅地处理值缺失的情况。然而,在某些情况下,如果值缺失或者值并不满足特定的条件,你的代码可能没办法继续执行。这时,你可以在你的代码中触发一个断言(assertion)来结束代码运行并通过调试来找到值缺失的原因。
Debugging with Assertions (利用断言进行调试)
An assertion is a runtime check that a Boolean condition definitely evaluates totrue. Literally put, an assertion “asserts” that a condition is true. You use an assertion to make sure that an essential condition is satisfied before executing any further code. If the condition evaluates totrue, code execution continues as usual; if the condition evaluates tofalse, code execution ends, and your app is terminated.
断言会在运行时判断一个逻辑条件是否为true。从字面意思来说,断言“断言”一个条件是否为真。你可以使用断言来保证在运行其他代码之前,某些重要的条件已经被满足。如果条件判断为true,代码运行会继续进行;如果条件判断为false,代码执行结束,你的应用被终止。
If your code triggers an assertion while running in a debug environment, such as when you build and run an app in Xcode, you can see exactly where the invalid state occurred and query the state of your app at the time that the assertion was triggered. An assertion also lets you provide a suitable debug message as to the nature of the assert.
如果你的代码在调试环境下触发了一个断言,比如你在 Xcode 中构建并运行一个应用,你可以清楚地看到不合法的状态发生在哪里并检查断言被触发时你的应用的状态。此外,断言允许你附加一条调试信息。
You write an assertion by calling the Swift standard library globalassert(_:_:file:line:)function. You pass this function an expression that evaluates totrueorfalseand a message that should be displayed if the result of the condition isfalse:
你可以使用全局assert(_:_:file:line:)函数来写一个断言。向这个函数传入一个结果为true或者false的表达式以及一条信息,当表达式的结果为false的时候这条信息会被显示:
let age=-3
assert(age>=0,"A person's age cannot be less than zero")
// this causes the assertion to trigger, because age is not >= 0
// 因为 age < 0,所以断言会触发
In this example, code execution will continue only ifage >= 0evaluates totrue, that is, if the value ofageis non-negative. If the value ofageisnegative, as in the code above, thenage >= 0evaluates tofalse, and the assertion is triggered, terminating the application.
在这个例子中,只有age >= 0为true的时候,即age的值非负的时候,代码才会继续执行。如果age的值是负数,就像代码中那样,age >= 0为false,断言被触发,终止应用。
The assertion message can be omitted if desired, as in the following example:
如果不需要断言信息,可以省略,就像这样:
assert(age>=0)
Note
Assertions are disabled when your code is compiled with optimizations, such as when building with an app target’s default Release configuration in Xcode.
当代码使用优化编译的时候,断言将会被禁用,例如在 Xcode 中,使用默认的 target Release 配置选项来 build 时,断言会被禁用。
When to Use Assertions
Use an assertion whenever a condition has the potential to be false, but mustdefinitelybe true in order for your code to continue execution. Suitable scenarios for an assertion check include:
当条件可能为假时使用断言,但是最终一定要_保证_条件为真,这样你的代码才能继续运行。断言的适用情景:
1. An integer subscript index is passed to a custom subscript implementation, but the subscript index value could be too low or too high.
整数类型的下标索引被传入一个自定义下标实现,但是下标索引值可能太小或者太大。
2. A value is passed to a function, but an invalid value means that the function cannot fulfill its task.
需要给函数传入一个值,但是非法的值可能导致函数不能正常执行。
3. An optional value is currentlynil, but a non-nilvalue is essential for subsequent code to execute successfully.
一个可选值现在是nil,但是后面的代码运行需要一个非nil值。
See also Subscripts and Functions.
Note
Assertions cause your app to terminate and are not a substitute for designing your code in such a way that invalid conditions are unlikely to arise. Nonetheless, in situations where invalid conditions are possible, an assertion is an effective way to ensure that such conditions are highlighted and noticed during development, before your app is published.
断言可能导致你的应用终止运行,所以你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布之前,有时候非法条件可能出现,这时使用断言可以快速发现问题。
网友评论