Cuando modelas datos que solo pueden tomar un conjunto concreto de estados posibles, como los días de la semana, los puntos cardinales o los botones de un mando, los tipos básicos como Int o String tienen grandes inconvenientes.
Con enteros o strings, tu código tiene que estar comprobando constantemente si hay valores no válidos (como un código de estado 999 o una errata como "leftt"), y a quien lee el código le cuesta saber qué representan los números.
Swift resuelve este problema con las enumeraciones (a menudo abreviadas como enum). Una enumeración define un tipo común para un grupo de valores relacionados y con nombre. Como el compilador conoce de antemano todos los casos posibles, puede comprobar que tu código es correcto y está completo en tiempo de compilación. Las enumeraciones también pueden tener métodos, inicializadores y propiedades calculadas.
Define una enumeración con la palabra clave enum seguida del nombre del tipo, con sus casos indicados dentro de llaves.
Por convención en Swift, el nombre del tipo usa UpperCamelCase, mientras que cada caso usa lowerCamelCase:
enum NESButton {
case up
case down
case left
case right
case a
case b
case select
case start
}
También puedes definir varios casos en una sola línea separados por comas:
enum NESButton {
case up, down, left, right, a, b, select, start
}
Para referirte a un caso de una enumeración, escribe el nombre del tipo de la enumeración, un punto (.) y el nombre del caso. Cuando el compilador ya conoce el tipo o puede inferirlo, puedes omitir el nombre del tipo y usar la sintaxis abreviada con el punto:
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]
Las enumeraciones pueden definir métodos e inicializadores personalizados igual que las clases y las estructuras. Dentro de un método de una enumeración, self hace referencia al valor del caso actual:
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
Los casos de una enumeración se pueden rellenar de antemano con valores predeterminados llamados valores brutos.
Todos los valores brutos de una enumeración deben compartir el mismo tipo (como Int, String o 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 "⬅️"
Puedes inicializar una enumeración a partir de un valor bruto con init(rawValue:). Como es posible que se proporcione un valor bruto no válido, este inicializador devuelve un opcional:
let upButton = NESButton(rawValue: "⬆️") // Optional(NESButton.up)
let invalid = NESButton(rawValue: "🙄") // nil
Swift puede asignar automáticamente los valores brutos de las enumeraciones de tipo String e Int:
String, el valor bruto de cada caso es su propio nombre de caso de forma predeterminada.Int, los valores brutos empiezan en 0 y se incrementan de 1 en 1, a menos que se indique lo contrario.enum Planet: Int {
case mercury = 1, venus, earth, mars
}
print(Planet.earth.rawValue) // Prints 3
En este ejercicio vas a procesar líneas de registro.
Cada línea de registro es un string con el siguiente formato: "[<LVL>]: <MESSAGE>".
Estos son los distintos niveles de registro:
TRC (trace)DBG (debug)INF (info)WRN (warning)ERR (error)FTL (fatal)Tienes tres tareas, y debes completar cada una de ellas para proporcionar la funcionalidad necesaria.
Define una enumeración LogLevel que tenga seis casos correspondientes a los niveles de registro anteriores, más un caso desconocido para niveles ausentes o no estándar.
tracedebuginfowarningerrorfatalunknownA continuación, implementa el inicializador de LogLevel para analizar el nivel de registro de una línea de registro:
LogLevel("[INF]: File deleted")
// Returns LogLevel.info
LogLevel("Something went wrong!")
// Returns LogLevel.unknown
El nivel de registro de una línea de registro es bastante verboso.
Para reducir el espacio en disco necesario para almacenar las líneas de registro, se ha desarrollado un formato corto: "<ENCODED_LEVEL>:<MESSAGE>".
El nivel de registro codificado es una simple asignación de un nivel de registro a un número:
trace - 0
debug - 1
info - 4
warning - 5
error - 6
fatal - 7
unknown - 42
Implementa el método shortFormat(message: String) -> String que devuelve la línea de registro en formato corto como un String:
let overflow = LogLevel.error
overflow.shortFormat(message: "Stack overflow")
// Returns "6:Stack overflow"
Regístrate en Exercism para aprender y dominar Swift con 35 conceptos116 ejercicios y mentoría humana real, todo gratis.