【问题标题】:How can I write a protocol extension to get all the rawValues from an Swift enum如何编写协议扩展以从 Swift 枚举中获取所有 rawValues
【发布时间】:2015-11-07 23:32:44
【问题描述】:

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

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>($0).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() 并让它返回一个包含所有原始枚举值的字符串数组?

谢谢!

【问题讨论】:

  • 也许使用 MirrorType?
  • @MarceloFabri 镜像不起作用有几个原因,其中一个原因是您实际上需要一个枚举实例,我试图避免这种情况。此外,枚举没有属性:)

标签: swift generics enums protocols generator


【解决方案1】:

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

首先,您需要一种方法来迭代 Enum 案例。我从这里使用了这个实现:https://stackoverflow.com/a/28341290/914887

func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> {
    var i = 0
    return anyGenerator {
        let next = withUnsafePointer(&i) { UnsafePointer<T>($0).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 添加一个新案例,我只需要在一个地方添加它。

【讨论】:

  • 这很酷,与我最初想要完成的目标很接近 :) 感谢您提供替代解决方案!
【解决方案2】:

您可以添加一个静态属性来返回所有枚举值。例如:

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

【讨论】:

  • 这比我想的要容易得多。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多