为任意基于Int的枚举定义Swift协议

时间:2015-11-07 03:04:56

标签: swift enums protocols rawrepresentable

我有这个枚举代表一种颜色,我添加了几个方法来根据对原始原始值的算术运算方便地获取新实例:

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这里)。

结论:我已接受the answer by Zoff Dino。虽然the answer given by Rob Napier正是我所要求的,但事实证明我所要求的并不是最优雅的设计,而另一个答案则表明更好的方法。尽管如此,我仍然赞同这两个答案;谢谢大家。

2 个答案:

答案 0 :(得分:3)

你快到了。你只需要来自https://stackoverflow.com/a/27094913/97337的Nate Cook的案例计数代码。

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

答案 1 :(得分:1)

您应该扩展自定义协议而不是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)