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

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

let city = City.Melbourne

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

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

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

当前回答

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

然后,您可以将其用作枚举实例上的常规方法调用。 它可能也适用于以前的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"

如果你想为你所有的枚举提供这个功能,你可以让它成为一个扩展:

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

这只适用于Swift枚举。

其他回答

在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

内省在快速枚举似乎部分工作。

我看到了@drewag的回复,发现一个没有rawValues的Enum确实可以在Swift 5中进行自省。X与Xcode 11.5。这段代码可以工作。

public enum Domain: String {
    case network
    case data
    case service
    case sync
    var description: String {
        return "\(self)"     // THIS INTROSPECTION WORKS
    }
}
enum ErrorCode: Int, CustomStringConvertible {
    case success = 200
    case created = 201
    case accepted = 202
    case badRequest = 400
    case unauthorized = 401
    case forbidden = 403
    case notFound = 404
    var code: Int {
        return self.rawValue
    }
    var description: String {
        return "\(self)"      //THIS DOES NOT WORK - EXEC_BAD_ACCESS
    }
}
let errorCode = ErrorCode.notFound
let domain = Domain.network
print(domain.description, errorCode.code, errorCode.description)

在第二个Enum中,将"\(self)"替换为"string",你将得到以下打印输出: 网络404字符串

注意:在第一个枚举中使用String(self)而不是"\(self)"将要求Enum符合theLosslessStringConvertible '协议,并添加其他初始化器,因此字符串插值似乎是一个很好的解决方案。

要将var description: String添加到枚举中,您必须使用Switch语句将前面指出的所有枚举情况

var description: String {
    switch self {
    case .success: return "Success"
    case .created: return "Created"
    case .accepted: return "Accepted"
    }
}

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

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

Swift现在有所谓的隐式分配原始值。基本上,如果您不为每个case提供原始值,并且枚举类型为String,则它推断出case的原始值本身为字符串格式。去试试吧。

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

let city = City.Melbourne.rawValue

// city is "Melbourne"

这太令人失望了。

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