zekel
zekel

Reputation: 9457

In Swift, how can you use generic enum types in protocol extensions?

I want to share functionality between CatZoo and DogZoo since they're storing similar data under the hood but I also want them to know what they are so they can act on their specific data, as shown in the DogZoo.makeNoise() method.

What is the correct type for AnimalStorageProtocol.storage?

enum CatType: String {
    case lion
    case tiger
    case panther
}

enum DogType: String {
    case coyote
    case domestic
    case wolf
}

struct CatZoo: AnimalStorageProtocol {
    private var storage: [CatType: Int] // it's a bonus if they can stay private
}

struct DogZoo: AnimalStorageProtocol {
    private var storage: [DogType: Int]

    func makeNoise() {
        for (key, value) in storage {
            switch key  {
            case .coyote:
                print("\(value) yips!")
            case .domestic:
                print("\(value) barks!")
            case .wolf:
                print("\(value) howls!")
            }
        }
    }
}

I thought I could define a generic enum type in the protocol but I haven't been able to get it to work.

protocol AnimalStorageProtocol {
    // var storage: <RawRepresentable where RawRepresentable.RawValue == String: Int> { get set }
    var storage: [RawRepresentable: Int] { get set }
}

extension AnimalStorageProtocol {
    var isEmpty: Bool {
        get {
            for (_, value) in storage {
                if value != 0 {
                    return false
                }
            }
            return true
        }
    }
}

Upvotes: 2

Views: 3576

Answers (1)

Craig Siemens
Craig Siemens

Reputation: 13266

There are two different way you could do it depending on what your requirements are.


If you don't require the type to be a enum, you can simply do

protocol AnimalStorageProtocol {
    associatedtype AnimalType: Hashable
    var storage: [AnimalType: Int] { get set }
}

This will allow any hashable type to be used.


If you require that the types can only be RawRepresentable where the RawValue is a String you'll have to define another protocol that your animal types will have to conform to.

protocol AnimalType: Hashable, RawRepresentable {
    var rawValue: String { get }
}

protocol AnimalStorageProtocol {
    associatedtype Animal: AnimalType
    var storage: [Animal: Int] { get set }
}

Then you just have to set your enum types to conform to the AnimalType protocol.

enum CatType: String, AnimalType { ... }
enum DogType: String, AnimalType { ... }

Upvotes: 3

Related Questions