Swift: Перетворити значення enum у String?


141

З огляду на наступний перелік:

enum Audience {
    case Public
    case Friends
    case Private
}

Як отримати рядок "Public"від audienceпостійної внизу?

let audience = Audience.Public

2
будь ласка , перевірте цю відповідь, він може дати вам деякі ідеї про те, як можна досягти такої речі: stackoverflow.com/questions/24648726/enums-with-data-in-swift / ...
holex

у Swift 2 та xcode7 вам не потрібно нічого змінювати свій код, просто скористайтесяprint("\(audience)")
gbdavid

7
Я ненавиджу, що екологічний пейзаж Свіфта зараз наповнений дуже застарілими відповідями. Як і для XCode8.2 / Swift3, це так просто, якString(describing: yourEnumValue)
Тревіс Гріггс

@TravisGriggs Більше не працює для Xcode 11.4
DawnSong

Відповіді:


156

Не впевнені, у якій версії Swift була додана ця функція, але зараз ( Swift 2.1 ) вам потрібен лише цей код:

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

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

Коли рядки використовуються для необроблених значень, імпліцитним значенням для кожного випадку є текст імені цього випадку .

[...]

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

У наведеному вище прикладі CompassPoint.south має неявне значення "південь" тощо.

Ви отримуєте доступ до необмеженої вартості регістру перерахування з його властивістю rawValue:

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

Джерело


8
у xcode7.3 swift2.2, якщо я роблю такі речі, як: print("appState: \(application.applicationState)") я отримую, appState: UIApplicationState що є типом, а не фактичним рядковим поданням значення enum. Я щось тут пропускаю? (PS: для rawValue я просто отримую значення Int ...)
Мартін

@Cyrus ваш сценарій відрізняється від того, про що запитували в цій темі. .rawValueповерне сировинну вартість вашого перерахунку. Твоє - public enum UIApplicationState : Intце справді тип Int. Ви також ніколи не читали моєї відповіді, в якій є цитата з документів Apple. ... Якщо ви все ще хочете перетворити UIApplicationStateна рядок, я б запропонував вам розширити UIApplicationStateспеціальне обчислене властивістьextension UIApplicationState { var toString() -> String { /* check self for all diff. cases and return something like "Active" */ }
DevAndArtist

Не вирішує проблему із тим, що мають перерахунки типу String
denis631,

1
@ denis631 що ти маєш на увазі? Сирим типом перерахунку може бути все що завгодно. Перерахунок навіть може відповідати, OptionSetякщо ви цього дуже хочете. І оригінальне питання про Strings все одно.
DevAndArtist

1
якщо моя enum написана так, enum Test: Int {case A, B}, звичайно, rawValue повернеться int назад, те, що ми шукаємо, це спосіб отримати назву справи як String. Саме це і зробив @DanilShaykhutdinov. Подивіться на його відповідь і в оригінальному запитанні перелік не має типу, ані струни чи інта.
denis631

209

Ідіоматичний інтерфейс для 'отримання рядка' полягає у використанні CustomStringConvertible інтерфейсу та доступу до descriptionгеттера. Визначте enumяк:

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

Дія:

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

Оновлено : для Swift> = 2.0, замінено PrintableнаCustomStringConvertible

Примітка . Використання CustomStringConvertibleдозволяє Fooприйняти інший вихідний тип. Наприклад enum Foo : Int, CustomStringConvertible { ... }, можливо. Ця свобода може бути корисною.


2
Ще один коротший спосіб створити рядок println: "Рядок для 'foo' є (foo)"
Джон МП Нокс

3
@ JohnM.P.Knox не забудьте зворотну косу рису, як у "Рядок для" foo "є \ (foo)". Редагувати ОК, це редактор позбувся цього, мені довелося ввести 2 з них, щоб він з’явився
zmit

У чому сенс, CustomStringConvertibleякщо без нього це працює так само добре?
Даніель ван дер Мерве

3
CustomStringConvertibleдозволяє / вимагає визначити, descriptionякий дозволяє вирішити, який рядок використовувати для кожного випадку перерахунку - це важливо для безумовної інтернаціоналізації та, можливо, читабельності коду. Якщо ви не переймаєтесь цим, ви можете скористатися 'enum Foo: String {/ * ... * /} `
GoZoner

2
Це правильна відповідь, якщо ваш перерахунок не є String або ви хочете інший рядок, ніж rawValue. @ denis631
Haagenti

32

Поки що я перезначу перелік як:

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

щоб я міг робити:

audience.toRaw() // "Public"

Але хіба це нове визначення перерахунків не є зайвим? Чи можу я зберегти початкове визначення перерахунків і зробити щось на кшталт:

audience.toString() // "Public"

3
Станом на Xcode 7 Beta 3, ви можете просто написати свою відповідь, але без того, = Stringщо вона автоматично отримує нераціональне значення (назва регістру), якщо ви цього не вказали.
Qbyte

3
Замість .toString () тепер використовуйте .rawValue
SoftDesigner

У Swift 1.2 ви можете використовувати: println (Audience.Friends.rawValue)
Олег Попов

32

У швидкому 3, ви можете використовувати це

var enumValue = Customer.Physics
var str = String(describing: enumValue)

від Swift, як використовувати enum, щоб отримати значення рядка


2
Це дуже корисно, особливо якщо моя enumне заснована на Strings
даспіаніст

1
"\(enumValue)"Робить те саме. ^^
еоніст

Це краща відповідь. Не вимагає введення типу Stum enum.
сард

24

Я хотів би використовувати Printableз Raw Values.

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

    var description: String {
        return self.rawValue
    }
}

Тоді ми можемо зробити:

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

або

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

1
Мені подобається цей спосіб краще, ніж обрана відповідь, тому що я можу це зробитиAudience(rawValue: "Friends")
tidwall

12

Оновлено до випуску Xcode 7 GM. Це працює, як можна було б сподіватися зараз - дякую 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
У Swift 2.0 відповідність CustomStringConvertibleфактично дозволить використовувати саме print(r)в цьому випадку.
мат.

У Xcode 7 beta 4, відображення (), здається, вимкнено на користь дзеркала (відображає: x). Однак повернутий об’єкт має іншу структуру.
GSnyder

1
Оновіть відповідь будь ласка
Бен Сінклер

10

Він не міг бути простішим, ніж це у Swift 2 та останньому Xcode 7 (не потрібно вказувати тип enum, або .rawValue, дескриптори тощо ...)

Оновлено для Swift 3 та Xcode 8:

    enum Audience {
        case Public
        case Friends
        case Private
    }

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

Відмінно співпрацював із моїми інтами, що підтримуються
chrislarson

Лише зауваження: це працює для самонадеяних переліків, але не працює для чогось типу HKWorkoutActivityType
Ace Green

Як і для локалізованих рядків;)
Євген Брагінець

2
Первісне запитання стосувалося перетворення значення enum у рядок у ваші власні перерахунки, тож саме на це я і відповів ... Якщо вам подобається обробляти UIKit / AppKit Enums, звичайно, це вже інша історія.
gbdavid

1
@gbdavid - Чи існує Q для UIKit / AppKit Enums? Я гуглив і не міг його знайти. Я можу подати Q, якщо це потрібно.
benc

8

Швидкий приклад 3 і вище, якщо ви використовуєте Ints в 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

Елегантне рішення. "\ (категорія)" або безпосередньо String (що описує: категорію) також буде працювати. Навіть для Інт-енумів.
t1ser

8

Для всіх, хто читає приклад у розділі "Швидка екскурсія" розділу "Швидка мова програмування" та шукає спосіб спростити метод simpleDescription (), перетворивши саму перерахунок на String, 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
Просто переконайтеся, що не використовуєте enum за допомогою "@objc". Це призводить до невдачі цього підходу.
Метт Берсон

5

Спробувавши кілька різних способів, я виявив, що якщо ви не хочете користуватися:

let audience = Audience.Public.toRaw()

Ви все ще можете архівувати його за допомогою структури

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

то ваш код:

let audience = Audience.Public

буде працювати, як очікувалося. Це не дуже, і є деякі недоліки, оскільки ви не використовуєте "перерахунок", ви не можете використовувати ярлик лише додаючи.


Виглядає акуратно. Цікаво, що було б найкращою практикою для даного конкретного випадку. Я вважаю за краще використовувати синтаксис stru через простоту, але використовувати stru замість enum не здається правильним, чи, можливо, це лише я? Ну, ніщо не заважає вам просто декларувати постійні змінні деінде, на цей раз ви просто додасте їх всередині структури, так що вона організована. Думки?
schystz

Саме воно працює як постійні змінні, але більш організовані. Як я вже говорив, єдиною проблемою є "справа перемикача" та ярлики ". Приват". Якщо ви будуєте з нуля додаток, спробуйте перейти з "enum", використовуйте структури, лише якщо "enum" чомусь не задовольняє ваш код. Я особисто уникаю змінних констант, а завжди використовую структури.
Адріано Спадоні

Я використовую це для клавіш за замовчуванням. Замість того, щоб запам'ятати ключі за замовчуванням у програмі, я скидаю їх у структуру та витягую їх звідти.
Адріан

3

Існує кілька способів зробити це. Або ви могли б визначити функцію в enum, яка повертає рядок на основі значення типу enum:

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

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

Або ви можете спробувати це:

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

І використовувати його:

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

1

Починаючи з Swift 3.0 ви можете

var str = String(describing: Audience.friends)

1
Неймовірно, але це прекрасно спрацьовує. Набагато коротший, ніж "ідіоматичний" підхід. Дякую!
Роман
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.