Menu
Coddy logo textTech

Riepilogo - Parser di file

Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 58 di 107.

challenge icon

Sfida

Facile

Creiamo 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:

    • ErrEmptyContent con il messaggio "file content is empty"
    • ErrInvalidFormat con il messaggio "invalid configuration format"

    Crea un tipo di errore personalizzato ParseError con i campi Line (int) e Message (string). Il suo metodo Error() 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 ConfigParser con un campo booleano parsed per tenere traccia del completamento corretto dell'analisi.

    Implementa questi metodi:

    • NewConfigParser() *ConfigParser - crea un nuovo parser con parsed impostato su false
    • ParseLine(lineNum int, line string) error - convalida una singola riga. Se la riga non contiene il carattere =, restituisce un *ParseError con il numero di riga e il messaggio "missing key-value separator". Altrimenti restituisce nil.
    • Parse(content string) error - il metodo principale di analisi che:
      • Restituisce ErrEmptyContent se il contenuto è vuoto
      • Restituisce ErrInvalidFormat se il contenuto non contiene almeno un carattere di nuova riga
      • Suddivide il contenuto in base alle nuove righe e chiama ParseLine per ogni riga (la numerazione delle righe parte da 1)
      • Se ParseLine restituisce un errore, lo avvolge con "parsing configuration: %w" e lo restituisce
      • In caso di successo, imposta parsed su true e restituisce nil
    • Status() string - restituisce "ready" se parsed è 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 defer per 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() sia errors.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() 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 avvolto, poi stampa su una nuova riga Fix 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: ready

E 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 parsed

Provalo 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

Esercitati da solo: Compilatore Go online