Как стать автором
Обновить

Некоторые советы, которые я почерпнул из книги «100 ошибок в Go»

Время на прочтение6 мин
Количество просмотров7.1K
Всего голосов 7: ↑5 и ↓2+6
Комментарии11

Комментарии 11

Ошибка rows.Close присваивается другой переменной: closeErr. Прежде чем присвоить ее переменной err, мы проверяем, отличается ли err от nil. Если это так, то ошибка уже была возвращена функцией getBalance, поэтому мы решаем записать err в лог и вернуть существующую ошибку.

Странный момент. Как по мне лучше вернуть и closeErr, если таковая имеется.
err = errors.Join(err, closeErr)
И уже вызывающая сторона решит как реагировать на ошибку.

Можно создать для этого ошибку
var cErr = errors.New("Close error")
Узнать была ли она if errors.In(err, cErr) ...

или через type CloseError struct ... если нужны подробности ошибки
Тогда проверка if _, ok := err.(*CloseError); ok ...

Лень расписывать, кто пишет на golang, тот поймет.

Короче пример очень плохой обработки ошибки (

а почему не errors.As/Is?

здесь `if _, ok := err.(*CloseError); ok ...` можно As
Расписывать возможности в комментарии не было смысла. Основной посыл, что функция должна вернуть все ошибки, а не пытаться их логировать

С утечкой capacity тоже фигня какая-то... Обещали копию всего слайса, а по-факту, копируется только структура с указателем, длиной и размером.

https://go.dev/play/p/MDLJQ6whbwR

Или я что-то не так понял?

Тогда причем там аллокация гигабайтов памяти? В общем, складывается впечатление, что автор оригинала не совсем понимает то, что пишет.

Я думаю что там подразумевается что storeMessageType складывает полученный слайс куда-то ещё в память, и GC не придёт за изначальным мегабайтным слайсом данных, т.к. на него ещё висит ссылка в виде 5-элементного слайса, который где-то висит в памяти

Как я понял там речь не про копию слайса, а о том, что если вы решите слайс из 5 элементов (который образован из слайса на 1мб через [:5]) где-то сохранить на длительное время и остальная часть от 1мб вам никогда не понадобится, то gc память не очистит.

При этом, если создадите новый слайс и скопируете 5 элементов, то с условием выше (остальная часть от 1мб вам никогда не понадобится) gc очистит лишнюю память.

Проверить варианты (в 12 строке true и !true):

https://go.dev/play/p/hxh4kWBhPaO

Пока что эта гипотеза наиболее правдоподобна, спасибо!

func getMessageType(msg []byte) []byte {
return msg[:5]
}

func receiveMessage() []byte {
return make([]byte, 1_000_000)
}

func storeMessageType([]byte) {}

Понимаю, что пример синтетический, но нельзя такое в книгах писать: новички видят, потом используют. Во-первых слайс байт, который мы передаём, он же откуда-то взялся. Скорее всего из ридера. "Принимай интерфейсы, отдавай структуры". Автор другим советует принимать интерфейс (вместо файла), а себе не смог. Во-вторых в Go не принято принуждать к аллокациям. А если я а хочу 10 тыс раз сделать receiveMessage()? А если я точно знаю, что буду делать их по очереди и хотел бы переиспользовать слайс вместо его многократного выделения?

Зарегистрируйтесь на Хабре, чтобы оставить комментарий