您可以有条件地扩展RawRepresentable使其符合其他协议吗?

Is there a way to add conformance to a protocol for types that already conform to RawRepresentable?

Consider a basic example of a class that can store primitive values in a sqlite database:

protocol DatabaseStoreable {}

extension Int: DatabaseStoreable {}
extension Double: DatabaseStoreable {}
extension String: DatabaseStoreable {}
extension Data: DatabaseStoreable {}

func storeValue<T: DatabaseStoreable>(_ value: T) {
  ...
}

I'd like to also include any type that conforms to RawRepresentable where RawValue: DatabaseStorable:

extension RawRepresentable: DatabaseStoreable where Self.RawValue: DatabaseStoreable {}

但是,这会产生以下错误:

协议“ RawRepresentable”的扩展不能具有继承   条款

有没有一种方法可以解决此问题,因为此刻我必须声明具有以下签名的第二个函数:

func storeValue<T: RawRepresentable>(_ value: T) where T.RawValue: DatabaseStoreable {
  // Calls through to the function above.
}
评论
  • 贪婪
    贪婪 回复

    由于您的错误消息已经告诉您无法将继承添加到协议中。您只能将继承添加到对象。

    因此,这将不起作用:

    extension RawRepresentable: DatabaseStoreable {}
    

    但是,您可以这样添加扩展名:

    protocol DatabaseStoreable {}
    
    extension Int: DatabaseStoreable {}
    extension Double: DatabaseStoreable {}
    extension String: DatabaseStoreable {}
    extension Data: DatabaseStoreable {}
    
    func storeValue<T: DatabaseStoreable>(_ value: T) {
         print("T store(\(value))")
    }
    
    extension RawRepresentable {
        func storeValue<T: DatabaseStoreable>(_ value: T) {
            print("RawRepresentable store(\(value))")
        }
    }
    
    enum Test: String {
        case A
        case B
    }
    
    class DataBaseStore: DatabaseStoreable {}
    
    let myTest = Test.A
    let databaseStore = DataBaseStore()
    myTest.storeValue(databaseStore) // prints RawRepresentable store(__lldb_expr_15.DataBaseStore)
    
  • sit_et
    sit_et 回复

    您可以利用条件一致性来执行以下操作:

    extension RawRepresentable where RawValue: DatabaseStoreable {
    
        func storeValue<T: DatabaseStoreable>(_ value: T) {
            // do stuff
        }
    }
    
    enum Foo: String, DatabaseStoreable { 
        case bar
    }
    
    Foo.bar.storeValue("test")
    

    By the way: it should be DatabaseStorable and not DatabaseStoreable.