侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

设计一个同时支持值类型和引用类型的缓存协议

2025-12-11 / 0 评论 / 4 阅读

题目

设计一个同时支持值类型和引用类型的缓存协议

信息

  • 类型:问答
  • 难度:⭐⭐

考点

协议设计,值类型与引用类型,泛型约束,内存管理

快速回答

设计一个缓存协议需考虑:

  • 使用associatedtype定义泛型Key和Value
  • 使用mutating修饰值类型的修改方法
  • 通过where子句约束Key为Hashable
  • 引用类型实现时省略mutating
  • 通过AnyCache类型擦除器统一处理
## 解析

原理说明

Swift中协议需要同时支持结构体(值类型)和类(引用类型)时,核心挑战在于:

  • 值类型方法修改自身需要mutating关键字
  • 引用类型不需要mutating
  • 协议中无法同时声明带和不带mutating的相同方法

协议设计与实现

基础协议定义:

protocol CacheProtocol {
    associatedtype Key: Hashable
    associatedtype Value

    mutating func set(_ value: Value, forKey key: Key)
    func get(forKey key: Key) -> Value?
}

值类型实现(结构体):

struct MemoryCache<K: Hashable, V>: CacheProtocol {
    private var storage: [K: V] = [:] 

    mutating func set(_ value: V, forKey key: K) {
        storage[key] = value
    }

    func get(forKey key: K) -> V? {
        return storage[key]
    }
}

引用类型实现(类):

class PersistentCache<K: Hashable, V>: CacheProtocol {
    private var storage: [K: V] = [:] 

    // 注意:这里不需要 mutating
    func set(_ value: V, forKey key: K) {
        storage[key] = value
        saveToDisk() // 引用类型特有的持久化操作
    }

    func get(forKey key: K) -> V? {
        return storage[key]
    }

    private func saveToDisk() { /* ... */ }
}

类型擦除统一处理

由于协议包含关联类型,需使用类型擦除器:

struct AnyCache<K: Hashable, V>: CacheProtocol {
    private var _set: (V, K) -> Void
    private var _get: (K) -> V?

    init<T: CacheProtocol>(_ cache: T) where T.Key == K, T.Value == V {
        var mutableCache = cache
        _set = { value, key in
            mutableCache.set(value, forKey: key)
        }
        _get = { key in
            cache.get(forKey: key)
        }
    }

    func set(_ value: V, forKey key: K) {
        _set(value, key)
    }

    func get(forKey key: K) -> V? {
        return _get(key)
    }
}

// 使用示例
let memory: AnyCache<String, Int> = AnyCache(MemoryCache())
let disk: AnyCache<String, Int> = AnyCache(PersistentCache())

最佳实践

  • 优先使用mutating声明协议方法,引用类型实现时可忽略该关键字
  • 对Key使用Hashable约束确保字典兼容性
  • 通过类型擦除器隐藏具体实现类型
  • 值类型实现时注意inout参数传递的合规性

常见错误

  • 在类实现中添加mutating导致编译错误
  • 忘记关联类型约束,导致无法使用字典存储
  • 直接使用CacheProtocol作为变量类型(需通过类型擦除)
  • 值类型的方法中修改自身但未标记mutating

扩展知识

  • Copy-on-Write(COW): 大型值类型推荐实现COW优化性能
  • 内存管理: 引用类型需注意循环引用,可使用weak引用
  • 协议组合: 可组合AnyObject约束实现类专属协议
    protocol ClassOnlyCache: CacheProtocol, AnyObject { /* ... */ }