Quando modelas dados que só podem assumir um conjunto específico de estados possíveis, como os dias da semana, as direções da bússola ou os botões de um comando, os tipos básicos como Int ou String têm grandes desvantagens.
Com inteiros ou strings, o teu código tem de verificar constantemente se há valores inválidos (como um código de estado 999 ou um erro de escrita como "leftt"), e quem lê o código não consegue perceber facilmente o que os números representam.
O Swift resolve este problema com as Enumerações (muitas vezes abreviadas para enums). Uma enumeração define um tipo comum para um conjunto de valores relacionados e com nome. Como o compilador conhece todos os casos possíveis de antemão, pode verificar a exatidão e a completude do teu código em tempo de compilação. As enumerações também podem ter métodos, inicializadores e propriedades calculadas.
Para definir uma enumeração, usa a palavra-chave enum seguida do nome do tipo, com os casos indicados dentro de chavetas.
Por convenção do Swift, o nome do tipo usa UpperCamelCase, enquanto cada caso usa lowerCamelCase:
enum NESButton {
case up
case down
case left
case right
case a
case b
case select
case start
}
Também podes definir vários casos numa única linha, separados por vírgulas:
enum NESButton {
case up, down, left, right, a, b, select, start
}
Para te referires a um caso de uma enumeração, escreve o nome do tipo da enumeração, um ponto (.) e o nome do caso. Quando o tipo é conhecido ou pode ser inferido pelo compilador, podes omitir o nome do tipo e usar a sintaxe abreviada com o ponto:
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]
As enumerações podem definir métodos e inicializadores personalizados tal como as classes e as estruturas. Dentro de um método de uma enumeração, self refere-se ao valor do caso atual:
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
Os casos de uma enumeração podem ser preenchidos previamente com valores predefinidos chamados valores brutos.
Todos os valores brutos de uma enumeração têm de ser do mesmo tipo (como Int, String ou 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 "⬅️"
Podes inicializar uma enumeração a partir de um valor bruto com init(rawValue:). Como pode ser fornecido um valor bruto inválido, este inicializador devolve um opcional:
let upButton = NESButton(rawValue: "⬆️") // Optional(NESButton.up)
let invalid = NESButton(rawValue: "🙄") // nil
O Swift pode atribuir automaticamente valores brutos a enumerações de String e de Int:
String, o valor bruto de cada caso é, por predefinição, o nome do caso.Int, os valores brutos começam em 0 e aumentam de 1 em 1, salvo indicação em contrário.enum Planet: Int {
case mercury = 1, venus, earth, mars
}
print(Planet.earth.rawValue) // Prints 3
Neste exercício vais processar linhas de log.
Cada linha de log é uma string formatada da seguinte forma: "[<LVL>]: <MESSAGE>".
Estes são os diferentes níveis de log:
TRC (trace)DBG (debug)INF (info)WRN (warning)ERR (error)FTL (fatal)Tens três tarefas, e cada uma delas tem de ser concluída para forneceres a funcionalidade necessária.
Define um enum LogLevel com seis casos correspondentes aos níveis de log acima, mais um caso unknown para níveis de log em falta ou não padrão.
tracedebuginfowarningerrorfatalunknownA seguir, implementa o inicializador de LogLevel para interpretar o nível de log de uma linha de log:
LogLevel("[INF]: File deleted")
// Returns LogLevel.info
LogLevel("Something went wrong!")
// Returns LogLevel.unknown
O nível de log de uma linha de log é bastante extenso.
Para reduzir o espaço em disco necessário para guardar as linhas de log, foi criado um formato curto: "<ENCODED_LEVEL>:<MESSAGE>".
O nível de log codificado é um mapeamento simples de um nível de log para um número:
trace - 0
debug - 1
info - 4
warning - 5
error - 6
fatal - 7
unknown - 42
Implementa o método shortFormat(message: String) -> String, que devolve a linha de log no formato curto como String:
let overflow = LogLevel.error
overflow.shortFormat(message: "Stack overflow")
// Returns "6:Stack overflow"
Inscreve-te no Exercism para aprenderes e dominares Swift com 35 conceitos116 exercícios, e mentoria humana real, tudo grátis.