Podsumowanie — parser plików
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 58 z 107.
Wyzwanie
ŁatwyZbudujmy parser plików konfiguracyjnych, który łączy wszystkie techniki obsługi błędów z tego rozdziału. Twój parser będzie obsługiwać różne scenariusze awarii za pomocą własnych typów błędów, błędów znacznikowych, opakowywania błędów oraz prawidłowego sprzątania z użyciem defer.
Rozmieścisz kod w trzech plikach:
errors.go: Zdefiniuj infrastrukturę błędów dla parsera.Utwórz dwa błędy znacznikowe:
ErrEmptyContentz komunikatem"file content is empty"ErrInvalidFormatz komunikatem"invalid configuration format"
Utwórz własny typ błędu
ParseErrorz polamiLine(int) iMessage(string). Jego metodaError()powinna zwracać:parse error at line [Line]: [Message]parser.go: Zbuduj parser konfiguracji z warstwową obsługą błędów.Utwórz strukturę
ConfigParserz polem logicznymparsed, które będzie śledzić, czy parsowanie zakończyło się powodzeniem.Zaimplementuj te metody:
NewConfigParser() *ConfigParser– tworzy nowy parser z wartościąparsedustawioną nafalseParseLine(lineNum int, line string) error– sprawdza poprawność pojedynczej linii. Jeśli linia nie zawiera znaku=, zwraca*ParseErrorz numerem linii i komunikatem"missing key-value separator". W przeciwnym razie zwracanil.Parse(content string) error– główna metoda parsująca, która:- Zwraca
ErrEmptyContent, jeśli treść jest pusta - Zwraca
ErrInvalidFormat, jeśli treść nie zawiera co najmniej jednego znaku nowej linii - Dzieli treść według znaków nowej linii i wywołuje
ParseLinedla każdej linii (numerowanie linii rozpoczyna się od 1) - Jeśli
ParseLinezwraca błąd, opakowuje go w"parsing configuration: %w"i zwraca - W przypadku powodzenia ustawia
parsednatruei zwracanil
- Zwraca
Status() string– zwraca"ready", jeśliparsedma wartość true, a w przeciwnym razie"not parsed"
main.go: Odczytaj treść konfiguracji i pokaż kompleksowe sprawdzanie błędów.Odczytaj dwa wiersze wejściowe, które razem tworzą treść konfiguracji (połącz je znakiem nowej linii). Użyj
defer, aby zawsze na końcu wypisać stan parsera, niezależnie od tego, czy operacja się powiedzie, czy nie.Po próbie parsowania sprawdź ewentualny błąd za pomocą zarówno
errors.Is(), jak ierrors.As(), aby przekazać konkretne informacje o przyczynie problemu.
Podane zostaną następujące dane wejściowe:
- Wiersz 1: Pierwszy wiersz treści konfiguracji
- Wiersz 2: Drugi wiersz treści konfiguracji
Obsłuż błędy, wypisując konkretne komunikaty:
- Jeśli
errors.Is()znajdzieErrEmptyContent: wypiszError: No configuration provided - Jeśli
errors.Is()znajdzieErrInvalidFormat: wypiszError: Configuration must have multiple lines - Jeśli
errors.As()znajdzie wartość typu*ParseError: wypisz pełny opakowany błąd, a następnie w nowym wierszu wypiszFix line [Line]: [Message] - Jeśli parsowanie się powiedzie: wypisz
Configuration parsed successfully
Po obsłużeniu wyniku (powodzenia lub błędu) odroczony komunikat o stanie powinien zostać wypisany w nowym wierszu: Parser status: [status]
Na przykład dla danych host=localhost i port=8080 wynik powinien wyglądać następująco:
Configuration parsed successfully
Parser status: readyA dla danych host=localhost i invalid line wynik powinien wyglądać następująco:
parsing configuration: parse error at line 2: missing key-value separator
Fix line 2: missing key-value separator
Parser status: not parsedSpróbuj swoich sił
package main
import (
"bufio"
"errors"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Wczytaj pierwszą linię konfiguracji
line1, _ := reader.ReadString('\n')
line1 = line1[:len(line1)-1] // Usuń końcowy znak nowej linii
// Wczytaj drugą linię konfiguracji
line2, _ := reader.ReadString('\n')
if len(line2) > 0 && line2[len(line2)-1] == '\n' {
line2 = line2[:len(line2)-1]
}
// Połącz obie linie znakiem nowej linii, aby utworzyć treść konfiguracji
content := line1 + "\n" + line2
// Utwórz nowy parser
parser := NewConfigParser()
// TODO: Użyj defer, aby na końcu zawsze wypisać stan parsera
// Format: "Parser status: [status]"
// TODO: Spróbuj przeanalizować treść
// TODO: Obsłuż błędy za pomocą errors.Is() i errors.As()
// - Jeśli errors.Is() znajdzie ErrEmptyContent: wypisz "Error: No configuration provided"
// - Jeśli errors.Is() znajdzie ErrInvalidFormat: wypisz "Error: Configuration must have multiple lines"
// - Jeśli errors.As() znajdzie *ParseError: wypisz pełny błąd wraz z błędami, które opakowuje,
// następnie w nowym wierszu wypisz "Fix line [Line]: [Message]"
// - Jeśli parsowanie się powiedzie: wypisz "Configuration parsed successfully"
_ = errors.Is // wskazówka: użyj errors.Is do obsługi błędów sygnalizacyjnych
_ = errors.As // wskazówka: użyj errors.As do obsługi niestandardowych typów błędów
_ = fmt.Println
}
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP w Go
Pliki zewnętrzneObszar roboczy i moduły GoPakiety i importyNazwy eksportowane i nieeksportowaneWprowadzenie do OOP w GoStruktury jako klasyDefiniowanie metod dla strukturOdbiorniki wskaźnikowe i wartościoweInicjalizacja strukturFunkcje konstruktoraPodsumowanie – prosty kalkulator4Interfejsy
Wprowadzenie do interfejsówImplementacja niejawnaInterfejs jako kontraktPusty interfejs (any)Asercja typuPrzełącznik typówKompozycja interfejsówInterfejsy Stringer i ErrorPowtórka — kalkulator figur7Hermetyzacja
Pola eksportowane i nieeksportowaneHermetyzacja na poziomie pakietuMetody pobierające i ustawiająceUkrywanie informacji w GoPowtórka – dane studentów10Typy generyczne (Go 1.18+)
Wprowadzenie do typów generycznychParametry typówOgraniczenia typówStruktury generyczneObejście ograniczeń metod generycznychPodsumowanie — generyczna kolekcja2Typy i struktury w praktyce
Typy proste i złożoneDefiniowanie własnych typówTagi pól strukturStruktury anonimoweStruktury zagnieżdżoneWartości zerowe i domyślnePodsumowanie – książka kontaktów5Kompozycja zamiast dziedziczenia
Dlaczego Go nie ma dziedziczeniaPodstawy osadzania strukturPromowanie metodOsadzanie wielu strukturOsadzanie a agregacjaPrzesłanianie osadzonych metodPodsumowanie — hierarchia pracowników8Obsługa błędów i programowanie obiektowe
Interfejs błęduWłasne typy błędówOpakowywanie błędów (fmt.Errorf)Błędy wartowniczeerrors.Is() i errors.As()Panic, Defer i RecoverPodsumowanie — parser plików3Wskaźniki i pamięć
Podstawy wskaźników w GoWskaźniki do strukturPrzekazywanie przez wartość a przez referencjęFunkcja new()Odśmiecanie pamięci w GoPowtórka — kreator listy wiązanej6Polimorfizm w Go
Polimorfizm za pomocą interfejsówDuck typing w GoZasady spełniania interfejsówKolekcje polimorficzneWstrzykiwanie zależnościPowtórka — procesor płatności9Współbieżność i OOP
Podstawy goroutinesKanały i komunikacjaKanały buforowane i niebuforowaneInstrukcja selectsync.Mutex i sync.RWMutexsync.WaitGroupProjektowanie struktur bezpiecznych wątkowoPowtórka – pula workerów12Zaawansowane zagadnienia programowania obiektowego
Wzorzec opcji funkcyjnychWzorzec Builder w GoŁańcuchowe wywoływanie metodAliasy typów a definicje typówPodstawy refleksjiPrzegląd generowania koduPoćwicz samodzielnie: Kompilator Go online