6

我有这个表示颜色的枚举,并且我添加了几种方法来方便地基于原始值的算术运算获得新实例:

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我想我应该在where上定义一个协议扩展RawValue == Int

extension RawRepresentable where RawValue == Int
{

...但这就是我对语法的理解结束的地方。

理想情况下,我希望需要一个返回案例数量的静态方法,并提供考虑到这一点的两者random()及以上的默认实现(而不是这里的硬编码 6)。shifted(_:)

结论:我接受了 Zoff Dino 的回答。尽管Rob Napier 给出的答案正是我所要求的,但事实证明我所要求的毕竟不是最优雅的设计,而另一个答案表明了一种更好的方法。不过,我对这两个答案都投了赞成票。感谢大家。

4

2 回答 2

5

您应该扩展您的自定义协议而不是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)
于 2015-11-07T04:18:43.317 回答
4

您快到了。您只需要来自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
    }
}
于 2015-11-07T05:01:46.213 回答