我有一个带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
但那是相当满口的。是否至少可以用某种类型的别名在地毯下扫一扫?
答案 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中使用此代码。