TGViewer
Channel Public Channel
Go tests

Go tests

@golangtests

По всем вопросам- @haarrp

@itchannels_telegram - 🔥полезные ит-каналы

https://t.me/Golang_google - Golang программирование

@golangl - golang chat

@GolangJobsit - golang channel jobs

@golang_jobsgo - go chat jobs
Subscribers
7.84K
Photos
316
Videos
6
Links
114
Recent Posts 20 shown
Post #936 750
👣 Задача на Go 1.27: concurrent job scheduler с generic methods

Нужно реализовать библиотеку scheduler, которая запускает задачи параллельно, ограничивает concurrency, поддерживает context.Context, retry, timeout и возвращает типизированные результаты.

💡 Требования

Создайте generic-тип:


type Scheduler[T any] struct {
// ...
}

Он должен поддерживать регистрацию задач:

type Job[T any] func(ctx context.Context) (T, error)

И новый generic method Go 1.27:

func (s *Scheduler[T]) Map[R any](
ctx context.Context,
fn func(context.Context, T) (R, error),
) ([]R, error)
Функциональность

Scheduler должен уметь:

выполнять не более N задач одновременно;
отменять все оставшиеся задачи при отмене context.Context;
задавать timeout для каждой задачи;
делать до K retry с exponential backoff;
сохранять исходный порядок результатов;
не иметь data race;
корректно завершать goroutines без утечек;
возвращать ошибку с информацией, какая задача упала.

Пример API:

```go
s := scheduler.New[int](
scheduler.WithWorkers(8),
scheduler.WithRetries(3),
scheduler.WithTimeout(2*time.Second),
)

for i := range 100 {
n := i

s.Add(func(ctx context.Context) (int, error) {
return expensiveOperation(ctx, n)
})
}

values, err := s.Run(ctx)

strings, err := s.Map(ctx, func(
ctx context.Context,
value int,
) (string, error) {
return strconv.Itoa(value), nil
})


Ограничения

• Нельзя использовать сторонние worker-pool библиотеки.
• Можно использовать только standard library.
• Нельзя запускать goroutine на каждую задачу без ограничения.
• Нельзя игнорировать ctx.Done().

Решение должно проходить:

go test ./...
go test -race ./...
go vet ./...
Дополнительный уровень


Добавьте:


func (s *Scheduler[T]) Stream(
ctx context.Context,
) <-chan Result[T]


где результаты приходят сразу после завершения задач, а не после окончания всего batch.

Ещё сложнее:


priority queue;
dynamic worker count;
graceful shutdown;
metrics через expvar;
retry только для определённых типов ошибок;
panic recovery внутри job;
benchmark;
fuzz tests.


Главный вопрос

Как реализовать Scheduler так, чтобы одновременно обеспечить:

bounded concurrency + cancellation + ordering + retries + no goroutine leaks + no races
  • ❤ 3
  • 🥰 1
Post #935 704
🔥 Хочешь расти в IT быстрее остальных? Перестань учиться в одиночку

Можно годами смотреть курсы, читать документацию и всё равно топтаться на месте.

А можно попасть в правильное окружение, где каждый день обсуждают новые инструменты, вакансии, реальные кейсы, ошибки и то, что уже завтра станет стандартом.

Здесь собраны папки и каналы по разным направлениям IT, чтобы ты быстрее находил нужных людей, идеи и полезный контент - без бесконечного поиска.

AI: t.me/ai_machinelearning_big_data
Python: t.me/pythonl
Linux: t.me/linuxacademiya
Хакинг: t.me/linuxkalii
DevOps: t.me/DevOPSitsec
Docker: https://t.me/+90Z5TAyfuNU5YmRi
Golang: t.me/Golang_google
Rust: t.me/rust_code
C++: t.me/cpluspluc
C#: t.me/csharp_ci
Java: t.me/javatg
JavaScript: t.me/javascriptv
React: t.me/react_tg
Frontend: t.me/front
PHP: t.me/phpshka
Android: t.me/android_its
Мобильная разработка: t.me/mobdevelop
Базы данных: t.me/sqlhub
Data Science: t.me/data_analysis_ml
Big Data: t.me/bigdatai
Математика: t.me/data_math
Физика: t.me/fizmat
Kubernetes: t.me/kubernetc
GameDev: https://t.me/gamedev
Haskell: t.me/haskell_tg

Собеседования и карьера:

DS собеседования: t.me/machinelearning_interview
Python собеседования: t.me/python_job_interview

Папка с вакансиями: t.me/addlist/_zyy_jQ_QUsyM2Vi
Папка Go разработчика: t.me/addlist/MUtJEeJSxeY2YTFi
Папка Python разработчика: t.me/addlist/eEPya-HF6mkxMGIy
Папка ML: https://t.me/addlist/2Ls-snqEeytkMDgy
Папка Frontend: https://t.me/addlist/mzMMG3RPZhY2M2Iy

Полезное сверху:

ИТ-мемы: t.me/memes_prog
Английский для программистов: t.me/english_forprogrammers
ИИ и технологии: t.me/vistehno
954 ГБ open-source курсов: https://t.me/+rKBQEMccAA01MTcy
ИТ-книги бесплатно: https://t.me/addlist/BkskQciUW_FhNjEy

Max Ai: https://max.ru/ai_machinelearning_big_data
Max python: https://max.ru/pythonl
ТЕХНО: https://max.ru/vistehno
Max Go: https://max.ru/Golang_google
Max Linux: https://max.ru/linuxkalii
Devops: https://max.ru/DevOPSitsec
C#: https://max.ru/csharp_ci
C++: https://max.ru/cpluspluc
SQL: https://max.ru/sqlhub
Java: https://max.ru/javatg

Подпишись и сохрани, здесь регулярно появляются новые подборки, инструменты и материалы, которые реально помогают расти быстрее.
  • ❤ 1
  • 👍 1
  • 🔥 1
Post #934 1.51K
👣 Go 1.27: почему две разные closure внезапно могут иметь одинаковый адрес функции?

Что выведет этот код и почему на Go 1.27 поведение стало особенно интересным?


package main

import (
"fmt"
"reflect"
)

func makeFn(x int) func() int {
return func() int {
return x
}
}

func main() {
a := makeFn(10)
b := makeFn(20)

pa := reflect.ValueOf(a).Pointer()
pb := reflect.ValueOf(b).Pointer()

fmt.Println(a(), b())
fmt.Println(pa == pb)
}


Интуитивно хочется сказать:

a и b замыкают разные значения, значит это две разные функции и адреса должны отличаться.

Но в Go 1.27 компилятор стал агрессивнее объединять одинаковый машинный код function literals.

У a и b может быть:

один и тот же code pointer
но разное closure data
поэтому a() возвращает 10, а b() - 20

То есть функция в Go на уровне runtime - это не просто адрес машинного кода.

У замыкания фактически есть ещё окружение с захваченными данными.

Именно поэтому сравнивать функции по reflect.Value.Pointer() как способ определить, «одна ли это функция», нельзя.

Go 1.27 специально предупреждает: разные closure с разными захваченными данными теперь могут чаще иметь одинаковые code pointers из-за оптимизаций компилятора.
  • 👍 10
  • 🔥 5
  • ❤ 1
  • 🥰 1
Post #933 1.87K
Go-задача: что выведет этот код?


package main

import "fmt"

func main() {
var funcs []func()

for i := range 3 {
funcs = append(funcs, func() {
fmt.Println(i)
})
}

for _, f := range funcs {
f()
}
}


Что будет в выводе?


A)

0
0
0

😎

2
2
2

C)

0
1
2

D) Код не скомпилируется


Правильный ответ: C — 0, 1, 2

Почему?

В современных версиях Go переменная цикла для каждой итерации получает отдельное значение для замыканий.

Плюс range теперь можно использовать прямо по integer:

```go
for i := range 3
```

Это даёт значения:

```go
0
1
2
```

Поэтому каждое замыкание запоминает своё i.

Несколько лет назад похожие примеры часто ломались из-за захвата одной общей переменной цикла, и разработчики писали:

```go
i := i
```
внутри цикла.

Хороший вопрос на собеседовании:

Почему этот код сегодня выводит 0, 1, 2, хотя раньше похожий пример мог вести себя иначе?
  • ❤ 5
  • 🔥 5
  • 🥰 2
Post #932 2.27K
Задача Go 1.26, на которой легко ошибиться даже опытному разработчику

Что выведет этот код?


package main

import "fmt"

type Config struct {
Timeout *int
}

func main() {
a := Config{
Timeout: new(30),
}

b := a
*b.Timeout = 60

c := Config{
Timeout: new(*a.Timeout),
}
*c.Timeout = 90

fmt.Println(
*a.Timeout,
*b.Timeout,
*c.Timeout,
)
}


Попробуйте определить ответ до запуска.

```text
60 60 90
```

Почему?

```go
b := a
```

Структура копируется, но указатель внутри неё остаётся тем же. Поэтому `a.Timeout` и `b.Timeout` указывают на одну переменную:

```go
*b.Timeout = 60
```

Изменение видно через обе структуры.

А здесь создаётся уже новая переменная:

```go
Timeout: new(*a.Timeout)
```

Go сначала получает значение `60`, затем выделяет для него отдельную память. Поэтому изменение `c.Timeout` не влияет на `a` и `b`.

```text
a ─┐
├──► 60
b ─┘

c ─────► 90
```

Это важный нюанс: копирование структуры с указателями, слайсами или map не создаёт глубокую копию данных.

Синтаксис `new(30)` появился в **Go 1.26**. Раньше `new` принимал только тип, а теперь может сразу создать указатель на переданное значение.

Код актуален для последней стабильной версии **Go 1.26.5**.

#Golang #Go126 #Programming
  • 👍 15
  • ❤ 3
Post #930 2.25K
🧠 Редкая задача для Go-разработчиков

Версия: Go 1.23+
Именно в Go 1.23 появился range по функциям-итераторам и пакет iter.

Нужно реализовать:


func MergeSorted(a, b iter.Seq[int]) iter.Seq[int]


Функция получает два ленивых отсортированных итератора и возвращает один общий поток в отсортированном порядке.

Пример:


a := Seq(1, 4, 7, 10)
b := Seq(2, 3, 8, 9)

for v := range MergeSorted(a, b) {
fmt.Println(v)
}


Результат:


1 2 3 4 7 8 9 10


Но есть условия:

* нельзя превращать входы в []int;
* нельзя использовать горутины и каналы;
* память должна быть O(1);
* если внешний цикл сделал break, оба исходных итератора должны прекратить работу;
* каждый элемент исходного iterator можно получить только один раз.

🔥 Дополнительный уровень: сделать generic-версию:


func MergeSorted[T cmp.Ordered](
a, b iter.Seq[T],
) iter.Seq[T]


На первый взгляд обычный merge. На практике придётся хорошо понять, как устроены push/pull iterators, `yield` и раннее завершение `range` в Go 1.23.
  • 👍 10
Post #928 2.13K
В Go 1.26 появился типобезопасный errors.AsType, который ищет ошибку нужного типа внутри дерева обёрток.


package main

import (
"errors"
"fmt"
)

type CodeError struct {
Code int
}

func (e *CodeError) Error() string {
return fmt.Sprintf("code=%d", e.Code)
}

type MaskError struct {
Value int
}

func (e MaskError) Error() string {
return "masked"
}

func (e MaskError) As(target any) bool {
dst, ok := target.(**CodeError)
if !ok {
return false
}

*dst = &CodeError{Code: e.Value}
return true
}

func main() {
err := errors.Join(
fmt.Errorf("left: %w", MaskError{Value: 10}),
errors.Join(
&CodeError{Code: 20},
fmt.Errorf("right: %w", &CodeError{Code: 30}),
),
)

result, ok := errors.AsType[*CodeError](err)
fmt.Println(ok, result.Code)
}


Что будет выведено?

true 10

Кажется, ответ должен быть 20: это первая настоящая ошибка типа *CodeError. Но errors.AsType обходит дерево в глубину, начиная с первой ветки.

MaskError встречается раньше и через собственный метод As притворяется *CodeError, записывая значение с кодом 10. Поэтому дальнейший поиск прекращается.

Cлучай, когда тип ошибки определяется не только её реальным типом, но и поведением метода As.
  • ❤ 5
  • 👍 1
Post #926 1.94K
👣 Go давно починил старую ловушку с замыканиями в цикле.

Но concurrency всё ещё может кусаться.

Что не так с этим кодом?


package main

import (
"fmt"
"sync"
)

func main() {
nums := []int{1, 2, 3, 4}

var wg sync.WaitGroup
result := make([]int, 0, len(nums))

for i, n := range nums {
wg.Go(func() {
result = append(result, i*n)
})
}

wg.Wait()

fmt.Println(result)
}


На первый взгляд всё нормально.

i и n уже не общие для всех итераций. В современном Go каждая итерация получает свои переменные, поэтому старого бага с замыканием тут нет.

Проблема в другом месте.

`append` меняет slice header и может трогать общий backing array. Несколько горутин делают это одновременно. Значит, здесь data race, даже если loop variables теперь безопасные.

Правильный вариант:

```go id="9f32ws"
package main

import (
"fmt"
"sync"
)

func main() {
nums := []int{1, 2, 3, 4}

var wg sync.WaitGroup
result := make([]int, len(nums))

for i, n := range nums {
wg.Go(func() {
result[i] = i * n
})
}

wg.Wait()

fmt.Println(result)
}
```

Теперь каждая горутина пишет в свой индекс.

Без mutex.
Без channel.
Без лишнего копирования переменных.

Хороший тест на то, понимаешь ли ты Go после 1.22, а не просто помнишь старую страшилку про closures.
  • 👍 6
  • 🔥 3
  • ❤ 1
  • 👎 1
Post #924 2.57K
👣 Golang-задача с подвохом

Версия: Go 1.23+

Что выведет код?


package main

import "fmt"

func numbers(yield func(int) bool) {
defer fmt.Println("iterator: defer")

for i := 0; i < 5; i++ {
if !yield(i) {
fmt.Println("iterator: stopped")
return
}

fmt.Println("iterator: after yield", i)
}
}

func main() {
for n := range numbers {
fmt.Println("main:", n)

if n == 2 {
break
}
}

fmt.Println("main: done")
}


Многие ждут, что после break итератор просто мгновенно исчезнет.

Но в Go 1.23 появился range по функции.

Под капотом yield возвращает false, если внешний цикл остановился через break.

Ответ:

```txt id="5glpxa"
main: 0
iterator: after yield 0
main: 1
iterator: after yield 1
main: 2
iterator: stopped
iterator: defer
main: done
```

Подвох в том, что `break` происходит во внешнем цикле, но функция-итератор получает сигнал остановки через `yield`.

Если не проверить `!yield(i)`, можно продолжить работу после того, как потребитель уже вышел из цикла.
  • ❤ 3
  • 👍 2
  • 🔥 1
Post #920 3.24K
  • 👏 2
  • ❤ 1
Post #918 4.42K
Что выведет код?
Post #916 4.11K
  • ❤ 2
  • 👏 1
Post #912 3.19K
  • ❤ 2
Post #910 3.16K
❓ Почему код падает и как это исправить

Функция должна заполнить срез и мапу,
но сейчас она падает с panic.

В чём проблема?


func fillData(s []int, m map[string]int) {
// Добавляем в срез
s = append(s, 10, 20, 30)

// Добавляем в мапу
m["count"] = len(s)
m["total"] = 60

fmt.Println("Срез:", s)
fmt.Println("Мапа:", m)
}

func main() {
fillData(nil, nil)
}


💡 Подсказка: срез и мапа ведут себя по-разному

append к nil срезу работает нормально
запись в nil map → panic

🔥 В чём ошибка

m не инициализирована → это nil map
в неё нельзя записывать значения
  • ❤ 6
  • 👍 5
  • 🔥 5
Post #908 2.92K
Хитрая Go-задача:


package main

import "fmt"

type uint128 struct {
Hi uint64
Lo uint64
}

func f(φ uint128, β int) uint32 {
return uint32(φ.Hi >> (63 - β))
}

func main() {
x := uint128{Hi: 0x8000000000000001}

fmt.Println(f(x, 0))
fmt.Println(f(x, 1))
fmt.Println(f(x, 63))
}


Вопросы:

Что выведет код?
Что будет при β = 64?
Можно ли объявить одновременно beta и β?

Ожидаемый ответ:

1
2
1

Подвох:

сдвиг зависит от β
возможен отрицательный shift
обрезание до uint32
beta и β - разные переменные


• Вам нужно понять, как работает сдвиг вправо
заметить, что в конце результат режется до uint32

• увидеть, что при β = 64 получится отрицательный сдвиг:

63 - 64 = -1
и ещё понять, что beta и β в Go - это разные имена переменных

То есть с виду задача про один shift, а на деле она проверяет сразу несколько знаний.


Запустить код: https://go.dev/play/

Полезные ресурсы Go 🚀Max

@golangtests
  • 👎 15
  • ❤ 3
  • 🔥 2
  • 👍 1
Post #907 3.68K
👣 Задача: что выведет программа?


package main

import "fmt"

func main() {
for i := 0; i < 3; i++ {
defer fmt.Println(i)
}

for i := 0; i < 3; i++ {
defer func() {
fmt.Println(i)
}()
}

for i := 0; i < 3; i++ {
i := i
defer func() {
fmt.Println(i)
}()
}
}


Ответ: https://go.dev/play/p/pntndQy2jzo
  • 👍 11
  • ❤ 4
  • 🔥 3
Post #905 3.25K
🧠 Хитрая Go-задача про интерфейсы и память (x64)

Код:


package main

import (
"fmt"
"unsafe"
)

type Foo struct {
A int64
}

type IFoo interface {
Get() int64
}

func (f Foo) Get() int64 { return f.A }

func main() {
var a int64 = 10
var s Foo = Foo{A: 42}
var i IFoo = s

fmt.Println(unsafe.Sizeof(a))
fmt.Println(unsafe.Sizeof(s))
fmt.Println(unsafe.Sizeof(i))
}


Вопросы
Сколько байт занимает a на x64?
• Сколько байт занимает s?
• Сколько байт занимает i?
• Почему размер i не равен размеру Foo?
• Что реально хранится внутри interface{} в Go?

Разберём по шагам, как это работает в Go на x64.

Код:
```go
var a int64 = 10
var s Foo = Foo{A: 42}
var i IFoo = s
```
1) Размер a
unsafe.Sizeof(a)
```go
int64 = 8 байт
```
На x64:

a = 8 байт
2) Размер s
```go
type Foo struct {
A int64
}```

В структуре одно поле int64.
```go
s = 8 байт
```
3) Размер интерфейса i
```go
var i IFoo = s
unsafe.Sizeof(i)
```go
На x64:
```go
i = 16 байт```


Запустить код: https://go.dev/play/p/NLIG3q-jFc9
  • ❤ 4
  • 👍 4
  • 🔥 3
Post #903 2.62K
  • 👎 14
  • 👍 9
  • 🥰 2
  • 🔥 1
  • 🤔 1
Older posts →

About this channel

How can I read @golangtests without a Telegram account?
TGViewer shows the public web preview Telegram publishes for Go tests: recent posts, photos, videos and the subscriber count, with no app, login or account.
How many subscribers does Go tests have?
Go tests (@golangtests) has 7.84K subscribers on Telegram, refreshed roughly every 30 minutes.
Does Go tests know I viewed it here?
No. Public channel previews carry no viewer identity, and TGViewer has no accounts or tracking of what you look up.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →