是否有基于字符串的枚举的Swift类型?

时间:2017-09-04 07:10:33

标签: swift generics enums

我有一个带String标记参数的函数:

func findFooByTag(_ tag: String) -> Foo

现在我想通过引入有效标记值的枚举来使代码更短更安全:

enum Tags: String {
    case one
    case two
    case three
}

但我仍然需要使用String调用该函数:

let foo = findFooByTag(Tags.one.rawValue)

有没有办法说“findFooByTag采用任何基于字符串的枚举”?我发现了这个:

func findFooByTag<T>(_ tag: T) -> Foo where T: RawRepresentable, T.RawValue == String

但那是相当满口的。是否至少可以用某种类型的别名在地毯下扫一扫?

4 个答案:

答案 0 :(得分:1)

你发现的东西看起来很棒,但我仍然建议如下:

protocol Taggable {
    var raw: String { get }
}

extension String: Taggable {
    var raw: String { return self }
}

enum Tag: String, Taggable {
    var raw: String {
        return self.rawValue
    }

    case one = "aa"
    case two = "bb"
    case three = "cc"
}

func findByTag(_ tag: Taggable) {
    if tag.raw == "aa" { ... }
    // do something...
}

findByTag(Tag.one) // works
findByTag("abc")   // also works

答案 1 :(得分:0)

为此,您可以使用任何类型的包装器对象。例如:

enum TypeNotSpecifiedTag {
    case one
}

enum StringTag: String {
    case one
}

enum IntTag: Int {
    case one = 1
}

enum Wrapper<T>: RawRepresentable {
    typealias RawValue = T

    case value(T)

    init?(rawValue: RawValue) {
        self = .value(rawValue)
    }

    var rawValue: RawValue {
        switch self {
        case let .value(item):
            return item
        }
    }
}

print(Wrapper.value(TypeNotSpecifiedTag.one).rawValue) // "one"
print(Wrapper.value(StringTag.one.rawValue).rawValue) // "one"
print(Wrapper.value(IntTag.one.rawValue).rawValue) // 1

请注意,根据documentation about RawValue,您并不总是需要指定RawValue,这就是为什么第一个示例也会编译的原因。

答案 2 :(得分:0)

也许您可以尝试使用CustomStringConvertible?

enum Tags: String, CustomStringConvertible {
  case one
  case two
  case three

  var description: String {
    return self.rawValue
  }
}

func findFooByTag<T>(_ tag: T) -> Foo where T: CustomStringConvertible

看起来更好

或只是

func findFooByTag<T>(_ tag: CustomStringConvertible) -> Foo

答案 3 :(得分:0)

由于enum拥有String RawValue之间没有任何共同之处,因此这些协议或没有协议都没有共同类型。

但是,Swift 4使用SE-0142中描述的where子句引入了关联类型的类型约束。使用此新功能,您可以使用关联类型定义协议,使用enum String描述rawValue的类型约束,然后您只需要使Tags enum符合对于此协议,您将不再需要函数定义中的类型约束。

class Foo {}

protocol StringEnum {
    associatedtype EnumType: RawRepresentable = Self where EnumType.RawValue == String
    static func findFooByTag<EnumType>(_ tag: EnumType) -> Foo
}

extension StringEnum where EnumType == Self {
    static func findFooByTag<EnumType>(_ tag: EnumType) -> Foo {
        return Foo()
    }
}

enum Tags: String, StringEnum {
    case one
    case two
    case three
}

let foo = Tags.findFooByTag(Tags.one)

这当然可以改进实现,但这只是一个示例,说明如何使用where子句来使用protocol及其associatedType来实现类型约束。

由于协议扩展中findFooByTag func的默认实现,您无需为具有String rawValue的所有自定义枚举类型实现此功能,您只需将它们声明为符合StringEnum协议。

如果您没有安装Xcode9,可以使用this链接在IBM Swift Sandbox中使用此代码。