如何编写协议扩展以从 Swift 枚举中获取所有原始值

How can I write a protocol extension to get all the rawValues from an Swift enum

我想做的是创建一个协议扩展来从枚举中获取一组原始值。例如说我有以下内容:

enum TestType: String, EnumIteratable {
    case unitTest = "Unit Test"
    case uiTest = "UI Test"
}

class EnumIterator: NSObject {
    class func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T>  {
        var i = 0
        return anyGenerator {
            let next = withUnsafePointer(&i) { UnsafePointer<T>([=11=]).memory }
            return next.hashValue == i++ ? next : nil
        }
    }

   class func getValues<T: Hashable>(_: T.Type) -> [T] {
        let iterator = self.iterateEnum(T)
        var returnArray = [T]()
        for val in iterator {
            returnArray.append(val)
        }
        return returnArray
    }

}

我如何实现 EnumIteratable 协议,以便我可以调用 TestType.getRawValues() 并使其成为 return 所有原始枚举值的字符串数组?

谢谢!

您可以将静态 属性 添加到 return 所有枚举值。例如:

 enum RelationshipStatus: String {

  case Single = "Single"
  case Married = "Married"
  case ItsComplicated = "It's complicated"

  static let all: [RelationshipStatus] = [.Single, .Married, .ItsComplicated]

}

for status in RelationshipStatus.all {
  print(status.rawValue)
}

Scott 的解决方案可能就是您想要的。但是,如果您正在寻找可以应用于任意未来枚举并允许其他情况的更通用的东西,您可以试试这个:

首先,您需要一种方法来迭代枚举案例。我从这里使用了这个实现:

func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> {
    var i = 0
    return anyGenerator {
        let next = withUnsafePointer(&i) { UnsafePointer<T>([=10=]).memory }
        return next.hashValue == i++ ? next : nil
    }
}

然后,您可以创建您的协议,定义您想要的静态函数:

protocol EnumIteratable {
    typealias ENUM_TYPE:Hashable, RawRepresentable = Self
    static func getAllValues() -> [ ENUM_TYPE ]
    static func getRawValues() -> [ ENUM_TYPE.RawValue ]
}

我使用关联类型来允许符合规范的枚举将它们的类型指定给协议。 getAllValues 不是绝对必要的,但它简化了逻辑。

然后,您可以定义您的通用默认实现:

extension EnumIteratable {
    static func getAllValues() -> [ ENUM_TYPE ]
    {
        var retval = [ ENUM_TYPE ]()
        for item in iterateEnum( ENUM_TYPE )
        {
            retval.append( item )
        }
        return retval
    }

    static func getRawValues() -> [ ENUM_TYPE.RawValue ]
    {
        return getAllValues().map( { ( item:ENUM_TYPE ) -> ENUM_TYPE.RawValue in item.rawValue } )
    }
}

最后,您需要做的就是在需要迭代枚举时随时遵守该协议:

enum TestType: String, EnumIteratable {
    case unitTest = "Unit Test"
    case uiTest = "UI Test"
}

TestType.getRawValues()

这里的优点是,我可以为 integrationTest 添加一个新案例,我只需要在一个地方添加它。