【问题标题】:Use protocol in swift's generic with type constraint在 swift 的泛型中使用带有类型约束的协议
【发布时间】:2020-10-26 08:06:12
【问题描述】:

我编写了一个自定义存储,它应该只支持符合某些协议的对象:

protocol MyBaseProtocol {
    func baseMethod()
}
class Stor <ElementType : MyBaseProtocol>  {
    var storage = [ElementType]()
    
    func addElement(_ element: ElementType) {
        storage.append(element)
    }
}

接下来我创建了一个子协议,并且只想存储符合子协议的对象:

protocol MyProtocol : MyBaseProtocol {
    func method()
}
var otherStorage = Stor<MyProtocol>() //compilation error
class C1 : MyProtocol {
    func method() {
    }
    func baseMethod() {
    }
}
class S1 : MyProtocol {
    func method() {
    }
    func baseMethod() {
    }
}
otherStorage.addElement(C1())
otherStorage.addElement(S1())

我有一个错误:

Value of protocol type 'MyProtocol' cannot conform to 'MyBaseProtocol'; only struct/enum/class types can conform to protocols

如何创建一个 Stor 实例,它只能存储符合 MyBaseProtocol 的对象?

【问题讨论】:

    标签: swift generics types swift-protocols type-constraints


    【解决方案1】:

    您遇到了protocols not conforming to themselves 的问题。您可以通过创建一个符合 MyProtocol 的具体类型并将所有符合的类型转换为该类型,然后将它们存储在您的 Store 中来解决此问题。

    class AnyMyProtocol: MyProtocol {
        private let _baseMethod: () -> ()
        private let _method: () -> ()
    
        init(base: MyProtocol) {
            _baseMethod = base.baseMethod
            _method = base.method
        }
    
        func baseMethod() {
            _baseMethod()
        }
    
        func method() {
            _method()
        }
    }
    
    extension MyProtocol {
        var erased: AnyMyProtocol {
            AnyMyProtocol(base: self)
        }
    }
    
    var otherStorage = Store<AnyMyProtocol>()
    
    class C1 : MyProtocol {
        func method() {}
        func baseMethod() {}
    }
    
    struct S1 : MyProtocol {
        func method() {}
        func baseMethod() {}
    }
    
    enum MyEnum: MyProtocol {
        case some
    
        func method() {}
        func baseMethod() {}
    }
    
    otherStorage.addElement(C1().erased)
    otherStorage.addElement(S1().erased)
    otherStorage.addElement(MyEnum.some.erased)
    

    【讨论】:

    • 我需要在同一个数组中使用任何类型的对象(枚举、类、结构)。并且拥有一些基类对于我的目标来说不是一个好的选择。
    • @AndrewRomanov 您可以使用我创建的已擦除类型AnyMyProtocol 的任何类型(无论是枚举、结构还是类)。如果这不符合您的需求,您将需要重新考虑您的要求和Store 的实现,因为没有其他方法可以解决您的协议问题。
    • @AndrewRomanov 更新了答案,并将 structenum 存储在 Store
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多