Написание программ на Go доставляет массу удовольствия. Но новичку действительно сложно понять новые концепции этого языка. Я уже кое-что узнал: Go - это другое

Можно использовать шаблоны проектирования ориентированных на объекты, но это не очень хорошо работает. На YouTube много разговоров по этой теме, но я не нашел хороших примеров или руководств, которые могли бы использовать новички.

Вначале мне было очень сложно понять логику интерфейса io.Reader и io.Writer.

Я читал, что это Go-способ использовать эти интерфейсы, но все примеры очень сложны для меня как новичка или они не были Go-way. Особенно просто использовать io.Reader и io.Writer. На сложных примерах новичку очень сложно понять эту простую абстракцию.

Итак, вот очень простой пример io.Writer для всех новичков.

В этом простом примере мы хотим создать метод записи для простой структуры. Эта структура является частью нашего пакета:

type Person struct {
 Id int
 Name string
 Age int
}

Внутри нашего пакета мы хотим предоставить метод чтения и записи, с помощью которого данные могут быть сохранены или загружены. Таким образом мы реализуем интерфейс читателя и писателя.

В этом примере я просто собираюсь описать использование io.Writer.

Итак, давайте посмотрим на определение интерфейса io.Writer:

type Writer interface {
    Write(p []byte) (n int, err error)
}

Есть только один метод «Запись», который принимает на входе кусок байта и возвращает количество записанных байтов и переменную ошибки.

Пришло время подумать о чем-то очень простом. Чтобы реализовать интерфейс писателя, мы просто используем метод Write. Чтобы использовать этот метод, нам нужно преобразовать нашу структуру в кусок байта. Есть много разных форматов для хранения таких данных. Допустим, мы хотим хранить наши данные в формате JSON. Итак, нам нужно закодировать нашу структуру в этот формат.

Использование io.Writer - это путь, поэтому стандартные пакеты поддерживают этот способ. Если мы посмотрим на документ пакета JSON, мы найдем функцию Marshal, которая принимает интерфейс (= нашу структуру) и возвращает фрагмент байта и ошибку. Итак, тада - вот недостающее звено для интерфейса io.Writer.

  • Шаг 1: преобразуйте структуру в фрагмент байта с помощью json.Marshal
  • Шаг 2: используйте метод Write интерфейса io.Writer

Вот так выглядит наш метод:

func (p *Person) Write(w io.Writer) {
 b, _ := json.Marshal(*p)
 w.Write(b)
}

Это все! В этом магия го. Из-за определения io.Writer внутри вашего пакета больше ничего не делается. Реализация метода Write готова.

Эта абстракция действительно эффективна, потому что вы можете использовать каждый пакет, который создает io.Writer вместе с вашим пакетом. Внутри вашего кода вам не нужно решать, как и куда писать данные. И реализовать его предельно просто. Компилятор Go гарантирует, что ваш код работает, когда вызывается метод Write.

Полный пример на игровой площадке Go показывает, как работает абстракция. Внутри вашего метода вас не волнуют методы интерфейса. Внутри основной функции вы можете объявить любой тип io.Writer для своего метода. Это также упрощает тестирование вашего метода. Вам не нужно проверять записанные файлы, потому что внутри вашего теста вы можете использовать io.Writer, который хранит записанные байты, например, внутри буфера.

Упражнение: приготовил еще один незаконченный пример на детской площадке. Лучшая абстракция на этом этапе - исключить функцию json.Marshal из нашего метода Write. Чтобы добиться этого, мы определяем кодировщик типов, который является функцией. Этот тип принимает тип Person и возвращает часть байта. Внутри нашего метода записи мы просто используем этот тип. Чтобы все работало, нам нужно определить переменную, которая включает тип кодировщика.