为任意基于 Int 的枚举定义 Swift 协议
Defining a Swift Protocol for Arbitrary, Int-based Enums
我有这个代表颜色的枚举,我添加了几个方法来方便地根据原始值的算术运算获取新实例:
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)。
结论:我接受了. Even though 正是我所要求的,结果我所要求的毕竟不是最优雅的设计,而且另一个答案提出了一种更好的方法。尽管如此,我还是赞成这两个答案;谢谢大家
您应该扩展您的自定义协议而不是 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)
你快到了。您只需要来自 .
的 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
}
}
我有这个代表颜色的枚举,我添加了几个方法来方便地根据原始值的算术运算获取新实例:
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)。
结论:我接受了
您应该扩展您的自定义协议而不是 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)
你快到了。您只需要来自 .
的 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
}
}