基础语法
常量 & 变量
定义常量 & 变量
let PI = 3.14159
var x = 1, y = 2, z = 3
如果给赋值过的常量赋值,会在代码编译时报错。
类型标注
可以对常量或变量进行类型标注:
var welcomeMessage: String
一般很少会用到类型标注。如果你给定了常量或变量的初始值,Swift 会自己推断其类型。
常量变量的命名
可以用任何字符命名,包括 Unicode 字符:
let 你好 = "你好世界"
let 🐶🐮 = "dogcow"
但是名字不能:
包含空白字符、数学符号、箭头、私用 Unicode 字符等字符;
以数字开头;
为已定义的常量变量名,或 Swift 的关键字;
如果迫不得已想使用 Swift 的关键字作为名字,请用
`
包裹名字。
打印常量变量
使用 print(_:separator:terminator:)
打印一个值:
let hello = "hello world!"
print(hello)
注释
可以用 //
或 /* ... */
进行注释,后者支持嵌套:
// 这是一行注释.
/* 这是外层注释的开头
/* 打印 hello */
print(hello)
这是外层注释的结尾 */
分号
Swift 并不要求你在每条语句后面加上分号,除非你在一行里写了多个语句:
let cat = "🐱"; print(cat)
整数
Swift 提供有符号或无符号的 8、16、32、64 位整数。类型名与 C 语言中的类似,比如 8 位无符号为 UInt8 。
Swift 中所有类型名都是首字母大写的。
整数范围
可以访问整数类型名的 min
和 max
属性获取其最大最小值:
let minValue = UInt8.min // => 0
let maxValue = UInt8.max // => 255
Int & UInt
在 Swift 中,你可以直接用 Int 或 UInt 作为整数类型:
对于 32 位的系统 Int 和 Int32 一样大小,UInt 同理;
对于 64 位的系统,Int 和 Int64 一样大小,UInt 同理。
大部分场景还是 Int 用的多一点,除非确实是想使用无符号类型。
浮点数
Swift 中的两种浮点数类型:
Double 为 64 位浮点数类型(能保证的精度为 15 位);
Float 为 32 位浮点数类型(能保证的精度为 6 位)。
类型安全 & 类型推断
Swift 会在编译阶段对代码进行类型检查。同时,对于未明确类型的值,Swift 会进行类型推断:
// Swift 会将整数推断为 Int 类型
var age = 22
// Swift 会将浮点数推断为 Double 类型
let PI = 3.14159
数值字面量
二、八、十六进制的前缀分别为
0b
、0o
、0x
;十进制浮点数可以用
e
orE
带上指数,十六进制则用p
orP
;可以有多余的前缀 0 ;
可以用 _ 来按位数分隔,提高数值的可读性;
let a = 10 // => 10
let b = 0b10001 // => 17
let c = 1.25e-2 // => 0.0125
let d = 000123.45 // => 123.45
let e = 1_000_000 // => 1000000
数值类型的转换
// 范围外的数会直接报错
let a: UInt8 = -1 // ERROR
// 计算中发生的溢出也会直接报错
let b: Int8 = Int8.max + 1 // ERROR
let c = Int16(Int8.max) + 1 // 128
// 浮点数转为整数会直接截断,而不是四舍五入
let d = Int(3.14159) // 3
类型别名
可以用 typealias 关键字来给一个类型取别名:
typealias AudioSample = UInt16
布尔值
Swift 的布尔值类型名为 Bool ,值可为 true
or false
。
元组 Tuple
可以用元组直接将多个值包裹成一个值:
// 类型为 (Int, String)
let http404Error = (404, "Not Found")
同时可以用类似元组的语法来分解一个元组值:
let (statusCode, statusMessage) = http404Error
// 如果想忽略一个值,用下划线 _ 代替
let (justTheStatusCode, _) = http404Error
可以用索引属性访问元组值里的元素:
http404Error.0 // => 404
http404Error.1 // => "Not Found"
元组支持对元素进行命名,元素名将对应地成为属性名:
let http200Status = (statusCode: 200, description: "OK")
http404Error.statusCode // => 404
http404Error.description // => "Not Found"
在函数中,可以直接使用元组来返回多个值。但对于数据结构较为复杂的,应当使用结构体或类。
可选值 Optional
可以在类型名后面加个问号 ?
,表示该类型可能为空,即 nil
:
// 一个可选的 Int 类型
var serverResponseCode: Int? = 404
serverResponseCode = nil
// 如果没有给定初值,则初值会自动为 nil
var surveyAnswer: String? // => nil
不能给非可选类型的常量变量赋值为
nil
。
强制非空
如果确定一个可选值不为空,可以用 ! 来告诉 Swift :
if optionalNum != nil {
print("optionalNum has an integer value of \(optionalNum!).")
}
对一个空值使用
!
会触发运行时错误。
可选值绑定
可以通过 let 搭配控制语句,来提取可选值中的值:
if let num = optionalNum {
// 如果 optionalNum 不为空,则进入该分支,且 num 为其值
} else {
// 如果 optionalNum 为空,则进入该分支
}
可以用逗号 ,
来列出多个可选值绑定:
while let a = optionalA, b = optionalB, c = optionalC {
// ...
}
隐式的强制非空
在声明一个常量变量时也可以用 !
来强制其为非空:
let possibleStr: String? = "An optional string."
let forcedStr: String = possibleStr! // 需要 `!`
let assumedStr: String! = "An implicitly unwrapped optional string."
let implicitStr: String = assumedStr // 不需要 `!`
但如果赋值的对象不是一个明确给定类型、且类型非可选,则依然表现为可选值:
let optionalStr = assumedStr // optionalStr 类型为 `String?`
隐式的强制非空可选值也可以进行可选值绑定。与普通的可选值的区别在于,非空的情况分支里不再需要 ! 来强制非空:
if let definiteStr = assumedStr {
print(definiteStr)
}
错误处理
函数声明时可以用 throws 表明可能会抛出错误:
func canThrowAnError() throws {
// this function may or may not throw an error
}
错误可以用 do-catch 语句捕获:
do {
try canThrowAnError()
// no error was thrown
} catch {
// an error was thrown
}
对不同的错误可以定义相应的处理:
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
断言 & 前置条件
断言( Assertion )一般是用于开发阶段发现错误;
前置条件( Preconditiaon )一般是用于生产阶段检测问题。
两者都是用在运行时的。与错误处理不同,断言 or 前置条件一旦触发则会导致程序终止。
使用断言进行调试
可以用 assert(_:_:file:line:)
进行断言:
let age = -3
assert(age >= 0, "一个人的年龄不可能小于 0 。") // 会导致失败
或者用 assertionFailure(_:file:line:)
直接宣告失败:
if age > 10 {
print("你可能在上中学。")
} else if age >= 0 {
print("你可能在上幼儿园。")
} else {
assertionFailure("一个人的年龄不可能小于 0 。")
}
使用前置条件来强制判断
可以用 precondition(_:_:file:line:)
进行前置条件判断:
// 在一个下标方法中 ...
precondition(index > 0, "索引值必须大于 0 。")
同样可以用 preconditionFailure(_:file:line:)
直接宣告失败。