Итоги — Парсер файлов
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 58 из 107.
Задание
ЛегкоДавайте создадим парсер конфигурационных файлов, который объединит все техники обработки ошибок из этой главы. Ваш парсер будет обрабатывать несколько сценариев сбоев с использованием пользовательских типов ошибок, сигнальных ошибок (sentinel errors), оборачивания ошибок и правильной очистки ресурсов с помощью defer.
Вы организуете свой код в трех файлах:
errors.go: Определите инфраструктуру ошибок для парсера.Создайте две сигнальные ошибки:
ErrEmptyContentс сообщением"file content is empty"ErrInvalidFormatс сообщением"invalid configuration format"
Создайте пользовательский тип ошибки
ParseErrorс полямиLine(int) иMessage(string). Его методError()должен возвращать:parse error at line [Line]: [Message]parser.go: Создайте парсер конфигурации с многоуровневой обработкой ошибок.Создайте структуру
ConfigParserс логическим полемparsedдля отслеживания успешного завершения парсинга.Реализуйте следующие методы:
NewConfigParser() *ConfigParser— создает новый парсер с полемparsed, установленным вfalseParseLine(lineNum int, line string) error— проверяет одну строку. Если строка не содержит символа=, возвращает*ParseErrorс номером строки и сообщением"missing key-value separator". В противном случае возвращаетnil.Parse(content string) error— основной метод парсинга, который:- Возвращает
ErrEmptyContent, если содержимое пустое - Возвращает
ErrInvalidFormat, если содержимое не содержит хотя бы одного символа новой строки - Разбивает содержимое по символам новой строки и вызывает
ParseLineдля каждой строки (номера строк начинаются с 1) - Если
ParseLineвозвращает ошибку, оборачивает ее с помощью"parsing configuration: %w"и возвращает результат - Устанавливает
parsedвtrueпри успехе и возвращаетnil
- Возвращает
Status() string— возвращает"ready", еслиparsedравно true, иначе"not parsed"
main.go: Считайте содержимое конфигурации и продемонстрируйте комплексную проверку ошибок.Считайте две строки ввода, которые вместе образуют содержимое конфигурации (объедините их символом новой строки). Используйте
defer, чтобы всегда выводить статус парсера в конце, независимо от успеха или неудачи.После попытки парсинга проверьте любую возникшую ошибку, используя как
errors.Is(), так иerrors.As(), чтобы предоставить конкретную обратную связь в зависимости от того, что пошло не так.
Будут предоставлены следующие входные данные:
- Строка 1: Первая строка содержимого конфигурации
- Строка 2: Вторая строка содержимого конфигурации
Обрабатывайте ошибки со специфическими сообщениями:
- Если
errors.Is()находитErrEmptyContent: выведитеError: No configuration provided - Если
errors.Is()находитErrInvalidFormat: выведитеError: Configuration must have multiple lines - Если
errors.As()находит*ParseError: выведите полную обернутую ошибку, затем на новой строке выведитеFix line [Line]: [Message] - Если парсинг прошел успешно: выведите
Configuration parsed successfully
После обработки результата (успеха или ошибки) отложенный статус должен быть выведен на новой строке: Parser status: [status]
Например, для ввода host=localhost и port=8080 ваш вывод должен быть:
Configuration parsed successfully
Parser status: readyА для ввода host=localhost и invalid line ваш вывод должен быть:
parsing configuration: parse error at line 2: missing key-value separator
Fix line 2: missing key-value separator
Parser status: not parsedПопробуйте сами
package main
import (
"bufio"
"errors"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Чтение первой строки конфигурации
line1, _ := reader.ReadString('\n')
line1 = line1[:len(line1)-1] // Удаление завершающего символа новой строки
// Чтение второй строки конфигурации
line2, _ := reader.ReadString('\n')
if len(line2) > 0 && line2[len(line2)-1] == '\n' {
line2 = line2[:len(line2)-1]
}
// Объединение двух строк символом новой строки для формирования содержимого конфигурации
content := line1 + "\n" + line2
// Создание нового парсера
parser := NewConfigParser()
// TODO: Используйте defer, чтобы всегда выводить статус парсера в конце
// Формат: "Parser status: [status]"
// TODO: Попытайтесь выполнить парсинг содержимого
// TODO: Обработайте ошибки с помощью errors.Is() и errors.As()
// - Если errors.Is() находит ErrEmptyContent: выведите "Error: No configuration provided"
// - Если errors.Is() находит ErrInvalidFormat: выведите "Error: Configuration must have multiple lines"
// - Если errors.As() находит *ParseError: выведите полную обернутую ошибку,
// затем на новой строке выведите "Fix line [Line]: [Message]"
// - Если парсинг прошел успешно: выведите "Configuration parsed successfully"
_ = errors.Is // подсказка: используйте errors.Is для сигнальных ошибок
_ = errors.As // подсказка: используйте errors.As для пользовательских типов ошибок
_ = fmt.Println
}
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП в Go
Внешние файлыРабочее пространство и модули GoПакеты и импортыЭкспортируемые и неэкспортируемые именаВведение в ООП в GoСтруктуры как классыОпределение методов структурПолучатели-указатели и получатели-значенияИнициализация структурФункции-конструкторыИтоги — Простой калькулятор4Интерфейсы
Введение в интерфейсыНеявная реализацияИнтерфейс как контрактПустой интерфейс (any)Утверждение типаПереключатель типовКомпозиция интерфейсовИнтерфейсы Stringer и ErrorПовторение: Калькулятор фигур7Инкапсуляция
Экспортируемые и неэкспортируемые поляИнкапсуляция на уровне пакетовГеттеры и сеттерыСокрытие информации в GoИтоги — Записи о студентах10Обобщения (Generics) (Go 1.18+)
Введение в GenericsПараметры типовОграничения типовОбобщенные структурыОбходной путь для обобщенных методовИтоги — Обобщенная коллекция13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн Abstract FactoryПаттерн ObserverПаттерн Strategy2Глубокое погружение в типы и структуры
Базовые и составные типыОпределение пользовательских типовТеги структурАнонимные структурыВложенные структурыНулевые значения и значения по умолчаниюПовторение — Контактная книга5Композиция вместо наследования
Почему в Go нет наследованияОсновы встраивания структурПродвижение методовВстраивание нескольких структурВстраивание против агрегацииЗатенение встроенных методовИтоги — Иерархия сотрудников8Обработка ошибок и ООП
Интерфейс errorПользовательские типы ошибокОбертывание ошибок (fmt.Errorf)Sentinel-ошибкиerrors.Is() и errors.As()Panic, Defer и RecoverИтоги — Парсер файлов11Стандартная библиотека и ООП
io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикMiddleware как Декоратор3Указатели и память
Основы указателей в GoУказатели на структурыПередача по значению и по ссылкеФункция new()Сборка мусора в GoПовторение: Конструктор связного списка6Полиморфизм в Go
Полиморфизм через интерфейсыУтиная типизация в GoПравила реализации интерфейсовПолиморфные коллекцииВнедрение зависимостейИтоги — Обработчик платежей9Конкурентность и ООП
Основы горутинКаналы и взаимодействиеБуферизованные и небуферизованные каналыОператор selectsync.Mutex и sync.RWMutexsync.WaitGroupПроектирование потокобезопасных структурПовторение — Worker Pool