Не программируйте интерфейсы, открывайте их.
1 Ұнайды
Этот программный дизайн привычен для разработчиков, имеющих опыт работы с C # или с Java. Но в Go в большинстве случаев так делать не следует.
В этом примере вызываем функцию getOperations, которая возвращает срез типа float32. Далее мы хотим вызывать функцию handle только в том случае, если этот срез содержит элементы. Вот первая (ошибочная) версия кода этих действий:
func handleOperations(id string) {
operations := getOperations(id)
if operations != nil { Проверяется, является ли срез operations нулевым
handle(operations)
}
}
func getOperations(id string) []float32 {
operations := make([]float32, 0) Инициализируется срез operations
if id == "" {
return operations Возвращается operations, если заданный id пуст
}
// Добавление элементов к operations
return operations
}
Мы определяем, есть ли в срезе элементы, проверяя, не является ли срез operations нулевым. Но у этого кода есть проблема: функция getOperations никогда не возвращает нулевой срез, она возвращает пустой срез. Поэтому значение проверки operations != nil всегда будет true.
Внутри себя context.WithTimeout создает горутину, которая будет храниться в памяти в течение 4 секунд или до тех пор, пока не будет вызвана cancel.
Лучшей практикой при обработке контекстных ключей будет создание неэкспортируемого пользовательского типа:
package provider
type key string
const myCustomKey key = "key"
func f(ctx context.Context) {
ctx = context.WithValue(ctx, myCustomKey, "foo")
// ...
}
вызов cancel в качестве функции defer означает, что при выходе из родительской функции контекст будет отменен, а созданная горутина остановлена. Это мера предосторожности, чтобы при возвращении мы не оставили в памяти сохраненные объекты.
Контекст переносит крайний срок, сигнал отмены и другие значения через границы API.
Взгляните и на golangci-lint (https://github.com/golangci/golangci-lint). Это инструмент для анализа кода, который обеспечивает видимость поверх многих полезных линтеров и форматировщиков. Он позволяет запускать линтеры параллельно для повышения скорости анализа, что весьма удобно.
ит-тестов, потому что они не будут отвечать за закрытие переменной db.
Обратите внимание, что мы можем зарегистрировать несколько функций очистки. В этом случае они будут выполняться так же, к
Можно пойти еще дальше. Вместо создания служебных функций можно создать специфический тип и предоставить Sort как метод так:
package stringset
type Set map[string]struct{}
func New(...string) Set { ... }
func (s Set) Sort() []string { ... }
Это изменение делает клиент еще более простым. На пакет stringset будет только одна ссылка:
set := stringset.New("c", "a", "b")
fmt.Println(set.Sort())
Небольшой рефакторинг убирает бессмысленное имя пакета и дает выразительный API. Как упомянул Дейв Чейни (член команды проекта Go), мы достаточно часто находим служебные пакеты, которые управляют стандартными возможностями. Например, если мы решим иметь клиентский и серверный пакеты, куда нужно поместить общие типы? В этом случае одним из возможных решений будет объединение клиента, сервера и общего кода в единый пакет.
