简体   繁体   English

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

[英]Defining a Swift Protocol for Arbitrary, Int-based Enums

I have this enumeration representing a color, and I have added several methods to conveniently obtain new instances based on arithmetic operations on the original's raw value: 我有一个代表颜色的枚举,并且添加了几种方法,可以根据对原始原始值的算术运算方便地获取新实例:

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

(This harks back to the old enums being just int constants) (这回想起只是int常量的旧枚举)

The problem is, I have several other int-based enums where I would like to introduce similar functionality, but without duplicating code. 问题是,我还有其他几个基于int的枚举,我想在其中引入类似的功能,但又不重复代码。

I think I should define a protocol extension on RawRepresentable where RawValue == Int : 我认为我应该在RawRepresentable上定义协议扩展,其中RawValue == Int

extension RawRepresentable where RawValue == Int
{

...but that's where my understanding of the syntax ends. ...但这就是我对语法的理解的终点。

Ideally, I would like to require a static method returning the number of cases, and a provide default implementation of both random() and shifted(_:) above that takes that into account (instead of the hard-coded 6 here). 理想情况下,我想要求使用静态方法返回案例数,并提供对random()shifted(_:)默认实现,并将其考虑在内(而不是此处的硬编码6)。

CONCLUSION: I have accepted the answer by Zoff Dino . 结论:我已经接受了佐夫·迪诺的回答 Even though the answer given by Rob Napier is exactly what I asked for, it turns out what I was asking for was not the most elegant design after all, and the other answer suggests a better approach. 即使Rob Napier给出的答案恰好是我所要求的,但事实证明,我所要求的毕竟不是最优雅的设计,而其他答案则建议了一种更好的方法。 Still, I have upvoted both answers; 不过,我对两个答案都赞成。 thanks everyone. 感谢大家。

You're almost there. 你快到了。 You just need Nate Cook's case-counting code from https://stackoverflow.com/a/27094913/97337 . 您只需要来自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
    }
}

You should extend your custom protocol instead of RawRepresentable . 您应该扩展自定义协议,而不是RawRepresentable Try this: 尝试这个:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM