axiom-ownership-conventions
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseborrowing & consuming — Parameter Ownership
borrowing & consuming — 参数所有权
Explicit ownership modifiers for performance optimization and noncopyable type support.
用于性能优化和支持非可复制类型的显式所有权修饰符。
When to Use
适用场景
✅ Use when:
- Large value types being passed read-only (avoid copies)
- Working with noncopyable types ()
~Copyable - Reducing ARC retain/release traffic
- Factory methods that consume builder objects
- Performance-critical code where copies show in profiling
❌ Don't use when:
- Simple types (Int, Bool, small structs)
- Compiler optimization is sufficient (most cases)
- Readability matters more than micro-optimization
- You're not certain about the performance impact
✅ 适用场景:
- 以只读方式传递大型值类型(避免拷贝)
- 处理非可复制类型()
~Copyable - 减少ARC的保留/释放开销
- 消耗构建器对象的工厂方法
- 性能敏感代码,且性能分析显示存在拷贝开销
❌ 不适用场景:
- 简单类型(如Int、Bool、小型结构体)
- 编译器优化已足够的场景(大多数情况)
- 可读性比微优化更重要的场景
- 不确定优化对性能的影响时
Quick Reference
速查参考
| Modifier | Ownership | Copies | Use Case |
|---|---|---|---|
| (default) | Compiler chooses | Implicit | Most cases |
| Caller keeps | Explicit | Read-only, large types |
| Caller transfers | None needed | Final use, factories |
| Caller keeps, mutable | None | Modify in place |
| 修饰符 | 所有权归属 | 拷贝情况 | 适用场景 |
|---|---|---|---|
| (默认) | 编译器自动选择 | 隐式拷贝 | 大多数场景 |
| 调用者保留所有权 | 仅显式调用 | 只读、大型类型 |
| 调用者转移所有权 | 无需拷贝 | 最终使用、工厂方法 |
| 调用者保留所有权,可修改 | 无拷贝 | 原地修改 |
Default Behavior by Context
不同上下文的默认行为
| Context | Default | Reason |
|---|---|---|
| Function parameters | | Most params are read-only |
| Initializer parameters | | Usually stored in properties |
| Property setters | | Value is stored |
Method | | Methods read self |
| 上下文 | 默认值 | 原因 |
|---|---|---|
| 函数参数 | | 大多数参数为只读 |
| 初始化器参数 | | 通常会存储到属性中 |
| 属性设置器 | | 值会被存储 |
方法的 | | 方法通常读取self |
Patterns
实践模式
Pattern 1: Read-Only Large Struct
模式1:只读大型结构体
swift
struct LargeBuffer {
var data: [UInt8] // Could be megabytes
}
// ❌ Default may copy
func process(_ buffer: LargeBuffer) -> Int {
buffer.data.count
}
// ✅ Explicit borrow — no copy
func process(_ buffer: borrowing LargeBuffer) -> Int {
buffer.data.count
}swift
struct LargeBuffer {
var data: [UInt8] // 可能占用数兆字节
}
// ❌ 默认行为可能会触发拷贝
func process(_ buffer: LargeBuffer) -> Int {
buffer.data.count
}
// ✅ 显式borrow — 无拷贝
func process(_ buffer: borrowing LargeBuffer) -> Int {
buffer.data.count
}Pattern 2: Consuming Factory
模式2:消耗型工厂方法
swift
struct Builder {
var config: Configuration
// Consumes self — builder invalid after call
consuming func build() -> Product {
Product(config: config)
}
}
let builder = Builder(config: .default)
let product = builder.build()
// builder is now invalid — compiler error if usedswift
struct Builder {
var config: Configuration
// 消耗self — 调用后builder不再可用
consuming func build() -> Product {
Product(config: config)
}
}
let builder = Builder(config: .default)
let product = builder.build()
// builder现在已无效 — 使用会触发编译器错误Pattern 3: Explicit Copy in Borrowing
模式3:borrowing中的显式拷贝
With , copies must be explicit:
borrowingswift
func store(_ value: borrowing LargeValue) {
// ❌ Error: Cannot implicitly copy borrowing parameter
self.cached = value
// ✅ Explicit copy
self.cached = copy value
}使用时,必须显式调用拷贝:
borrowingswift
func store(_ value: borrowing LargeValue) {
// ❌ 错误:无法隐式拷贝borrowing参数
self.cached = value
// ✅ 显式拷贝
self.cached = copy value
}Pattern 4: Consume Operator
模式4:consume操作符
Transfer ownership explicitly:
swift
let data = loadLargeData()
process(consume data)
// data is now invalid — compiler prevents use显式转移所有权:
swift
let data = loadLargeData()
process(consume data)
// data现在已无效 — 编译器会阻止使用Pattern 5: Noncopyable Type
模式5:非可复制类型
For types, ownership modifiers are required:
~Copyableswift
struct FileHandle: ~Copyable {
private let fd: Int32
init(path: String) throws {
fd = open(path, O_RDONLY)
guard fd >= 0 else { throw POSIXError.errno }
}
borrowing func read(count: Int) -> Data {
// Read without consuming handle
var buffer = [UInt8](repeating: 0, count: count)
_ = Darwin.read(fd, &buffer, count)
return Data(buffer)
}
consuming func close() {
Darwin.close(fd)
// Handle consumed — can't use after close()
}
deinit {
Darwin.close(fd)
}
}
// Usage
let file = try FileHandle(path: "/tmp/data.txt")
let data = file.read(count: 1024) // borrowing
file.close() // consuming — file invalidated对于类型,必须使用所有权修饰符:
~Copyableswift
struct FileHandle: ~Copyable {
private let fd: Int32
init(path: String) throws {
fd = open(path, O_RDONLY)
guard fd >= 0 else { throw POSIXError.errno }
}
borrowing func read(count: Int) -> Data {
// 不消耗句柄进行读取
var buffer = [UInt8](repeating: 0, count: count)
_ = Darwin.read(fd, &buffer, count)
return Data(buffer)
}
consuming func close() {
Darwin.close(fd)
// 句柄已被消耗 — close()后无法使用
}
deinit {
Darwin.close(fd)
}
}
// 使用示例
let file = try FileHandle(path: "/tmp/data.txt")
let data = file.read(count: 1024) // borrowing
file.close() // consuming — file已失效Pattern 6: Reducing ARC Traffic
模式6:减少ARC开销
swift
class ExpensiveObject { /* ... */ }
// ❌ Default: May retain/release
func inspect(_ obj: ExpensiveObject) -> String {
obj.description
}
// ✅ Borrowing: No ARC traffic
func inspect(_ obj: borrowing ExpensiveObject) -> String {
obj.description
}swift
class ExpensiveObject { /* ... */ }
// ❌ 默认行为:可能会触发保留/释放操作
func inspect(_ obj: ExpensiveObject) -> String {
obj.description
}
// ✅ Borrowing:无ARC开销
func inspect(_ obj: borrowing ExpensiveObject) -> String {
obj.description
}Pattern 7: Consuming Method on Self
模式7:作用于Self的消耗型方法
swift
struct Transaction {
var amount: Decimal
var recipient: String
// After commit, transaction is consumed
consuming func commit() async throws {
try await sendToServer(self)
// self consumed — can't modify or reuse
}
}swift
struct Transaction {
var amount: Decimal
var recipient: String
// 提交后,transaction被消耗
consuming func commit() async throws {
try await sendToServer(self)
// self已被消耗 — 无法修改或复用
}
}Common Mistakes
常见错误
Mistake 1: Over-Optimizing Small Types
错误1:过度优化小型类型
swift
// ❌ Unnecessary — Int is trivially copyable
func add(_ a: borrowing Int, _ b: borrowing Int) -> Int {
a + b
}
// ✅ Let compiler optimize
func add(_ a: Int, _ b: Int) -> Int {
a + b
}swift
// ❌ 无必要 — Int是可 trivial 拷贝的类型
func add(_ a: borrowing Int, _ b: borrowing Int) -> Int {
a + b
}
// ✅ 交由编译器优化
func add(_ a: Int, _ b: Int) -> Int {
a + b
}Mistake 2: Forgetting Explicit Copy
错误2:忘记显式拷贝
swift
func cache(_ value: borrowing LargeValue) {
// ❌ Compile error
self.values.append(value)
// ✅ Explicit copy required
self.values.append(copy value)
}swift
func cache(_ value: borrowing LargeValue) {
// ❌ 编译错误
self.values.append(value)
// ✅ 需要显式拷贝
self.values.append(copy value)
}Mistake 3: Consuming When Borrowing Suffices
错误3:在borrowing足够的场景下使用consuming
swift
// ❌ Consumes unnecessarily — caller loses access
func validate(_ data: consuming Data) -> Bool {
data.count > 0
}
// ✅ Borrow for read-only
func validate(_ data: borrowing Data) -> Bool {
data.count > 0
}swift
// ❌ 不必要的消耗 — 调用者失去访问权限
func validate(_ data: consuming Data) -> Bool {
data.count > 0
}
// ✅ 只读场景使用borrowing
func validate(_ data: borrowing Data) -> Bool {
data.count > 0
}Performance Considerations
性能考量
When Ownership Modifiers Help
所有权修饰符的有效场景
- Large structs (arrays, dictionaries, custom value types)
- High-frequency function calls in tight loops
- Reference types where ARC traffic is measurable
- Noncopyable types (required, not optional)
- 大型结构体(数组、字典、自定义值类型)
- 循环中的高频函数调用
- ARC开销可观测的引用类型
- 非可复制类型(必填,非可选)
When to Skip
无需使用的场景
- Default behavior is almost always optimal
- Small value types (primitives, small structs)
- Code where profiling shows no benefit
- API stability concerns (modifiers affect ABI)
- 默认行为几乎总是最优的
- 小型值类型(基本类型、小型结构体)
- 性能分析显示无收益的代码
- 关注API稳定性的场景(修饰符会影响ABI)
Decision Tree
决策树
Need explicit ownership?
├─ Working with ~Copyable type?
│ └─ Yes → Required (borrowing/consuming)
├─ Large value type passed frequently?
│ ├─ Read-only? → borrowing
│ └─ Final use? → consuming
├─ ARC traffic visible in profiler?
│ ├─ Read-only? → borrowing
│ └─ Transferring ownership? → consuming
└─ Otherwise → Let compiler choose是否需要显式所有权?
├─ 是否处理~Copyable类型?
│ └─ 是 → 必须使用(borrowing/consuming)
├─ 是否频繁传递大型值类型?
│ ├─ 只读?→ 使用borrowing
│ └─ 最终使用?→ 使用consuming
├─ 性能分析中ARC开销可见?
│ ├─ 只读?→ 使用borrowing
│ └─ 转移所有权?→ 使用consuming
└─ 其他情况 → 交由编译器选择Resources
参考资料
Swift Evolution: SE-0377
WWDC: 2024-10170
Skills: axiom-swift-performance, axiom-swift-concurrency
Swift Evolution: SE-0377
WWDC: 2024-10170
相关技能: axiom-swift-performance, axiom-swift-concurrency