如果我有一个原始整型值的枚举:

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

let city = City.Melbourne

如何将城市值转换为字符串墨尔本?这种类型名称内省在语言中可用吗?

类似于(这段代码将不起作用):

println("Your city is \(city.magicFunction)")
> Your city is Melbourne

当前回答

从Xcode 7 beta 5 (Swift版本2)开始,你现在可以默认使用print(_:)打印类型名和enum大小写,或者使用String的init(_:)初始化器或字符串插值语法转换为String。举个例子:

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"

因此,不再需要定义和维护一个方便的函数来切换每个大小写以返回字符串字面量。此外,即使没有指定原始值类型,它也会自动适用于任何枚举。

debugPrint(_:) & String(reflection:)可以用于完全限定名:

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

let cityDebugName = String(reflecting: city)
// cityDebugName contains "App.City.Melbourne"

请注意,您可以自定义在这些场景中打印的内容:

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)"

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

String的init(_:)和init(reflections:)初始化器上面的注释描述了打印的内容,具体取决于反射的类型:

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

有关此更改的信息,请参阅发布说明。

其他回答

从Xcode 7 beta 5 (Swift版本2)开始,你现在可以默认使用print(_:)打印类型名和enum大小写,或者使用String的init(_:)初始化器或字符串插值语法转换为String。举个例子:

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"

因此,不再需要定义和维护一个方便的函数来切换每个大小写以返回字符串字面量。此外,即使没有指定原始值类型,它也会自动适用于任何枚举。

debugPrint(_:) & String(reflection:)可以用于完全限定名:

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

let cityDebugName = String(reflecting: city)
// cityDebugName contains "App.City.Melbourne"

请注意,您可以自定义在这些场景中打印的内容:

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)"

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

String的init(_:)和init(reflections:)初始化器上面的注释描述了打印的内容,具体取决于反射的类型:

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

有关此更改的信息,请参阅发布说明。

这太令人失望了。

当你需要这些名字的时候(编译器完全知道这些名字的准确拼写,但拒绝访问)——谢谢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()
        }
    }
}

您可以使用上述如下:

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

println("fetching element \(elementType), column: \(column.string()), row: \(row)")

您将得到预期的结果(列的代码类似,但没有显示)

fetching element Title, column: Collections, row: 0

在上面,我已经使description属性引用回string方法,但这是一个品味问题。还要注意,所谓的静态变量需要通过其封闭类型的名称来限定作用域,因为编译器太健忘了,无法自行召回上下文…

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

在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"

然而,我的意思是,对于“简单”枚举,上面基于反射的标签计算属性只返回nil (boo-hoo)。

print(City.Chelyabinsk.label) // prints out nil

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

print(String(City.Chelyabinsk)) // prints out Cheylabinsk

目前在枚举情况下没有自省。你必须手动声明它们:

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

    var description: String {
        get {
            return self.rawValue
        }
    }
}

如果你需要原始类型是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"
      }
    }
  }
}

对于Objective-C枚举来说,目前唯一的方法似乎是,例如,用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"
        }
    }
}

然后将枚举类型转换为String:

String(UIDevice.currentDevice().batteryState)