Inicializadores que pueden fallar
Parte de la sección Programación orientada a objetos del Journey de Swift de Coddy. Lección 20 de 57.
Algunos valores no se pueden construir a partir de cualquier entrada. Un inicializador fallible, escrito como init?, devuelve nil en lugar de una instancia cuando la entrada no es válida, por lo que nunca puede existir una instancia no válida:
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)Salida:
42
-1El resultado de un inicializador que puede fallar es opcional, por lo que quien lo llama debe desempaquetarlo, normalmente con if let o 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)")
}
}Salida:
valid: ada@mail.com
invalid: not-an-emailLos propios tipos de Swift utilizan la misma idea: Int("42") y Double("x") son inicializadores que pueden fallar, al igual que el init(rawValue:) de un enumerado. Un inicializador que puede fallar puede llamarlos y transmitir el fallo:
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)Salida:
true
falseUsa init? cuando un valor faltante sea información suficiente. Usa un inicializador que lance errores, init(...) throws, cuando el llamador deba saber qué regla falló:
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
}
}Desafío
FácilCompleta la estructura Rgb, que almacena un color como red, green y blue de 0 a 255. Su inicializador que puede fallar init?(hex:) lee texto como #FF8000: devuelve nil a menos que el texto sea # seguido exactamente de seis dígitos hexadecimales. Usa Int(text, radix: 16) para cada par. Añade una propiedad calculada label que devuelva rgb(255, 128, 0).
El código proporcionado lee un color por línea e imprime la etiqueta o invalid: text.
Tu código va en Rgb.swift. main.swift contiene el código de entrada/salida proporcionado y no se puede editar.
Pruébalo tú mismo
// Código de entrada/salida suministrado: déjalo 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)")
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación orientada a objetos
1Clases y objetos
Trabajar con archivosDefinir clasesMétodos y selfInicializadoresLas clases son referenciasRepaso: tarjeta de biblioteca4Encapsulación
Control de accesoSolo lectura desde fueraProtección del estadoInicializadores que pueden fallarRepaso - Cuenta bancaria7Polimorfismo y genéricos
PolimorfismoConversión de tiposFunciones genéricasTipos genéricosRepaso - Calculadora de formas2Structs y tipos por valor
StructsSemántica de valoresMétodos mutablesStruct o claseRepaso - elemento del inventario5Herencia
SubclasesSobrescritura de métodosInicializadores y superfinal y jerarquíasRepaso: jerarquía de empleados8Protocolos estándar
CustomStringConvertibleEquatableComparableHashableRepaso - Ordenamiento personalizado11Proyecto: Gestión de bibliotecas
Libros y miembrosPréstamo de librosPractica por tu cuenta: Playground de Swift