11 декабря(уже в четверг!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Go-разработчика.
Как это будет:
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Go-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_go_bot
Реклама.
О рекламодателе.
Please open Telegram to view this post
VIEW IN TELEGRAM
❓ Что выведет программа?
Всё выглядит так:
Мы передаём объект в mutate → внутри меняем → значения должны измениться.
Тут ловушка в том, что:
- интерфейсы в Go копируют значение, если оно не pointer receiver
- type assertion s, ok := i.(S) создаёт новую копию
- мы мутируем копию, а не оригинал
Так что вывод будет:
10
10
А не 100.
👉 Запустить код
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()) // ???
}
Всё выглядит так:
Тут ловушка в том, что:
- интерфейсы в Go копируют значение, если оно не pointer receiver
- type assertion s, ok := i.(S) создаёт новую копию
- мы мутируем копию, а не оригинал
Так что вывод будет:
10
10
А не 100.
👉 Запустить код
👍11🔥3❤2
Чтобы не собирать вручную десятки однотипных команд для облачной CLI, мы в MWS Cloud Platform сделали генератор: он берёт OpenAPI-спеки и сам создаёт готовый инструмент для управления облаком.
В статье кратко:
— почему выбрали Go + Cobra и кодогенерацию;
— как из путей и методов рождаются mws <service> <component> <op>;
— профили, автообновление, удобный вывод;
— что получилось в итоге и зачем это бизнесу.
Читать статью
В статье кратко:
— почему выбрали Go + Cobra и кодогенерацию;
— как из путей и методов рождаются mws <service> <component> <op>;
— профили, автообновление, удобный вывод;
— что получилось в итоге и зачем это бизнесу.
Читать статью
❓ Что выведет программа?
И объясни, почему вывод - НЕ тот, который ожидает большинство 🙂
🔥 Разбор
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 --и два, казалось бы, одинаковых куска кода могут работать по-разному без единой строки изменения.
👉 Запустить код
И объясни, почему вывод - НЕ тот, который ожидает большинство 🙂
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 --и два, казалось бы, одинаковых куска кода могут работать по-разному без единой строки изменения.
👉 Запустить код
❤5👍3😱1
This media is not supported in your browser
VIEW IN TELEGRAM
🚀 Как Go 1.26 ловит утечки горутин
Перед тобой классический пример утечки goroutine, который долгое время было сложно отлавливать автоматически.
Проблема возникает, когда:
- используются небуферизированные каналы
- запускаются goroutine в цикле
- происходит ранний return по ошибке
В такой ситуации часть goroutine продолжает попытки записи в канал, но получателя уже нет — они зависают навсегда.
Раньше такие баги:
- проявлялись только под нагрузкой
- маскировались как рост памяти или странные тайминги
- находились уже в продакшене
В Go 1.26 runtime научился детектить такие утечки автоматически, если включено профилирование.
https://www.youtube.com/shorts/Wvimjygw_ys
Перед тобой классический пример утечки 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 https://localhost:6060/debug/pprof/goroutineleak
https://www.youtube.com/shorts/Wvimjygw_ys
👍10❤3🔥2