Ao modelar dados que só podem assumir um conjunto específico de estados possíveis, como dias da semana, direções da bússola ou botões de um controle, tipos básicos como Int ou String têm grandes desvantagens.
Com inteiros ou strings, seu código precisa verificar o tempo todo se há valores inválidos (como um código de status 999 ou um erro de digitação como "leftt"), e quem lê o código não consegue identificar facilmente o que os números representam.
O Swift resolve esse problema com Enumerações (muitas vezes abreviadas para enums). Um enum define um tipo comum para um grupo de valores relacionados e nomeados. Como o compilador conhece todos os casos possíveis de antemão, ele consegue verificar a exatidão e a completude do seu código em tempo de compilação. Enums também podem ter métodos, inicializadores e propriedades computadas.
Para definir um enum, use a palavra-chave enum seguida do nome do tipo, com os casos listados entre chaves.
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
}
Você também pode definir vários casos em uma única linha, separados por vírgulas:
enum NESButton {
case up, down, left, right, a, b, select, start
}
Para se referir a um caso de enum, escreva o nome do tipo do enum, um ponto (.) e o nome do caso. Quando o tipo já é conhecido ou pode ser inferido pelo compilador, você pode omitir o nome do tipo e usar a sintaxe de ponto mais curta:
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]
Enums podem definir métodos e inicializadores personalizados assim como classes e structs. Dentro de um método de enum, self se refere 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 um enum podem ser preenchidos previamente com valores padrão chamados valores brutos.
Todos os valores brutos de um enum precisam ter o 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 "⬅️"
Você pode inicializar um enum a partir de um valor bruto usando init(rawValue:). Como um valor bruto inválido pode ser fornecido, esse inicializador retorna um opcional:
let upButton = NESButton(rawValue: "⬆️") // Optional(NESButton.up)
let invalid = NESButton(rawValue: "🙄") // nil
O Swift consegue atribuir valores brutos automaticamente para enums de String e Int:
String, o valor bruto de cada caso é, por padrão, o nome do caso.Int, os valores brutos começam em 0 e aumentam de 1 em 1, a menos que você especifique o contrário.enum Planet: Int {
case mercury = 1, venus, earth, mars
}
print(Planet.earth.rawValue) // Prints 3
Neste exercício, você vai 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 (rastreamento)DBG (depuração)INF (informação)WRN (aviso)ERR (erro)FTL (fatal)Você tem três tarefas, e cada uma delas precisa ser concluída para fornecer a funcionalidade necessária.
Defina um enum LogLevel com seis casos correspondentes aos níveis de log acima, além de um caso desconhecido para níveis ausentes ou fora do padrão.
tracedebuginfowarningerrorfatalunknownEm seguida, implemente o inicializador de LogLevel para analisar 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 verboso.
Para reduzir o espaço em disco necessário para armazenar 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
Implemente o método shortFormat(message: String) -> String, que gera o formato reduzido da linha de log como uma String:
let overflow = LogLevel.error
overflow.shortFormat(message: "Stack overflow")
// Returns "6:Stack overflow"
Crie sua conta no Exercism para aprender e dominar Swift com 35 conceitos116 exercícios e mentoria humana de verdade, tudo de graça.