可复用性与约束
使用 类型约束 (例如 Value: Comparable )设计泛型包装器,通过 where 添加针对性 API,并组合多个包装器。
可复用性与约束 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 2 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 3 节课。
为什么需要约束?
编写一个包装器,并通过添加约束使其成为泛型,从而在多种类型之间复用。使用条件子句添加专用接口,并组合小型包装器。
泛型 + 可比较
使用可比较,让一个Bounded适用于整数、字符串等类型。无效类型会在编译时被拒绝。
@propertyWrapper
struct Bounded<Value: Comparable> {
private var value: Value
private let range: ClosedRange<Value>
var wrappedValue: Value {
get { value }
set {
// clamp using Comparable
if newValue < range.lowerBound { value = range.lowerBound }
else if newValue > range.upperBound { value = range.upperBound }
else { value = newValue }
}
}
init(wrappedValue: Value, _ range: ClosedRange<Value>) {
self.range = range
self.value = min(max(wrappedValue, range.lowerBound), range.upperBound)
}
}
struct Stats {
@Bounded(0...100) var score: Int = 120
@Bounded("a"..."z") var letter: String = "Swift"
}
var st = Stats()
print(st.score) // 100
st.letter = "m"
print(st.letter)受约束的扩展
使用约束条件,仅在类型支持相应功能时提供额外能力(例如整数标志位或浮点更新)。
extension Bounded where Value: BinaryInteger {
var isMaxed: Bool { wrappedValue == range.upperBound }
}
extension Bounded where Value: FloatingPoint {
mutating func bump(by delta: Value) { wrappedValue = wrappedValue + delta }
}
struct Meter {
@Bounded(0...10) var steps: Int = 9
@Bounded(0.0...1.0) var progress: Double = 0.25
}
var m = Meter()
print(m.$steps) // projectedValue not defined; accessing wrapper is not allowed directly here
print(m._steps) // compiler creates backing storage name; shown for illustration only
print(m.steps) // 9
print(m._progress) // backing storage (illustrative)
m._progress.bump(by: 0.6)
print(m.progress) // 0.85 (clamped if exceeded)仅适用于集合的包装器
通过约束为RangeReplaceableCollection,将接口限制为集合。它适用于字符串和数组。
@propertyWrapper
struct MaxLength<Value: RangeReplaceableCollection> where Value.Element: Sendable {
private var storage: Value
private let limit: Int
var wrappedValue: Value {
get { storage }
set {
var v = newValue
if v.count > limit { v.removeLast(v.count - limit) }
storage = v
}
}
init(wrappedValue: Value, _ limit: Int) {
self.limit = limit
self.storage = wrappedValue
if storage.count > limit { storage.removeLast(storage.count - limit) }
}
}
struct Post {
@MaxLength(10) var title: String = "hello swift learners"
@MaxLength(5) var tags: [String] = ["swift","ios","spm"]
}
var p = Post()
print(p.title) // "hello swif"
print(p.tags) // ["swift","ios","spm"]包装器组合
您可以叠加小型包装器。在这里,Trimmed先运行,然后由NonEmpty确保提供备用值。
@propertyWrapper
struct Trimmed {
private var s: String = ""
var wrappedValue: String {
get { s }
set { s = newValue.trimmingCharacters(in: .whitespacesAndNewlines) }
}
init(wrappedValue: String) { self.wrappedValue = wrappedValue }
}
@propertyWrapper
struct NonEmpty {
private var s: String = ""
var wrappedValue: String {
get { s }
set { s = newValue.isEmpty ? "N/A" : newValue }
}
init(wrappedValue: String) { self.wrappedValue = wrappedValue }
}
struct Profile {
@NonEmpty @Trimmed var displayName: String = " "
}
var prof = Profile()
print(prof.displayName) // "N/A"局部变量 + 复用
包装器同样适用于局部变量。让它们保持泛型,以便在多个模块之间复用。
@propertyWrapper
struct Default<Value> {
private var value: Value
private let make: () -> Value
var wrappedValue: Value {
get { value }
set { value = newValue }
}
init(wrappedValue: Value, _ factory: @escaping () -> Value) {
self.value = wrappedValue
self.make = factory
}
mutating func reset() { value = make() }
}
// Local variable usage
do {
@Default({ 0 }) var counter: Int = 5
print(counter) // 5
_counter.reset()
print(counter) // 0
}包装器的编译时约束
快速检查:如何将包装器限制为可比较类型?
回顾
回顾:让包装器保持泛型,添加约束以确保使用安全,使用带有条件子句的接口,并组合小型包装器以提升清晰度。
常见问题解答
「可复用性与约束」课时是免费的吗?
是的 — 「可复用性与约束」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 3 节课。
「可复用性与约束」这节课中我会学到什么?
使用 类型约束 (例如 Value: Comparable )设计泛型包装器,通过 where 添加针对性 API,并组合多个包装器。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Swift Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 3 节。
「可复用性与约束」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Swift Academy 课中编写并运行代码吗?
能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。