The Swift Programming Language

基础部分(The Basics)web

1.0 翻译:numbbbbb, lyuka, JaySurplus 校对:lslxdx编程

2.0 翻译+校对:xtymichael安全

2.1 翻译:Prayer 校对:shanks,overtrue 本页包含内容:服务器

常量和变量 声明常量和变量 类型标注 常量和变量的命名 输出常量和变量 注释 分号 整数 整数范围 Int UInt 浮点数 类型安全和类型推断 数值型字面量 数值型类型转换 整数转换 数整数和浮点数转换 类型别名 布尔值 元组 可选 nil if 语句以及强制解析 可选绑定 隐式解析可选类型 错误处理 断言 Swift 是一门开发 iOS, OS X 和 watchOS 应用的新语言。然而,若是你有 C 或者 Objective-C 开发经验的话,你会发现 Swift 的不少内容都是你熟悉的。数据结构

Swift 包含了 C 和 Objective-C 上全部基础数据类型,Int表示整型值;Double和Float表示浮点型值;Bool是布尔型值;String是文本型数据。Swift 还提供了三个基本的集合类型,Array,Set和Dictionary,详见集合类型。架构

就像 C 语言同样,Swift 使用变量来进行存储并经过变量名来关联值。在 Swift 中,普遍的使用着值不可变的变量,它们就是常量,并且比 C 语言的常量更强大。在 Swift 中,若是你要处理的值不须要改变,那使用常量可让你的代码更加安全而且更清晰地表达你的意图。app

除了咱们熟悉的类型,Swift 还增长了 Objective-C 中没有的高阶数据类型好比元组(Tuple)。元组可让你建立或者传递一组数据,好比做为函数的返回值时,你能够用一个元组能够返回多个值。less

Swift 还增长了可选(Optional)类型,用于处理值缺失的状况。可选表示“那儿有一个值,而且它等于 x ”或者“那儿没有值”。可选有点像在 Objective-C 中使用nil,可是它能够用在任何类型上,不只仅是类。可选类型比 Objective-C 中的nil指针更加安全也更具表现力,它是 Swift 许多强大特性的重要组成部分。编程语言

Swift 是一门类型安全的语言,可选类型就是一个很好的例子。Swift 可让你清楚地知道值的类型。若是你的代码指望获得一个String,类型安全会阻止你不当心传入一个Int。你能够在开发阶段尽早发现并修正错误。函数

常量和变量 常量和变量把一个名字(好比maximumNumberOfLoginAttempts或者welcomeMessage)和一个指定类型的值(好比数字10或者字符串"Hello")关联起来。常量的值一旦设定就不能改变,而变量的值能够随意更改。

声明常量和变量

常量和变量必须在使用前声明,用let来声明常量,用var来声明变量。下面的例子展现了如何用常量和变量来记录用户尝试登陆的次数:

let maximumNumberOfLoginAttempts = 10 var currentLoginAttempt = 0 这两行代码能够被理解为:

“声明一个名字是maximumNumberOfLoginAttempts的新常量,并给它一个值10。而后,声明一个名字是currentLoginAttempt的变量并将它的值初始化为0。”

在这个例子中,容许的最大尝试登陆次数被声明为一个常量,由于这个值不会改变。当前尝试登陆次数被声明为一个变量,由于每次尝试登陆失败的时候都须要增长这个值。

你能够在一行中声明多个常量或者多个变量,用逗号隔开:

var x = 0.0, y = 0.0, z = 0.0 注意: 若是你的代码中有不须要改变的值,请使用let关键字将它声明为常量。只将须要改变的值声明为变量。

类型标注

当你声明常量或者变量的时候能够加上类型标注(type annotation),说明常量或者变量中要存储的值的类型。若是要添加类型标注,须要在常量或者变量名后面加上一个冒号和空格,而后加上类型名称。

这个例子给welcomeMessage变量添加了类型标注,表示这个变量能够存储String类型的值:

var welcomeMessage: String 声明中的冒号表明着“是...类型”,因此这行代码能够被理解为:

“声明一个类型为String,名字为welcomeMessage的变量。”

“类型为String”的意思是“能够存储任意String类型的值。”

welcomeMessage变量如今能够被设置成任意字符串:

welcomeMessage = "Hello" 你能够在一行中定义多个一样类型的变量,用逗号分割,并在最后一个变量名以后添加类型标注:

var red, green, blue: Double 注意: 通常来讲你不多须要写类型标注。若是你在声明常量或者变量的时候赋了一个初始值,Swift能够推断出这个常量或者变量的类型,请参考类型安全和类型推断。在上面的例子中,没有给welcomeMessage赋初始值,因此变量welcomeMessage的类型是经过一个类型标注指定的,而不是经过初始值推断的。

常量和变量的命名

你能够用任何你喜欢的字符做为常量和变量名,包括 Unicode 字符:

let π = 3.14159 let 你好 = "你好世界" let 🐶🐮 = "dogcow" 常量与变量名不能包含数学符号,箭头,保留的(或者非法的)Unicode 码位,连线与制表符。也不能以数字开头,可是能够在常量与变量名的其余地方包含数字。

一旦你将常量或者变量声明为肯定的类型,你就不能使用相同的名字再次进行声明,或者改变其存储的值的类型。同时,你也不能将常量与变量进行互转。

注意: 若是你须要使用与Swift保留关键字相同的名称做为常量或者变量名,你可使用反引号(`)将关键字包围的方式将其做为名字使用。不管如何,你应当避免使用关键字做为常量或变量名,除非你别无选择。 你能够更改现有的变量值为其余同类型的值,在下面的例子中,friendlyWelcome的值从"Hello!"改成了"Bonjour!":

var friendlyWelcome = "Hello!" friendlyWelcome = "Bonjour!" // friendlyWelcome 如今是 "Bonjour!" 与变量不一样,常量的值一旦被肯定就不能更改了。尝试这样作会致使编译时报错:

let languageName = "Swift" languageName = "Swift++" // 这会报编译时错误 - languageName 不可改变

输出常量和变量

你能够用print(_:separator:terminator:)函数来输出当前常量或变量的值:

print(friendlyWelcome) // 输出 "Bonjour!" print(:separator:terminator:)是一个用来输出一个或多个值到适当输出区的全局函数。若是你用 Xcode,print(:separator:terminator:)将会输出内容到“console”面板上。separator和terminator参数具备默认值,所以你调用这个函数的时候能够忽略它们。默认状况下,该函数经过添加换行符来结束当前行。若是不想换行,能够传递一个空字符串给terminator参数--例如,print(someValue, terminator:"")。关于参数默认值的更多信息,请参考默认参数值。

Swift 用字符串插值(string interpolation)的方式把常量名或者变量名当作占位符加入到长字符串中,Swift 会用当前常量或变量的值替换这些占位符。将常量或变量名放入圆括号中,并在开括号前使用反斜杠将其转义:

print("The current value of friendlyWelcome is (friendlyWelcome)") // 输出 "The current value of friendlyWelcome is Bonjour! 注意: 字符串插值全部可用的选项,请参考字符串插值。

注释 请将你的代码中的非执行文本注释成提示或者笔记以方便你未来阅读。Swift 的编译器将会在编译代码时自动忽略掉注释部分。

Swift 中的注释与 C 语言的注释很是类似。单行注释以双正斜杠(//)做为起始标记:

// 这是一个注释 你也能够进行多行注释,其起始标记为单个正斜杠后跟随一个星号(/),终止标记为一个星号后跟随单个正斜杠(/):

/* 这是一个, 多行注释 */ 与 C 语言多行注释不一样,Swift 的多行注释能够嵌套在其它的多行注释之中。你能够先生成一个多行注释块,而后在这个注释块之中再嵌套成第二个多行注释。终止注释时先插入第二个注释块的终止标记,而后再插入第一个注释块的终止标记:

/* 这是第一个多行注释的开头 /* 这是第二个被嵌套的多行注释 */ 这是第一个多行注释的结尾 */ 经过运用嵌套多行注释,你能够快速方便的注释掉一大段代码,即便这段代码之中已经含有了多行注释块。

分号 与其余大部分编程语言不一样,Swift 并不强制要求你在每条语句的结尾处使用分号(;),固然,你也能够按照你本身的习惯添加分号。有一种状况下必需要用分号,即你打算在同一行内写多条独立的语句:

let cat = "🐱"; print(cat) // 输出 "🐱"

整数 整数就是没有小数部分的数字,好比42和-23。整数能够是有符号(正、负、零)或者无符号(正、零)。

Swift 提供了8,16,32和64位的有符号和无符号整数类型。这些整数类型和 C 语言的命名方式很像,好比8位无符号整数类型是UInt8,32位有符号整数类型是Int32。就像 Swift 的其余类型同样,整数类型采用大写命名法。

整数范围

你能够访问不一样整数类型的min和max属性来获取对应类型的最小值和最大值:

let minValue = UInt8.min // minValue 为 0,是 UInt8 类型 let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型 min和max所传回值的类型,正是其所对的整数类型(如上例UInt8, 所传回的类型是UInt8),可用在表达式中相同类型值旁。

Int

通常来讲,你不须要专门指定整数的长度。Swift 提供了一个特殊的整数类型Int,长度与当前平台的原生字长相同:

在32位平台上,Int和Int32长度相同。 在64位平台上,Int和Int64长度相同。 除非你须要特定长度的整数,通常来讲使用Int就够了。这能够提升代码一致性和可复用性。即便是在32位平台上,Int能够存储的整数范围也能够达到-2,147,483,648~2,147,483,647,大多数时候这已经足够大了。

UInt

Swift 也提供了一个特殊的无符号类型UInt,长度与当前平台的原生字长相同:

在32位平台上,UInt和UInt32长度相同。 在64位平台上,UInt和UInt64长度相同。 注意: 尽可能不要使用UInt,除非你真的须要存储一个和当前平台原生字长相同的无符号整数。除了这种状况,最好使用Int,即便你要存储的值已知是非负的。统一使用Int能够提升代码的可复用性,避免不一样类型数字之间的转换,而且匹配数字的类型推断,请参考类型安全和类型推断。

浮点数 浮点数是有小数部分的数字,好比3.14159,0.1和-273.15。

浮点类型比整数类型表示的范围更大,能够存储比Int类型更大或者更小的数字。Swift 提供了两种有符号浮点数类型:

Double表示64位浮点数。当你须要存储很大或者很高精度的浮点数时请使用此类型。 Float表示32位浮点数。精度要求不高的话可使用此类型。 注意: Double精确度很高,至少有15位数字,而Float只有6位数字。选择哪一个类型取决于你的代码须要处理的值的范围。

类型安全和类型推断 Swift 是一个类型安全(type safe)的语言。类型安全的语言可让你清楚地知道代码要处理的值的类型。若是你的代码须要一个String,你绝对不可能不当心传进去一个Int。

因为 Swift 是类型安全的,因此它会在编译你的代码时进行类型检查(type checks),并把不匹配的类型标记为错误。这可让你在开发的时候尽早发现并修复错误。

当你要处理不一样类型的值时,类型检查能够帮你避免错误。然而,这并非说你每次声明常量和变量的时候都须要显式指定类型。若是你没有显式指定类型,Swift 会使用类型推断(type inference)来选择合适的类型。有了类型推断,编译器能够在编译代码的时候自动推断出表达式的类型。原理很简单,只要检查你赋的值便可。

由于有类型推断,和 C 或者 Objective-C 比起来 Swift 不多须要声明类型。常量和变量虽然须要明确类型,可是大部分工做并不须要你本身来完成。

当你声明常量或者变量并赋初值的时候类型推断很是有用。当你在声明常量或者变量的时候赋给它们一个字面量(literal value 或 literal)便可触发类型推断。(字面量就是会直接出如今你代码中的值,好比42和3.14159。)

例如,若是你给一个新常量赋值42而且没有标明类型,Swift 能够推断出常量类型是Int,由于你给它赋的初始值看起来像一个整数:

let meaningOfLife = 42 // meaningOfLife 会被推测为 Int 类型 同理,若是你没有给浮点字面量标明类型,Swift 会推断你想要的是Double:

let pi = 3.14159 // pi 会被推测为 Double 类型 当推断浮点数的类型时,Swift 老是会选择Double而不是Float。

若是表达式中同时出现了整数和浮点数,会被推断为Double类型:

let anotherPi = 3 + 0.14159 // anotherPi 会被推测为 Double 类型 原始值3没有显式声明类型,而表达式中出现了一个浮点字面量,因此表达式会被推断为Double类型。

数值型字面量 整数字面量能够被写做:

一个十进制数,没有前缀 一个二进制数,前缀是0b 一个八进制数,前缀是0o 一个十六进制数,前缀是0x 下面的全部整数字面量的十进制值都是17:

let decimalInteger = 17 let binaryInteger = 0b10001 // 二进制的17 let octalInteger = 0o21 // 八进制的17 let hexadecimalInteger = 0x11 // 十六进制的17 浮点字面量能够是十进制(没有前缀)或者是十六进制(前缀是0x)。小数点两边必须有至少一个十进制数字(或者是十六进制的数字)。十进制浮点数也能够有一个可选的指数(exponent),经过大写或者小写的 e 来指定;十六进制浮点数必须有一个指数,经过大写或者小写的 p 来指定。

若是一个十进制数的指数为exp,那这个数至关于基数和10^exp的乘积:

1.25e2 表示 1.25 × 10^2,等于 125.0。 1.25e-2 表示 1.25 × 10^-2,等于 0.0125。 若是一个十六进制数的指数为exp,那这个数至关于基数和2^exp的乘积:

0xFp2 表示 15 × 2^2,等于 60.0。 0xFp-2 表示 15 × 2^-2,等于 3.75。 下面的这些浮点字面量都等于十进制的12.1875:

let decimalDouble = 12.1875 let exponentDouble = 1.21875e1 let hexadecimalDouble = 0xC.3p0 数值类字面量能够包括额外的格式来加强可读性。整数和浮点数均可以添加额外的零而且包含下划线,并不会影响字面量:

let paddedDouble = 000123.456 let oneMillion = 1_000_000 let justOverOneMillion = 1_000_000.000_000_1

数值型类型转换 一般来说,即便代码中的整数常量和变量已知非负,也请使用Int类型。老是使用默认的整数类型能够保证你的整数常量和变量能够直接被复用而且能够匹配整数类字面量的类型推断。

只有在必要的时候才使用其余整数类型,好比要处理外部的长度明确的数据或者为了优化性能、内存占用等等。使用显式指定长度的类型能够及时发现值溢出而且能够暗示正在处理特殊数据。

整数转换

不一样整数类型的变量和常量能够存储不一样范围的数字。Int8类型的常量或者变量能够存储的数字范围是-128~127,而UInt8类型的常量或者变量能存储的数字范围是0~255。若是数字超出了常量或者变量可存储的范围,编译的时候会报错:

let cannotBeNegative: UInt8 = -1 // UInt8 类型不能存储负数,因此会报错 let tooBig: Int8 = Int8.max + 1 // Int8 类型不能存储超过最大值的数,因此会报错 因为每种整数类型均可以存储不一样范围的值,因此你必须根据不一样状况选择性使用数值型类型转换。这种选择性使用的方式,能够预防隐式转换的错误并让你的代码中的类型转换意图变得清晰。

要将一种数字类型转换成另外一种,你要用当前值来初始化一个指望类型的新数字,这个数字的类型就是你的目标类型。在下面的例子中,常量twoThousand是UInt16类型,然而常量one是UInt8类型。它们不能直接相加,由于它们类型不一样。因此要调用UInt16(one)来建立一个新的UInt16数字并用one的值来初始化,而后使用这个新数字来计算:

let twoThousand: UInt16 = 2_000 let one: UInt8 = 1 let twoThousandAndOne = twoThousand + UInt16(one) 如今两个数字的类型都是UInt16,能够进行相加。目标常量twoThousandAndOne的类型被推断为UInt16,由于它是两个UInt16值的和。

SomeType(ofInitialValue)是调用 Swift 构造器并传入一个初始值的默认方法。在语言内部,UInt16有一个构造器,能够接受一个UInt8类型的值,因此这个构造器能够用现有的UInt8来建立一个新的UInt16。注意,你并不能传入任意类型的值,只能传入UInt16内部有对应构造器的值。不过你能够扩展示有的类型来让它能够接收其余类型的值(包括自定义类型),请参考扩展。

整数和浮点数转换

整数和浮点数的转换必须显式指定类型:

let three = 3 let pointOneFourOneFiveNine = 0.14159 let pi = Double(three) + pointOneFourOneFiveNine // pi 等于 3.14159,因此被推测为 Double 类型 这个例子中,常量three的值被用来建立一个Double类型的值,因此加号两边的数类型须相同。若是不进行转换,二者没法相加。

浮点数到整数的反向转换一样行,整数类型能够用Double或者Float类型来初始化:

let integerPi = Int(pi) // integerPi 等于 3,因此被推测为 Int 类型 当用这种方式来初始化一个新的整数值时,浮点值会被截断。也就是说4.75会变成4,-3.9会变成-3。

注意: 结合数字类常量和变量不一样于结合数字类字面量。字面量3能够直接和字面量0.14159相加,由于数字字面量自己没有明确的类型。它们的类型只在编译器须要求值的时候被推测。

类型别名 类型别名(type aliases)就是给现有类型定义另外一个名字。你可使用typealias关键字来定义类型别名。

当你想要给现有类型起一个更有意义的名字时,类型别名很是有用。假设你正在处理特定长度的外部资源的数据:

typealias AudioSample = UInt16 定义了一个类型别名以后,你能够在任何使用原始名的地方使用别名:

var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound 如今是 0 本例中,AudioSample被定义为UInt16的一个别名。由于它是别名,AudioSample.min其实是UInt16.min,因此会给maxAmplitudeFound赋一个初值0。

布尔值 Swift 有一个基本的布尔(Boolean)类型,叫作Bool。布尔值指逻辑上的值,由于它们只能是真或者假。Swift 有两个布尔常量,true和false:

let orangesAreOrange = true let turnipsAreDelicious = false orangesAreOrange和turnipsAreDelicious的类型会被推断为Bool,由于它们的初值是布尔字面量。就像以前提到的Int和Double同样,若是你建立变量的时候给它们赋值true或者false,那你不须要将常量或者变量声明为Bool类型。初始化常量或者变量的时候若是所赋的值类型已知,就能够触发类型推断,这让 Swift 代码更加简洁而且可读性更高。

当你编写条件语句好比if语句的时候,布尔值很是有用:

if turnipsAreDelicious { print("Mmm, tasty turnips!") } else { print("Eww, turnips are horrible.") } // 输出 "Eww, turnips are horrible." 条件语句,例如if,请参考控制流。

若是你在须要使用Bool类型的地方使用了非布尔值,Swift 的类型安全机制会报错。下面的例子会报告一个编译时错误:

let i = 1 if i { // 这个例子不会经过编译,会报错 } 然而,下面的例子是合法的:

let i = 1 if i == 1 { // 这个例子会编译成功 } i == 1的比较结果是Bool类型,因此第二个例子能够经过类型检查。相似i == 1这样的比较,请参考基本操做符。

和 Swift 中的其余类型安全的例子同样,这个方法能够避免错误并保证这块代码的意图老是清晰的。

元组 元组(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 print("The status code is (statusCode)") // 输出 "The status code is 404" print("The status message is (statusMessage)") // 输出 "The status message is Not Found" 若是你只须要一部分元组值,分解的时候能够把要忽略的部分用下划线(_)标记:

let (justTheStatusCode, _) = http404Error print("The status code is (justTheStatusCode)") // 输出 "The status code is 404" 此外,你还能够经过下标来访问元组中的单个元素,下标从零开始:

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" 你能够在定义元组的时候给单个元素命名:

let http200Status = (statusCode: 200, description: "OK") 给元组中的元素命名后,你能够经过名字来获取这些元素的值:

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)元组来描述是否获取成功。和只能返回一个类型的值比较起来,一个包含两个不一样类型值的元组可让函数的返回信息更有用。请参考函数参数与返回值。

注意: 元组在临时组织值的时候颇有用,可是并不适合建立复杂的数据结构。若是你的数据结构并非临时使用,请使用类或者结构体而不是元组。请参考类和结构体。

可选类型 使用可选类型(optionals)来处理值可能缺失的状况。可选类型表示:

有值,等于 x 或者

没有值 注意: C 和 Objective-C 中并无可选类型这个概念。最接近的是 Objective-C 中的一个特性,一个方法要不返回一个对象要不返回nil,nil表示“缺乏一个合法的对象”。然而,这只对对象起做用——对于结构体,基本的 C 类型或者枚举类型不起做用。对于这些类型,Objective-C 方法通常会返回一个特殊值(好比NSNotFound)来暗示值缺失。这种方法假设方法的调用者知道并记得对特殊值进行判断。然而,Swift 的可选类型可让你暗示_任意类型_的值缺失,并不须要一个特殊值。 来看一个例子。Swift 的String类型有一种构造器,做用是将一个String值转换成一个Int值。然而,并非全部的字符串均可以转换成一个整数。字符串"123"能够被转换成数字123,可是字符串"hello, world"不行。

下面的例子使用这种构造器来尝试将一个String转换成Int:

let possibleNumber = "123" let convertedNumber = Int(possibleNumber) // convertedNumber 被推测为类型 "Int?", 或者类型 "optional Int" 由于该构造器可能会失败,因此它返回一个可选类型(optional)Int,而不是一个Int。一个可选的Int被写做Int?而不是Int。问号暗示包含的值是可选类型,也就是说可能包含Int值也可能不包含值。(不能包含其余任何值好比Bool值或者String值。只能是Int或者什么都没有。)

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 语句以及强制解析

你可使用if语句和nil比较来判断一个可选值是否包含值。你可使用“相等”(==)或“不等”(!=)来执行比较。

若是可选类型有值,它将不等于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." 更多关于if语句的内容,请参考控制流。

注意: 使用!来获取一个不存在的可选值会致使运行时错误。使用!来强制解析值以前,必定要肯定可选包含一个非nil的值。

可选绑定

使用可选绑定(optional binding)来判断可选类型是否包含值,若是包含就把值赋给一个临时常量或者变量。可选绑定能够用在if和while语句中,这条语句不只能够用来判断可选类型中是否有值,同时能够将可选类型中的值赋给一个常量或者变量。if和while语句,请参考控制流。

像下面这样在if语句中写一个可选绑定:

if let constantName = someOptional { statements } 你能够像上面这样使用可选绑定来重写possibleNumber这个例子:

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" 这段代码能够被理解为:

“若是Int(possibleNumber)返回的可选Int包含一个值,建立一个叫作actualNumber的新常量并将可选包含的值赋给它。”

若是转换成功,actualNumber常量能够在if语句的第一个分支中使用。它已经被可选类型 包含的 值初始化过,因此不须要再使用!后缀来获取它的值。在这个例子中,actualNumber只被用来输出转换结果。

你能够在可选绑定中使用常量和变量。若是你想在if语句的第一个分支中操做actualNumber的值,你能够改为if var actualNumber,这样可选类型包含的值就会被赋给一个变量而很是量。

你能够包含多个可选绑定在if语句中,并使用where子句作布尔值判断。

if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < secondNumber { print("(firstNumber) < (secondNumber)") } // prints "4 < 42"

隐式解析可选类型

如上所述,可选类型暗示了常量或者变量能够“没有值”。可选能够经过if语句来判断是否有值,若是有值的话能够经过可选绑定来解析值。

有时候在程序架构中,第一次被赋值以后,能够肯定一个可选类型_总会_有值。在这种状况下,每次都要判断和解析可选值是很是低效的,由于能够肯定它总会有值。

这种类型的可选状态被定义为隐式解析可选类型(implicitly unwrapped optionals)。把想要用做可选的类型的后面的问号(String?)改为感叹号(String!)来声明一个隐式解析可选类型。

当可选类型被第一次赋值以后就能够肯定以后一直有值的时候,隐式解析可选类型很是有用。隐式解析可选类型主要被用在 Swift 中类的构造过程当中,请参考无主引用以及隐式解析可选属性。

一个隐式解析可选类型其实就是一个普通的可选类型,可是能够被当作非可选类型来使用,并不须要每次都使用解析来获取可选值。下面的例子展现了可选类型String和隐式解析可选类型String之间的区别:

let possibleString: String? = "An optional string." let forcedString: String = possibleString! // 须要惊叹号来获取值

let assumedString: String! = "An implicitly unwrapped optional string." let implicitString: String = assumedString // 不须要感叹号 你能够把隐式解析可选类型当作一个能够自动解析的可选类型。你要作的只是声明的时候把感叹号放到类型的结尾,而不是每次取值的可选名字的结尾。

注意: 若是你在隐式解析可选类型没有值的时候尝试取值,会触发运行时错误。和你在没有值的普通可选类型后面加一个惊叹号同样。 你仍然能够把隐式解析可选类型当作普通可选类型来判断它是否包含值:

if assumedString != nil { print(assumedString) } // 输出 "An implicitly unwrapped optional string." 你也能够在可选绑定中使用隐式解析可选类型来检查并解析它的值:

if let definiteString = assumedString { print(definiteString) } // 输出 "An implicitly unwrapped optional string." 注意: 若是一个变量以后可能变成nil的话请不要使用隐式解析可选类型。若是你须要在变量的生命周期中判断是不是nil的话,请使用普通可选类型。

错误处理 你可使用错误处理(error handling)来应对程序执行中可能会遇到的错误条件。

相对于可选中运用值的存在与缺失来表达函数的成功与失败,错误处理能够推断失败的缘由,并传播至程序的其余部分。

当一个函数遇到错误条件,它能报错。调用函数的地方能抛出错误消息并合理处理。

func canThrowAnError() throws { // 这个函数有可能抛出错误 } 一个函数能够经过在声明中添加throws关键词来抛出错误消息。当你的函数能抛出错误消息时, 你应该在表达式中前置try关键词。

do { try canThrowAnError() // 没有错误消息抛出 } catch { // 有一个错误消息抛出 } 一个do语句建立了一个新的包含做用域,使得错误能被传播到一个或多个catch从句。

这里有一个错误处理如何用来应对不一样错误条件的例子。

func makeASandwich() throws { // ... }

do { try makeASandwich() eatASandwich() } catch Error.OutOfCleanDishes { washDishes() } catch Error.MissingIngredients(let ingredients) { buyGroceries(ingredients) } 在此例中,makeASandwich()(作一个三明治)函数会抛出一个错误消息若是没有干净的盘子或者某个原料缺失。由于makeASandwich()抛出错误,函数调用被包裹在try表达式中。将函数包裹在一个do语句中,任何被抛出的错误会被传播到提供的catch从句中。

若是没有错误被抛出, eatASandwich()函数会被调用。若是一个匹配Error.OutOfCleanDishes的错误被抛出,washDishes函数会被调用。若是一个匹配Error.MissingIngredients的错误被抛出,buyGroceries(_:)函数会随着被catch所捕捉到的关联值[String]被调用。

抛出,捕捉,以及传播错误会在错误处理章节详细说明。

断言 可选类型可让你判断值是否存在,你能够在代码中优雅地处理值缺失的状况。然而,在某些状况下,若是值缺失或者值并不知足特定的条件,你的代码可能没办法继续执行。这时,你能够在你的代码中触发一个断言(assertion)来结束代码运行并经过调试来找到值缺失的缘由。

使用断言进行调试

断言会在运行时判断一个逻辑条件是否为true。从字面意思来讲,断言“断言”一个条件是否为真。你可使用断言来保证在运行其余代码以前,某些重要的条件已经被知足。若是条件判断为true,代码运行会继续进行;若是条件判断为false,代码执行结束,你的应用被终止。

若是你的代码在调试环境下触发了一个断言,好比你在 Xcode 中构建并运行一个应用,你能够清楚地看到不合法的状态发生在哪里并检查断言被触发时你的应用的状态。此外,断言容许你附加一条调试信息。

你可使用全局assert(_:_file:line:)函数来写一个断言。向这个函数传入一个结果为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) 注意: 当代码使用优化编译的时候,断言将会被禁用,例如在 Xcode 中,使用默认的 target Release 配置选项来 build 时,断言会被禁用。 什么时候使用断言

当条件可能为假时使用断言,可是最终必定要_保证_条件为真,这样你的代码才能继续运行。断言的适用情景:

整数类型的下标索引被传入一个自定义下标脚本实现,可是下标索引值可能过小或者太大。 须要给函数传入一个值,可是非法的值可能致使函数不能正常执行。 一个可选值如今是nil,可是后面的代码运行须要一个非nil值。 请参考下标脚本和函数。

注意: 断言可能致使你的应用终止运行,因此你应当仔细设计你的代码来让非法条件不会出现。然而,在你的应用发布以前,有时候非法条件可能出现,这时使用断言能够快速发现问题。

相关文章
相关标签/搜索