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

基于字符串的枚举是否有Swift类型?,swift,generics,enums,Swift,Generics,Enums,我有一个函数,它接受一个String标记参数: func findFooByTag(_ tag: String) -> Foo 现在,我想通过引入有效标记值的枚举,使代码更短、更安全: enum Tags: String { case one case two case three } 但是我仍然必须使用字符串调用函数: let foo = findFooByTag(Tags.one.rawValue) 有没有办法说“findFooByTag接受任何基于字符串

我有一个函数,它接受一个
String
标记参数:

func findFooByTag(_ tag: String) -> Foo
现在,我想通过引入有效标记值的枚举,使代码更短、更安全:

enum Tags: String {
    case one
    case two
    case three
}
但是我仍然必须使用
字符串调用函数:

let foo = findFooByTag(Tags.one.rawValue)
有没有办法说“
findFooByTag
接受任何基于字符串的枚举”?我发现:

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

但那真是太多了。至少可以用一个类型别名将其扫到地毯下吗?

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

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

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

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
枚举类型未指定标记{
案例一
}
枚举字符串标记:字符串{
案例一
}
枚举IntTag:Int{
案例一=1
}
枚举包装器:可表示{
typealias RawValue=T
案例值(T)
初始化?(rawValue:rawValue){
self=.value(原始值)
}
var-rawValue:rawValue{
切换自身{
案例价值(项目):
退货项目
}
}
}
打印(Wrapper.value(TypeNotSpecifiedTag.one.rawValue)/“一”
打印(Wrapper.value(StringTag.one.rawValue.rawValue)/“一”
打印(Wrapper.value(IntTag.one.rawValue.rawValue)//1

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

也许您可以尝试使用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
枚举标记:字符串,自定义字符串{ 案例一 案例二 案例三 变量说明:字符串{ 返回self.rawValue } } func findFooByTag(tag:T)->Foo其中T:CustomStringConvertible
看起来好多了

或者只是

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

由于
enum
具有
字符串的
RawValue
之间没有任何共同之处,因此这些没有共同的类型,也没有所有人都会遵守的协议

但是,Swift 4使用where子句在关联类型上引入类型约束,如中所述。使用这一新功能,您可以使用
字符串
rawValue
定义一个具有关联类型的协议,即描述
enum
的类型约束,然后您只需使
标记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)
class Foo{}
协议字符串枚举{
associatedtype EnumType:RawRepresentable=Self,其中EnumType.RawValue==String
静态func findFooByTag(tag:EnumType)->Foo
}
扩展StringEnum,其中EnumType==Self{
静态func findFooByTag(tag:EnumType)->Foo{
返回Foo()
}
}
枚举标记:字符串,StringEnum{
案例一
案例二
案例三
}
让foo=Tags.findFooByTag(Tags.one)
这是一个当然可以改进的实现,但这只是一个示例,展示了如何使用
where
子句,使用
协议及其
关联类型来实现类型约束

由于协议扩展中的
findFooByTag
func的默认实现,您不需要为所有具有
String
rawValue
的自定义枚举类型实现该函数,您只需要声明它们符合
StringEnum
协议


如果没有安装Xcode9,可以使用link在IBM Swift沙盒中使用此代码。

如何使用
标记
内部
findByTag
?您所知道的只是它是一个空协议。@zoul我已经填充了更多内容。
CustomStringConvertible
与OP试图实现的目标无关。任何类都可以符合
CustomStringCollectible
,唯一的一致性要求是具有类型为
String
的名为
description
的属性。。。您的函数也可以使用类类型调用,或者使用具有
Int
rawValue
或根本没有
rawValue
的枚举类型调用,只要它们符合
CustomStringConvertible