Riepilogo - Parser di file
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 58 di 107.
Sfida
FacileCreiamo un parser per file di configurazione che riunisca tutte le tecniche di gestione degli errori di questo capitolo. Il parser gestirà diversi scenari di errore con tipi di errore personalizzati, errori sentinella, wrapping degli errori e una corretta pulizia usando defer.
Organizzerai il codice in tre file:
errors.go: Definisci l'infrastruttura degli errori per il parser.Crea due errori sentinella:
ErrEmptyContentcon il messaggio"file content is empty"ErrInvalidFormatcon il messaggio"invalid configuration format"
Crea un tipo di errore personalizzato
ParseErrorcon i campiLine(int) eMessage(string). Il suo metodoError()deve restituire:parse error at line [Line]: [Message]parser.go: Crea il parser di configurazione con una gestione degli errori a più livelli.Crea una struct
ConfigParsercon un campo booleanoparsedper tenere traccia del completamento corretto dell'analisi.Implementa questi metodi:
NewConfigParser() *ConfigParser- crea un nuovo parser conparsedimpostato sufalseParseLine(lineNum int, line string) error- convalida una singola riga. Se la riga non contiene il carattere=, restituisce un*ParseErrorcon il numero di riga e il messaggio"missing key-value separator". Altrimenti restituiscenil.Parse(content string) error- il metodo principale di analisi che:- Restituisce
ErrEmptyContentse il contenuto è vuoto - Restituisce
ErrInvalidFormatse il contenuto non contiene almeno un carattere di nuova riga - Suddivide il contenuto in base alle nuove righe e chiama
ParseLineper ogni riga (la numerazione delle righe parte da 1) - Se
ParseLinerestituisce un errore, lo avvolge con"parsing configuration: %w"e lo restituisce - In caso di successo, imposta
parsedsutruee restituiscenil
- Restituisce
Status() string- restituisce"ready"separsedè true, altrimenti"not parsed"
main.go: Leggi il contenuto della configurazione e mostra un'ispezione completa degli errori.Leggi due righe di input che insieme formano il contenuto della configurazione (uniscile con una nuova riga). Usa
deferper stampare sempre lo stato del parser alla fine, indipendentemente dal successo o dall'errore.Dopo aver tentato l'analisi, esamina eventuali errori usando sia
errors.Is()siaerrors.As()per fornire un feedback specifico in base a ciò che è andato storto.
Verranno forniti i seguenti input:
- Riga 1: prima riga del contenuto della configurazione
- Riga 2: seconda riga del contenuto della configurazione
Gestisci gli errori con messaggi specifici:
- Se
errors.Is()trovaErrEmptyContent: stampaError: No configuration provided - Se
errors.Is()trovaErrInvalidFormat: stampaError: Configuration must have multiple lines - Se
errors.As()trova un*ParseError: stampa l'errore completo avvolto, poi stampa su una nuova rigaFix line [Line]: [Message] - Se l'analisi riesce: stampa
Configuration parsed successfully
Dopo aver gestito il risultato (successo o errore), lo stato differito deve essere stampato su una nuova riga: Parser status: [status]
Ad esempio, con host=localhost e port=8080, l'output dovrebbe essere:
Configuration parsed successfully
Parser status: readyE con host=localhost e invalid line, l'output dovrebbe essere:
parsing configuration: parse error at line 2: missing key-value separator
Fix line 2: missing key-value separator
Parser status: not parsedProvalo tu
package main
import (
"bufio"
"errors"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Leggi la prima riga della configurazione
line1, _ := reader.ReadString('\n')
line1 = line1[:len(line1)-1] // Rimuovi il carattere di nuova riga finale
// Leggi la seconda riga della configurazione
line2, _ := reader.ReadString('\n')
if len(line2) > 0 && line2[len(line2)-1] == '\n' {
line2 = line2[:len(line2)-1]
}
// Unisci le due righe con un carattere di nuova riga per formare il contenuto della configurazione
content := line1 + "\n" + line2
// Crea un nuovo parser
parser := NewConfigParser()
// TODO: Usa defer per stampare sempre lo stato del parser alla fine
// Formato: "Parser status: [status]"
// TODO: Prova ad analizzare il contenuto
// TODO: Gestisci gli errori usando errors.Is() e errors.As()
// - Se errors.Is() trova ErrEmptyContent: stampa "Error: No configuration provided"
// - Se errors.Is() trova ErrInvalidFormat: stampa "Error: Configuration must have multiple lines"
// - Se errors.As() trova un *ParseError: stampa l'errore completo con il relativo contesto,
// poi, su una nuova riga, stampa "Fix line [Line]: [Message]"
// - Se l'analisi riesce: stampa "Configuration parsed successfully"
_ = errors.Is // suggerimento: usa errors.Is per gli errori sentinella
_ = errors.As // suggerimento: usa errors.As per i tipi di errore personalizzati
_ = fmt.Println
}
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP in Go
File esterniWorkspace e moduli GoPacchetti e importazioniNomi esportati e non esportatiIntroduzione all’OOP in GoGli struct come classiDefinire metodi sugli structReceiver con puntatore vs receiver con valoreInizializzazione degli structFunzioni costruttriciRiepilogo - Calcolatrice semplice4Interfacce
Introduzione alle interfacceImplementazione implicitaL’interfaccia come contrattoInterfaccia vuota (any)Asserzione di tipoSwitch sul tipoComposizione di interfacceInterfacce Stringer ed ErrorRipasso - Calcolatore di forme7Incapsulamento
Campi esportati e non esportatiIncapsulamento a livello di packageMetodi Getter e SetterNascondimento delle informazioni in GoRiepilogo - Registri degli studenti10Tipi generici (Go 1.18+)
Introduzione ai tipi genericiParametri di tipoVincoli di tipoStruct genericheSoluzione alternativa per i metodi genericiRiepilogo - Collezione generica13Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello Abstract FactoryModello ObserverModello Strategy2Approfondimento su tipi e struct
Tipi di base e compostiDefinizioni di tipi personalizzatiTag delle structStruct anonimeStruct annidateValori zero e predefinitiRipasso - Rubrica5Composizione invece dell'ereditarietà
Perché Go non ha l'ereditarietàFondamenti dell'embedding delle structPromozione dei metodiEmbedding di più structEmbedding e aggregazione a confrontoMascheramento dei metodi embeddedRiepilogo: gerarchia dei dipendenti8Gestione degli errori e OOP
L'interfaccia errorTipi di errore personalizzatiWrapping degli errori (fmt.Errorf)Errori sentinellaerrors.Is() ed errors.As()Panic, Defer e RecoverRiepilogo - Parser di file11Libreria standard e OOP
io.Reader e io.Writersort.InterfaceInterfaccia fmt.Stringerencoding/json con le structInterfaccia http.HandlerRipasso - modelli REST API14Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeMiddleware come Decorator3Puntatori e memoria
Concetti base dei puntatori in GoPuntatori a structPassaggio per valore vs per riferimentoLa funzione new()Garbage collection in GoRiepilogo - Costruttore di liste concatenate6Polimorfismo in Go
Polimorfismo tramite interfacceDuck typing in GoRegole di soddisfacimento delle interfacceCollezioni polimorficheIniezione delle dipendenzeRiepilogo - Elaboratore di pagamenti9Concorrenza e OOP
Basi delle goroutineCanali e comunicazioneCanali bufferizzati vs non bufferizzatiIstruzione selectsync.Mutex e sync.RWMutexsync.WaitGroupProgettazione di struct thread-safeRiepilogo: worker poolEsercitati da solo: Compilatore Go online