Swift 快速入门 (上)
本文介绍 Swift 语言的基础内容, 面向已经熟练掌握某项开发语言的开发者, 因此内容力求简洁. “Swift 快速入门” 上篇包括常用的数据类型、控制语句、函数, 以及 Swift 特有的闭包语法. 下篇将介绍 Swift 的结构体、类与继承以及协议等内容.
1. 基础
Swift 是一门强类型语言,使用关键字 var 定义变量, let 定义常量.
数据类型
常用的数据类型有:
-
整形
Int, 默认为Int64.Int16相当于short, 2 字节, [-32768, 32767].Int32相当于int, 4 字节, [-2147483648, 2147483647].Int64相当于long, 8 字节, [-9223372036854775808, 9223372036854775807].
-
字符串
Sting, 使用双引号定义字面量.-
使用三双引号可以换行, 但使用三引号时需另起一行.
-
使用
\(variable)语法定义模版字符串let to = "world" var greeting = "Hello, \(to)!" var gretting2 = """ Hello \(to) """
-
-
Double, 双精度浮点数 -
Bool,true/false
类型推断
Swift 在定义变量时会进行类型推断. 也可以通过 variable: Type 的语法显示指定类型:
let album: String = "Reputation"
let year: Int = 1989
let height: Double = 1.78
let taylorRocks: Bool = true
查看类型
通过函数 type(of: variable) 查看 variable 的类型.
type(of: year) == Int.self // true
2. 复杂数据类型
数组 Array
声明数组变量:
var a: [String] = []
var b: Array<String> = []
var c: [Any] = ["ss", 1]
数组访问不能越界, 否则会报错.
Swift 会自动推断数组类型,但当数组中有不同类型元素时要显式声明类型. 例如使用 Any 类型 (Any 是一种特殊的类型,可以表示任何类型):
var songs: [Any] = ["Shake it Off", "You Belong with Me", "Back to December", 3]`
只是声明数组变量并不会实际创建它:
var songs: [String]
songs[0] = "Shake it off"
// error: variable 'songs' passed by reference before being initialized
使用下面两种语法,则会被立即创建:
var songs: [String] = []
var songs = [String]()
集合 Set
无顺序, 不重复. 但可以被迭代. 可以通过 contains 判断某个元素是否在集合中.
let names = Set(["Hozen", "Libai", "Quyuan", "Hozen"])
// (3 elements) {"Libai", "Quyuan", "Hozen"}
for name in names {
print(name)
}
names.contains("hozen") // false
names.contains("Hozen") // true
元组
- 顺序固定.
- 一旦定义, 不可增删.
- 但可以通过
.操作符来修改.
var hozen = (name: "hozen", age: 22)
hozen.name = "hozenli"
hozen.1 = 27
hozen
// (name "hozen", age 27)
字典 Dictionary
var hozen: [String: Any] = ["name": "hozen", "age": 21]
hozen["name"]
访问不存在的键时,返回 nil,也可设置默认值:
hozen["gender", default: "unkonw"]
创建空字典时需要显示指定数据类型, 然后再添加条目
var teams = [String: String]()
teams["Paul"] = "red"
枚举 Enum
和很多语言中的枚举类型类似, 在 Swift 中枚举类型没有特别的含义, 但使用它可以使得编码更加安全高效.
enum Result {
case success
case failure
}
var res = Result.failure
res = Result.success
可以使用简略语法:
enum Weekday {
case monday, tuesday, wednesday, thursday, friday
}
var day = Weekday.monday
day = .tuesday
day = .friday
可以为枚举类型设置关联属性,以方便的适应一些场景
enum Result {
case success(code: Int, msg: String)
case failure(code: Int, msg: String)
}
var res = Result.failure(code: 404, msg: "Not Found")
当指定枚举值为 Int 类型时, Swift 会为枚举值从 0 开始自动设置原始值, 此时可以通过 rawValue 定义一个枚举值.
enum Planet: Int {
case mercury
case venus
case earth
case mars
}
let earth = Planet(rawValue: 2)
也可以手动设置枚举值的原始值,
enum ResultCode: Int {
case success = 200
case notFound = 404
}
补充和小结
不同于数组、集合、字典, Swift 中元组是一种匿名数据类型.
Swift 为 Array 和 Dictionary 设置了特殊的语法, 而 Set 没有:
var arr = [Int]()
var dict = [String, Int]()
除了各自字面量定义语法还支持尖括号的定义语法:
var arr = Array<Int>()
var dict = Dictionary<String, Int>()
var sset = Set<String>()
3. 运算符和控制语句
运算符
- 可重载,
- 可复合:
+= - 比较运算符:
><>=<=两边必须同类型. ==,!=判等会进行隐式类型转换.&&,||要求两侧都是Bool类型.
和 Python 类似, 数组可以通过 + 拼接.
条件语句
var cdt = true
if cdt {
print("true")
} else {
print("false")
}
// true\n
三元运算符 [cdt] ? [exp] : [exp]
Swift 有和 C 语言类似的三元运算符语法
switch 语句
Swift 的 switch 语句中各个 case 默认是自动结束的, 因此不需要 break, 相反当需要继续执行时需要 fallthrough.
var weather = "sunny"
switch weather {
case "rain":
print("Bring an umbrella")
case "snow":
print("Wrap up warm")
case "sunny":
print("Wear sunscreen")
fallthrough
default:
print("Enjoy your day!")
}
switch 要确保覆盖所有场景,因此很多情况下 default 是必须的,但也有例外,比如对于 enum 变量来说,容易穷尽所有 case.
范围运算符 ..< ...
范围运算符会返回 Range<Int>. 例如 1..<4 表示 1, 2, 3, 而 1...4 表示 1, 2, 3, 4.
let score = 85
switch score {
case 0..<50:
print("You failed badly.")
case 50..<85:
print("You did OK.")
default:
print("You did great!")
}
// You did great!\n
for in 循环
for 循环中的迭代变量为临时变量.
当不使用迭代变量时, 可以用 _ 代替.
for _ in 0..<4 {
print("good")
}
while 和 repeat while
var number = 18
while number <= 20 {
print(number)
number += 1
}
repeat {
print(number) // 21\n
} while number <= 20
使用 break 结束当前循环, 使用 continue 跳过当前迭代.
为循环语句添加标签可以使用 break label 跳出指定循环.
5. 函数
函数基本语法
func square(number: Int) -> Int{
number * number
}
let res: Int = square(number: 8)
需要指明形参名和参数类型. 当函数有返回值时要指明返回类型.
使用 return 语句返回, 当函数体只有一行时, 可以省略 return.
和 Python 类似, 可以使用元组返回多个值.
参数标签
除了形式参数名, Swift 还为还为参数添加了标签. 标签用于外部(调用时), 形参名用于内部, 以实现更好的语义化.
func sayHello(to name: String) {
print("hello! \(name)")
}
sayHello(to: "Allen")
调用函数时, 需要指明参数标签. 没有定义标签时使用形参名作为标签. 也可以把参数标签指定为 _ 来省略调用时的参数标签:
func sayHello(_ name: String) {
print("hello! \(name)")
}
sayHello("Allen")
默认参数值
与 C 语言类似的语法指定默认参数值
func greet(_ name: String, nicely: Bool = true) {
if nicely {
print("hello, \(name)")
} else {
print ("oh no, it's \(name) again...")
}
}
greet("Hozen")
greet("Hozen", nicely: false)
可变参数
在参数类型后添加 ... 使函数可以接受可变数量的参数, 函数体内该参数会被转换为数组. 注意调用时可变参数的写法.
func square(numbers: Int...) {
for number in numbers {
print ("\(number) squared is \(number * number)")
}
}
square(numbers: 1,2,3)
可能抛出异常的函数
可能抛出异常的函数要在返回类型前添加关键字 throws. 并在需要抛出异常的地方使用 throw 语句抛出异常.
enum PasswordError: Error {
case short, obvious
}
func checkPassword(_ password: String) throws -> String {
if password.count < 5 {
throw PasswordError.short
}
if password == "12345" {
throw PasswordError.obvious
}
if password.count < 8 {
return "OK"
} else if password.count < 10 {
return "Good"
} else {
return "Excellent"
}
}
当调用可能会抛出异常的函数时要使用 do try catch 语句.
let string = "12345"
do {
let result = try checkPassword(string)
print("Password rating: \(result)")
} catch PasswordError.short {
print("Please use a longer password.")
} catch PasswordError.obvious {
print("I have the same combination on my luggage!")
} catch {
print("There was an error.")
}
inout 参数
在 Swift 中, 参数默认都是 let 常量不可被修改. 下面的函数会报错, 因为期望修改 number 的值.
func doubleInPlace(_ number: Int) {
number *= number
// Left side of mutating operator isn't mutable: 'number' is a 'let' constant
}
如果想要修改参数的值, 需要在定义函数的参数类型前加上关键字 inout. 并且在调用时要在实参变量前加上 &.
func doubleInPlace(_ number: inout Int) {
number *= number
}
var num = 5
doubleInPlace(&num)
print(num)
这么设计的目的其实是要求函数不会对传入的值造成副作用, 除非明确的指明. inout 参数的使用类似于 C 语言的指针.
6. 闭包
函数作为“一等公民”可以被赋值给变量, 并作为参数传递, 称之为闭包. (这与 JavaScript 中闭包的概念并不完全相同)
闭包定义和调
let driving = {
print("I am driving in my car")
}
driving()
对于闭包函数, 定义参数时要使用 in 关键字, 且不可定义参数标签, 调用时也无法使用标签.
let driving = {(place: String) in
print("I am going to \(place) in my car")
}
driving("ShangHai")
闭包的返回和函数类似, 只有一行时可以省略 return.
let drivingWithReturn = { (place: String) -> String in
"I am going to \(place) in my car"
}
let message = drivingWithReturn("shanghai")
print(message)
闭包作为参数传递
闭包可以作为参数传递. 使用 func 定义的函数也可以.
闭包和函数作为参数传递时, 需要使用形如 (arg1: Int) -> Void 的语法为参数声明类型.
func travel(action: () -> Void) {
print("I'm getting ready to go")
action()
print("I arrived")
}
travel(action: driving)
尾随闭包语法
这是 Swift 中很独特且又常用的语法形式.
当函数作为最后一个参数时, 可以使用以下语法调用. 即直接使用大括号将要传入的函数以闭包的形式定义.
func travel(action: () -> Void) {
print("I'm getting ready to go")
action()
print("I arrived")
}
travel() {
print("trailing closure syntax")
}
更特别地, 当没有其他参数时可以省略小括号:
travel {
print("trailing closure syntax")
}
常见的闭包语法
-
带参数的闭包作为参数
func travel(action: (String) -> Void) { print("I'm getting ready to go") // 把 London 传入闭包 actiong action("London") print("I arrived") } travel() {(place: String) in print("trailing closure syntax with param \(place)") } -
有返回值的闭包作为参数
func travel(action: (String) -> String) { print("I'm getting ready to go") let message = action("London") print(message) print("I arrived") } travel() {(place: String) in "trailing closure syntax with param \(place)" } -
一系列简写语法
-
当闭包作为参数时, 它的参数被明确, 则定义闭包时可以省略类型
-
类似
func, 函数体只有一行时可以省略return.travel() {place in "trailing closure syntax with param \(place)" } -
参数在声明时类型被明确, 定义时甚至可以直接省略形参, 使用
$[num]代表.func travel(action: (String, Int) -> String) { print("I'm getting ready to go.") print(action("London", 60)) print("I arrived") } travel { "I'm goning to \($0) at \($1) miles hour" }
-
返回闭包
func travel() -> (String) -> Void {
return {(place) in
print("I 'm going to \(place)")
}
}
travel()("London")
// I 'm going to London
闭包作用域保存
闭包会保存作用域链, 这一点和 JavaScript 类似.
func travel() -> (String) -> Void {
var counter = 0
return {(place: String) in
counter += 1
print("I am going to \(place). (calling \(counter) times)")
}
}
let action = travel()
action("Shanghai")
// I am going to Shanghai. (calling 1 times)
action("Jinan")
// I am going to Jinan. (calling 2 times)评论
登录 — 登录后参与讨论。