Thank Go!

Description
Неожиданный взгляд на язык программирования Go. Конструктив от @mikeberezin с нотками сарказма от @nalgeon
Advertising
We recommend to visit

Официальный новостной канал криптобиржи OKX | www.okx.com на русском языке.

? Комьюнити: t.me/okx_russian

?‍? Поддержка: [email protected]

АДМИН: @DaniiOKX
Маркетинг: @CoffeeTrends

Last updated 2 weeks, 2 days ago

Здесь простым языком про TON, DFC и крипту.

Принимаем автоматически.
Ссылка для друзей: https://t.me/+-EOfWx2pRKhmNGE6
Связь: @deftalk_bot

Last updated 1 month ago

#1 канал о блокчейне, криптовалютах и децентрализованных финансах.

🔥 Реклама — @DCTeam

Last updated 1 day, 6 hours ago

1 month, 3 weeks ago

Go 1.23

Тут вышел Go 1.23, ну а мы с вами успели разобрать основные изменения заранее:

Итераторы
Таймеры
Уникальные значения
Скопировать каталог
Куки

Все вместе с интерактивными примерами:
https://antonz.org/go-1-23

1 month, 4 weeks ago

Большая крыса Go

Прежде чем вы решите, что я сошел с ума — речь на самом деле о типе big.Rat.

В отличие от float64, он позволяет работать с обыкновенными дробями (a/b) без потери точности.

Например, из школьного курса математики мы знаем, что 1/10 + 2/10 = 3/10. Однако, float64 другого мнения:

x := 0.1 y := 0.2 fmt.Println(x + y) // 0.30000000000000004

А вот big.Rat справляется с такими вычислениями без проблем:

x := big.NewRat(1, 10) y := big.NewRat(2, 10) z := new(big.Rat) z.Add(x, y) fmt.Println(z) // 3/10

Если вдруг придется работать с обыкновенными дробями — имейте «крысу» в виду.

2 months ago

Статический HTTP-сервер

Вы, наверно, слышали про встроенный в Python статический сервер:

python \-m http.server 8080

На Go его можно реализовать в десять строчек кода (плюс импорты):

```
func main() {
port := "8000"
if len(os.Args) > 1 {
port = os.Args[1]
}

fs := http.FileServer(http.Dir("."))
http.Handle("/", fs)

log.Printf("Serving HTTP on port %s...\n", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
```

И запускать вот так:

go run http.go 8080

3 months ago

Git в примерах

Зашел я на Степик в новые курсы, а там «Основы Git». В связи этим вспомнил, что у меня тоже есть интерактивная книга / сборник рецептов по гиту, называется Git by example.

Удобный краткий формат с конкретными примерами, я сам туда постоянно подглядываю (особенно в раздел undo).

Загляните и вы, если не обзавелись еще черным поясом по гиту.

https://antonz.org/git-by-example

P.S. А вы же знаете, что по Go тоже такая есть?

3 months, 1 week ago

Безопасные ворота

Вот три способа безопасно закрыть ворота, один другого краше.

➊ sync.Mutex

Дубовый, но надежный способ. Защищаем изменение логического поля closed мьютексом:

```
type Gates struct {
// признак закрытия ворот
closed bool
// мьютекс для защиты closed
mu sync.Mutex
}

func (g *Gates) Close() {
g.mu.Lock()
defer g.mu.Unlock()
if g.closed {
// игнорируем повторное закрытие
return
}
// закрыть ворота
g.closed = true
// освободить ресурсы
}
```

➋ atomic.Bool

Compare-and-set на атомарном bool гарантирует, что только одна горутина сможет поменять значение с false на true:

```
type Gates struct {
// признак закрытия ворот
closed atomic.Bool
}

func (g *Gates) Close() {
if !g.closed.CompareAndSwap(false, true) {
// игнорируем повторное закрытие
return
}
// закрыли ворота,
// можно освободить ресурсы
}
```

➌ sync.Once

Once.Do гарантирует однократное выполнение в конкурентной среде, поэтому не приходится даже явно хранить состояние:

```
type Gates struct {
// гарантирует однократное выполнение
once sync.Once
}

func (g *Gates) Close() {
g.once.Do(func() {
// освободить ресурсы
})
}
```

Правда, такие ворота уже не получится открыть обратно, в отличие от предыдущих вариантов.

Кто ваш любимчик? Поделитесь в комментариях.

3 months, 1 week ago

Опасные ворота

Вот наши ворота:

```
type Gates struct {
// признак закрытия ворот
closed chan struct{}
}

func (g *Gates) Close() {
select {
case <-g.closed:
// игнорируем повторное закрытие
return
default:
// закрыть ворота
close(g.closed)
// освободить ресурсы
}
}
```

Метод Close — небезопасный. Если две горутины одновременно вызовут Close, обе могут провалиться в default-ветку селекта, обе попытаются закрыть канал, и второе закрытие приведет к панике.

Другими словами, здесь гонки на закрытии канала. Селект сам по себе не защищает от гонок. Sad but true.

Что с этим делать — традиционно в следующей заметке.

3 months, 1 week ago

Баян [::]

Гошный баян (вообще он «полносрезное выражение» или full slice expression, но «баян» мне ближе) имеет такой синтаксис:

s[low : high : max]

Баян создает срез длиной high\-low и емкостью max\-low. Используется крайне редко.

Чтобы понять разницу между обычным срезом и баяном, рассмотрим пример.

Как вы знаете, под каждым срезом лежит массив с данными (сам срез данных не содержит). Обычно этот массив создается неявно, но мы для наглядности сделаем так:

```
arr := [5]int{1, 2, 3}
// [1 2 3 0 0]

s := arr[0:3]
// [1 2 3]

len(s) // 3
cap(s) // 5
```

Срез s указывает на массив arr. Его длина (length) равна 3, а емкость (capacity, размер массива под срезом) равна 5.

Добавление элемента в срез добавляет его в массив, поскольку емкость это позволяет:

```
s = append(s, 4)

fmt.Println(arr)
// [1 2 3 4 0]

fmt.Println(s)
// [1 2 3 4]
```

А вот что будет, если создать срез с помощью баяна:

```
arr := [5]int{1, 2, 3}
// [1 2 3 0 0]

s := arr[0:3:3]
// [1 2 3]

len(s) // 3
cap(s) // 3
```

Все как раньше, только емкость среза равна 3. Поэтому добавление элемента в срез приведет к созданию нового массива под срезом. Исходный массив arr не изменится:

```
s = append(s, 4)

fmt.Println(arr)
// [1 2 3 0 0]

fmt.Println(s)
// [1 2 3 4]
```

Такие дела. За разновидностями баянов приглашаю в комментарии.

?

3 months, 1 week ago

Обновил курс до Go 1.22

Добавил в базовый курс по Go новые блоки и темы:

— range по целым числам;
— встроенные функции min, max и clear;
— комбинация ошибок через errors.Join;
— причина отмены контекста и context.AfterFunc (+ забористая задачка);
— дженерики, пакеты slices и maps (про них уже писал выше);
— тип-обертка Null в database/sql.

Заодно добавил маленький урок 1.9 со всякой всячиной (пока там блоки, группы и йота).

P.S. А еще на этом уроке вам предстоит победить Сквернолапа. Ну или Когтевика. В крайнем случае — Огнежора ?

3 months, 1 week ago

Пустой срез vs. nil-срез

Как вы знаете, объявленная без инициализации переменная в Go автоматически получает нулевое значение соответствующего типа:

var num int // 0 var str string // "" var flag bool // false

Для среза нулевое значение — nil:

var snil []int // []int(nil)

С другой стороны, бывает инициализированный, но пустой срез:

sempty := []int{} // or // sempty = make([]int, 0)

Это разные значения, которые не равны между собой:

reflect.DeepEqual(snil, sempty) // false

И в то же время, пустой срез и nil-срез почти всегда взаимозаменямы:

```
len(snil) // 0
cap(snil) // 0
snil = append(snil, 1) // []int{1}

len(sempty) // 0
cap(sempty) // 0
sempty = append(sempty, 1) // []int{1}

reflect.DeepEqual(snil, sempty)
// true
```

Почти всегда ваш код не должен делать разницы между пустым и nil-срезом.

Есть и исключения, конечно. Приглашаю поделиться ими в комментариях.

3 months, 2 weeks ago
We recommend to visit

Официальный новостной канал криптобиржи OKX | www.okx.com на русском языке.

? Комьюнити: t.me/okx_russian

?‍? Поддержка: [email protected]

АДМИН: @DaniiOKX
Маркетинг: @CoffeeTrends

Last updated 2 weeks, 2 days ago

Здесь простым языком про TON, DFC и крипту.

Принимаем автоматически.
Ссылка для друзей: https://t.me/+-EOfWx2pRKhmNGE6
Связь: @deftalk_bot

Last updated 1 month ago

#1 канал о блокчейне, криптовалютах и децентрализованных финансах.

🔥 Реклама — @DCTeam

Last updated 1 day, 6 hours ago