Home > Net >  Swift: Protocol X as a type cannot conform to 'Hashable'
Swift: Protocol X as a type cannot conform to 'Hashable'

Time:11-06

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'

What could I do? Thank you for your help

CodePudding user response:

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 . 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. 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
}

CodePudding user response:

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. But when you are about to use the enum, you have to make up your mind about the actual type the set will use.

e.g. if you have class Person: TestElement {..., you can use the enum like this:

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

See a good writeup on it here

  • Related