Swift: przekonwertować wartość wyliczenia na ciąg?


141

Biorąc pod uwagę następujące wyliczenie:

enum Audience {
    case Public
    case Friends
    case Private
}

Jak uzyskać ciąg znaków "Public"ze audiencestałej poniżej?

let audience = Audience.Public

2
sprawdź tę odpowiedź, może ona dać ci kilka pomysłów na to, jak możesz to osiągnąć: stackoverflow.com/questions/24648726/enums-with-data-in-swift/ ...
— holex

w Swift 2 i xcode7 nie musisz nic zmieniać w swoim kodzie, po prostu użyjprint("\(audience)")
— gbdavid

7
Nienawidzę tego, że Swift ecoscape jest teraz wypełniony bardzo przestarzałymi odpowiedziami, takimi jak ta. Podobnie jak w przypadku XCode8.2 / Swift3, jest to tak proste, jakString(describing: yourEnumValue)
— Travis Griggs

@TravisGriggs To już nie działa dla Xcode 11.4
— DawnSong

Odpowiedzi:


156

Nie jestem pewien, w której wersji Swift ta funkcja została dodana, ale teraz ( Swift 2.1 ) potrzebujesz tylko tego kodu:

enum Audience : String {
    case public
    case friends
    case private
}

let audience = Audience.public.rawValue // "public"

Gdy ciągi są używane dla surowych wartości, niejawną wartością dla każdego przypadku jest tekst jego nazwy .

[…]

enum CompassPoint : String {
    case north, south, east, west
}

W powyższym przykładzie CompassPoint.south ma niejawną wartość surową „południe” i tak dalej.

Dostęp do surowej wartości przypadku wyliczenia uzyskuje się z jego właściwością rawValue:

let sunsetDirection = CompassPoint.west.rawValue
// sunsetDirection is "west"

Źródło.


8
w xcode7.3 swift2.2, jeśli robię takie rzeczy, jak: print("appState: \(application.applicationState)") otrzymuję appState: UIApplicationState typ, a nie rzeczywistą reprezentację ciągu wartości wyliczeniowej. Czy coś mi umyka? (PS: dla rawValue po prostu otrzymuję wartość Int ...)
— Martin

@Cyrus Twój scenariusz różni się od tego, o który pytano w tym wątku. .rawValuezwróci surową wartość twojego wyliczenia. Twój jest public enum UIApplicationState : Intrzeczywiście typowy Int. Nigdy też nie czytałeś mojej odpowiedzi, która zawiera cytat z dokumentów Apple. ... Jeśli nadal chcesz konwertować UIApplicationStatena ciąg znaków, sugeruję rozszerzenie UIApplicationStateo niestandardową właściwość obliczonąextension UIApplicationState { var toString() -> String { /* check self for all diff. cases and return something like "Active" */ }
— DevAndArtist

Nie rozwiązuje problemu z posiadaniem
— wyliczeń

1
@ denis631 co masz na myśli? Surowy typ wyliczenia może być dowolny. Wyliczenie może się nawet dostosować, OptionSetjeśli naprawdę chcesz. I tak oryginalne pytanie dotyczy Stringsa.
— DevAndArtist

1
jeśli moje wyliczenie jest napisane w ten sposób, enum Test: Int {case A, B}, rawValue oczywiście zwróci int back, szukamy sposobu na uzyskanie nazwy przypadku jako String. Dokładnie to zrobił @DanilShaykhutdinov. Spójrz na jego odpowiedź, aw pierwotnym pytaniu wyliczenie nie ma typu, ani String ani Int.
— denis631

209

Idiomatyczny interfejs do „pobierania ciągu znaków” polega na użyciu CustomStringConvertible interfejsu i dostępie do metody descriptionpobierającej. Zdefiniuj enumjako:

enum Foo : CustomStringConvertible {
  case Bing
  case Bang
  case Boom
  
  var description : String { 
    switch self {
    // Use Internationalization, as appropriate.
    case .Bing: return "Bing"
    case .Bang: return "Bang"
    case .Boom: return "Boom"
    }
  }
}

W akcji:

 > let foo = Foo.Bing
foo: Foo = Bing
 > println ("String for 'foo' is \(foo)"
String for 'foo' is Bing

Zaktualizowany : Dla Swift> = 2,0, otrzymuje PrintablesięCustomStringConvertible

Uwaga : użycie CustomStringConvertiblepozwala Foona przyjęcie innego surowego typu. Na przykład enum Foo : Int, CustomStringConvertible { ... }jest to możliwe. Ta wolność może być przydatna.


2
Innym krótszym sposobem utworzenia ciągu println jest: „Ciąg znaków 'foo' to (foo)”
— John MP Knox

3
@ JohnM.P.Knox nie zapomnij o ukośniku odwrotnym, tak jak w „Ciągu znaków 'foo' to \ (foo)”. Edycja OK, to edytor się go pozbył, musiałem wpisać 2 z nich, żeby się
— pojawiły

Jaki jest sens, CustomStringConvertiblejeśli to działa równie dobrze bez niego?
— Daniel van der Merwe

3
CustomStringConvertiblepozwala / wymaga zdefiniowania, descriptionktóry pozwala zdecydować, jakiego ciągu użyć dla każdego przypadku wyliczenia - jest to z pewnością ważne dla internacjonalizacji i być może dla czytelności kodu. Jeśli Cię to nie obchodzi, możesz użyć 'enum Foo: String {/ * ... * /} `
— GoZoner

2
To jest poprawna odpowiedź, jeśli wyliczenie nie jest ciągiem lub chcesz mieć inny ciąg niż rawValue. @ denis631
— Haagenti

32

Na razie przedefiniuję wyliczenie jako:

enum Audience: String {
    case Public = "Public"
    case Friends = "Friends"
    case Private = "Private"
}

abym mógł:

audience.toRaw() // "Public"

Ale czy ta nowa definicja wyliczenia nie jest zbędna? Czy mogę zachować początkową definicję wyliczenia i zrobić coś takiego:

audience.toString() // "Public"

3
Począwszy od Xcode 7 Beta 3, możesz po prostu napisać swoją odpowiedź, ale bez, = Stringponieważ automatycznie otrzymuje ona nieprzetworzoną wartość (nazwę sprawy), jeśli jej nie podasz.
— Qbyte

3
Zamiast .toString () użyj teraz .rawValue
— SoftDesigner

W Swift 1.2 możesz użyć: println (Audience.Friends.rawValue)
— Oleg Popov


24

Lubię używać Printablez Raw Values.

enum Audience: String, Printable {
    case Public = "Public"
    case Friends = "Friends"
    case Private = "Private"

    var description: String {
        return self.rawValue
    }
}

Wtedy możemy zrobić:

let audience = Audience.Public.description // audience = "Public"

lub

println("The value of Public is \(Audience.Public)") 
// Prints "The value of Public is Public"

1
Tak mi się podoba bardziej niż wybrana odpowiedź, bo mogęAudience(rawValue: "Friends")
— tidwall

12

Zaktualizowano w celu wydania Xcode 7 GM. Teraz działa tak, jak można by się spodziewać - dzięki Apple!

enum Rank:Int {
    case Ace = 1, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King
}

let r = Rank.Ace

print(r)               // prints "Ace"
print("Rank: \(r)!")   // prints "Rank: Ace!"

2
W Swift 2.0 dostosowanie się do CustomStringConvertiblefaktycznie pozwoliłoby na użycie właśnie print(r)w tym przypadku.
— matm

W Xcode 7 beta 4, odbicie () wydaje się być wyłączone na korzyść Mirror (odbicie: x). Jednak zwracany obiekt ma inną strukturę.
— GSnyder

1
Zaktualizuj odpowiedź, proszę
— Ben Sinclair,

10

To nie może być prostsze niż to w Swift 2 i najnowszym Xcode 7 (nie ma potrzeby określania typu wyliczenia ani .rawValue, deskryptorów itp.)

Zaktualizowano dla Swift 3 i Xcode 8:

    enum Audience {
        case Public
        case Friends
        case Private
    }

    let audience: Audience = .Public  // or, let audience = Audience.Public
    print(audience) // "Public"

Działało idealnie z moimi
— wyliczeniami

Tylko uwaga: działa to w przypadku samodzielnie utworzonych wyliczeń, ale nie działa w przypadku czegoś takiego jak HKWorkoutActivityType
— Ace Green

Jak również dla zlokalizowanych smyczków;)
— Eugene Braginets

2
Pierwotne pytanie dotyczyło konwersji wartości wyliczenia na ciąg znaków we własnych wyliczeniach, więc właśnie na to odpowiedziałem ... Jeśli chcesz obsługiwać wyliczenia UIKit / AppKit, to oczywiście inna historia.
— gbdavid

1
@gbdavid - Czy istnieje Q dla wyliczeń UIKit / AppKit? Wyszukałem w Google i nie mogłem go znaleźć. Jeśli to konieczne, mogę przesłać pytanie.
— benc

8

Szybki przykład 3 i wyżej, jeśli używasz Ints w Enum

public enum ECategory : Int{
        case Attraction=0, FP, Food, Restroom, Popcorn, Shop, Service, None;
        var description: String {
            return String(describing: self)
        }
    }

let category = ECategory.Attraction
let categoryName = category.description //string Attraction

Eleganckie rozwiązanie. Działałby również „\ (kategoria)” lub bezpośrednio Ciąg (opisujący: kategorię). Nawet dla wyliczeń Int.
— t1ser

8

Dla każdego, kto czyta przykład w rozdziale „Swift Tour” książki „Swift Programming Language” i szuka sposobu na uproszczenie metody simpleDescription (), wystarczy przekonwertowanie samego wyliczenia na String przez wykonanie String(self):

enum Rank: Int
{
    case Ace = 1 //required otherwise Ace will be 0
    case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
    case Jack, Queen, King
    func simpleDescription() -> String {
        switch self {
            case .Ace, .Jack, .Queen, .King:
                return String(self).lowercaseString
            default:
                return String(self.rawValue)
        }
     }
 }

2
Tylko upewnij się, że nie używasz wyliczenia z „@objc”. To powoduje, że takie podejście zawodzi.
— Matt Bearson

5

Po wypróbowaniu kilku różnych sposobów stwierdziłem, że jeśli nie chcesz używać:

let audience = Audience.Public.toRaw()

Nadal możesz zarchiwizować go za pomocą struktury

struct Audience {
   static let Public  = "Public"
   static let Friends = "Friends"
   static let Private = "Private"
}

to twój kod:

let audience = Audience.Public

będzie działać zgodnie z oczekiwaniami. To nie jest ładne i ma pewne wady, ponieważ nie używasz "wyliczenia", nie możesz użyć skrótu tylko dodając .Private też nie będzie działać z przełącznikami.


Wygląda schludnie. Zastanawiam się, jaka byłaby najlepsza praktyka w tym konkretnym przypadku. Wolałbym używać składni struct ze względu na prostotę, ale użycie struct zamiast enum nie wydaje się właściwe, a może to tylko ja? Cóż, nic nie stoi na przeszkodzie, aby zadeklarować stałe zmienne gdziekolwiek indziej, tym razem po prostu dodajesz je do struktury, aby była zorganizowana. Myśli?
— schystz

Dokładnie, działa jako zmienne stałe, ale jest bardziej zorganizowany. Jak powiedziałem wcześniej, jedynym problemem jest „obudowa przełącznika” i skróty „.Private”. Jeśli tworzysz aplikację od podstaw, spróbuj użyć „wyliczenia”, używaj struktur tylko wtedy, gdy „wyliczenie” z jakiegoś powodu nie spełnia wymagań kodu. Osobiście unikam stałych zmiennych i zamiast tego zawsze używam struktur.
— Adriano Spadoni

Używam tego do kluczy domyślnych. Zamiast zapamiętywać domyślne klucze w aplikacji, zrzucam klucze do struktury i wyciągam je stamtąd.
— Adrian,

3

Można to zrobić na wiele sposobów. Albo możesz zdefiniować funkcję w wyliczeniu, która zwraca ciąg na podstawie wartości typu wyliczenia:

enum Audience{
    ...
func toString()->String{
  var a:String

  switch self{
   case .Public:
    a="Public"
   case .Friends:
    a="Friends"
   ...
 }
 return a
}

Lub możesz spróbować tego:

enum Audience:String{
   case Public="Public"
   case Friends="Friends"
   case Private="Private"
}

I aby z niego skorzystać:

var a:Audience=Audience.Public
println(a.toRaw())

1

Począwszy od Swift 3.0 możesz

var str = String(describing: Audience.friends)

1
Niewiarygodne, ale to doskonale działa. Dużo krócej niż podejście „idiomatyczne”. Dzięki!
— Roman
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.