基于字符串的枚举是否有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
。