【问题标题】:Can you conditionally extend RawRepresentable to conform to another protocol?您可以有条件地扩展 RawRepresentable 以符合另一个协议吗?
【发布时间】:2020-05-11 07:08:36
【问题描述】:

有没有办法为已经符合RawRepresentable 的类型添加对协议的一致性?

考虑一个可以在sqlite 数据库中存储原始值的类的基本示例:

protocol DatabaseStoreable {}

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

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

我还想包含符合RawRepresentable 的任何类型,其中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.
}

【问题讨论】:

  • 在进行了一些初步研究后,我仍然感到困惑,并且有点好奇最近版本的 Swift 是否有任何变化,因为 SwiftUI 已经出现了一些更新。无论如何,第一个链接有一个引用 SE-0143 的答案,而这又在 Alternatives Considered 下有一个很好的总结,我错过了。
  • 我认为您所描述的内容转换为extension RawRepresntable where Self : DatabaseStoreable, Self.RawValue : DatabaseStoreable {},但我不知道它是否会起作用。

标签: swift generics protocols


【解决方案1】:

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

extension RawRepresentable where RawValue: DatabaseStoreable {

    func storeValue<T: DatabaseStoreable>(_ value: T) {
        // do stuff
    }
}

enum Foo: String, DatabaseStoreable { 
    case bar
}

Foo.bar.storeValue("test")

顺便说一句:应该是DatabaseStorable 而不是DatabaseStoreable

【讨论】:

    【解决方案2】:

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

    因此这是行不通的:

    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多