Menu
Coddy logo textTech

Inicializadores que Podem Falhar

Parte da seção Programação Orientada a Objetos do Journey de Swift da Coddy. Lição 20 de 57.

Alguns valores não podem ser construídos a partir de qualquer entrada. Um inicializador que pode falhar, escrito como init?, retorna nil em vez de uma instância quando a entrada é inválida, portanto nenhuma instância inválida pode existir:

struct Percentage {
    let value: Int

    init?(_ value: Int) {
        guard value >= 0, value <= 100 else { return nil }
        self.value = value
    }
}

print(Percentage(42)?.value ?? -1)
print(Percentage(150)?.value ?? -1)

Saída:

42
-1

O resultado de um inicializador que pode falhar é um opcional, portanto o chamador precisa desembrulhá-lo, geralmente com if let ou guard let:

struct Email {
    let address: String

    init?(_ text: String) {
        let parts = text.split(separator: "@")
        guard parts.count == 2, parts[1].contains(".") else { return nil }
        address = text.lowercased()
    }
}

for text in ["Ada@Mail.com", "not-an-email"] {
    if let email = Email(text) {
        print("valid: \(email.address)")
    } else {
        print("invalid: \(text)")
    }
}

Saída:

valid: ada@mail.com
invalid: not-an-email

Os próprios tipos do Swift usam a mesma ideia: Int("42") e Double("x") são inicializadores falíveis, assim como o init(rawValue:) de um enum. Um inicializador falível pode chamá-los e repassar a falha:

struct Coordinate {
    let lat: Double
    let lon: Double

    init?(text: String) {
        let parts = text.split(separator: ",")
        guard parts.count == 2,
              let lat = Double(parts[0]), let lon = Double(parts[1]),
              abs(lat) <= 90, abs(lon) <= 180 else { return nil }
        self.lat = lat
        self.lon = lon
    }
}

print(Coordinate(text: "51.5,-0.1") != nil)
print(Coordinate(text: "95,10") != nil)

Saída:

true
false

Use init? quando um valor ausente for informação suficiente. Use um inicializador que lança erros, init(...) throws, quando o chamador precisar saber qual regra falhou:

struct Username {
    let text: String
    init(_ text: String) throws {
        guard text.count >= 3 else { throw NameError.tooShort }
        guard text.allSatisfy({ $0.isLetter }) else { throw NameError.badCharacters }
        self.text = text
    }
}
challenge icon

Desafio

Fácil

Complete a struct Rgb, que armazena uma cor como red, green e blue de 0 a 255. Seu inicializador que pode falhar init?(hex:) lê textos como #FF8000: ele retorna nil, a menos que o texto seja # seguido exatamente por seis dígitos hexadecimais. Use Int(text, radix: 16) para cada par. Adicione uma label calculada que retorne rgb(255, 128, 0).

O código fornecido lê uma cor por linha e imprime o rótulo ou invalid: text.

Seu código deve estar em Rgb.swift. main.swift contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

// Código de entrada/saída fornecido: mantenha-o como está
var input: [String] = []
while let line = readLine() { input.append(line) }
for line in input {
    if let color = Rgb(hex: line) {
        print(color.label)
    } else {
        print("invalid: \(line)")
    }
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Playground de Swift