Cортировки и битовые маски, обработка ошибок и создание изображений, генерация перестановок и работа с хэш-суммами, запуск HTTP-сервера, юнит-тесты и другие распространенные задачи, решаемые с помощью Go.
1. Две реализации
очереди FIFO в Go
Для временной очереди используйте слайс. Для long-livingочередей удобнее использовать динамическую структуру
данных, такую как связанный список.
Используем слайс
Простой способ
реализовать временную структуру данных очереди в Go – использовать слайс:
для enqueue-запроса используйте встроенную функцию append;
для dequeue-запроса – применяйте слайс к первому элементу.
Следим за утечками
памяти Go
Возможно, вы захотите
удалить первый элемент перед dequeue-запросом.
Память, выделенная под
массив, никогда не «вернется». При использовании долгоживущих очередей, используйте связанные списки.
Связанный список
Пакет container/list реализует двусвязный список, который можно
использовать в качестве очереди.
2. Основные реализации
множества в Go
Реализация множества через map
Распространенный способ
реализации множества в Go – использование map.
Альтернативный подход
Если память,
используемая под булевы значения, создает дискомфорт, вы можете заменить их
пустыми структурами. В Go пустая структура, как правило, не использует всю
память.
Реализация bitset
При использовании в небольших множествах целых чисел можно применить bitset – небольшой набор булевых значений – флагов, представленных битами. Об этом подробнее рассказано ниже.
3. Базовая структура стека (LIFO)
В Go реализовать структуру данных стека (очередь LIFO) можно с помощью слайса и функции
append:
Ознакомьтесь с понятием амортизированным временем для лучшего понимания процесса: добавление одного элемента к слайсу занимает постоянное амортизированное время.
4. Доступ к переменным
среды Go
Для чтения и записи переменных окружения используйте функции
Setenv, Getenv, Unsetenv и Environ :
5. Доступ к приватным
полям с рефлексией
В этом примере мы
получаем доступ к несообщаемому полю len в структуре List пакета container/list:
Этот код считывает
значение len с помощью рефлексии.
6. Bitmasks, bitsets и
флаги
Битовая маска –
множество булевых значений-флагов, представленных битами,
состоящих из одного или нескольких чисел.
Пример использования простой битовой маски в Go
Большие битсеты
Для представления
больших битсетов может понадобиться кастомная структура данных. Есть удобный сторонний пакет bit, предоставляющий реализацию битового массива.
Поскольку битовый
массив использует параллелизм, ограничивает доступ к памяти и использует кэш
данных, часто он качественно превосходит другие структуры данных. Попробуйте
код bit.Set
из упомянутого пакета bit
и вы будете приятно удивлены.
7. Проверка на простое
число
Целочисленные типы
Для целочисленных типов
используйте функцию ProbablyPrime(0)
из пакета math/big.
Этот тест на простые числа является 100% точным примерно для 264
вхождений.
Большие числа
Для больших чисел,
необходимо обеспечить требуемое количество тестов из ProbablyPrime(n). Для n тестов вероятность возврата true для
случайно выбранного непростого числа составляет не более (1/4)n. Для
примера: при n = 20 на выходе получится 0,000,000,000,001.
8. Поиск строк по шаблону
Как написать базовое
CLI-приложение.
Этот пример является
упрощенной версией команды grep из *nix. Код ищет в файле строки, содержащие
заданный шаблон, и выводит их на экран.
9. Аргументы и флаги командной строки
Вы можете получить
доступ к аргументам командной строки, включая имя программы и флаги, через
os.Args variable:
Кстати, пакет flag реализует базовый синтаксический анализ флагов
командной строки.
10. Вычисление абсолютного значения int/float в Go
Целые числа
Для целых чисел соответствующую функцию легко написать самостоятельно:
Памятка:
наименьшее значение целого числа со знаком не имеет соответствующего
положительного значения:
math.MinInt64 – это -9223372036854775808;
math.MaxInt64 – это 9223372036854775807.
К сожалению, в таких
случаях функция Abs возвращает отрицательное значение:
Впрочем, подобным образом ведут себя библиотеки Java и C.
Float
Функция math.Abs может
возвращать и абсолютные значения:
Частный случай:
11. Вычисление максимума из двух int/float
Напишем код для
вычисления минимума и максимума целых чисел. Используем math.Min и math.Max
для чисел с плавающей точкой.
Int
Float
Частный случай:
12. Конвертирование размеров
Функции для
преобразования размера файла в байтах в удобочитаемый формат. Следующий код поддерживает и формат SI(десятичный), и IEC(двоичный).
13. Обрабатываем ошибки в Go
Строковая ошибка
Кастомные ошибки с данными
Для такого типа ошибок необходимо
объявить error interface:
Два примера:
Если Foo – это функция,
возвращающая SyntaxError или InternalError, их можно обработать следующим
образом:
14. Создание картинок
Для программного
создания PNG-изображения обычно используются пакеты image, image/color и image/png.
Вывод:
Поддержка изображений
Пакет image реализует базовую 2-D библиотеку изображений без функции рисования. В cтатье The Go image package подробно изложена тема изображений, цветовых моделей и форматов в Go. Кроме того, пакет image/draw предоставляет функции композиции изображений, которые можно использовать для выполнения ряда распространенных задач манипулирования картинками. В статье The Go image/draw package найдете массу примеров.
15. Генерация перестановок
Как сгенерировать все перестановки среза или строки в Go:
Вызов http.HandleFunc сообщает пакету net.http, что обработкой всех запросов к «корню» занимается HelloServer;
http.ListenAndServe сообщает серверу, что он должен прослушивать адрес по порту 8080. Эта функция блокируется, пока программа не завершится;
http.ResponseWriter отправляет данные HTTP-клиенту;
http.Request – структура данных клиентского HTTP-запроса;
r.URL.Path – компонент URL-адреса. В нашем случае "/world" является компонентом ссылки "http://localhost:8080/world".
При обращении к http://localhost:8080/world, где работает приведенный код, вы увидите
такую страницу:
Примечание: что ещё почитать
Если желаете глубже разобраться в вопросе, рекомендуем туториал The Writing Web Applications, в котором вы узнаете как: создать структуру данных с помощью методов загрузки и сохранения; использовать пакет net/http для создания веб-приложений; использовать пакет html/template для обработки HTML-шаблонов; использовать regexp для валидации ввода.
18. Реализация итератора
Go имеет встроенный
цикл для итерации по слайсам, массивам, строкам, картам и каналам. Для перебора других типов данных у функции итератора есть обратные вызовы.
Базовый паттерн итератора
В действии:
Итератор с break
В действии:
19. Четыре примера йота-перечислений
Йота: базовый пример
Ключевое слово iotaпозволяет создавать последовательные целочисленные константы: 0, 1, 2 и т. д. Значение iota сбрасывается к нулю, когда в исходном коде появляется слово const.
Можно уменьшить так:
Начало с единицы
Чтобы начать список
констант с 1 вместо 0, можно использовать iota в арифметическом выражении:
Пропуск значения
Для пропуска значения в списке констант можно использовать пустой идентификатор:
20. Максимальное значение int
Go имеет два целочисленных
типа с реализацией конкретных размеров:
uint (беззнаковое целое), 32 или 64 бита;
int (целое) имеет такой же размер, как uint.
Код ниже вычисляет
предельные значения нетипизированных констант:
Константа UintSize
также доступна в пакете math/bits.
21. Округление float до n знаков после запятой
Float
в string
Чтобы отобразить
значение в виде строки, используйте метод fmt.Sprintf.
Float
во Float
Чтобы округлить до
значения с плавающей запятой, используйте один из этих методов:
22. Юнит-тесты в Go
Пусть у нас есть код, который
мы хотим протестить:
Поместим тестовый код в файл, имя которого заканчивается на _test.go;
напишем функцию TestXXX с одним аргументом типа *testing.T;
для указания на неудачный тест, вызовем функцию t.Errorf.
Используйте
функцию sort.Slice– она сортирует слайс с помощью функции less(i, j int). Чтобы
отсортировать слайс, сохраняя исходный порядок элементов, используйте сортировку sort.SliceStable:
Сортировка пользовательских структур
Используйте универсальные
функции sort.Sort и sort.Stable.
Пример:
Сортировка map по ключу или значению
Как вы знаете, map – это
неупорядоченная коллекция пар ключ-значение. Если же нужен стабильный порядок
итераций, нужно использовать другую структуру данных. В этом примере кода для сортировки карты по ключам используется слайс ключей.
***
Если эти примеры были полезны, вы можете подписаться на наш телеграм-канал @goproglib – в нём мы публикуем последние статьи о языке Go и другие полезные материалы на русском и английском языках.
Поделитесь вашими любимыми кусочками кода на Go, в комментариях работает Markdown-разметка