Swift 中基础概念:「函数」与「方法」

为什么要区分「函数」和「方法」

写 Swift 时,我们每天都在写 func

但同一个关键字,有时叫「函数」,有时又叫「方法」。

名字不同,背后其实是作用域与归属权的差异:

  • 函数(function)------独立存在,像一把瑞士军刀,谁都能拿来用。
  • 方法(method)------寄居在类型内部,能直接访问类型的数据,像家电的遥控器,只能操控指定品牌。

搞清这一点,再读苹果文档或第三方库源码,就不会迷糊。

函数:真正独立的代码块

  1. 定义与调用
swift 复制代码
// 函数定义:全局可用,不依赖任何类型
func greet(name: String) -> String {
    return "Hello, \(name)!"
}

// 调用
let msg = greet(name: "Alice")
print(msg)   // 输出:Hello, Alice!
  1. 生活化比喻

把函数想成微波炉:你把它搬到任何厨房(项目),它都能加热食物(完成任务)。

微波炉不隶属于某套房子(对象),完全独立。

  1. 再看一个无参无副作用的工具函数
swift 复制代码
/// 返回当前时间戳(秒)
func currentTimestamp() -> TimeInterval {
    return Date().timeIntervalSince1970
}

这种「纯工具」逻辑,做成函数最合适,因为任何类型都可能用得到。

方法:绑定在类型上的函数

方法 = 函数 + 上下文。

上下文就是类型(class/struct/enum)里的属性与其他方法。

  1. 实例方法(Instance Method)
swift 复制代码
struct Car {
    var speed: Int      // 属性

    // 实例方法:只能由具体 Car 实例调用
    func describe() -> String {
        return "The car is going \(speed) km/h."
    }
}

let myCar = Car(speed: 100)
print(myCar.describe())   // 输出:The car is going 100 km/h.

要点:

  • describe 写在 Car 内部,直接读取 speed
  • 如果脱离 Car 实例,describe 无法存在。
  1. 变异方法(Mutating Method)

值类型(struct/enum)默认不可修改自身属性,需要显式标记 mutating

swift 复制代码
struct Counter {
    var count = 0

    // 变异方法:可以修改属性
    mutating func increment() {
        count += 1
    }
}

var counter = Counter()
counter.increment()
print(counter.count)   // 输出:1

注意:

  1. 只有 值类型 才用 mutating;class 是引用类型,直接改即可。

  2. 调用者必须用 var 声明,不能用 let

  3. 类型方法(Type Method)

相当于其他语言的「静态方法」,由类型本身调用,不依赖实例。

swift 复制代码
class Car {
    // 类型属性
    static let defaultWheelCount = 4
    
    // 类型方法
    static func numberOfWheels() -> Int {
        return defaultWheelCount
    }
}

print(Car.numberOfWheels())   // 输出:4

使用场景:

  • 工厂方法(创建实例)
  • 与实例无关的全局配置或工具逻辑

函数与方法协同实战:跑步记录器

下面把「函数」与「方法」放在同一段业务里,感受它们如何各司其职。

swift 复制代码
// 1️⃣ 独立函数:公里转英里,任何模块都能用
func convertToMiles(kilometers: Double) -> Double {
    return kilometers * 0.621371
}

// 2️⃣ 类型:Runner
struct Runner {
    var name: String
    var distanceInKm: Double
    
    // 实例方法:生成专属报告
    func progressReport() -> String {
        // 直接调用上面的独立函数
        let miles = convertToMiles(kilometers: distanceInKm)
        return "\(name) 今天跑了 \(String(format: "%.2f", miles)) 英里"
    }
    
    // 变异方法:增加跑量
    mutating func runExtra(km: Double) {
        distanceInKm += km
    }
}

// 3️⃣ 使用
var emma = Runner(name: "Emma", distanceInKm: 5)
print(emma.progressReport())   // Emma 今天跑了 3.11 英里

emma.runExtra(km: 2)
print(emma.progressReport())   // Emma 今天跑了 4.35 英里

看到吗?

  • convertToMiles 是纯逻辑,与任何类型无关。
  • progressReport 需要 Runner 内部数据,所以做成实例方法。
  • 两者组合,代码既复用又内聚。

易错点小结

场景 正确做法 常见错误
struct 里想改属性 mutating 忘记写,编译报错
类型方法里用实例属性 ❌ 不能 static 当实例方法用
全局工具逻辑 写成函数 强行塞进某个类型,导致复用困难

理解 & 使用原则

  1. 优先写成函数:只要逻辑不依赖任何实例数据,就独立出来。

    方便单元测试、跨模块复用,也减少类型体积。

  2. 升阶为方法的时机:

    • 需要频繁访问类型内部私有属性
    • 需要多态(子类重写)
    • 需要链式调用(return self

    满足一条,再考虑搬进类型。

  3. 命名统一,作用域清晰:

    函数用「动词」开头,convertdownloadvalidate...

    方法也用「动词」,但可省略主语,describeincrementsave...

    让调用者一眼看出谁属于谁。

扩展场景:把知识用到实际项目

  1. 网络层
swift 复制代码
   // 独立函数,任何模型都能调
   func GET<T: Decodable>(_ url: URL) async throws -> T { ... }

   // 模型内部方法,自己知道怎么拼装 URL
   struct Article {
       let id: Int
       func detailURL() -> URL { ... }
   }
  1. SwiftUI 视图
swift 复制代码
   // 全局函数,做颜色插值
   func interpolateColor(from: Color, to: Color, percent: Double) -> Color { ... }

   // 视图的方法,负责自己的业务
   struct ProgressCircle: View {
       var progress: Double
       private func strokeColor() -> Color {
           return interpolateColor(from: .green, to: .red, percent: progress)
       }
   }
  1. 算法库

    快速排序、哈希函数等纯算法,一律写成函数,避免绑定具体类型。

结语

所有方法都是函数,但函数不一定是方法。

记住「是否依赖类型数据」这一把尺子,该独立就独立,该内聚就内聚。

当你把边界划清楚,代码会自然呈现出高内聚、低耦合的漂亮形态。

希望这篇笔记能帮你把「函数 vs 方法」彻底吃透,写出更 Swifty 的代码!

参考资料

Swift 官方语言指南 - Functions

Swift 官方语言指南 - Methods

相关推荐
西西弗Sisyphus1 天前
将用于 Swift 微调模型的 JSON Lines(JSONL)格式数据集,转换为适用于 Qwen VL 模型微调的 JSON 格式
swift·qwen3
songgeb1 天前
🧩 iOS DiffableDataSource 死锁问题记录
ios·swift
大熊猫侯佩1 天前
【大话码游之 Observation 传说】上集:月光宝盒里的计数玄机
swiftui·swift·weak·observable·self·引用循环·observations
HarderCoder2 天前
Swift 方法全解:实例方法、mutating 方法与类型方法一本通
swift
HarderCoder2 天前
Swift 类型转换实用指北:从 is / as 到 Any/AnyObject 的完整路线
swift
HarderCoder2 天前
Swift 嵌套类型:在复杂类型内部优雅地组织枚举、结构体与协议
swift
HarderCoder3 天前
Swift 枚举完全指南——从基础语法到递归枚举的渐进式学习笔记
swift
非专业程序员Ping3 天前
从0到1自定义文字排版引擎:原理篇
ios·swift·assembly·font
HarderCoder4 天前
【Swift 筑基记】把“结构体”与“类”掰开揉碎——从值类型与引用类型说起
swift