Swift编程语言3.0----第一章 语言基础

来源:互联网 发布:董洁 王大治 知乎 编辑:程序博客网 时间:2024/06/06 03:27

Swift 编程语言 3.0 (目录参考Xcode帮助文档中的目录, 文档翻译的是EPUB格式的那个3.0文档,取自Swift官网)

Language Guide
[TOC]

1 语言基础(The Basics)

Swift 中提供了许多对应于之前C和OC中的数据类型, 如整形 Int , 浮点型 Double 和 Float , 布尔类型Bool, 文本类型String. Swift中还提供了三个重要的结构类型, 数组 Array , 集合 Set , 字典 Dictionary .

和C一样, Swift 也通过变量来存储和使用数据. 另外 Swift 中对常量作了扩展, 使得 Swift 中的常量比C中的要强大许多. 通过常量的使用, 可以让代码更加安全和清晰.

相比OC, 在 Swift 中还新增了许多新的数据类型, 比如元组 Tuple , 使用元组可以创建或传递成组的数据, 另外还可以通过函数返回元组.

Swift中还引入了 optional 的概念, 用于有值或无值的表示. Optional 可以表示两种意思, 要么是”这里有值, 而且值是x”, 要么就是”这里没有任何值”. Optional 的使用类似于使用nil, 只是Optional可以用在任何类型上, 而不仅仅是类.

Swift 是一种类型安全语言(type-safe), 即语言自身机制就可以帮助用户正确使用类型和数据. 比如某变量需要赋值一个 String, 类型安全就可以绝对避免用户错误赋值 Int.

1.1 常量和变量

常量和变量都具有名字, 并且常量在定义之后值就不能再进行修改.

1.1.1 常量和变量的定义

使用 let 关键字定义常量, 使用 var 关键字定义变量.

let max = 10var temp = 0

也可以在同一行定义多个常量或变量:

var x = 0.0, y = 0.0, z = 0.0

NOTE

若某个量中存放的数据是不变的, 那就将它定义为常量.

1.1.2 类型声明

在定义常量或变量时, 可以显式声明其类型:

var welcomeMessage: String

可以在同一行显式声明多个相同数据类型的变量:

var red, green, blue: Double

NOTE

实际编程中很少使用类型声明, 因为在提供了初值之后, 该常量或变量的类型就已经确定下来(类型推导).

1.1.3 常量和变量的命名

和C类似, 只是多了Unicode. 虽然Swift中可以用(`)内包含关键字的办法使用关键字名称, 但应尽量避免.

1.1.4 打印常量和变量

使用 print(_:separator:terminator:) 函数可以打印常量或变量:

print(welcomeMessage)

print 函数在Swift中是一个全局函数, 负责将内容输出到合适的 output 上. 比如使用 Xcode 时, print 函数会将内容输出到 Xcode 的 console 中. separator 和 terminator 参数都有默认值, 一般使用时可以忽略, 也可以指定参数:

print(someValue, terminator: "")

默认的 terminator 参数值是换行, 上面的代码指定其为空.

Swift 中使用”字符串内插”来处理字符串内的变量或常量:

let someValue = 1.0print("value is \(someValue)") //Prints "value is 1.0"

1.2 注释

基本和C中的类似, 只是多行注释在 Swift 中是可以进行嵌套的.

1.3 分号

Swift 中不强制要求表达式末尾加分号, 但如果想在单行写多条表达式, 则必须以分号分隔表达式.

let someValue = "abc";print(someValue)//Prints "abc"

1.4 整型

整数类型和数学上的整数定义类似, 42 或 -23 都是整数类型的值.

Swift中提供了有符号或无符号的整数类型, 并且有 8, 16, 32, 64bit 四种形式的整数类型. 并且命名和C中类似, 比如无符号的8位整型为 UInt8, 32位有符号整型为 Int32.

Swift中所有的数据类型都遵循大写化的命名规则.

1.4.1 整型的范围

可以使用整型的 minmax 属性查看整型的范围:

let minValue = UInt8.min    //minValue is equal to 0, and is of type UInt8.let maxValue = UInt8.max    //maxValue is equal to 255, and is of type UInt8.

1.4.2 Int类型

大多数情况下, 用户都无需考虑使用哪种特殊种类的整型, Swift中提供了额外的整数类型 Int , 并且它的大小和平台相关:

  • 当在32位平台使用时, Int 的大小为32位, 即和 Int32 相同.
  • 当在64位平台使用时, Int 的大小为64位, 即和 Int64 相同.

若没有特殊需要, 一般在代码中都使用 Int 类型来存放整数.

1.4.3 UInt类型

和 Int 类似, Swift 中提供了一种额外的无符号整形 UInt, 大小同样和平台相关:

  • 当在32位平台使用时, UInt 的大小为32位, 即和 UInt32 相同.
  • 当在64位平台使用时, UInt 的大小为64位, 即和 UInt64 相同.

NOTE

无特殊需要时, 都使用 Int 存放整型数据, 这样可以保证最少的类型转换.

1.5 浮点类型

诸如 3.1415, -273.15 这样的数都使用浮点类型存放.

相比整型, 浮点类型可以表示的范围更广, 在 Swift 中提供了两种浮点类型:

  • Double 类型: 64位浮点数
  • Float 类型: 32位浮点数

NOTE

Double 的数字精度为15位, Float 为6位. 根据工作需要及数据范围选择合适的浮点类型, 当两种类型都合适时, 尽量选择 Double.

1.6 类型安全和类型推导

Swift 是一种类型安全语言, 类型安全语言要求你在使用变量时必须明确其类型. 并且由于Swift 是类型安全的, 故在编译时, 编译器会对代码进行类型检查.

Swift 的另外一个特色是类型推导, 即不需要每处都显式指定类型.

1.7 数值常量

整型常量可以写成:

  • 无前缀的十进制数
  • 前缀为 0b 的二进制数
  • 前缀为 0o 的八进制数
  • 前缀为 0x 的十六进制数

如整数17 上述四种表示分别为:

  • 17
  • 0b10001
  • 0o21
  • 0x11

浮点型常量可以写成无前缀十进制数, 或者十六进制的(前缀0x). 但二者小数点左右都必须有数字. 十进制表示的浮点数也可以以指数形式表示, 以e来指定(10的多少次方). 十六进制浮点数必须使用p来指定指数(2的多少次方):

  • 1.25e2 表示 125.0
  • 1.25e-2 表示 0.0125
  • 0xFp2 对应十进制的 15 x 2的2次方, 或60.0
  • 0xFp-2 对应十进制的 15 x 2的-2次方, 或3.75

数值常量可以带格式化字符以帮助阅读, 整数或浮点数都可以使用多个0或下划线作为格式化字符, 并且不会对数值产生影响:

  • 123.456 可以格式化表示为 000123.456
  • 1_000
  • 1_000.000

1.8 数值类型转换

尽量使用Int类型的常量或变量来存放整型数值, 即便知道这些数值是非负的, 这样可以保证最低限度的数值类型转换.

只有当任务的确有特殊需要时, 再考虑使用其他类型.

1.8.1 整型间的类型转换

由于有8, 16, 32, 64位整型, 并且存在有符号或无符号整型, 故整型之间也存在许多的类型转换.

Int8 表示范围为 -128 到 127, 而 UInt8 表示范围为 0 到 255, 当一个数值不能满足类似范围要求而存放到该类型中, 则在编译时会报错:

let cannotBeNegative: UInt8 = -1    //这样的就会报错let tooBig: Int8 = Int8.max + 1     //超过范围也报错

上面可以看到, 不同整数类型都有不同的存放范围, 所以当有特殊要求使用特殊类型时, 必须针对不同场景来判断, 选择合适类型. 而编译器的这种超限报错, 可以最大限度减少程序运行中出现错误的机会.

由于不同类型无法直接相加, 故下面的例子中将用到类型转换:

let twoThousand: UInt16 = 2_000let one: UInt8 = 1let twoThousandAndOne = twoThousand + UInt16(one)   //转换后相加

注意转换后的范围只有是包含之前的范围, 才可以保证转换成功.

Swift 中默认的类型转换方式为: someType(someValue) . 这样的转换实际是因为UInt16有一个初始化方法, 它接受一个UInt8 类型的数值, 产生 UInt16 类型的对象, 从而实现UInt8 到 UInt16的转换. 故并非支持所有的类型, 如果遇到不支持的类型想要进行这样的类型转换, 可以使用 Extension 来扩展该类型的初始化方法以接受更多类型即可.

1.8.2 整型和浮点型之间的转换

整型和浮点型间的类型转换必须显式地进行:

let three = 3let pointOneFourOneFiveNine = 0.14159let pi = Double(three) + pointOneFourOneFiveNine    //显式转换后相加

上面代码中使用 three 来生成了一个 Double.

而浮点型到整型也是类似:

let pi = 3.14159let integerPi = Int(pi)     //使用pi转换为Int

转换时都是将小数部分截断, 无论是正数还是负数:

  • 4.75 转换后为 4
  • -3.73 转换后为 -3

NOTE

变量间类型转换的规则与常量间的类型转换不同.

由于常量在编译之前是没有显式类型的, 故只有当编译时对常量进行类型推导并进行计算, 故整型常量与浮点常量可以直接进行运算:

let pi = 3 + 0.14159

1.9 类型别名

(Type aliases )

类型别名即当前类型的替代名称. 使用 typealias 关键字来声明类型别名.

当想让类型在上下文中更具有自身意义时, 可以使用类型别名, 例如当某类型存放的是特殊类型的数值时:

typealias AudioSample = UInt16var maxAmplitudeFound = AudioSample.min //更具可读性且在上下文中意义更好识别

声明了类型别名后, 即可在任何位置使用, 当调用 AudioSample.min 时, 实际是调用 UInt16.min.

1.10 布尔类型

Swift 中拥有基本布尔类型 Bool, 即逻辑值. Swift中提供两种逻辑常量值, 即: truefalse.

Bool 类型在条件语句中尤为有用:

if turnipsAreDelicious {  print("MM, tasty turnips!")}else {  print("...")}

Swift 中的类型安全机制可以保证其他类型不会被误用为 Bool:

let i = 1if i {  //这里会报错, 因为将整型误用为布尔类型  ...}

上述代码需要修改为如下的形式:

let i = 1if i == 1 { //这样才不会报错  ...}

上面代码中 i == 1 的结果就是 Bool 类型的.

这样的做法可以避免类型误用, 并且使得代码更加清晰.

1.11 元组

元组(tuple)即一组值的集合. 元组中的值类型是任意的, 且不必全部都是相同类型. 比如 (404, "not found") 即为一个元组. 而这个元组的类型可以描述为 (Int, String).

元组中可以包含任意多个元素, 并且其中元素类型任意.

可以将元组在一条语句中将所有元素赋值给变量:

let http404Error = (404, "not found")let (statusCode, statusMessage) = http404Error//此时 statusCode为404, 类型为Int, 而statusMessage为"not found", 类型为String.

如果只需要元组中单个元素的值, 则可以像如下这样:

let (statusCode, _) = http404Error      //statusCode的值为404.

也可以使用下标访问(下标从0开始):

let statusCode = http404Error.0     //statusCode的值为404.

可以为元组中的元素添加名称, 以后则可以通过名称访问:

let http404Error = (statusCode: 404, description: "not found")//访问时可以直接使用名称访问:print(http404Error.statusCode)          //输出404.

元组的一个最大用处是作为函数的返回值. 比如某个获取网页内容的函数可能返回值为 (Int, String) 类型的元组, 相比于单个返回元素, 这样的返回值更加地方便实用.

NOTE

元组的主要用途是用于暂存一组相关的元素值, 并不适合去存放复杂的数据结构. 假如你想长期存放(超过暂存的范畴)某个数据结构, 则需要将这个数据结构以 class 或 structure 进行建模.

1.12 可选类型

(Optionals) 重点的概念内容.

一个可选类型表示的只有两种可能性: 有值, 并且可以对可选量进行解包访问; 或者是无值.

NOTE

可选类型在C或OC中都不存在, 它是Swift中新增的概念. 与它比较接近的就是返回nil或对象的函数, 假设某操作失败, 该函数返回nil, 否则返回一个对象. 但OC中的这种机制只适合于对象, 而不适合结构体, 以及C中的原子类型或是枚举类型. 对于这些类型, OC的解决方案是返回一个特殊的值来表示”没有”, 比如NSNotFound来表明无值.

而Swift中使用Optional 来让所有类型都得到统一的处理, 无值都是nil, 而不管是什么类型的变量被封装到可选类型中.

例如, Swift 中 Int 类型中有一个方法, 可以将某字符串转换为数值(只要字符串是可转换的话), 比如 String 类型的 “123.456”, 可以转换为 Int 类型的 123.456. 但如果是 “hello world” 参与转换呢?

Swift 中这样的情况都是返回的可选类型封包的变量. 即转换函数返回的是 Int? 类型的, 问号表示这个类型为可选类型, 而 Int 一看便知可选类型中封包的是 Int 型变量, Int 和问号合在一起就表示: 这个类型的变量要么有值, 并且可以解包, 要么就是nil.

1.12.1 nil

如果想将可选类型状态变为”无值”, 则可以将其赋值为nil.

var serverResponseCode: Int? = 404  //当前变量类型为可选Int类型, 值为404serverResponseCode = nil            //赋值nil后, 变量便无值了.

NOTE

Swift 中 nil 只能用在可选类型的赋值上, 这样也就保证了语言内的所有类型的统一处理. 如果某个值在特定情况下会出现无值的情况, 则必须将它声明为可选类型才能够得到恰当处理.

如果在定义可选类型的时候未赋初值, Swift 会自动将其置为 nil.

NOTE

Swift 中 nil 和 OC 中的 nil 意义并不相同. OC 中的 nil 实际是一个指针, 指向的是一个并不存在的对象. 而在 Swift 中, nil 并非一个指针, 它是某种类型的值, 表示的是该类型”无值”的特殊情况.

Swift 中任意类型的可选值都可以被赋值为 nil, 而不仅仅是对象类型.

1.12.2 If 语句和强制解包

可以使用 If 语句来判断可选量是否有值:

if convertNumber != nil {  ...}

当确定可选量中有值后, 就可以对其进行访问, 访问需要先进行解包, 解包操作符是 !, 感叹号的意思是: 已经知道里面有值, 需要解包访问, 即对可选量进行强制解包:

if convertedNumber != nil {  print("number is \(convertedNumber!)")    //强制解包后打印}

需要注意的是: 只有可选量不是nil的情况下才能使用强制解包, 否则会出现运行时错误.

1.12.3 可选绑定

可选绑定的意思是: 先看看可选量是否是 nil, 如果不是 nil , 则进行解包并将内部值赋值给某变量.

实际上就是将判断可选量是否为 nil 以及解包访问这两步操作合为一条语句.

使用可选绑定的方式有两种, 在 if 语句中使用, 在 while 语句中使用, 下面演示 if 语句中的用法:

if let constantName = someOptional {  //若 someOptional 不为 nil, 则进入语句块中, 此时 constantName 为该可选量解包之后的值}//当然也可以用变量来进行可选绑定:if var constantName = someOptional {  //同样的效果, 用法不同而已.}

可选绑定集判断与解包于一体, 故不必再在其中使用强制解包操作 !.

并且可选绑定可以同时对多个可选量进行:

if let first = Int("abc"), second = Int("404") where first < second {  //当任意一个可选绑定不成功, 或where语句为false, 则条件都被判断为不成功}

NOTE

在可选绑定中定义的常量或变量, 其生命期都只在该可选绑定的语句块范围内.

但使用 guard 语句定义的常量或变量, 生命期是在guard语句行之后. (详见Early Exit)

1.12.4 隐式已解包可选类型

在某些情况下, 有的可选量在初次设定之后就永远都拥有值(设定前为 nil), 则如果在之后的使用过程中还一直对它进行判断有无, 显然是一种浪费资源的行为.

Swift 中对于这种情况的处理方法是: 将这种情况的常量或变量声明为隐式已解包可选类型(Implicitly Unwrapped Optional, 或 IU 可选类型)

在声明 IU可选类型时, 使用 !替代?进行声明.

IU 可选类型的主要用途就是在类的初始化过程中. IU 可选量和普通的可选量本质上都是可选类型, 只是在使用时, IU可选量省去解包的一环, 可以像普通常量或变量那样直接使用.

NOTE

假如一个 IU可选类型为nil, 而外界尝试解包访问它, 仍然会造成运行时错误. 因为IU可选量和普通可选量本质都是一个样的.

使用时也可以将 IU可选量像普通的可选量那样去使用.

if assumeNotNilOptional != nil {  //...}

IU可选量也可以参与可选绑定:

if let someConstant = assumeNotNilOptional {  //...}

NOTE
只有在确定的情况下才可以使用IU可选类型, 假设该可选量有可能出现nil, 则不要将其声明为IU可选类型.

1.13 错误处理

(Error Handling)

使用 Swift 中的错误处理手段来处理程序在运行时可能遭遇的运行时错误.

Swift 中函数可以使用可选类型返回值来表示成功与失败, 而错误处理允许处理其他情况引起的失败情况, 并且如果需要, 可以将失败情况交由程序的另外部分处理.

当函数遭遇错误时, 会抛出(throw)一个错误(error). 而函数的调用者可以捕捉(catch)这个错误:

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

函数在定义时使用 throws 关键字来表示其可能会抛出错误, 而调用者看到这个函数可能会抛出错误, 自然就要使用 try 来调用这个函数了, 并且错误处理是交由 catch 语句块负责:

do {  try canThrowAnError()  //如果没有错误, 则向下, 否则跳入catch语句块中.} catch {  //...错误处理.}

上面的 do catch语句是 Swift 中特有的, 它制造了一个小的作用域, 使得错误得以在内部进行处理.

下面的代码演示一个典型的多类型错误处理过程:

func makeASandwich() throws {  //...}...do {  try makeASandwich()   //尝试制作三明治  eatASandwich()        //没有错误, 可以吃三明治} catch SandwichError.outOfCleanDishes {    //无盘子错误  washDishes()} catch SandwichError.missingIngredients(let ingredients) { //无原料错误  byGroceries(ingredients)}

1.14 断言

(Assertion)

有时当某些特定条件无法满足时, 程序便无法再继续运行下去. 这样的情况, 可以在代码中使用断言(assertion)来中断代码运行并提供调试那些缺少的或无效的值的机会.

1.14.1 利用断言调试

断言是一种运行时检查手段, 即指定一个条件状态一直为真, 若不满足条件, 则中断运行之后的代码. 使用断言可以检查许多必须的条件程序运行所需的条件状态.

当在 Debug 模式下触发断言, 比如在 Xcode 中构建和运行程序, 则可以明确地知道是在哪个位置发生的无效状态, 并且可以知道当触发断言时程序的所有状态. 并且断言还提供了打印相应信息的功能.

写断言使用到的是 Swift 标准库中提供的全局函数 assert(_:_:file:line:). 向这个函数传入假定为 true 或 false 的条件, 以及触发断言时的打印信息:

let age = -3assert(age >= 0, "A person's age cannot be less than zero.")

代码中当断言触发时, 打印一句话. 只有当 age >= 0 时, 程序才会一直执行, 否则会触发断言并终止程序运行.

assert 函数中的log参数可以不写:

assert(age >= 0)

NOTE

当以优化模式编译时, 断言就会自动关闭, 例如在 Release 模式编译的情况下.

1.14.2 断言使用时机

若某条件当代码运行时必须一直为 true, 而实际又可能会出现 false 的情况时, 就可以使用断言.

下面是一些断言使用的典型情况:

  • 当某些时候可能下标超限时
  • 函数需要某个参数, 但参数可能无效时
  • 需要某可选类型不能为空时

NOTE

断言只是作为调试工具, 而非在程序设计时使用. 当可能出现无效条件时, 断言可以保证找到该处并在开发时进行相应调整, 而不是等到程序发布后才发现可能出现无效条件.

1 0
原创粉丝点击