Copy-on-Write是在保持值语义的同时延后复制存储区的实现策略。修改共享存储区之前先分离;如果已经独占,就直接修改。并非每个struct都会自动实现这项策略。
原理与设计判断
标准集合的值语义与自定义存储区的实现责任不同。这里用private类持有整数数组,并在修改方法中用isKnownUniquelyReferenced检查强引用是否唯一。所有修改路径都必须遵守这项规则。 一手资料
复现代码
IntBuffer赋值后,先通过identity确认两者共享同一个Storage。向副本添加3时应分离存储区,保留原来的数组。接着添加4时,副本已独占Storage,因此不应再次分离。
这个独立示例已于 2026-10-23 使用 Apple Swift 6.4,以 Swift 6 语言模式在 arm64 macOS 目标环境运行。不需要网络或额外软件包。
请在下载文件的文件夹中运行。检查不通过时,precondition 会终止程序。请勿使用 -Ounchecked,因为它会移除这些检查。
swift -swift-version 6 swift-copy-on-write-prototype-pattern.swift
struct IntBuffer {
private final class Storage {
var values: [Int]
init(_ values: [Int]) { self.values = values }
}
private var storage: Storage
private(set) var detachments = 0
init(_ values: [Int]) { storage = Storage(values) }
var values: [Int] { storage.values }
func sharesStorage(with other: IntBuffer) -> Bool {
storage === other.storage
}
mutating func append(_ value: Int) {
if !isKnownUniquelyReferenced(&storage) {
storage = Storage(storage.values)
detachments += 1
}
storage.values.append(value)
}
}
let original = IntBuffer([1, 2])
var copy = original
precondition(copy.sharesStorage(with: original))
copy.append(3)
precondition(!copy.sharesStorage(with: original))
precondition(original.values == [1, 2] && copy.values == [1, 2, 3])
copy.append(4)
precondition(copy.detachments == 1 && copy.values == [1, 2, 3, 4])
print("shared-before=true shared-after=false detachments=1 original=[1,2] copy=[1,2,3,4]")
运行结果与解读
shared-before=true shared-after=false detachments=1 original=[1,2] copy=[1,2,3,4]
detachments=1代表自制Storage包装层分离了一次。原本保持[1,2],副本变成[1,2,3,4]。这不是底层Array缓冲区的实际分配次数,内部Array仍可能采用自己的CoW实现。
适用范围与限制
这是单一执行流程的教学示例,不是线程安全的集合。唯一性检查不是同步机制。包含类实例的数组也不会深拷贝元素对象,因此不能说值类型替代了所有原型模式的用途。
接下来要确认的事
先区分哪些数据需要独立副本、哪些可以共享。性能收益应以实际工作负载测量;没有自定义需求时优先使用标准集合。内部引用的共享方式可参考class与struct实验。
来源与验证
- Swift Standard Library: isKnownUniquelyReferencedSwift.org · 官方文档 · 核查 2026年10月23日依据: 实现契约与说明的依据。运行输出另由本文所附实验确认。

