首页 > 解决方案 > 如何仅为类类型提供 subsript 的默认协议一致性?

问题描述

用“类”标记 CacheManager 解决了我的问题。

情况是这样的:一个简单的缓存器,变异的 get 不是我想要的,那么对于引用类型或类类型应该怎么做?

protocol Cacher {
    associatedtype K
    associatedtype V
    subscript (key: K) -> V? {get set}
}

protocol MemoryCacher: Cacher {}

protocol FileCacher: Cacher {}

更新了。添加 PrimayCacher | SecondaryCacher 关联类型

protocol CacheManager {
    associatedtype Key
    associatedtype Value
    associatedtype PrimaryCacher: MemoryCacher where PrimaryCacher.K == Key, PrimaryCacher.V == Value
    associatedtype SecondaryCacher: FileCacher where SecondaryCacher.K == Key, SecondaryCacher.V == Value
    var primaryCacher: PrimaryCacher  { get set }
    var secondaryCacher: SecondaryCacher{ get set }
    subscript(key: Key) -> Value? { get set }
}

//try to provide a default subscript conformance, but actually not for the `mutating` get
extension CacheManager  {
    subscript(key: Key) -> Value? {
        mutating get {
            guard let result = primaryCacher[key] else {
                if let value = secondaryCacher?[key] {
                    primaryCacher[key] = value // the mutating is required for this
                    return value
                }
                return nil
            }
            return result
        }
        set {
            primaryCacher[key] = newValue
            secondaryCacher?[key] = newValue
        }
    }
}

标签: swiftprotocols

解决方案


你只需要添加一个类型限制AnyObject,所有类都符合。

extension CacherManager where Self: AnyObject {
    subscript(key: Key) -> Value? {
        get {
            guard let result = primaryCacher[key] else {
                if let value = secondaryCacher?[key] {
                    primaryCacher[key] = value // the mutating is required for this
                    return value
                }
                return nil
            }
            return result
        }
        set {
            primaryCacher[key] = newValue
            secondaryCacher?[key] = newValue
        }
    }
}

我还必须稍微修改您CacheManager的代码声明以编译并添加所需的协议方法,MemoryCacher并且FileCacher您在问题中省略了这些方法。

protocol Cacher {
    associatedtype K
    associatedtype V
    subscript (key: K) -> V? {get set}
}

class MemoryCacher<K, V>: Cacher {
    private var value: V?

    subscript(key: K) -> V? {
        get {
            return value
        }
        set {
            value = newValue
        }
    }
}

class FileCacher<K, V>: Cacher {
    private var value: V?

    subscript(key: K) -> V? {
        get {
            return value
        }
        set {
            value = newValue
        }
    }
}

protocol CacheManager {
    associatedtype Key
    associatedtype Value
    var primaryCacher: MemoryCacher<Key,Value> { get set }
    var secondaryCacher: FileCacher<Key,Value>? { get set }
    subscript(key: Key) -> Value? { get set }
}

推荐阅读