一、Swift基础语法
1.6 函数(Function)
函数是代码复用的核心,Swift 支持多种函数特性(外部参数、可变参数、输入输出参数等)。
1. 函数基本定义
- 语法:
func 函数名(参数列表) -> 返回类型 { 函数体 },无返回值时返回类型可省略或写Void。
Swift
// 1. 有返回值函数(返回 String)
func runoob(site: String) -> String {
return site
}
print(runoob(site: "www.bytedance.com")) // 输出:www.bytedance.com
// 2. 多参数函数
func runoob(name: String, site: String) -> String {
return name + ":" + site
}
print(runoob(name: "字节跳动", site: "www.bytedance.com")) // 输出:字节跳动:www.bytedance.com
// 3. 无返回值函数(省略 -> Void)
func siteName() {
print("www.bytedance.com")
}
siteName() // 输出:www.bytedance.com
// 4. 返回元组(支持多返回值)
func minMax(array: [Int]) -> (min: Int, max: Int)? { // 返回可选元组(处理空数组)
if array.isEmpty { return nil }
var currentMin = array[0], currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin { currentMin = value }
else if value > currentMax { currentMax = value }
}
return (currentMin, currentMax)
}
// 调用返回元组的函数(用可选绑定解析)
let boundArray: [Int] = [3, 54, 21, 214, 6, 0]
if let minMaxValue = minMax(array: boundArray) {
print("minValue = \(minMaxValue.min) maxValue = \(minMaxValue.max)") // 输出:min 0, max 214
}
2. 函数参数特性
(1)外部参数名
- 为参数添加外部名(调用时需显式传入),语法:
func 函数名(外部名 内部名: 类型) -> 返回类型。 - 若外部名与内部名相同,可简写为
#内部名(Swift 3+ 推荐显式写外部名)。
Swift
// 外部参数名:firstArg(外部)、a(内部);secondArg(外部)、b(内部)
func pow(firstArg a: Int, secondArg b: Int) -> Int {
var res = a
for _ in 1..<b {
res *= a
}
print("result = \(res)")
return res
}
pow(firstArg: 2, secondArg: 10) // 调用时必须传入外部名,输出:1024
(2)可变参数
- 允许传入任意个数的相同类型参数,语法:
参数名: 类型...(函数内部视为数组)。
Swift
// 泛型可变参数(支持任意类型)
func vari<N>(members: N...) {
for i in members {
print(i, terminator: " ")
}
print()
}
vari(members: 1, 2, 3, 4, 5) // 输出:1 2 3 4 5
vari(members: 4.5, 3.1, 5.6) // 输出:4.5 3.1 5.6
vari(members: "sdsad", "324", "x", "admin", "abc") // 输出:sdsad 324 x admin abc
(3)输入输出参数(inout)
- 允许函数修改外部变量的值(需传入变量地址
&),语法:inout 参数名: 类型。
Swift
// 交换两个 Int 变量的值
func swapTwoInts(_ a: inout Int, _ b: inout Int) { // _ 表示省略外部名
let temporaryA = a
a = b
b = temporaryA
}
var x = 10, y = 20
swapTwoInts(&x, &y) // 传入变量地址
print("x = \(x) , y = \(y)") // 输出:x = 20 , y = 10
3. 函数类型与高阶函数
(1)函数类型
- 函数也是一种类型,格式:
(参数类型列表) -> 返回类型,可赋值给变量/常量。
Swift
// 定义函数类型变量(匹配 pow 函数的类型:(Int, Int) -> Int)
var powFunc: (Int, Int) -> Int = pow
powFunc(2, 5) // 调用,输出:32
(2)函数作为参数/返回值
- 函数可作为参数传入其他函数,或作为返回值返回(高阶函数特性)。
Swift
// 函数作为参数
func sum(a: Int, b: Int) -> Int {
return a + b
}
func another(addition: (Int, Int) -> Int, a: Int, b: Int) {
print("输出结果: \(addition(a, b))")
}
another(addition: sum, a: 40, b: 89) // 输出:129
// 函数作为返回值(嵌套函数)
func calcDecrement(forDecrement total: Int) -> () -> Int {
var overallDecrement = 0
// 嵌套函数:捕获外部变量 overallDecrement(闭包特性)
func decrementer() -> Int {
overallDecrement -= total
return overallDecrement
}
return decrementer // 返回嵌套函数
}
let decrem = calcDecrement(forDecrement: 30)
print(decrem()) // 输出:-30
print(decrem()) // 输出:-60(状态被保留)
1.7 闭包(Closure)
闭包是"自包含的函数代码块",可捕获外部变量,支持语法简化,是 Swift 高阶特性的核心。
1. 闭包基本定义
- 语法:
{ (参数列表) -> 返回类型 in 闭包体 },in分隔参数/返回值与闭包体。
Swift
// 1. 无参数无返回值闭包
let studname = { print("Swift 闭包实例") }
studname() // 输出:Swift 闭包实例
// 2. 有参数有返回值闭包
let divide = { (val1: Int, val2: Int) -> Int in
return val1 / val2
}
print(divide(2, 1)) // 输出:2
2. 闭包语法简化
Swift 对闭包有多重简化规则,核心是"能省则省":
(1)类型推断(省略参数类型与返回类型)
若上下文可推断出参数类型和返回类型,可省略。
Swift
// 原闭包:sorted(by: {(s1: Int, s2: Int) -> Bool in return s1 < s2})
let sortedValues = [2, 3423, 234, 23, 3]
// 简化后:省略参数类型和返回类型(上下文推断为 (Int, Int) -> Bool)
let resultValues = sortedValues.sorted(by: { s1, s2 in s1 < s2 })
(2)参数缩写($0、$1、$2...)
用 $0 表示第一个参数,$1 表示第二个参数,以此类推,可省略参数列表和 in。
Swift
// 进一步简化:用 $0、$1 代替参数
let resultValues2 = sortedValues.sorted(by: { $0 < $1 })
(3)尾随闭包(Trailing Closure)
若闭包是函数的最后一个参数,可将闭包写在函数括号外,甚至省略括号。
Swift
// 尾随闭包写法(闭包在括号外)
let resultValues3 = sortedValues.sorted { $0 < $1 }
// 若函数无其他参数,可省略括号:sorted { $0 < $1 }
(4)运算符函数简化
若闭包体仅调用一个二元运算符,可直接传入运算符函数。
Swift
// 最终简化:< 是 (Int, Int) -> Bool 类型的运算符函数
let resultValues4 = sortedValues.sorted(by: <)
print(resultValues4) // 输出:[2, 3, 23, 234, 3423]
3. 闭包捕获值
闭包可捕获外部作用域的变量/常量,即使外部作用域销毁,捕获的值仍可访问(捕获机制由 ARC 管理)。
Swift
var capturedValue = 100
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0 // 外部变量,被闭包捕获
func incrementor() -> Int {
runningTotal += amount // 捕获 runningTotal
return runningTotal
}
return incrementor
}
// 闭包捕获 runningTotal,状态被保留
let incrementByTen = makeIncrementor(forIncrement: capturedValue)
print(incrementByTen()) // 输出:100
print(incrementByTen()) // 输出:200(runningTotal 累计)
// 多个闭包共享同一捕获值
let alsoIncrementByTen = incrementByTen
print(alsoIncrementByTen()) // 输出:300(与 incrementByTen 共享 runningTotal)
1.8 枚举(Enumeration)
枚举是"一组相关值的集合",Swift 枚举支持关联值、原始值、方法等高级特性。
1. 枚举基本定义
- 语法:
enum 枚举名 { case 成员1, 成员2, ... },成员无默认值(需显式关联或指定原始值)。
Swift
enum DayOfWeek {
case Sunday, Monday, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, Saturday
}
// 使用枚举
var weekDay: DayOfWeek // 延迟初始化
weekDay = .Sunday // 类型可推断时,可省略枚举名
// switch 匹配枚举(需覆盖所有成员或加 default)
switch weekDay {
case .Sunday: print("星期天")
case .Monday: print("星期一")
case .TUESDAY: print("星期二")
// ... 其他成员
default: print("其他星期")
}
2. 枚举关联值(Associated Values)
- 为枚举成员关联自定义类型的值,类似"带参数的枚举",常用于表示"同一抽象类型的不同具体情况"。
Swift
// 枚举关联值:表示学生的两种信息(姓名/分数)
enum Student {
case Name(String) // 关联 String 类型
case Mark(Int, Int, Int) // 关联三个 Int 类型
}
// 赋值关联值
var studDetails = Student.Name("Runoob")
var studMarks = Student.Mark(98, 97, 95)
// 提取关联值(switch 绑定)
switch studMarks {
case .Name(let studName):
print("学生的名字是: \(studName)。")
case .Mark(let Mark1, let Mark2, let Mark3):
print("学生的成绩是: \(Mark1),\(Mark2),\(Mark3)。") // 输出:98,97,95
}
3. 枚举原始值(Raw Values)
- 为枚举成员指定默认值(所有成员的原始值类型相同),支持自动递增(如 Int 类型),原始值可通过
rawValue属性访问。
Swift
// 枚举原始值:Int 类型,January 为 1,后续成员自动 +1
enum Month: Int {
case January = 1, February, March, April, May, June, July, August, September, October, November, December
}
// 访问原始值
let yearMonthRaw = Month.February.rawValue
print("yearMonthRaw = \(yearMonthRaw)") // 输出:2
// 通过原始值创建枚举实例(返回可选类型,需解包)
if let december = Month(rawValue: 12) {
print("December 的原始值是 \(december.rawValue)") // 输出:12
}
4. 枚举方法
枚举可定义实例方法和类型方法,支持 mutating 关键字(修改枚举自身值)。
Swift
enum Days: Daysofaweek { // Daysofaweek 是自定义协议
case sun, mon, tue, wed, thurs, fri, sat
// 实例方法,mutating 修饰(修改枚举自身)
mutating func show() {
switch self {
case .sun:
self = .sun
print("Sunday")
case .mon:
self = .mon
print("Monday")
// ... 其他成员
}
}
}
var res = Days.wed
res.show() // 输出:Wednesday
1.9 结构体与类(Struct & Class)
结构体和类是 Swift 中封装数据和行为的核心类型,核心区别是值类型 vs 引用类型 。
1. 区别对比
| 特性 | 结构体(Struct) | 类(Class) |
|---|---|---|
| 类型本质 | 值类型(赋值/传参时深拷贝) | 引用类型(赋值/传参时传内存地址) |
| 继承 | 不支持 | 支持(单继承) |
| 初始化器 | 自动生成成员初始化器 | 需显式定义(除非所有属性有默认值) |
| 析构器(deinit) | 不支持 | 支持 |
| 引用计数(ARC) | 无 | 有(管理实例生命周期) |
| 常量实例可变性 | 不可修改任何属性(即使 var) | 可修改 var 属性(let 仅限制引用) |
| mutating 方法 | 修改属性需加 mutating | 无需加 mutating |
2. 结构体示例
Swift
// 结构体定义(自动生成成员初始化器)
struct Marks {
var mark1: Int = 100
var mark2: Int = 200
var mark3: Int = 300
}
// 使用自动生成的成员初始化器
let mark = Marks()
print("mark1 = \(mark.mark1)") // 输出:100
// 结构体带自定义初始化器
struct MarkStruct {
var mark1: Int, mark2: Int, mark3: Int
// 自定义初始化器(需初始化所有属性)
init(mark1: Int, mark2: Int, mark3: Int) {
self.mark1 = mark1
self.mark2 = mark2
self.mark3 = mark3
}
}
// 结构体方法的 mutating(修改属性必需)
struct Area {
var length = 1, breadth = 1
// 修改属性的方法需加 mutating
mutating func scaleBy(res: Int) {
length *= res
breadth *= res
}
}
var val = Area(length: 3, breadth: 5)
val.scaleBy(res: 3)
print("length = \(val.length), breadth = \(val.breadth)") // 输出:9, 15
3. 类示例
Swift
// 类定义(需显式定义初始化器)
class MarksStruct {
var mark: Int
// 自定义初始化器
init(mark: Int) {
self.mark = mark
}
}
// 类的继承与方法重写
class SuperClass {
func show() {
print("这是超类 SuperClass")
}
}
class SubClass: SuperClass {
// 重写父类方法需加 override
override func show() {
print("这是子类 SubClass")
}
}
// 类的引用特性(=== 判断引用是否相同)
let superObj = SuperClass()
let subObj = SubClass()
let subObj2 = subObj // 传引用,subObj 与 subObj2 指向同一实例
print(subObj === subObj2) // 输出:true(引用相同)
// 类的析构器(deinit,实例销毁前执行)
class FileHandler {
let filename: String
init(filename: String) {
self.filename = filename
print("打开文件:\(filename)")
}
deinit {
print("关闭文件:\(filename)")
}
}
// 超出作用域时,析构器自动调用
func openFile() {
let handler = FileHandler(filename: "test.txt")
}
openFile() // 输出:打开文件:test.txt → 关闭文件:test.txt
1.10 属性(Property)
属性是"关联到类型或实例的值",分为存储属性 (存储数据)和计算属性(计算数据),支持属性观察器。
1. 存储属性(Stored Property)
- 直接存储值,适用于结构体和类,支持
let(不可变)和var(可变)。
Swift
class Person {
let name: String // 不可变存储属性(初始化后不可改)
var age: Int // 可变存储属性
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
let person = Person(name: "小明", age: 18)
person.age = 19 // 合法(var 可变)
// person.name = "小红" // 错误(let 不可变)、
延迟存储属性(lazy)
- 用
lazy修饰,延迟到第一次访问时才初始化(仅适用于var,且必须有默认值或在初始化器中赋值)。
Swift
class MyNumber {
var name = "This is a number"
}
class Sample {
// 延迟属性:第一次访问 no 时才初始化 MyNumber 实例
lazy var no = MyNumber()
}
let firstSample = Sample()
print(firstSample.no.name) // 第一次访问,初始化 MyNumber,输出:This is a number
2. 计算属性(Computed Property)
- 不直接存储值,通过
get(读取)和set(写入)计算值,适用于结构体、类、枚举。 - 只读计算属性:省略
set和get关键字,直接返回计算结果。
Swift
class Sampl2 {
var no1: Double = 0, no2: Double = 0
var length = 300.0, breadth = 150.0
// 读写计算属性(get + set)
var middle: (Double, Double) {
get {
return (length / 2, breadth / 2) // 读取时计算
}
set(axis) { // axis 是新值的参数名,默认是 newValue
no1 = axis.0 - (length / 2)
no2 = axis.1 - (breadth / 2)
}
}
// 只读计算属性(省略 get)
var area: Double {
return length * breadth // 仅支持读取
}
}
let mSample2 = Sampl2()
print(mSample2.middle) // 调用 get,输出:(150.0, 75.0)
mSample2.middle = (0, 10) // 调用 set,修改 no1 和 no2
print(mSample2.no1) // 输出:-150.0
print(mSample2.area) // 调用只读计算属性,输出:45000.0
3. 属性观察器(Property Observers)
- 监控属性值的变化,触发
willSet(值修改前)和didSet(值修改后),适用于存储属性(包括继承的存储属性)。
Swift
class Samplepgm {
var counter: Int = 0 {
willSet(newTotal) { // newTotal 是新值(默认参数名)
print("计数器即将变为:\(newTotal)")
}
didSet(oldValue) { // oldValue 是旧值(默认参数名)
if counter > oldValue {
print("新增数:\(counter - oldValue)")
}
}
}
}
let newCounter = Samplepgm()
newCounter.counter = 100 // 触发 willSet(100)和 didSet(0→100)
// 输出:
// 计数器即将变为:100
// 新增数:100
4. 类型属性(Type Properties)
- 属于类型本身,而非实例,所有实例共享,用
static(结构体、枚举、类)或class(仅类,支持重写)修饰。
Swift
// 结构体的类型属性(static)
struct Student2 {
static let totalCount: Int = 0 // 不可变类型属性(所有学生共享)
var name: String // 实例属性(每个学生独有)
}
// 类的类型属性(static 不可重写,class 可重写)
class School {
static let maxStudents: Int = 1000 // 不可重写
class var schoolName: String { // 可重写的计算类型属性
return "Swift 学校"
}
}
// 访问类型属性(通过类型名,而非实例)
print(Student2.totalCount) // 输出:0
print(School.maxStudents) // 输出:1000
print(School.schoolName) // 输出:Swift 学校
1.11 方法(Method)
方法是"关联到类型或实例的函数",分为实例方法 (属于实例)和类型方法(属于类型)。
1. 实例方法(Instance Methods)
- 属于实例,需通过实例调用,可访问实例属性和其他实例方法。
Swift
class Counter {
var count = 0
// 实例方法:修改实例属性
func increment() {
count += 1
}
// 带参数的实例方法
func incrementBy(amount: Int) {
count += amount
}
// 无参数无返回值的实例方法
func reset() {
count = 0
}
}
let counter = Counter()
counter.increment() // 调用实例方法,count = 1
counter.incrementBy(amount: 5) // count = 6
print(counter.count) // 输出:6
counter.reset() // count = 0
2. 类型方法(Type Methods)
- 属于类型,用
static(结构体、枚举、类)或class(仅类,支持重写)修饰,通过类型名调用,可访问类型属性。
Swift
// 结构体的类型方法(static)
struct Math {
static func abs(number: Int) -> Int {
return number < 0 ? -number : number
}
}
// 类的类型方法(class,可重写)
class Calculator {
class func add(a: Int, b: Int) -> Int {
return a + b
}
}
// 调用类型方法(通过类型名)
print(Math.abs(number: -100)) // 输出:100
print(Calculator.add(a: 10, b: 20)) // 输出:30
3. 结构体方法的 mutating
- 结构体是值类型,默认实例方法不能修改实例属性,需用
mutating修饰(类无需)。
Swift
struct Area {
var length = 1, breadth = 1
// mutating 方法:修改结构体实例属性
mutating func scaleBy(res: Int) {
length *= res
breadth *= res
}
}
var area = Area(length: 3, breadth: 5)
area.scaleBy(res: 2)
print("length = \(area.length), breadth = \(area.breadth)") // 输出:6, 10
1.12 下标脚本(Subscript)
下标脚本是"通过 [] 访问类型实例的语法",类似数组和字典的下标,支持自定义参数和返回值。
1. 下标脚本基本定义
- 语法:
subscript(参数列表) -> 返回类型 { get { ... } set(newValue) { ... } },支持只读(省略set)。
Swift
// 结构体下标:通过下标返回"数值除以索引"的结果
struct SubExample {
let decrementer: Int
// 只读下标(省略 set)
subscript(index: Int) -> Int {
return decrementer / index
}
init(decrementer: Int) {
self.decrementer = decrementer
}
}
let division = SubExample(decrementer: 100)
print("100 / 9 = \(division[9])") // 输出:11
print("100 / 2 = \(division[2])") // 输出:50
2. 类的下标(支持读写)
Swift
// 类下标:模拟数组的读写功能
class DaysOfAWeek {
private var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
// 读写下标
subscript(index: Int) -> String {
get {
return days[index] // 读取
}
set(newValue) {
days[index] = newValue // 写入
}
}
}
let week = DaysOfAWeek()
print(week[1]) // 调用 get,输出:Monday
week[1] = "星期一" // 调用 set
print(week[1]) // 输出:星期一
3. 多参数下标
下标支持多个参数,适用于多维数据结构(如二维矩阵)。
Swift
// 二维矩阵的多参数下标
struct Matrix {
let rows: Int, columns: Int
var values: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
values = Array(repeating: 0.0, count: rows * columns)
}
// 双参数下标(row: 行,column: 列)
subscript(row: Int, column: Int) -> Double {
get {
return values[row * columns + column]
}
set {
values[row * columns + column] = newValue
}
}
}
var mat = Matrix(rows: 4, columns: 4)
mat[0, 0] = 1.0
mat[1, 1] = 2.0
print("mat[0,0] = \(mat[0,0])") // 输出:1.0
print("mat[1,1] = \(mat[1,1])") // 输出:2.0