In Swift, is it possible to convert a string to an enum?

If I have an enum with the cases a,b,c,d is it possible for me to cast the string "a" as the enum?

73668 次浏览

当然可以。枚举可以有一个原始值。引用文档:

Raw values can be strings, characters, or any of the integer or 浮点数类型浮点数类型

- 摘自: 苹果公司“迅速编程语言”,iBooks,https://itun.es/us/jEUH0.l,

所以你可以这样使用代码:

enum StringEnum: String
{
case one   = "value one"
case two   = "value two"
case three = "value three"
}


let anEnum = StringEnum(rawValue: "value one")!


print("anEnum = \"\(anEnum.rawValue)\"")

注意: 你不需要在每个例子后面写 = “ one”等等。默认的字符串值与大小写名称相同,因此调用 .rawValue只会返回一个字符串

EDIT

如果您需要字符串值来包含空格之类的东西,而这些空格作为 case 值的一部分是无效的,那么您需要显式地设置字符串。那么,

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


let anEnum = StringEnum.one
print("anEnum = \"\(anEnum)\"")

给予

AnEnum = “ one”

但是如果你想让 case one显示“值1”,你需要提供字符串值:

enum StringEnum: String
{
case one   = "value one"
case two   = "value two"
case three = "value three"
}

在使用 Int 类型的枚举时,可以这样做:

enum MenuItem: Int {
case One = 0, Two, Three, Four, Five //... as much as needs


static func enumFromString(string:String) -> MenuItem? {
var i = 0
while let item = MenuItem(rawValue: i) {
if String(item) == string { return item }
i += 1
}
return nil
}
}

And use:

let string = "Two"
if let item = MenuItem.enumFromString(string) {
//in this case item = 1
//your code
}

扩展邓肯 C 的回答

extension StringEnum: StringLiteralConvertible {


init(stringLiteral value: String){
self.init(rawValue: value)!
}


init(extendedGraphemeClusterLiteral value: String) {
self.init(stringLiteral: value)
}


init(unicodeScalarLiteral value: String) {
self.init(stringLiteral: value)
}
}

你只需要:

enum Foo: String {
case a, b, c, d
}


let a = Foo(rawValue: "a")
assert(a == Foo.a)


let 💩 = Foo(rawValue: "💩")
assert(💩 == nil)

在 Swift 4.2中,CaseIterable 协议可以用于包含 rawValue 的枚举,但是字符串应该与枚举大小写标签匹配:

enum MyCode : String, CaseIterable {


case one   = "uno"
case two   = "dos"
case three = "tres"


static func withLabel(_ label: String) -> MyCode? {
return self.allCases.first{ "\($0)" == label }
}
}

用途:

print(MyCode.withLabel("one")) // Optional(MyCode.one)
print(MyCode(rawValue: "uno"))  // Optional(MyCode.one)

迅捷4.2:

public enum PaymentPlatform: String, CaseIterable {
case visa = "Visa card"
case masterCard = "Master card"
case cod = "Cod"


var nameEnum: String {
return Mirror(reflecting: self).children.first?.label ?? String(describing: self)
}


func byName(name: String) -> PaymentPlatform {
return PaymentPlatform.allCases.first(where: {$0.nameEnum.elementsEqual(name)}) ?? .cod
}
}

对于 Int enum 及其 String 表示形式,我声明 enum 如下:

enum OrderState: Int16, CustomStringConvertible {


case waiting = 1
case inKitchen = 2
case ready = 3


var description: String {
switch self {
case .waiting:
return "Waiting"
case .inKitchen:
return "InKitchen"
case .ready:
return "Ready"
}
}


static func initialize(stringValue: String)-> OrderState? {
switch stringValue {
case OrderState.waiting.description:
return OrderState.waiting
case OrderState.inKitchen.description:
return OrderState.inKitchen
case OrderState.ready.description:
return OrderState.ready


default:
return nil
}
}
}

用法:

order.orderState = OrderState.waiting.rawValue


let orderState = OrderState.init(rawValue: order.orderState)
let orderStateStr = orderState?.description ?? ""
print("orderStateStr = \(orderStateStr)")

Riffing on djruss70's answer to create highly generalized solution:

extension CaseIterable {
static func from(string: String) -> Self? {
return Self.allCases.first { string == "\($0)" }
}
func toString() -> String { "\(self)" }
}

用法:

enum Chassis: CaseIterable {
case pieridae, oovidae
}


let chassis: Chassis = Chassis.from(string: "oovidae")!
let string: String = chassis.toString()

注意: 如果枚举被声明为@objecc,那么这将不起作用。据我所知,在 Swift 5.3中,除了蛮力解决方案(switch 语句)之外,没有其他方法可以让它与@objecc enum 一起工作。

如果有人碰巧知道一种方法可以使@objecc enums 工作,我会非常感兴趣的答案。

我用了这个:

public enum Currency: CaseIterable, Codable {
case AFN = 971 // Afghani (minor=2)
case DZD = 012 // Algerian Dinar (minor=2)


...


private static var cachedLookup: [String: Currency] = [:]
    

init?(string: String) {
if Self.cachedLookup.isEmpty {
Self.cachedLookup = Dictionary(uniqueKeysWithValues: Self.allCases.map { ("\($0)", $0) })
}
        

if let currency = Self.cachedLookup[string] {
self = currency
return
} else {
return nil
}
}
}

我发现其他的答案会让事情变得更复杂。下面是一个快速简洁的例子。

enum Gender: String {
case male, female, unspecified
}

简单的枚举,注意我在枚举本身中添加了“ : String”来将类型声明为字符串。

现在你要做的就是:

let example: Gender = Gender(rawValue: "male")

就是这样,“ example”现在是一个具有值为. men 的性别类型枚举

There is literally nothing else you need to do in Swift 4+.