es
Feedback
Библиотека Go для собеса | вопросы с собеседований

Библиотека Go для собеса | вопросы с собеседований

Ir al canal en Telegram

Вопросы с собеседований по Go и ответы на них. Покажем, как запустить своего ии-агента: https://clc.to/tvpmD По рекламе: @proglib_adv Для обратной связи: @proglibrary_feeedback_bot Наши каналы: https://t.me/proglibrary/9197

Mostrar más
7 429
Suscriptores
-324 horas
-167 días
+930 días
Archivo de publicaciones
Можно ли переиспользовать WaitGroup sync.WaitGroup можно переиспользовать, но только корректно завершив предыдущий цикл ожидания. Переиспользовать один и тот же экземпляр можно для партий выполняемых задач: дождались первую партию: counter вернулся к 0, Wait() вышел; и после этого можно снова делать Add и запускать новый набор горутин. 🐸 Библиотека Go для собеса

Что будет если вызвать WaitGroup.Add() с отрицательным числом Поведение зависит от того, как это влияет на внутренний счётчик. WaitGroup.Add() принимает любое целое число, включая отрицательные. Это можно использовать для уменьшения счётчика:
var wg sync.WaitGroup
wg.Add(5)  // счётчик = 5
wg.Add(-2) // счётчик = 3
Если Add() делает внутренний счётчик отрицательным, то возникнет паника: 🐸 Библиотека Go для собеса

Почему в Go 1.18 добавили алиас any, а не убрали interface{} Чтобы сохранить полную обратную совместимость, а не ломать миллионы строк существующего кода. С точки зрения компилятора и поведения программы any и interface{} абсолютно эквивалентны. 🐸 Библиотека Go для собеса

Что возвращает range для строки В цикле for index, value := range str строка str итерируется по UTF-8 рунам. index – байтовый индекс начала руны, value – значение руны. 🐸 Библиотека Go для собеса

Многопоточность в Golang с нуля. Бесплатный вебинар — 19 февраля в OTUS Многопоточность — одна из причин популярности Go в се
Многопоточность в Golang с нуля. Бесплатный вебинар — 19 февраля в OTUS Многопоточность — одна из причин популярности Go в серверной и системной разработке. Горутины и каналы позволяют писать производительный и масштабируемый код без сложных абстракций. — На открытом уроке разберём базовые принципы параллелизма и конкурентности в Go. — Поговорим о том, как работают горутины, зачем нужны каналы и в каких сценариях Go особенно эффективен. — На практических примерах покажем типовые задачи, где многопоточность даёт реальный прирост производительности, и обсудим базовые best practices.
Урок подойдёт новичкам, которые только начинают знакомство с Go, а также разработчикам с опытом в других языках, желающим понять философию конкурентности в Go.
👉 Записаться: https://clc.to/DXsJng Этот вебинар проходит в формате открытого урока в прямом эфире курса «Golang Developer. Basic». Реклама. ООО «Отус онлайн‑образование», ОГРН 1177746618576

Как Go обрабатывает операции ввода-вывода с файлами Go предоставляет встроенные инструменты для работы с файловой системой: пакет os для базовых операций открытия, создания и закрытия файлов, а также io и bufio для буферизованного ввода-вывода. Чтение файла Типичный паттерн: открыть файл через os.Open(), затем прочитать содержимое построчно с помощью bufio.Scanner:
package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
)

func main() {
    file, err := os.Open("example.txt")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        fmt.Println(scanner.Text())
    }
    
    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }
}
Запись и дозапись в файл Для создания нового файла используйте os.Create(), для дозаписи — os.OpenFile() с флагами os.O_APPEND|os.O_WRONLY:
// Создание и запись
file, err := os.Create("output.txt")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

file.WriteString("Hello, Go!\n")

// Дозапись в существующий файл
file, err := os.OpenFile("output.txt", 
    os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
    log.Fatal(err)
}
defer file.Close()

file.WriteString("Appended line\n")
Используйте bufio.Writer для буферизации при записи больших объёмов данных — это значительно ускорит операции ввода-вывода. 🐸 Библиотека Go для собеса

Интервью как ресурс: почему нельзя «сливать» попытки 💎 В текущем сезоне воронка найма сузилась 📉: получить приглашение на т
Интервью как ресурс: почему нельзя «сливать» попытки 💎 В текущем сезоне воронка найма сузилась 📉: получить приглашение на техническое собеседование стало сложнее, чем пройти его. В таких условиях каждый слот в календаре превращается в актив с высокой стоимостью, а импровизация при проверке hard-skills становится неоправданным риском. Качественная подготовка требует выхода за рамки базового синтаксиса Go. Необходимо охватить весь технологический стек, включая базы данных и архитектурные паттерны. Систематизировать знания поможет подборка из 55 реальных вопросов, которые сейчас задают на собеседованиях. Регулярный самоаудит по этому списку повышает шансы на успешный оффер 🧠.

❓ Можно ли вызвать анонимную функцию сразу при объявлении Да, добавьте () с аргументами в конце для немедленного вызова. Компилятор Go это поддерживает нативно.
result := func(a, b int) int { return a + b }(3, 5)
fmt.Println(result)  // 8
Функция создаётся и исполняется сразу. 🐸 Библиотека Go для собеса

Что Go-компилятор может сделать с кодом во время компиляции Если выражение состоит из констант, компилятор считает результат сразу. const x = 5 * 10 + 3 становится 53. Работает для арифметики, строк, булевых операций Функции до 80 байт встраиваются в место вызова. Компилятор подставляет тело, убирает call/ret overhead. Если код не используется вовсе, то компилятор его удалит. 🐸 Библиотека Go для собеса

Почему defer работает по LIFO Каждый defer добавляет вызов в стек текущей горутины. При возврате из функции runtime.deferreturn разматывает стек снизу вверх, LIFO-порядок. 🐸Библиотека Go для собеса

К каким типам циклов применяется анализатор forvar — ко всем for или только к range Согласно документации, анализатор forvar применяется только к range циклам. Причина в том, что проблема с переиспользованием переменной цикла существовала именно в контексте range:
// До Go 1.22 - проблемный код
for _, x := range items {
    go func() {
        fmt.Println(x) // все горутины видели последнее значение x
    }()
}

// Решение до Go 1.22
for _, x := range items {
    x := x // создание новой переменной для каждой итерации
    go func() {
        fmt.Println(x) // теперь каждая горутина видит свое значение
    }()
}
В обычных for циклах такой проблемы не было, так как переменная счетчика и так создавалась заново:
// Здесь проблемы не было даже до Go 1.22
for i := 0; i < 10; i++ {
    go func() {
        fmt.Println(i) // каждая итерация имела свой i
    }()
}
🐸Библиотека Go для собеса

Можно ли получить указатель на value в мапе В Go невозможно взять указатель на значение, хранящееся в мапе. Мапа в Go реализована как хеш-таблица, которая может динамически реорганизовываться при добавлении элементов. Когда мапа растёт, значения перемещаются в памяти, что делало бы любые указатели на них недействительными. Код, который выдаст ошибку
m := map[string]int{"a": 1}
p := &m["a"]  // cannot take the address of m["a"]
Что делать вместо этого Хранить указатели в мапе:
m := map[string]*int{}
val := 1
m["a"] = &val
Извлечь значение, изменить, записать обратно:
m := map[string]int{"a": 1}
val := m["a"]
val++
m["a"] = val
Использовать структуры:
type Data struct { value int }
m := map[string]*Data{"a": {1}}
m["a"].value++  //  работает
🐸Библиотека Go для собеса

В чём разница между nil-слайсом и пустым слайсом nil-слайс и пустой слайс имеют схожий внешний вид и поведение в большинстве операций, но отличаются по внутренней структуре. nil-слайс не инициализирован и не имеет базового массива, в то время как пустой слайс инициализирован, но без элементов. Обе формы безопасны: len, cap дают 0, append работает одинаково, цикл range не выполнится. Разница видна при JSON-маршалинге: nil-слайс → null, пустой → []. 🐸 Библиотека Go для собеса

Каким должен быть ключ в мапе Ключ должен быть comparable типом — то есть поддерживать операции == и !=.
var m map[string]int        //  работает
var m map[int]string        //  работает
var m map[[]byte]int        //  ошибка компиляции: slice не comparable
var m map[map[string]int]int //  ошибка: map не comparable
Что можно использовать как ключ: • bool • int, int8, int16, int32, int64 • uint, uint8, uint16, uint32, uint64, uintptr • float32, float64 • complex64, complex128 • string • pointer (*T) • channel (chan T) • interface — если динамический тип comparable • struct — если все поля comparable • array [N]T, если T comparable 🐸 Библиотека Go для собеса

Что возвращает функция recover() Функция recover() в Go возвращает значение, переданное в panic(), если она вызвана во время активной паники в текущей горутине и находится внутри отложенной функции. Пример использования:
func main() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Паника перехвачена:", r) // Вывод: Паника перехвачена: ошибка!
        }
    }()
    panic("ошибка!")
    fmt.Println("Этот код не выполнится") // Пропускается
}
🐸 Библиотека Go для собеса

Бот-сторож на Golang. Асинхронная верификация без паролей Конкурентность в Go лучше всего понимается на практических задачах.
Бот-сторож на Golang. Асинхронная верификация без паролей Конкурентность в Go лучше всего понимается на практических задачах. В этом открытом уроке мы разберём реальный сценарий — систему входа без паролей с использованием горутин и каналов. 📅 На вебинаре 11 февраля создадим Telegram-бота для проверки пользователей, разберём архитектуру асинхронной верификации, научим бота взаимодействовать с веб-приложением через WebSocket и реализуем потокобезопасное хранилище сессий. По ходу занятия обсудим, как избегать гонок данных и проектировать конкурентные сервисы.
Урок будет полезен Go-разработчикам, которые уже пишут код и хотят разобраться в конкурентности на практике, а также тем, кто разрабатывает веб-сервисы с нестандартной логикой авторизации.
👉 Записаться: https://clc.to/0ZEDNA Этот вебинар проходит в формате бесплатного открытого урока курса «Golang Developer. Basic» от OTUS. Реклама. ООО «Отус онлайн‑образование», ОГРН 1177746618576

Как выйти из горутины Горутина завершается автоматически, когда функция, которую она выполняет, завершает свою работу. Но есть несколько паттернов для контролируемого завершения. • Через done-канал
done := make(chan struct{})

go func() {
    for {
        select {
        case <-done:
            return // выходим из горутины
        default:
            // делаем работу
        }
    }
}()

// когда нужно остановить
close(done)
• Через context
ctx, cancel := context.WithCancel(context.Background())

go func() {
    for {
        select {
        case <-ctx.Done():
            return
        default:
            // делаем работу
        }
    }
}()

// когда нужно остановить
cancel()
Нельзя «убить» горутину извне силой и нет аналога thread.kill() из других языков. 🐸 Библиотека Go для собеса

Можно ли вызвать вложенную функцию рекурсивно Да, можно вызвать вложенную функцию рекурсивно, но для этого требуется специальный синтаксис: объявить переменную с типом функции до её определения. Пример:
package main

import "fmt"

func main() {
    var fib func(n int) int  // Объявляем переменную с типом функции
    fib = func(n int) int {  // Теперь можем ссылаться на fib внутри
        if n < 2 {
            return n
        }
        return fib(n-1) + fib(n-2)  // Рекурсивный вызов
    }
    fmt.Println(fib(7))  // Вывод: 13
}
Вложенные функции подходят для задач вроде обхода деревьев или чисел Фибоначчи. 🐸 Библиотека Go для собеса

Для чего используется wg.Done() wg.Done() используется для сигнализации завершения задачи в sync.WaitGroup. Это метод уменьшает внутренний счетчик WaitGroup на 1. Пример:
func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()  // Гарантированный вызов wg.Done()
    time.Sleep(time.Duration(id) * time.Second)
    fmt.Printf("Worker %d завершен\n", id)
}
🐸 Библиотека Go для собеса

Какие есть гарантии того, что defer выполнится Defer гарантированно выполнится при нормальном выходе из функции — это его основное предназначение. Но важно понимать нюансы: • При обычном return из функции — defer отработает до возврата управления • При панике — defer выполнится перед раскруткой стека • При достижении конца функции — все отложенные вызовы выполнятся в обратном порядке Когда defer НЕ выполнится: • os.Exit() — немедленно завершает программу, defer'ы игнорируются • Фатальные ошибки рантаймаSIGKILL, принудительное завершение • Бесконечные циклы — если функция никогда не завершится, defer не выполнится 🐸 Библиотека Go для собеса