Go tests
7.84K subscribers
315 photos
6 videos
113 links
По всем вопросам- @haarrp

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

https://xn--r1a.website/Golang_google - Golang программирование

@golangl - golang chat

@GolangJobsit - golang channel jobs

@golang_jobsgo - go chat jobs
Download Telegram
Что выведет код
Anonymous Quiz
15%
[1, 2, 3]
14%
[3, 2, 1]
55%
[1, 3, 2]
15%
[2, 3, 1]
👍3
👣 Что выведет код (Go 1.25)?


package main

import "fmt"

func main() {
s := []int{1, 2, 3, 4}
t := s[1:3] // t = [2, 3]
t = append(t, 99) // возможно, меняет s[3]
s[2] = 42 // изменяем s напрямую

fmt.Println("s:", s)
fmt.Println("t:", t)
}


Ответ :

s: [1 2 42 99]
t: [2 42 99]


⚡️ Запустить код: https://go.dev/play/p/96RGE1ea6Sq
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥43🤔2
This media is not supported in your browser
VIEW IN TELEGRAM
👣 Вот ещё одна задача на Go, которая проверяет знание интерфейсов, nil и типов - частая ловушка даже для опытных разработчиков


package main

import (
"errors"
"fmt"
)

type myError struct{}

func (m *myError) Error() string {
return "something went wrong"
}

func returnsNilError() error {
var e *myError = nil
return e
}

func main() {
err := returnsNilError()
fmt.Println("err == nil:", err == nil) // неожиданно false
fmt.Println("err:", err)
}


Вывод: err == nil: false
err: something went wrong


⚡️ Заплатить код: https://go.dev/play/p/lrw5DEthEvS

@golangtests
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2🥰1
This media is not supported in your browser
VIEW IN TELEGRAM
🚀 САМЫЙ ЭФФЕКТИВНЫЙ АЛГОРИТМ ПОИСКА В GO

Бинарный поиск - один из самых быстрых способов найти элемент в отсортированном слайсе. Вместо полного прохода он делит диапазон пополам, работая за O(log n). Используй его везде, где данные можно заранее отсортировать - прирост скорости огромный.


package main
import "fmt"

func binSearch(a []int, t int) bool {
l, r := 0, len(a)-1
for l <= r {
m := (l + r) / 2
if a[m] == t { return true }
if a[m] < t { l = m + 1 } else { r = m - 1 }
}
return false
}

func main() {
nums := []int{1,4,7,9,15,20,33,42}
fmt.Println(binSearch(nums, 33))
fmt.Println(binSearch(nums, 100))
}
👍53🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
👣 Как работает планировщик задач в Golang под капотом

Планировщик задач в Golang работает по схеме G-P-M:
горутины (G) распределяются по логическим процессорам (P), а те в свою очередь выполняются на системных потоках (M).
Так достигается мультиплексирование миллионов горутин на ограниченное число потоков ОС.

Когда горутина блокируется (syscall, mutex, канал без данных) - её паркуют, а поток освобождают.
Когда появляется работа — планировщик перебрасывает G между очередями P и старается держать все ядра загруженными.

Чтобы код работал эффективно:
- не плодите лишние горутины
- избегайте долгих блокировок
- контролируйте GOMAXPROCS
- проверяйте количество G через runtime


package main

import (
"fmt"
"runtime"
"time"
)

func main() {
runtime.GOMAXPROCS(runtime.NumCPU())

for i := 0; i < 5; i++ {
go func(id int) {
for {
fmt.Println("goroutine", id, "работает на потоке")
time.Sleep(200 * time.Millisecond)
}
}(i)
}

for {
fmt.Println("горутин сейчас:", runtime.NumGoroutine())
time.Sleep(time.Second)
}
}


https://www.youtube.com/shorts/XQmGO29JE7w

#junior #golang
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥1
👣 Что выйдете код ?



package main

import "fmt"

func main() {
s := []int{1, 2, 3}
t := s // t и s смотрят на один и тот же массив
u := append(s, 4)

s[0] = 99 // меняем через s
t = append(t, 5)

fmt.Println("s:", s)
fmt.Println("t:", t)
fmt.Println("u:", u)
}


Ответ:
s: [99 2 3]
t: [99 2 3 5]
u: [1 2 3 4]


Дополнительные Вопросы : Где именно произойдёт перераспределение массива, какие срезы продолжат делить общую память, а какие уже нет — в этом и фокус задачи


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

@golangtests
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥32👎1
Что выведет программа?


package main

import (
"fmt"
)

type S struct {
v int
}

func (s S) Value() int {
return s.v
}

type I interface {
Value() int
}

func mutate(i I) {
// Мы думаем, что меняем реальный объект...
if s, ok := i.(S); ok {
s.v = 100
}
}

func main() {
s := S{v: 10}
var i I = s

mutate(i)

fmt.Println(s.v) // ???
fmt.Println(i.Value()) // ???
}


Всё выглядит так:

Мы передаём объект в mutate → внутри меняем → значения должны измениться.

Тут ловушка в том, что:

- интерфейсы в Go копируют значение, если оно не pointer receiver

- type assertion s, ok := i.(S) создаёт новую копию

- мы мутируем копию, а не оригинал

Так что вывод будет:

10
10

А не 100.

👉 Запустить код
👍11🔥42
Что выведет программа?

И объясни, почему вывод - НЕ тот, который ожидает большинство 🙂



package main

import "fmt"

func main() {
s := []int{1, 2, 3, 4}
t := s[:2] // [1 2]
u := s[2:] // [3 4]

// Изменяем через t
t = append(t, 9)

// Изменяем через u
u[0] = 99

fmt.Println("s:", s)
fmt.Println("t:", t)
fmt.Println("u:", u)
}


🔥 Разбор

t := s[:2] и u := s[2:] смотрят на один и тот же underlying array

но append(t, 9) может либо
• дописать в тот же массив, либо
• выделить новый, если capacity закончилась

Именно тут начинается путаница:

если capacity исходного s >= 5 — append изменит исходный массив, и s, t, u будут видеть изменения друг друга

если capacity = 4 — append создаст новый backing array, и t “оторвётся” от s и u

То есть вывод зависит от capacity, а её большинство разработчиков не проверяют, но предполагают.

✔️ Добавим интриги — сделай capacity явной 👇
s := make([]int, 4, 4) // capacity = length
copy(s, []int{1,2,3,4})


Теперь:

- append(t, 9) создаёт новый массив

и t уже не связан с s

Вывод будет:

```
s: [1 2 99 4]
t: [1 2 9]
u: [99 4]

```
Но если capacity увеличить:

```go
s := make([]int, 4, 10) // capacity > length
copy(s, []int{1,2,3,4})

```

Мы получим:


```
s: [1 2 9 99]
t: [1 2 9]
u: [99 4]

```

Потому что в этот раз append записал в тот же underlying array.


В Go поведение slice зависит от capacity --и два, казалось бы, одинаковых куска кода могут работать по-разному без единой строки изменения.


👉 Запустить код
6👍3👎3😱1
This media is not supported in your browser
VIEW IN TELEGRAM
🚀 Как Go 1.26 ловит утечки горутин

Перед тобой классический пример утечки goroutine, который долгое время было сложно отлавливать автоматически.

Проблема возникает, когда:
- используются небуферизированные каналы
- запускаются goroutine в цикле
- происходит ранний return по ошибке

В такой ситуации часть goroutine продолжает попытки записи в канал, но получателя уже нет — они зависают навсегда.

Раньше такие баги:
- проявлялись только под нагрузкой
- маскировались как рост памяти или странные тайминги
- находились уже в продакшене

В Go 1.26 runtime научился детектить такие утечки автоматически, если включено профилирование.


func fetchUsers(ids []int) ([]*User, error) {
ch := make(chan *User)

for _, id := range ids {
go func(id int) {
user := fetchUser(id)
ch <- user // блокируется навсегда при раннем return
}(id)
}

for range ids {
user := <-ch
if user == nil {
return nil, errors.New("failed") // LEAK: другие goroutine зависли
}
}
return nil, nil
}

Запуск с детекцией утечек goroutine
GOEXPERIMENT=goroutineleakprofile go run main.go

Проверка профиля
curl http://localhost:6060/debug/pprof/goroutineleak



https://www.youtube.com/shorts/Wvimjygw_ys
👍11🔥43
This media is not supported in your browser
VIEW IN TELEGRAM
🎄 Новогодняя елка на Golang 🎁

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

Отличный пример для тренировки логики и работы с циклами. Подписывайся, больше фишек каждый день !


package main

import "fmt"

func main() {
height := 8
for i := 1; i <= height; i++ {
// пробелы
for s := 0; s < height-i; s++ {
fmt.Print(" ")
}
// ветви
for j := 0; j < 2*i-1; j++ {
fmt.Print("*")
}
fmt.Println()
}
// ствол
for i := 0; i < 2; i++ {
for s := 0; s < height-1; s++ {
fmt.Print(" ")
}
fmt.Println("|")
}
}
6👍6👎2😁2
👣 Что выведет программа построчно?


package main

import "fmt"

func main() {
s := make([]int, 2, 3)
s[0], s[1] = 1, 2

a := s[:2]
b := append(s, 3)

modify(a)
modify(b)

fmt.Println(s)
fmt.Println(a)
fmt.Println(b)
}

func modify(x []int) {
x = append(x, 100)
x[0] = 999
}


- Какие append используют тот же underlying array, а какие нет?

- В какой момент происходит реаллокация памяти?

Подсказка:

s, a и b сначала делят один backing array,

но не все изменения доходят до всех слайсов.


Ответ:
[999 2]
[999 2]
[999 2 100]



📌 Запустить код: https://go.dev/play/p/wVRz6QFmMCv
Please open Telegram to view this post
VIEW IN TELEGRAM
10👍5🔥3
👣 Go 1.26: `bytes.Buffer.Peek()` - заглянуть в буфер без чтения

В Go 1.26 добавили очень удобный метод: Buffer.Peek(n) в пакете bytes.

Что делает:
- возвращает следующие N байт
- не сдвигает указатель чтения
- то есть можно “подсмотреть”, что впереди, и не портить поток

Это идеальная штука для:
- парсеров протоколов
- stream processing
- проверок заголовков/сигнатур
- peek-before-read логики

Важный нюанс:
Peek() возвращает срез, который указывает прямо на внутренний буфер.
То есть:
- он валиден, пока буфер не изменился
- если ты поменяешь срез - поменяешь буфер (осторожно!)

Мини-юзкейс: сначала peek, потом решаешь - читать дальше или нет.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍134🔥3
👣 Понимание выравнивания памяти в Go

В Go важно понимать, как компилятор размещает данные в памяти - это напрямую влияет на скорость работы и объём используемой памяти.

Что такое выравнивание?

Выравнивание памяти - это правило: данные должны находиться по адресам, кратным их размеру. Это нужно, чтобы процессор мог читать и записывать значения за одну операцию.

Например:
- int64 требует выравнивания по 8 байтам
- int32 - по 4 байтам
- byte - по 1 байту

Если значение лежит “неудобно”, CPU делает несколько операций вместо одной - это медленнее.

Почему появляется padding

Компилятор Go автоматически вставляет пустые байты (padding) между полями структуры, чтобы соблюсти правила выравнивания.

Размер структуры - это не просто сумма размеров полей.

Пример:


type Example struct {
a byte // 1 байт
b int64 // 8 байт (нужно выравнивание по 8)
c byte // 1 байт
}



Хотя “полезных” данных тут 10 байт, структура занимает больше из-за вставленного паддинга.

Почему это важно

Если структура используется миллионы раз (в кэше, массивах, базах, сетевых пакетах), лишние байты превращаются в:

• большее потребление памяти
• худшее попадание в CPU cache
• падение производительности

Как оптимизировать

• Порядок полей имеет значение.
• Крупные типы лучше ставить первыми:


type Optimized struct {
b int64
a byte
c byte
}



Так компилятору нужно меньше padding, и структура становится компактнее.

Главное правило

В Go порядок полей в структуре влияет на производительность.

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

Сохрани себе - пригодится при проектировании структур данных.

Больше примеров
Please open Telegram to view this post
VIEW IN TELEGRAM
👍207🔥4
Это один из самых любимых вопросов на Go-собеседованиях.
Проверяют, понимаешь ли ты, как устроены slice, len / cap и что реально делает append.

Что выведет программа?


package main

import "fmt"

func add(s []int) {
s = append(s, 99)
}

func main() {
a := make([]int, 2, 4)
a[0], a[1] = 1, 2

add(a)

fmt.Println("a:", a)
fmt.Println("a[:3]:", a[:3])
}


Разбор

```go
a := make([]int, 2, 4)
len = 2
cap = 4
underlying array = [1, 2, _, _]
```

Слайс - это структура:
```go
pointer -> array
len
cap
```

При передаче в функцию копируется заголовок, но указывает он на тот же массив.

Внутри:
```go
s = append(s, 99)
```

Так как cap=4, места хватает → новый массив НЕ создаётся.
В память записывается:

```go
[1, 2, 99, _]
```

Но:

s внутри функции: len=3

```go
a в main: len=2
```

Вывод
```go
a: [1 2]
a[:3]: [1 2 99]
```

Вопрос 2 (сложнее)
package main



import "fmt"

func add(s []int) {
s = append(s, 99)
s[0] = 42
}

func main() {
a := []int{1, 2}
add(a)

fmt.Println("a:", a)
}


Разбор
```go
a := []int{1,2}
len=2
cap=2
```

Теперь в append места нет → создаётся новый массив.

Внутри add:
```go
new array = [1 2 99]
s -> указывает на новый массив
```

Но a всё ещё указывает на старый:

```go
old array = [1 2]
```

Строка:

```go
s[0] = 42
```

Меняет новый массив, не старый.

Вывод
```go
a: [1 2]
```

Главная идея

Поведение append зависит от capacity.

Условие Что происходит
cap хватает меняется тот же массив
cap не хватает создаётся новый

Slice передаётся по значению, но содержит указатель на массив.
append может незаметно "оторвать" его от исходных данных.

Как писать безопасно
```go
func add(s []int) []int {
s = append(s, 99)
return s
}

a = add(a)
```

Что этим проверяют на собесе

• slice ≠ массив
• len vs cap
• устройство slice header
• поведение append
• aliasing памяти

Если это не понимать, будут странные баги в продакшене.


Запустить код: https://go.dev/play/p/V9KyryLj3TV
👍146🔥5👎1
В Go nil - это не просто «пусто».
Иногда это причина самых странных багов в продакшене.

nil в Go - это не одно значение, а множество разных nil.


1. Interface и nil — ловушка


var err error = nil
fmt.Println(err == nil) // true

var e *MyError = nil
var err error = e
fmt.Println(err == nil) // false (!)


Почему так?

Интерфейс в Go хранит:

• тип
• значение

В этом случае:

• тип = *MyError

• значение = nil

Интерфейс не nil, потому что тип задан.

Именно так появляются ошибки вида:

if err != nil срабатывает

но внутри на самом деле nil


2. Typed nil vs untyped nil
var p *int = nil
var s []int = nil
var m map[string]int = nil


Все они nil, но разных типов.
И Go сравнивает не только значение, но и тип.


3. Panic из-за nil внутри interface
type User struct{}

func (u *User) Name() string {
return "John"
}

var u *User = nil
var i interface{} = u

i.(*User).Name() // panic


Интерфейс не nil → метод вызывается → внутри nil → panic.

4. Частый баг с error

Плохой код:

func do() error {
var e *MyError = nil
return e
}


Правильно:

func do() error {
if somethingWrong {
return &MyError{}
}
return nil
}

Главное правило

Если работаешь с interface:
• всегда проверяй, что возвращаешь чистый nil

помни:

interface != nil, если внутри typed nil


https://sushantdhiman.dev/nil-in-go-is-not-what-you-think/
6👍4🔥4
🔥 PrimeView - реальная производительность языков без маркетинга

https://plummerssoftwarellc.github.io/PrimeView/report

PrimeView - это живой бенчмарк, который сравнивает языки программирования на одной задаче: генерация простых чисел.

Без синтетических тестов.
Без “идеальных условий”.
Только:

* один алгоритм
* одинаковые правила
* реальные оптимизации от разработчиков

Что показывают результаты:

* C и C++ стабильно в лидерах
* Rust и Zig уверенно конкурируют с нативным кодом
* Go показывает сильные результаты при грамотной оптимизации
* разница между реализациями внутри одного языка часто больше, чем между языками

Ключевой инсайт:

Производительность определяет не язык.
Производительность определяет инженер.

SIMD, работа с памятью, кэш-локальность и битовые оптимизации дают больший эффект, чем выбор технологии.

plummerssoftwarellc.github.io/PrimeView/report
👍3🔥3🥰1
👣 На Stepik вышел новый курс: Go - с нуля до рабочего backend-проекта

Ты знаешь синтаксис Go.
Но готов написать сервис с нуля и запустить его в продакшене?

Большинство курсов учат командам.
Этот курс учит думать как Go-разработчик.

Внутри:

- путь от основ до полноценного сервиса
- архитектура, API, база данных, структура проекта
- конкурентность и работа с нагрузкой
- только реальные практики без воды
- финальный проект, который можно добавить в портфолио

Это не теория ради галочки.
Это навыки, которые нужны на работе.

🎯 Результат - вы умеете писать и запускать Go-сервисы, а не просто знаете синтаксис.

Скидка 50%

Начать учиться: https://stepik.org/a/274119/
Please open Telegram to view this post
VIEW IN TELEGRAM
3🔥3👍2🤬2🥰1
Какой размер у переменной, типом которой является интерфейс на x64 архитектуре
Anonymous Quiz
9%
4 байта
39%
8 байт
27%
16 байт
24%
Зависит от интерфейса
👎12👍8🥰2🔥1
🔍Тестовое собеседование с Go ТехЛидом из WildBerries в этот четверг

26 февраля(в четверг!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Go-разработчика.

Как это будет:
📂 Рамиль Мясоутов, ТехЛид из WildBerries, ex-Купер будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Рамиль будет комментировать каждый ответ респондента, чтобы дать понять, чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Рамилю

Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Go-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.

Переходи в нашего бота, чтобы получить ссылку на эфир →
@shortcut_go_bot

Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
🧠 Хитрая 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
👍3🔥21