【问题标题】:Conformance to a protocol (as a protocol)符合协议(作为协议)
【发布时间】:2017-07-30 00:38:05
【问题描述】:

假设我有一个协议Item,以及一个符合它的结构ConcreteItem

protocol Item {
    var name: String { get }
}

struct ConcreteItem: Item {
    let name: String
}

在某个时候,我想拥有两组ConcreteItem

let set1 = Set([ConcreteItem(name: "item1")])
let set2 = Set([ConcreteItem(name: "item2"), ConcreteItem(name: "item1")])

我希望返回名称为 "item1" 的项目。


我可以使ConcreteItem 符合Hashable 并且Set 代码将起作用。但是,可以说我还有以下内容:

struct AnotherConcreteItem: Item {
    let name: String
}

我希望 AnotherConcreteItem 也符合 Hashable 只是因为符合 Item

但是,当我尝试实现这个想法时:

extension Item: Hashable {
    var hashValue: Int {
        return name.characters.count
    }
}

我收到以下错误:Extension of protocol 'Item' cannot have an inheritance clause

【问题讨论】:

    标签: swift protocols


    【解决方案1】:

    协议“项目”的扩展不能有继承子句

    这里的项目是协议,所以符合Hashable 协议将不起作用。更多详情请参考here

    【讨论】:

    • 条件一致性表达了泛型类型仅在其类型参数满足某些要求时才符合特定协议的概念。例如,Array 集合只有在其元素本身是 Equatable 时才能实现 Equatable 协议,这可以通过以下对 Equatable 的条件一致性来表示。 github.com/apple/swift-evolution/blob/master/proposals/…
    • 所以在你的情况下这是不可能的。
    • 也许我可以让我的异构项目列表都成为一些一般受限的类型。
    【解决方案2】:

    您尝试做的事情可以通过某些协议实现,但不是全部。如果您尝试遵循的协议没有任何关联类型或Self,这是可能的。

    例子:

    protocol A {
        func foo()
    }
    
    protocol Item: A {
        var name: String { get }
    }
    
    struct ConcreteItem: Item {
        let name: String
    }
    
    extension Item {
        func foo() {
    
        }
    }
    

    符合Item 的所有内容也将符合A

    但是,Hashable 具有 Self 约束。要符合Hashable,您还必须符合Equatable。为了符合Equatable== 的实现必须在具体类中,而不是在另一个协议中,因为Equatable 不能用作参数类型。你能做的最多是这样的:

    protocol Item: Hashable {
        var name: String { get }
    }
    
    struct ConcreteItem: Item {
        let name: String
        // you need to implement == in every concrete class
        static func ==(lhs: ConcreteItem, rhs: ConcreteItem) -> Bool {
            return ...
        }
    }
    
    extension Item {
        var hashValue: Int {
            return name.characters.count
        }
    }
    

    【讨论】:

    • 对于==,您可以在协议扩展中拥有Self 类型的参数,请参阅gist.github.com/hamishknight/ff678e0fe8e351e655b65ba08d376ba9。您当前对== 的实现也不正确; Hashable 的要求是两个相等的类型必须具有相同的哈希值,not 两个具有相同哈希值的类型是相等的。在您的代码中,ConcreteItem(name: "baz") == ConcreteItem(name: "fez") 为真,这显然是错误的。
    • @Hamish 好的,我会让 OP 决定他/她想要什么实现
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-23
    • 2017-07-22
    • 2017-07-11
    • 2019-10-14
    • 2018-11-30
    • 1970-01-01
    相关资源
    最近更新 更多