Определение протокола Swift для произвольных перечислений на основе Int

У меня есть это перечисление, представляющее цвет, и я добавил несколько методов для удобного получения новых экземпляров, основанных на арифметических операциях с исходным значением оригинала:

enum Color : Int
{
    case Red = 0
    case Green
    case Blue

    case Cyan
    case Magenta
    case Yellow


    static func random() -> Color
    {
        return Color(rawValue: Int(arc4random_uniform(6)))!
    }

    func shifted(by offset:Int) -> Color
    {
        return Color(rawValue: (self.rawValue + offset) % 6)!
        // Cyclic: wraps around
    }
}

(Это возвращает нас к старым перечислениям, являющимся просто константами int)

Проблема в том, что у меня есть несколько других перечислений, основанных на int, где я хотел бы представить похожую функциональность, но без дублирования кода.

Я думаю, что я должен определить расширение протокола на RawRepresentable где RawValue == Int:

extension RawRepresentable where RawValue == Int
{

... но на этом мое понимание синтаксиса заканчивается.

В идеале я хотел бы требовать статический метод, возвращающий количество случаев, и обеспечить реализацию по умолчанию обоих random() а также shifted(_:) выше это учитывает это (вместо жестко закодированных 6 здесь).

ВЫВОД: Я принял ответ Зоффа Дино. Даже несмотря на то, что ответ, данный Робом Напиром, был именно тем, о чем я просил, оказалось, что я просил не самый элегантный дизайн в конце концов, а другой ответ предлагает лучший подход. Тем не менее, я проголосовал за оба ответа; Спасибо всем.

2 ответа

Решение

Вы должны расширить свой собственный протокол вместо RawRepresentable, Попробуй это:

protocol MyProtocol {
    static var maxRawValue : Int { get }

    static func random() ->  Self
    func shifted(by offset: Int) -> Self
}

enum Color : Int, MyProtocol
{
    case Red = 0
    case Green
    case Blue

    case Cyan
    case Magenta
    case Yellow

    // The maximum value of your Int enum
    static var maxRawValue: Int {
        return Yellow.rawValue
    }
}

extension MyProtocol where Self: RawRepresentable, Self.RawValue == Int {
    static func random() -> Self {
        let random = Int(arc4random_uniform(UInt32(Self.maxRawValue + 1)))
        return Self(rawValue: random)!
    }

    func shifted(by offset: Int) -> Self {
        return Self(rawValue: (self.rawValue + offset) % (Self.maxRawValue + 1))!
    }
}

let x = Color.random()
let y = x.shifted(by: 1)

Ты почти там. Вам просто нужен код счета Нейта Кука с /questions/37194635/kak-ya-mogu-poluchit-kolichestvo-perechislenij-swift/37194647#37194647.

extension RawRepresentable where RawValue == Int {
    // See http://natecook.com/blog/2014/10/loopy-random-enum-ideas/
    static var caseCount: Int {
        var max: Int = 0
        while let _ = self.init(rawValue: ++max) {}
        return max
    }

    static func random() -> Self {
        return Self(rawValue: Int(arc4random_uniform(UInt32(caseCount))))!
    }

    func shifted(by offset:Int) -> Self {
        return Self(rawValue: (self.rawValue + offset) % self.dynamicType.caseCount)!
        // Cyclic: wraps around
    }
}
Другие вопросы по тегам