如何在Swift中获取枚举值的名称?

Evg*_*nii 145 enumeration swift

如果我有一个带有原始Integer值的枚举:

enum City: Int {
  case Melbourne = 1, Chelyabinsk, Bursa
}

let city = City.Melbourne
Run Code Online (Sandbox Code Playgroud)

如何将city值转换为字符串Melbourne?这种类型的名称内省是否可用于该语言?

像(这段代码不起作用):

println("Your city is \(city.magicFunction)")
> Your city is Melbourne
Run Code Online (Sandbox Code Playgroud)

Stu*_*art 118

作为Xcode的7测试版5,你可以在默认情况下使用现在打印类型名称和枚举的情况下print(_:),或转换到String使用Stringinit(_:)初始化字符串或内插语法.所以对于你的例子:

enum City: Int {
    case Melbourne = 1, Chelyabinsk, Bursa
}
let city = City.Melbourne

print(city)
// prints "Melbourne"

let cityName = "\(city)"   // or `let cityName = String(city)`
// cityName contains "Melbourne"
Run Code Online (Sandbox Code Playgroud)

因此,不再需要定义和维护一个便利功能,该功能可以打开每个案例以返回字符串文字.此外,即使没有指定原始值类型,这也适用于任何枚举.

debugPrint(_:)&String(reflecting:)可用于完全限定名称:

debugPrint(city)
// prints "App.City.Melbourne" (or similar, depending on the full scope)

let cityDebugName = String(reflecting: city)
// cityDebugName contains "App.City.Melbourne"
Run Code Online (Sandbox Code Playgroud)

请注意,您可以自定义在以下每种方案中打印的内容:

extension City: CustomStringConvertible {
    var description: String {
        return "City \(rawValue)"
    }
}

print(city)
// prints "City 1"

extension City: CustomDebugStringConvertible {
    var debugDescription: String {
        return "City (rawValue: \(rawValue))"
    }
}

debugPrint(city)
// prints "City (rawValue: 1)"
Run Code Online (Sandbox Code Playgroud)

(我还没有找到一种方法来调用这个"默认"值,例如,打印"城市是墨尔本"而不诉诸于switch语句.\(self)description/ 的实现中使用debugDescription会导致无限递归.)


上述评论Stringinit(_:)&init(reflecting:)初始化描述打印什么,这取决于所反射的类型符合:

extension String {
    /// Initialize `self` with the textual representation of `instance`.
    ///
    /// * If `T` conforms to `Streamable`, the result is obtained by
    ///   calling `instance.writeTo(s)` on an empty string s.
    /// * Otherwise, if `T` conforms to `CustomStringConvertible`, the
    ///   result is `instance`'s `description`
    /// * Otherwise, if `T` conforms to `CustomDebugStringConvertible`,
    ///   the result is `instance`'s `debugDescription`
    /// * Otherwise, an unspecified result is supplied automatically by
    ///   the Swift standard library.
    ///
    /// - SeeAlso: `String.init<T>(reflecting: T)`
    public init<T>(_ instance: T)

    /// Initialize `self` with a detailed textual representation of
    /// `subject`, suitable for debugging.
    ///
    /// * If `T` conforms to `CustomDebugStringConvertible`, the result
    ///   is `subject`'s `debugDescription`.
    ///
    /// * Otherwise, if `T` conforms to `CustomStringConvertible`, the result
    ///   is `subject`'s `description`.
    ///
    /// * Otherwise, if `T` conforms to `Streamable`, the result is
    ///   obtained by calling `subject.writeTo(s)` on an empty string s.
    ///
    /// * Otherwise, an unspecified result is supplied automatically by
    ///   the Swift standard library.
    ///
    /// - SeeAlso: `String.init<T>(T)`
    public init<T>(reflecting subject: T)
}
Run Code Online (Sandbox Code Playgroud)


有关此更改的信息, 请参阅发行说明.

  • 重要的捕获,这***适用于Swift枚举.如果您将其标记为@objc以允许OS X上的绑定支持,则无效. (37认同)
  • 另外,如果你想要字符串值而不使用`print(enum)`,你可以使用`String(enum)` (8认同)
  • 伟大的Swift特定答案; 但是,如果你需要在非swift枚举上执行此操作,例如在`locationManager didChangeAuthorizationStatus`委托回调中打印(Objective C)`CLAuthorizationStatus`枚举值,则需要定义协议扩展.例如:`extension CLAuthorizationStatus:CustomStringConvertable {public var description:String {switch self {case .AuthorizedAlways:return"AuthorizedAlways"<etc>}}}` - 一旦你完成了它,它应该按照你的期望工作: print("Auth status:(\ status))". (8认同)
  • "从Xcode 7 beta 5开始"毫无意义.Xcode不是定义任何一个,它是Swift编译器和Swift Runtime Libaries.我可以使用Xcode 9.3但我的代码仍然可以是Swift 3然后我不能使用Swift 4功能.使用Xcode 9.3,尽管Xcode 9.3比Xcode 7更新,但此代码不起作用. (3认同)
  • 谢谢杰弗罗。稍微更正:它是 **CustomStringConvertible** 而不是 CustomStringConvertable。 (2认同)
  • 我得到了初始化程序“ init(_ :)”,要求City符合Swift 5的xcode 10.2上的“ LosslessStringConvertible”。 (2认同)
  • 为什么`print(UNNotificationSetting.disabled)`不打印`disabled`而是打印`UNNotificationSetting`? (2认同)

dre*_*wag 73

目前对枚举案件没有反省.您必须手动声明它们:

enum City: String, CustomStringConvertible {
    case Melbourne = "Melbourne"
    case Chelyabinsk = "Chelyabinsk"
    case Bursa = "Bursa"

    var description: String {
        get {
            return self.rawValue
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:该__CODE__协议目前不适用于Playgrounds.如果你想在游乐场中看到字符串,你必须手动调用toRaw()

如果您需要原始类型为Int,则必须自己进行切换:

enum City: Int, CustomStringConvertible {
  case Melbourne = 1, Chelyabinsk, Bursa

  var description: String {
    get {
      switch self {
        case .Melbourne:
          return "Melbourne"
        case .Chelyabinsk:
          return "Chelyabinsk"
        case .Bursa:
          return "Bursa"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • Noob问题,但为什么要把get {return self.rawValue}而不是只返回self.value?我尝试了后者,它运作得很好. (2认同)
  • 如果你没有定义一个 setter,你也可以省略 `get { ... }` 部分为简洁起见。 (2认同)

小智 34

在Swift-3中(使用Xcode 8.1测试),您可以在枚举中添加以下方法:

/**
 * The name of the enumeration (as written in case).
 */
var name: String {
    get { return String(describing: self) }
}

/**
 * The full name of the enumeration
 * (the name of the enum plus dot plus the name as written in case).
 */
var description: String {
    get { return String(reflecting: self) }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以将其用作枚举实例上的常规方法调用.它可能也适用于之前的Swift版本,但我还没有测试过.

在你的例子中:

enum City: Int {
    case Melbourne = 1, Chelyabinsk, Bursa
    var name: String {
        get { return String(describing: self) }
    }
    var description: String {
        get { return String(reflecting: self) }
    }
}
let city = City.Melbourne

print(city.name)
// prints "Melbourne"

print(city.description)
// prints "City.Melbourne"
Run Code Online (Sandbox Code Playgroud)

如果要为所有枚举提供此功能,可以将其作为扩展名:

/**
 * Extend all enums with a simple method to derive their names.
 */
extension RawRepresentable where RawValue: Any {
  /**
   * The name of the enumeration (as written in case).
   */
  var name: String {
    get { return String(describing: self) }
  }

  /**
   * The full name of the enumeration
   * (the name of the enum plus dot plus the name as written in case).
   */
  var description: String {
    get { return String(reflecting: self) }
  }
}
Run Code Online (Sandbox Code Playgroud)

这仅适用于Swift枚举.


Mar*_*uro 16

对于Objective-C来说enum,目前似乎唯一的方法就是扩展枚举,CustomStringConvertible最后得到如下结果:

extension UIDeviceBatteryState: CustomStringConvertible {
    public var description: String {
        switch self {
        case .Unknown:
            return "Unknown"
        case .Unplugged:
            return "Unplugged"
        case .Charging:
            return "Charging"
        case .Full:
            return "Full"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其转换enumString:

String(UIDevice.currentDevice().batteryState)
Run Code Online (Sandbox Code Playgroud)


NSC*_*der 7

Swift 现在拥有所谓的隐式分配原始值。基本上,如果您不为每个案例提供原始值并且枚举是 String 类型,则它会推断案例的原始值本身就是字符串格式。继续尝试一下吧。

enum City: String {
  case Melbourne, Chelyabinsk, Bursa
}

let city = City.Melbourne.rawValue

// city is "Melbourne"
Run Code Online (Sandbox Code Playgroud)


mz2*_*mz2 7

除了对Swift 2.2中的枚举的String(...)(CustomStringConvertible)支持之外,还有一些对它们的反射支持.对于具有关联值的枚举案例,可以使用反射获取枚举案例的标签:

enum City {
    case Melbourne(String)
    case Chelyabinsk
    case Bursa

    var label:String? {
        let mirror = Mirror(reflecting: self)
        return mirror.children.first?.label
    }
}

print(City.Melbourne("Foobar").label) // prints out "Melbourne"
Run Code Online (Sandbox Code Playgroud)

然而,通过被打破,我意味着对于"简单"枚举,上面基于反射的label计算属性只返回nil(boo-hoo).

print(City.Chelyabinsk.label) // prints out nil
Run Code Online (Sandbox Code Playgroud)

显然,在Swift 3之后反思的情况应该会好转.现在的解决方案是String(…),正如其他一个答案中所建议的那样:

print(String(City.Chelyabinsk)) // prints out Cheylabinsk
Run Code Online (Sandbox Code Playgroud)

  • 这似乎适用于 Swift 3.1,无需将其设为可选:`var label:String { let mirror = Mirror(reflecting: self); if let label = mirror.children.first?.label { return label } else { return String(describing:self) } }` (2认同)

Sev*_*Sev 7

我碰到了这个问题,想分享一个简单的方法来创建提到的magicFunction

enum City: Int {
  case Melbourne = 1, Chelyabinsk, Bursa

    func magicFunction() -> String {
        return "\(self)"
    }
}

let city = City.Melbourne
city.magicFunction() //prints Melbourne
Run Code Online (Sandbox Code Playgroud)


pka*_*amb 6

The String(describing:) initializer can be used to return the case label name even for enums with non-String rawValues:

enum Numbers: Int {
    case one = 1
    case two = 2
}

let one = String(describing: Numbers.one) // "one"
let two = String(describing: Numbers.two) // "two"
Run Code Online (Sandbox Code Playgroud)

Note that this does not work if the enum uses the @objc modifier:

https://forums.swift.org/t/why-is-an-enum-returning-enumname-rather-than-caselabel-for-string-describing/27327

Generated Swift interfaces for Objective-C types sometimes do not include the @objc modifier. Those Enums are nevertheless defined in Objective-C, and thus do not work like above.


ver*_*rec 5

这太令人失望了.

对于你需要这些名字的情况(编译器完全知道拼写的确切拼写,但拒绝让访问 - 谢谢Swift团队!! - )但不想或不能让String成为你枚举的基础,冗长,繁琐的替代方案如下:

enum ViewType : Int, Printable {

    case    Title
    case    Buttons
    case    View

    static let all = [Title, Buttons, View]
    static let strings = ["Title", "Buttons", "View"]

    func string() -> String {
        return ViewType.strings[self.rawValue]
    }

    var description:String {
        get {
            return string()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用以上内容:

let elementType = ViewType.Title
let column = Column.Collections
let row = 0

println("fetching element \(elementType), column: \(column.string()), row: \(row)")
Run Code Online (Sandbox Code Playgroud)

并且您将获得预期的结果(列的代码类似,但未显示)

fetching element Title, column: Collections, row: 0
Run Code Online (Sandbox Code Playgroud)

在上面,我已经让description财产参考了string方法,但这是一个品味问题.还要注意,所谓的static变量需要通过其封闭类型的名称进行范围限定,因为编译器过于遗忘并且无法单独调用上下文...

必须真正指挥斯威夫特团队.他们创建了你不能的枚举,你可以enumerate使用enumerate的是"序列",但不是enum!