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.