简体   繁体   English

Swift:协议 X 作为一种类型不能符合“Hashable”

[英]Swift: Protocol X as a type cannot conform to 'Hashable'

I would like to do something like this:我想做这样的事情:

enum TestEnum {
    case all
    case some(_ testElements: Set<TestElement>)
}

public protocol TestElement: Hashable {
    var identifier: String { get }
}

But I get this error:但我收到此错误:

Protocol 'TestElement' as a type cannot conform to 'Hashable'协议“TestElement”作为一种类型不能符合“Hashable”

What could I do?我能做什么? Thank you for your help感谢您的帮助

I am not exactly sure what do you want to use the TestEnum for, but I suggest rewriting it with using one additional element which would be instance of TestClass, so you can conform to TestEnum.some .我不确定您想将 TestEnum 用于什么目的,但我建议使用一个额外的元素来重写它,该元素将是 TestClass 的实例,因此您可以符合 TestEnum.some 。 Here is the code:这是代码:

    enum TestEnum {
    case all
    case some(_ testElements: Set<TestClass>)
}

public protocol TestElement: Hashable {
    var identifier: String { get }
}

struct TestClass: TestElement {
    var identifier: String
    //needed to conform to Equatable
    static func == (lhs: TestClass, rhs: TestClass) -> Bool {
        return true
    }
}

There is also an easier and more elegant solution , which is using TestElement as a struct, instead of protocol.还有一个更简单、更优雅的解决方案,它使用 TestElement 作为结构,而不是协议。 I would prersonally recommend this approach.我个人会推荐这种方法。 Here is the code:这是代码:

    enum TestEnum {
    case all
    case some(_ testElements: Set<TestElement>)
}

public struct TestElement: Hashable {
    public private (set) var identifier: String
}

Like it was mentioned: two concrete types cannot be in the same set (which would be allowed if the set is defined to a protocol), as it's unclear how to compare them.就像提到的那样:两个具体类型不能在同一个集合中(如果将集合定义为协议,则允许),因为尚不清楚如何比较它们。 So by the time the set is used, you've got to have a concrete single type in that set.因此,在使用该集合时,您必须在该集合中有一个具体的单一类型。

So you can do it like this:所以你可以这样做:

enum TestEnum<T: TestElement> {
    case all
    case some(_ testElements: Set<T>)
}

public protocol TestElement: Hashable {
    var identifier: String { get }
}

That is: your protocol remains what it is, and to define the enum you don't need any concrete types.也就是说:您的协议保持原样,并且定义枚举您不需要任何具体类型。 Also you restrict elements in the Set to conform to TestElement protocol, like you intended to.您还可以像您打算的那样限制Set元素以符合TestElement协议。 But when you are about to use the enum, you have to make up your mind about the actual type the set will use.但是当您将要使用枚举时,您必须决定集合将使用的实际类型。

eg if you have class Person: TestElement {... , you can use the enum like this:例如,如果你有class Person: TestElement {... ,你可以像这样使用枚举:

let persons = Set<Person>()
TestEnum<Person>.some(persons)

See a good writeup on it here这里看到一篇关于它的好文章

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM