在Swift中,可以将字符串转换为枚举吗?


93

如果我有一个用a,b,c,d的枚举,是否可以将字符串“ a”强制转换为枚举?


3
这些“转换”称为文字转换。
Vatsal Manot 2015年

Answers:


136

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

原始值可以是字符串,字符或任何整数或浮点数类型

—摘自:Apple Inc.“ Swift编程语言”。iBooks。https://itun.es/us/jEUH0.l

因此,您可以使用如下代码:

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

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

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

注意:在每种情况下,您无需写=“ one”等。默认的字符串值与案例名称相同,因此调用.rawValue只会返回一个字符串

编辑

如果您需要字符串值来包含诸如空格之类的无效内容,这些值不能作为case值的一部分,那么您需要显式设置字符串。所以,

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

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

anEnum =“一个”

但是,如果要case one显示“值一”,则需要提供字符串值:

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

原始值必须是字面可转换的。您不能只使用任何Hashable一种。
瓦塔诺Manot 2015年

1
好的...我引用了Apple文档,其中列出了可用作枚举原始值的值的类型。字符串,OP的问题,是受支持的类型之一。
Duncan C

1
嗯,想象一下case one = "uno"。现在,如何解析"one"为枚举值?(不能使用原始数据,因为它们已用于本地化)
Agent_L

也许您可以根据本地化在初始化时初始化原始String……或者对于不同的本地化,只需具有不同的枚举。无论如何,拥有枚举的全部目的是抽象出底层的原始内容,即本地化。一个好的代码设计不会在任何地方传递“ uno”作为参数,而是依靠StringEnum.one
SkyWalker

5
= "one"在每种情况下,您都不需要写等。默认字符串值与案例名称相同。
emlai

38

所有你需要的是:

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

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

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

从技术上来说,这不是正确的答案,因为这会检查原始值。在给定的示例中,没有指定原始值,因此它与案例名称隐式匹配,但是如果您有一个带有原始值的枚举,则会中断。
Mark A. Donohoe

26

在Swift 4.2中,CaseIterable协议可用于具有rawValues的枚举,但是字符串应与枚举的大小写标签匹配:

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)

2
这是一个很好的答案!它实际上解决了这个问题。
马特·朗德尔

3
这是按OP要求实际起作用的唯一答案,这与案例名称有关,而不是原始值。好答案!
Mark A. Donohoe

1
虽然这有效,但要做的却很愚蠢。请不要将功能基于代码中的案例名称。
苏珊(Sulthan)'18

7
他还应该做什么?如果他正在将枚举写入数据库,然后需要将其抛回去怎么办?

15

如果是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
    }
}

并使用:

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

1
疯狂的是,您不能只使用该语言内置的类似功能。我可以想象您例如通过枚举名称将值存储在JSON中,然后在解析时需要将其转换回。enumFromString为您使用的每个枚举编写方法似乎很疯狂。
Peterdk

1
@Peterdk,请提出最佳的替代方案。Igor解决方案实际上只对我有用。
Hemang,

@Hemang可以正常工作,但是更好的解决方案是Swift支持自动执行此操作。手动为每个枚举执行此操作非常疯狂。但是,可以。
Peterdk

@Peterdk,可否请您为它添加一个单独的答案?它肯定会帮助这里的每个人。
Hemang's

1
Swift本身不支持它并不奇怪。疯狂的事情是功能依赖于类型的名称。当值更改时,您将必须重构并重命名所有用法。这不是解决此问题的正确方法。
苏珊(Sulthan)'18

2

扩展邓肯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)
    }
}

2

Swift 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
    }
}

1

对于Int枚举及其字符串表示形式,我将枚举声明如下:

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)")
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.