常量和变量
用 let 来声明常量,用 var 来声明变量。代码中尽量使用let,必要的时候改用var。
类型注解Type Annotations
定义的时候指定类型,就是类型注解。大多数时候不需要,因为类型可以通过初始值推断出来。
一般没有初始值的定义需要添加类型注解,比如var welcomeMessage: String
输出常量和变量
你可以用 print(_:separator:terminator:) 函数来输出当前常量或变量的值。separator 和 terminator 参数具有默认值,一般不需要修改。
Swift 用字符串插值(string interpolation)的方式把常量名或者变量名当做占位符加入到长字符串中,Swift 会用当前常量或变量的值替换这些占位符。将常量或变量名放入圆括号中,并在开括号前使用反斜杠将其转义:
var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
// friendlyWelcome 现在是 "Bonjour!"
print("The current value of friendlyWelcome is \(friendlyWelcome)")
// 输出“The current value of friendlyWelcome is Bonjour!”
注释
单行注释用//,多行注释用/**/;多行注释可以嵌套。
分号
语句末尾的分号可加可不加。一般情况下不需要加。
整数
- 你可以访问不同整数类型的 min 和 max 属性来获取对应类型的最小值和最大值
let minValue = UInt8.min // minValue 为 0,是 UInt8 类型
let maxValue = UInt8.max // maxValue 为 255,是 UInt8 类型
- 一般情况,使用Int;必要的时候才使用UInt
浮点数
Double 表示64位浮点数。当你需要存储很大或者很高精度的浮点数时请使用此类型。
Float 表示32位浮点数。精度要求不高的话可以使用此类型。
- 优先使用Double
数值型字面量
- 整数字面量可以被写作:
一个十进制数,没有前缀;
一个二进制数,前缀是 0b;
一个八进制数,前缀是 0o;
一个十六进制数,前缀是 0x;
let decimalInteger = 17
let binaryInteger = 0b10001 // 二进制的17
let octalInteger = 0o21 // 八进制的17
let hexadecimalInteger = 0x11 // 十六进制的17
- 浮点字面量可以是十进制(没有前缀)或者是十六进制(前缀是 0x )。
如果一个十进制数的指数为 exp,那这个数相当于基数和10^exp 的乘积。
如果一个十六进制数的指数为 exp,那这个数相当于基数和2^exp 的乘积。
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1 // 12.1875 × 10^1
let hexadecimalDouble = 0xC.3p0 // (12 + 3 / 16) * 2 ^ 0 = 12.1875
- 数值类字面量可以包括额外的格式来增强可读性。整数和浮点数都可以添加额外的零并且包含下划线,并不会影响字面量。
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
数值型类型转换
SomeType(ofInitialValue) 是调用 Swift 构造器并传入一个初始值的默认方法。C语言中的是类型强制转换,这里的是构造器,写法是不一样的。
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one) // C语言的强制转换:(UInt16)one;两者写法不一样,原理不一样。
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi = Double(three) + pointOneFourOneFiveNine
// pi 等于 3.14159,所以被推测为 Double 类型
类型别名
类型别名(type aliases)就是给现有类型定义另一个名字。你可以使用 typealias 关键字来定义类型别名。
typealias AudioSample = UInt16 // 这个类似C中的typedef,不过写法不同
布尔值
Swift 有一个基本的布尔(Boolean)类型,叫做 Bool。布尔值指逻辑上的值,因为它们只能是真或者假。Swift 有两个布尔常量,true 和 false。
和C不同,if后面只能带Bool类型,不能带1之类的整数。
元组
元组(tuples)把多个值组合成一个复合值。元组内的值可以是任意类型,并不要求是相同类型。
let http404Error = (404, "Not Found")
// http404Error 的类型是 (Int, String),值是 (404, "Not Found")
// 你可以将一个元组的内容分解(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”
当遇到一些相关值的简单分组时,元组是很有用的。元组不适合用来创建复杂的数据结构。如果你的数据结构比较复杂,不要使用元组,用类或结构体去建模。
可选类型
可选类型表示两种可能: 或者有值, 你可以解析可选类型访问这个值, 或者根本没有值。
- Swift 的 nil 和 Objective-C 中的 nil 并不一样。在 Objective-C 中,nil 是一个指向不存在对象的指针。在 Swift 中,nil 不是指针——它是一个确定的值,用来表示值缺失。任何类型的可选状态都可以被设置为 nil,不只是对象类型。
var serverResponseCode: Int? = 404
// serverResponseCode 包含一个可选的 Int 值 404
serverResponseCode = nil
// serverResponseCode 现在不包含值
// 如果你声明一个可选常量或者变量但是没有赋值,它们会自动被设置为 nil:
var surveyAnswer: String?
// surveyAnswer 被自动设置为 nil
- 使用可选绑定(optional binding)来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。
var possibleNumber = "123"
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”
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”
- 强制解析,隐式解析,这两种可选类型都是加!有可能会崩溃,非必要时不要用。
错误处理
一个函数可以通过在声明中添加 throws 关键词来抛出错误消息。当你的函数能抛出错误消息时,你应该在表达式中前置 try 关键词。
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
使用断言进行调试
- 你可以调用 Swift 标准库的 assert(::file:line:) 函数来写一个断言。向这个函数传入一个结果为 true 或者 false 的表达式以及一条信息,当表达式的结果为 false 的时候这条信息会被显示:
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
// 因为 age < 0,所以断言会触发
- 如果代码已经检查了条件,你可以使用 assertionFailure(_:file:line:) 函数来表明断言失败了
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.")
}
强制执行先决条件
当一个条件可能为假,但是继续执行代码要求条件必须为真的时候,需要使用先决条件。例如使用先决条件来检查是否下标越界,或者来检查是否将一个正确的参数传给函数。你可以使用全局 precondition(::file:line:) 函数来写一个先决条件。
// 在一个下标的实现里...
precondition(index > 0, "Index must be greater than zero.")
空合运算符
空合运算符(a ?? b)将对可选类型 a 进行空判断,如果 a 包含一个值就进行解包,否则就返回一个默认值 b。
let defaultColorName = "red"
var userDefinedColorName: String? //默认值为 nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 的值为空,所以 colorNameToUse 的值为 "red"
区间运算符
- 闭区间运算符(a...b)定义一个包含从 a 到 b(包括 a 和 b)的所有值的区间。
for index in 1...5 {
print("\(index) * 5 = \(index * 5)")
}
// 1 * 5 = 5
// 2 * 5 = 10
// 3 * 5 = 15
// 4 * 5 = 20
// 5 * 5 = 25
- 半开区间运算符(a..<b)定义一个从 a 到 b 但不包括 b 的区间。
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
print("第 \(i + 1) 个人叫 \(names[i])")
}
// 第 1 个人叫 Anna
// 第 2 个人叫 Alex
// 第 3 个人叫 Brian
// 第 4 个人叫 Jack
- 闭区间操作符有另一个表达形式,可以表达往一侧无限延伸的区间 —— 例如,一个包含了数组从索引 2 到结尾的所有值的区间。在这些情况下,你可以省略掉区间操作符一侧的值。这种区间叫做单侧区间,因为操作符只有一侧有值。
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names[2...] {
print(name)
}
// Brian
// Jack
for name in names[...2] {
print(name)
}
// Anna
// Alex
// Brian