【发布时间】:2015-07-12 15:18:47
【问题描述】:
如果我有一个包含 a、b、c、d 情况的枚举,我可以将字符串“a”转换为枚举吗?
【问题讨论】:
-
这些“转换”称为文字转换。
如果我有一个包含 a、b、c、d 情况的枚举,我可以将字符串“a”转换为枚举吗?
【问题讨论】:
当然。枚举可以有一个原始值。引用文档:
原始值可以是字符串、字符或任何整数或 浮点数类型
— 摘自:Apple Inc. “The Swift Programming Language”。电子书。 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)\"")
注意:您不需要在每个 case 之后写 = "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 类型。
case one = "uno"。现在,如何将"one" 解析为枚举值? (不能使用 raws,因为它们用于本地化)
= "one"等。默认字符串值与案例名称相同。
我用过这个:
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
}
}
}
【讨论】:
借鉴 djruss70 的答案以创建高度通用的解决方案:
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()
注意:如果枚举被声明为@objc,这将很遗憾。据我所知,从 Swift 5.3 开始,除了蛮力解决方案(switch 语句)之外,没有办法让它与 @objc 枚举一起使用。
如果有人碰巧知道一种方法可以使 @objc 枚举工作,我会对答案非常感兴趣。
【讨论】:
对于 Int 枚举及其 String 表示,我将枚举声明如下:
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)")
【讨论】:
斯威夫特 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
}
}
【讨论】:
在 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)
【讨论】:
你只需要:
enum Foo: String {
case a, b, c, d
}
let a = Foo(rawValue: "a")
assert(a == Foo.a)
let ? = Foo(rawValue: "?")
assert(? == nil)
【讨论】:
如果使用 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
}
【讨论】:
enumFromString 方法似乎很疯狂。
扩展 Duncan 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)
}
}
【讨论】: