Inizializzatori che possono fallire
Fa parte della sezione Programmazione orientata agli oggetti del percorso Swift di Coddy. Lezione 20 di 57.
Alcuni valori non possono essere creati a partire da ogni input. Un inizializzatore fallibile, scritto init?, restituisce nil invece di un'istanza quando l'input non è valido, quindi non può mai esistere un'istanza non valida:
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)Output:
42
-1Il risultato di un inizializzatore fallibile è un optional, quindi chi lo richiama deve estrarne il valore, di solito 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)")
}
}Output:
valid: ada@mail.com
invalid: not-an-emailAnche i tipi propri di Swift usano la stessa idea: Int("42") e Double("x") sono inizializzatori fallibili, così come init(rawValue:) di un enum. Un inizializzatore fallibile può chiamarli e propagare il fallimento:
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)Output:
true
falseUsa init? quando un valore mancante è un’informazione sufficiente. Usa un inizializzatore che genera un errore, init(...) throws, quando chi chiama dovrebbe sapere quale regola non è stata rispettata:
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
}
}Sfida
FacileCompleta la struct Rgb, che memorizza un colore come red, green e blue da 0 a 255. Il suo inizializzatore fallibile init?(hex:) legge testo come #FF8000: restituisce nil a meno che il testo non sia # seguito esattamente da sei cifre esadecimali. Usa Int(text, radix: 16) per ogni coppia. Aggiungi una proprietà calcolata label che restituisce rgb(255, 128, 0).
Il codice fornito legge un colore per riga e stampa l'etichetta oppure invalid: text.
Il tuo codice va in Rgb.swift. main.swift contiene il codice di input/output fornito e non può essere modificato.
Provalo tu
// Codice di input/output fornito: lascialo così com'è
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)")
}
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Classi e oggetti
Lavorare con i fileDefinire le classiMetodi e selfInizializzatoriLe classi sono riferimentiRiepilogo - Tessera della biblioteca4Incapsulamento
Controllo degli accessiSola lettura dall’esternoProteggere lo statoInizializzatori che possono fallireRiepilogo - Conto bancario7Polimorfismo e tipi generici
PolimorfismoCasting dei tipiFunzioni genericheTipi genericiRipasso - Calcolatore di forme2Struct e tipi valore
Le structSemantica dei valoriMetodi mutantiStruct o classeRiepilogo - Articolo di inventario5Ereditarietà
SottoclassiSovrascrivere i metodiInizializzatori e superfinal e gerarchieRiepilogo - Gerarchia dei dipendenti8Protocolli standard
CustomStringConvertibleEquatableComparableHashableRiepilogo - Ordinamento personalizzato11Progetto: Gestione della biblioteca
Libri e utentiPrestito dei libriEsercitati da solo: Playground Swift