![](/img/trans.png)
[英]How to get the name of an enumeration case by its raw value in Swift 4?
[英]How to get the name of enumeration value in Swift?
如果我有一个带有原始Integer
数值的枚举:
enum City: Int {
case Melbourne = 1, Chelyabinsk, Bursa
}
let city = City.Melbourne
如何将city
值转换为字符串Melbourne
? 这种类型名称自省在语言中可用吗?
类似于(此代码不起作用):
println("Your city is \(city.magicFunction)")
> Your city is Melbourne
从 Xcode 7 beta 5(Swift 版本 2)开始,您现在可以默认使用print(_:)
打印类型名称和枚举案例,或者使用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"
所以不再需要定义和维护一个方便的函数来打开每个 case 以返回一个字符串文字。 此外,即使未指定原始值类型,这也会自动适用于任何枚举。
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"
请注意,您可以自定义在每个场景中打印的内容:
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)"
(我还没有找到调用这个“默认”值的方法,例如,打印“The city is Melbourne”而不求助于 switch 语句。在description
/ debugDescription
的实现中使用\\(self)
会导致无限递归。)
String
的init(_:)
和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)
}
有关此更改的信息,请参阅发行说明。
目前没有对枚举案例的内省。 您必须手动声明它们:
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-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 枚举。
对于 Objective-C enum
s,目前似乎唯一的方法是,例如,使用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"
}
}
}
然后将enum
为String
:
String(UIDevice.currentDevice().batteryState)
String(describing:)
describing String(describing:)
初始值设定项可用于返回 case 标签名称,即使对于具有非 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"
注意如果枚举使用,这并不工作@objc
修改:
String(describing:)
describing String(describing:)
返回“EnumName”而不是“caseLabel”? 为 Objective-C 类型生成的 Swift 接口有时不包含@objc
修饰符。 然而,这些枚举是在 Objective-C 中定义的,因此不像上面那样工作。
除了 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"
然而,通过被破坏,我的意思是对于“简单”枚举,上述基于反射的label
计算属性仅返回nil
(boo-hoo)。
print(City.Chelyabinsk.label) // prints out nil
显然,在 Swift 3 之后,反射的情况应该会变得更好。 现在的解决方案是String(…)
,正如其他答案之一所建议的:
print(String(City.Chelyabinsk)) // prints out Cheylabinsk
我碰到了这个问题,想分享一个简单的方法来创建提到的magicFunction
enum City: Int {
case Melbourne = 1, Chelyabinsk, Bursa
func magicFunction() -> String {
return "\(self)"
}
}
let city = City.Melbourne
city.magicFunction() //prints 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
方法,但这是一个品味问题。 另请注意,所谓的static
变量需要通过其封闭类型的名称进行范围限定,因为编译器太健忘并且无法自行回忆上下文......
Swift 团队必须真正受到指挥。 他们创建了你不能enumerate
,你可以使用enumerate
的是“序列”而不是enum
!
Swift 现在具有所谓的隐式分配原始值。 基本上,如果您不为每个 case 提供原始值并且枚举的类型为 String,则它会推断 case 的原始值本身就是字符串格式。 去试试吧。
enum City: String {
case Melbourne, Chelyabinsk, Bursa
}
let city = City.Melbourne.rawValue
// city is "Melbourne"
对于斯威夫特:
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"
}
}
}
如果您的变量“batteryState”然后调用:
self.batteryState.description
简单但有效...
enum ViewType : Int {
case Title
case Buttons
case View
}
func printEnumValue(enum: ViewType) {
switch enum {
case .Title: println("ViewType.Title")
case .Buttons: println("ViewType.Buttons")
case .View: println("ViewType.View")
}
}
Swift Enums 中的内省似乎部分起作用。
我看到@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"
,您将得到以下打印输出:network 404 string
注意: "\\(self)" in the first
Enum 中使用String(self)
而不是"\\(self)" in the first
will require the Enum to conform to the
LosslessStringConvertible` 协议,并添加其他初始值设定项,因此字符串插值似乎是一个很好的解决方法。
要将var description: String
添加到枚举中,您将必须使用 Switch 语句将所有枚举情况与之前指出的一样
var description: String {
switch self {
case .success: return "Success"
case .created: return "Created"
case .accepted: return "Accepted"
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.