Latest posts

Thank Go!
2 Sept, 12:29
Множественный разврат возвратСколько значений можно вернуть из функции через multi-return? Да сколько угодно!Например, функция readFloat в стандартной библиотеке возвращает семь штук.Вот это я понимаю, функциональное программирование 😁


Thank Go!
31 Aug, 11:03
Ошибка ошибка ошибка ошибкаЭто выражение выглядит странновато, но оно полностью корректно:error.Error(errors.ErrUnsupported)errors.ErrUnsupported — реальная, хотя и не слишком известная ошибка в пакете errors:var ErrUnsupported = New("unsupported operation")error — реальное название интерфейсного типа, а Error — метод на этом интерфейсе:type error interface { Error() string }Метод любого типа можно вызвать как обычную функцию, так что эти два вызова эквивалентны:var err = errors.New("oops") err.Error() // "oops"
Thank Go!
30 Aug, 15:09
1,640Open in Telegram
Thank Go!
25 Aug, 11:32
JSON v2 в Go 1.27Вторая версия json-пакета впервые появилась как экспериментальная в Go 1.25. Два релиза ее обкатывали, и наконец окончательно выпустили в 1.27.В связи с этим актуализировал свой гайд по отличиям между json и json/v2 (их много!).Все разобрано на конкретных примерах:https://habr.com/ru/articles/923404/
Thank Go!
12 Aug, 11:23
strings.CutLastИз небольших изменений в Go 1.27 я больше всего рад strings.CutLast. Эта функция делит строку по последнему вхождению разделителя.Конечно, реализовать ее несложно и самому:// CutLast делит s на части до и после последнего вхождения sep. func CutLast(s, sep string) (before, after string, found bool) { if i := strings.LastIndex(s, sep); i >= 0 { return s[:i], s[i+len(sep):], true } return s, "", false }Но приятно, что теперь делать этого не придется:s := "go|for|it" _, last, ok := strings.CutLast(s, "|") fmt.Println(last, ok) // it true
Thank Go!
10 Aug, 11:31
Generic-методы и их последствияДумаю, «джавафикация» экосистемы Go только усилится с появлением в 1.27 дженерик-методов (это методы, у которых может быть собственный параметр типа).// Sum - сумма целых чисел. type Sum[T int | int64] struct { v T }// Add добавляет число к сумме, приводя его к целому, если нужно. func (s Sum[T]) AddV int | int64 | float64 Sum[T] { s.v += T(v) return s }В этом примере T — параметр типа на структуре, а V — параметр типа на методе. В предыдущих версиях Go параметры вроде V приводили к ошибке "method must have no type parameters", а теперь будут разрешены.var s Sum[int] s.Add(30).Add(10).Add(2.3) fmt.Println(s.Val())
Thank Go!
6 Aug, 12:18
Тур по Go 1.27Со дня на день выйдет Go 1.27, так что самое время почитать, что там внутри.Я слегка задолбался делать обзоры релизов, но ребята из VictoriaMetrics решили принять эстафету, так что читайте у них в блоге. С интерактивными примерчиками, все как мы любим.Краткое содержание для ленивых:— Generic-методы с собственными (не привязанными к типу) параметрами — Компактные литералы для embedded-структур — Диагностика утечек горутин в продакшене (было experiment в 1.26) — UUID v4 и v7 — JSON v2 в продакшене (был experiment в 1.26) — Универсальный SIMD (experiment) — strings.CutLast (давно о ней мечтал) — Интерфейс maphash.Hasher — synctest.Sleep (= time.Sleep + synctest.Wait)https://victoriametrics.com/blog/go-1-27
Thank Go!
1 Aug, 16:18
Делаем себе сложноХотел я вам написать, как можно начать с очень простой реализации Backward, и прийти к чему-то похожему на стдлибу.Но заметка получилась великовата для канала, поэтому вынес ее на хабр. Не уверен, что тамошние обитатели будут в восторге.Вам же заметку рекомендую — в ней есть jira, жабы, и нелепый авторский юмор.https://habr.com/ru/articles/1065634
Thank Go!
31 Jul, 09:05

Thank Go!
28 Jul, 14:57edited
Что внутри у интерфейсаМногие знают, что интерфейс в Go реализован как обертка, внутри которой два указателя — на конкретное значение и на его тип.Но строго говоря, все несколько сложнее.Вот интерфейс:type iface struct { tab abi.ITab data unsafe.Pointer }data — это действительно указатель. Если мы заворачиваем в интерфейс значение, в data будет указатель на него (а само значение переедет в кучу при необходимости).Если же заворачиваем указатель (например os.File в io.Reader), то в data будет ровно этот самый указатель.А вот tab — не просто конкретный тип, а целая пачка метаданных:type ITab struct {
Thank Go!
24 Jul, 11:41
Метод-выражениеВсе, конечно, знают, что такое метод структуры:type counter struct { val uint }func (c counter) inc() { c.val++ }Но не все знают, что метод реализован как обычная функция, у которой первым параметром идет значение получателя (или указатель на него):// реализованы одинаково func (c counter) inc() func inc(c counter)На практике это означает, что вы можете использовать метод как функцию:
Thank Go!
20 Jul, 18:23
Рубрика «ненормальное программирование»Запихиваем максимальное количество встроенных функций в одно выражение:println(max( len(append(make([]int, 1, 2), new(int))), cap(make(chan struct{}, 3)), copy(make([]byte, 5), "hello"), min(int(real(complex(1, 2))), int(imag(complex(3, 4)))), map[any]int{}[recover()], ))Здесь их 13 🤓 В порядке появления:println max len append make new
Thank Go!
20 Jul, 15:08edited
18 встроенных функций GoВам, конечно же, не терпится увидеть полный список встроенных функций (нет). Ну раз вы так настаиваете, то вот он:make создает новый срез, карту или канал. new аллоцирует память под переменную.append добавляет одно или несколько значений в срез. copy копирует элементы из одного среза в другой (или байты из строки в срез). delete удаляет элемент из карты. clear очищает срез или карту.len и cap возвращают длину/емкость контейнера (строка, срез, карта, канал).close закрывает канал.min и max возвращают минимальный/максимальный из аргументов.complex, real и imag собирают и разбирают комплексные числа.
Thank Go!
18 Jul, 12:19
Встроенные функцииВсе регулярно используют встроенные функции (built-in). Это функции, которые не требуют импорта пакета, вроде len, make или panic.Но что такое вообще встроенная функция? Например, len в документации заявлена как часть пакета builtin:func len(v Type) intВо-первых, что это еще за builtin-пакет и тип Type в нем?Во-вторых, len явно дженерик, так где же наша любимая абракадабра вида len[S ~[]E, E any](x S), ну или хотя бы lenT any?И как вообще это добро работало начиная с версии Go 1.0, когда никаких дженериков даже на горизонте не было?Суровая правда в том, что len — вообще не функция. У нее нет собственного фрейма на стеке, как у обычных функций, и других присущих им особенностей.На самом деле, компилятор превращает вызов len(s) в прямое чтение s.len, где len — это обычное поле структуры среза (или аналогичное поле строки, карты или канала):type slice
Thank Go!
13 Jul, 13:50
Функциональные опцииДолжен признаться, что терпеть не могу паттерн «функциональных опций», полюбившийся многим программистам на Go.И особенно я не рад, что он пробрался в стдлибу вместе с новым пакетом json/v2 (финализирован в Go 1.27):type Options interface { ... }func Deterministic(v bool) Options func FormatNilMapAsNull(v bool) Options func FormatNilSliceAsNull(v bool) Options // ...func Marshal(in any, opts ...Options) (out []byte, err error)Обычная структура (см. скриншот) лучше во всех отношениях, на мой взгляд.А вы что думаете?


Thank Go!
8 Jul, 17:02edited
string ⇄ []byteВсе знают, как преобразовать байтовый срез в строку и обратно:b := []byte{...} s := string(b) // 1s := "..." b := []byte(s) // 2И ➀ string(b) и ➁ []byte(s) создают копию данных длиной len(x) — на стеке или в куче, в зависимости от ситуации.Цикл с преобразованием string(b) тоже создает копию:for _, r := range string(b) { ... }А вот цикл с преобразованием []byte(s) копию никогда не создает — итерация идет прямо по байтам оригинальной строки:
Thank Go!
2 Jul, 18:19
Флаг -raceФлаг -race включает проверку на гонки в коде (потенциальный конфликт при доступе к общим данным из нескольких горутин). Если при выполнении рантайм видит гонку, он пишет, где именно та произошла.Несложно догадаться, что проверка эта небесплатная. С включенным детектором гонок приложение использует в 5–10 раз больше памяти, а работает в 2–20 раз медленнее.Надо ли собирать продакшен с включенным -race? Разве что если в ваши планы входит потом «оптимизировать» производительность в 10 раз и получить за это почет и уважение. Ну или по башке, если кто-то проверит, что именно вы там наоптимизировали 😅
Thank Go!
2 Jul, 12:15

Thank Go!
30 Jun, 09:26
Грязный makeА хотите по-настоящему злую штуку? В стандартной библиотеке есть функция, которая создает срез байт, не зануляя память:// MakeNoZero makes a slice of length n // and capacity of at least n bytes // without zeroing the bytes. // It is the caller's responsibility // to ensure uninitialized bytes // do not leak to the end user. func MakeNoZero(n int) []byteФункция находится в пакете internal/bytealg, так что напрямую ее не вызвать. Но через go:linkname — можно://go:linkname makeNoZero internal/bytealg.MakeNoZero func makeNoZero(n int) []bytefunc main() { data := makeNoZero(10) // ...
Thank Go!
29 Jun, 16:05
Нулевое значениеПриятное отличие Go от C заключается в том, что он всегда инициализирует переменные нулевым значением (zero value) данного типа:var n int // 0 var b bool // false var s string // "" var p T // nilДля массивов и срезов (через make) это тоже так работает:var arr [3]int // [0 0 0] s := make([]int, 3) // [0 0 0]Но что будет, если создать срез с емкостью большей, чем длина?s := make([]int, 3, 6)Понятно, что первый-второй-третий элементы равны 0. А что с четвертым-пятым-шестым?
Related Channels
Other channels in the same section of the catalogue.
