Jak uzyskać nazwę wartości wyliczenia w języku Swift?

Jeśli mam wyliczenie z surowymi Integer wartościami:

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

let city = City.Melbourne

Jak mogę przekonwertować wartość city na łańcuch Melbourne? Czy tego rodzaju introspekcja typu jest dostępna w danym języku?

Coś w stylu (ten kod nie zadziała):

println("Your city is \(city.magicFunction)")
> Your city is Melbourne
Author: Templar, 2014-06-09

9 answers

Począwszy od Xcode 7 beta 5 możesz teraz domyślnie drukować nazwy typów i przypadki enum używając print(_:), lub przekonwertować na String używając inicjatora String lub składni interpolacji ciągu znaków. Więc dla Twojego przykładu:

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"

Nie ma więc potrzeby definiowania i utrzymywania wygodnej funkcji, która włącza każdy przypadek, aby zwrócić literalny łańcuch znaków. Ponadto działa to automatycznie dla każdego enum, nawet jeśli nie podano typu raw-value.

debugPrint(_:) & String(reflecting:) może być stosowany do nazwa w pełni kwalifikowana:

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

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

Zauważ, że możesz dostosować to, co jest drukowane w każdym z tych scenariuszy:

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

(nie znalazłem sposobu na wywołanie tej wartości "domyślnej", na przykład, aby wydrukować" miasto to Melbourne " bez uciekania się do instrukcji switch. Wykorzystanie \(self) w realizacji description/debugDescription powoduje nieskończoną rekurencję.)


Komentarze powyżej String ' s init(_:) & init(reflecting:) inicjalizatory opisują dokładnie to, co jest drukowane, w zależności na czym odpowiada Typ refleksyjny:

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


Informacje na temat tej zmiany można znaleźć w Uwagach do wydania .

 96
Author: Stuart,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-30 10:47:41

W tej chwili nie ma introspekcji na temat przypadków enum. Będziesz musiał zadeklarować każdy z nich ręcznie:

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

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

Uwaga : protokół Printable nie działa obecnie na placach zabaw. Jeśli chcesz zobaczyć ciąg znaków na placu zabaw, musisz ręcznie wywołać toRaw ()

Jeśli chcesz, aby surowy typ był Int, musisz zrobić przełącznik samodzielnie:

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"
      }
    }
  }
}
 67
Author: drewag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-27 16:08:11

W Swift - 3 (testowanym z XCode 8.1) możesz dodać następujące metody w swoim 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) }
}

Możesz użyć go jako normalnego wywołania metody na Twojej instancji enum. Może to również działać w poprzednich wersjach Swift, ale nie testowałem go.

W twoim przykładzie:

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"

Jeśli chcesz udostępnić tę funkcjonalność wszystkim swoim enumom, możesz zrobić z niej rozszerzenie:

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

To działa tylko dla Swift enums.

 20
Author: Matthias Voss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-16 15:22:10

Dla Objective-C enumS jedynym sposobem obecnie wydaje się na przykład rozszerzenie enum oCustomStringConvertible zakończone czymś w rodzaju:

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

A następnie rzuca enum jako String:

String(UIDevice.currentDevice().batteryState)
 13
Author: Markus Rautopuro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-02 14:15:21

To takie rozczarowujące.

W Przypadku, Gdy potrzebujesz tych nazw (które kompilator doskonale zna dokładną pisownię, ale odmawia dostępu -- dziękuję Swift team!! -jeśli nie chcesz lub nie możesz uczynić String bazą twojego enum, czasochłonna alternatywa jest następująca:

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

Możesz użyć powyższego w następujący sposób:

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

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

I otrzymasz oczekiwany wynik (kod dla kolumny podobny, ale nie pokazany)

fetching element Title, column: Collections, row: 0

W powyższym, I sprawiły, że właściwość description odnosi się z powrotem do metody string, ale jest to kwestia gustu. Zauważ również, że tak zwane zmienne static muszą być kwalifikowane przez nazwę ich typu, ponieważ kompilator jest zbyt amnezyjny i nie może sam przywołać kontekstu...

Drużyna Swift musi być naprawdę dowodzona. Stworzyli enum, którego nie można enumerate i na którym można użyć enumerate są "sekwencjami", ale nie enum!

 6
Author: verec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-24 13:51:26

Poza obsługą String (...) (CustomStringConvertible) dla enums w Swift 2.2, jest też nieco zepsuta obsługa odbicia dla nich. Dla przypadków enum z powiązanymi wartościami można uzyskać etykietę przypadku enum za pomocą odbicia:

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"

Mówiąc o złamaniu, miałem jednak na myśli, że dla" prostych " enum, powyższa właściwość obliczeniowa oparta na odbiciu label zwraca po prostu nil (boo-hoo).

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

Sytuacja z odbiciem powinna być coraz lepsza po Swift 3, najwyraźniej. Na razie jednak rozwiązaniem jest String(…), jak sugerowano w jednej z innych odpowiedzi:

print(String(City.Chelyabinsk)) // prints out Cheylabinsk
 5
Author: mz2,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-28 23:36:40

Proste, ale działa...

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")
    }
}
 2
Author: Jimbo Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-09 11:04:41

Swift ma teraz coś, co jest znane jako domyślnie przypisana wartość raw . Zasadniczo, jeśli nie podasz wartości nieprzetworzonych dla każdego przypadku, a enum jest typu String, wywnioskujesz, że nieprzetworzona wartość sprawy jest sama w formacie string. Spróbuj.

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

let city = City.Melbourne.rawValue

// city is "Melbourne"
 1
Author: NSCoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-02 14:41:30

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

Jeśli twoja zmienna "batteryState" to wywołaj:

Self.batteryState.Opis

 1
Author: xevser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-05 07:16:49