Итоги — Парсер файлов
Часть раздела Объектно-ориентированное программирование путешествия по 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Потренируйтесь самостоятельно: Онлайн-компилятор Go