Коли ми моделюємо дані, які можуть набувати лише певного набору можливих станів, як-от дні тижня, сторони світу чи кнопки на геймпаді, базові типи на кшталт Int або String мають серйозні недоліки.
З цілими числами чи рядками тексту код мусить постійно перевіряти значення на недопустимість (наприклад, код стану 999 чи одруківку на кшталт "leftt"), а людині, яка читає код, важко зрозуміти, що позначають ці числа.
Swift розвʼязує цю проблему за допомогою переліків (їх часто називають просто enum). Перелік визначає спільний тип для групи повʼязаних іменованих значень. Оскільки компілятор заздалегідь знає всі можливі варіанти, він може перевірити код на правильність і повноту під час компіляції. Переліки також можуть мати методи, ініціалізатори та обчислювані властивості.
Перелік визначають за допомогою ключового слова enum, після якого йде назва типу, а його варіанти перелічують усередині фігурних дужок.
За домовленістю Swift назва типу записується у UpperCamelCase, а кожен варіант - у lowerCamelCase:
enum NESButton {
case up
case down
case left
case right
case a
case b
case select
case start
}
Кілька варіантів можна також визначити в одному рядку, розділивши їх комами:
enum NESButton {
case up, down, left, right, a, b, select, start
}
Щоб звернутися до варіанта переліку, напишіть назву типу переліку, крапку (.) і назву варіанта. Коли тип уже відомий або його може вивести компілятор, назву типу можна опустити й скористатися коротшим синтаксисом із крапкою:
var lastPressed = NESButton.up
// Swift infers the type, so you can omit the type name:
lastPressed = .down
let konamiCode: [NESButton] = [.up, .up, .down, .down, .left, .right, .left, .right, .b, .a]
Переліки можуть визначати методи й власні ініціалізатори так само, як класи та структури. Усередині методу переліку self указує на поточне значення варіанта:
enum Coin {
case heads
case tails
init(_ value: Int) {
if value.isMultiple(of: 2) {
self = .heads
} else {
self = .tails
}
}
func flip() -> Coin {
switch self {
case .heads: return .tails
case .tails: return .heads
}
}
}
let tails = Coin(13) // .tails
let heads = Coin(0) // .heads
let flipped = heads.flip() // .tails
Варіанти переліку можна наперед заповнити типовими значеннями, які називають сирими значеннями.
Усі сирі значення в переліку мають бути одного типу (наприклад, Int, String або Character):
enum NESButton: Character {
case up = "⬆️"
case down = "⬇️"
case left = "⬅️"
case right = "➡️"
case a = "🅰️"
case b = "🅱️"
case select = "✅"
case start = "🚦"
}
print(NESButton.left.rawValue) // Prints "⬅️"
Перелік можна ініціалізувати із сирого значення за допомогою init(rawValue:). Оскільки може бути надано недопустиме сире значення, цей ініціалізатор повертає опціонал:
let upButton = NESButton(rawValue: "⬆️") // Optional(NESButton.up)
let invalid = NESButton(rawValue: "🙄") // nil
Swift може автоматично присвоювати сирі значення для переліків із типом String та Int:
String сире значення кожного варіанта типово дорівнює назві цього варіанта.Int сирі значення починаються з 0 й зростають на 1, якщо не вказано іншого.enum Planet: Int {
case mercury = 1, venus, earth, mars
}
print(Planet.earth.rawValue) // Prints 3
У цій вправі ми будемо працювати з рядками логу.
Кожен рядок логу - це рядок тексту (англ. string), відформатований так: "[<LVL>]: <MESSAGE>".
Ось різні рівні логу:
TRC (trace)DBG (debug)INF (info)WRN (warning)ERR (error)FTL (fatal)На нас чекають три завдання, і кожне з них потрібно виконати, щоб реалізувати потрібну функціональність.
Визначте перелік LogLevel із шістьма варіантами, що відповідають наведеним вище рівням логу, а також варіант unknown для рівнів, які відсутні або є нестандартними.
tracedebuginfowarningerrorfatalunknownДалі реалізуйте ініціалізатор LogLevel, який розбирає рівень логу з рядка логу:
LogLevel("[INF]: File deleted")
// Returns LogLevel.info
LogLevel("Something went wrong!")
// Returns LogLevel.unknown
Рівень логу в рядку логу досить багатослівний.
Щоб зменшити обсяг дискового простору, потрібний для зберігання рядків логу, розроблено короткий формат: "<ENCODED_LEVEL>:<MESSAGE>".
Закодований рівень логу - це просте зіставлення рівня логу з числом:
trace - 0
debug - 1
info - 4
warning - 5
error - 6
fatal - 7
unknown - 42
Реалізуйте метод shortFormat(message: String) -> String, який може виводити скорочений формат рядка логу як String:
let overflow = LogLevel.error
overflow.shortFormat(message: "Stack overflow")
// Returns "6:Stack overflow"
Зареєструйтеся на Exercism, щоб вивчати й опановувати Swift, а також 35 концепцій116 вправ та справжнє наставництво від людей, і все це безкоштовно.