Как получить имя значения перечисления в 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
' s init(_:)
синтаксис интерполяции инициализатора или строки. Итак, для вашего примера:
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"
таким образом, больше нет необходимости определять и поддерживать функцию удобства, которая включает каждый случай для возврата строкового литерала. Кроме того, это работает автоматически для любого перечисления, даже если не указан тип raw-значения.
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
'ы 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, Printable {
case Melbourne = "Melbourne"
case Chelyabinsk = "Chelyabinsk"
case Bursa = "Bursa"
var description : String {
get {
return self.rawValue
}
}
}
Примечание: элемент 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) вы можете добавить следующие методы в свое перечисление:
/**
* 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
as 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 действительно должна командовать. Они создали enum, что вы не можете 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.описание