Как получить имя значения перечисления в Swift?
если у меня есть перечисление с raw 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
9 ответов:
начиная с Xcode 7 beta 5 Теперь вы можете печатать имена типов и случаи перечисления по умолчанию с помощью
print(_:)
, или преобразовать вString
используяString
' sinit(_:)
синтаксис инициализатора или Строковой интерполяции. Так что для вашего примера: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(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)"
(я не нашел способа вызвать это значение "по умолчанию", например, чтобы напечатать "город Мельбурн", не прибегая к инструкции switch. Используя
\(self)
при осуществленииdescription
/debugDescription
вызывает бесконечную рекурсию.)
Комментарии вышеString
' sinit(_:)
&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, Printable { case Melbourne = "Melbourne" case Chelyabinsk = "Chelyabinsk" case Bursa = "Bursa" var description : String { get { return self.rawValue } } }
Примечание: The
Printable
протокол в настоящее время не работает в детские площадки. Если вы хотите увидеть строку на игровой площадке, вам придется вызвать toRaw() вручнуюЕсли вам нужен тип raw, чтобы быть Int, вам придется сделать переключатель самостоятельно:
enum City : Int, Printable { 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) вы можете добавить следующие методы в свой enum:
/** * 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) } } }
это работает только для быстрых перечислений.
Для 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)
это так обидно.
для случая, когда вам нужны эти имена (что компилятор прекрасно знает точное написание, но отказывается дать доступ-спасибо Swift team!! -- ) но не хотите или не можете сделать строку основой вашего перечисления, многословная, громоздкая альтернатива выглядит следующим образом:
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
on - это "последовательности", но неenum
!
в верхней части строки ( ... ) (CustomStringConvertible) поддержка перечислений в Swift 2.2, есть также несколько сломанная поддержка отражения для них. Для случаев перечисления со связанными значениями можно получить метку случая перечисления с помощью отражения:
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
(хнык-хнык).print(City.Chelyabinsk.label) // prints out nil
ситуация с отражением должна быть становится лучше после Swift 3, по-видимому. Решение на данный момент, хотя
String(…)
, как было предложено в одном из других ответов:print(String(City.Chelyabinsk)) // prints out Cheylabinsk
простой, но работает...
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 теперь имеет то, что известно как Неявно Присвоено Необработанное Значение. В основном, если вы не даете необработанные значения для каждого случая, а перечисление имеет тип String, он выводит, что необработанное значение случая само по себе находится в строковом формате. Перейти на дать ему попробовать.
enum City: String { case Melbourne, Chelyabinsk, Bursa } let city = City.Melbourne.rawValue // city is "Melbourne"
для swift:
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.описание