Библиотека Go для собеса | вопросы с собеседований
6.88K subscribers
225 photos
7 videos
1 file
435 links
Вопросы с собеседований по Go и ответы на них.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/0b524a15

Для обратной связи: @proglibrary_feeedback_bot

Наши каналы: https://t.iss.one/proglibrary/9197
Download Telegram
💬 Почему Go-процесс может использовать много виртуальной памяти?

Аллокатор памяти в Go резервирует большую область виртуальной памяти как арену для выделения. Эта виртуальная память локальна для конкретного процесса Go; резервирование не лишает другие процессы памяти.

Чтобы узнать количество фактически выделенной памяти процессу Go, можно использовать команду top в Unix (столбцы RES (Linux) или RSIZE (macOS)).
1
⚡️Самые полезные каналы по Go в одной папке

В ней:
интересные задачи
основной канал
книги по Go
лучшие вакансии из сферы
и наш чат, в котором можно общаться и задавать вопросы

Добавляйте 👉 тык сюда
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥42👍2
💬 Можно ли преобразовать []T в []interface{}?

Не напрямую. Спецификация Go запрещает это, поскольку эти два типа имеют разное представление в памяти. Необходимо копировать элементы по отдельности в целевой срез.

В примере срез типа int преобразуется в срез типа interface{}:

t := []int{1, 2, 3, 4}
s := make([]interface{}, len(t))
for i, v := range t {
s[i] = v
}
👍10
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.

Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.

Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
1
💬 Как в Go осуществляется доступ к полям структуры?

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

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

📌 Простой пример:

package main

import "fmt"

// Определяем структуру Person
type Person struct {
Name string // Экспортируемое поле
age int // Неэкспортируемое поле
}

func main() {
// Создаем экземпляр структуры Person
p := Person{Name: "Alice", age: 30}

// Доступ к экспортируемому полю Name
fmt.Println("Name:", p.Name)

// Доступ к неэкспортируемому полю age (возможен, т. к. мы находимся в том же пакете)
fmt.Println("Age:", p.age)
}


Доступ к полям структуры осуществляется через экземпляр p структуры Person с использованием точки (p.Name и p.age).
🥱22👍82
💬 Для чего используется дочерний контекст в Go, и как он связан с родительским контекстом? Приведите пример сценария, где это может быть полезно.

Дочерний контекст в Go используется для управления и контроля над отдельными операциями или задачами, которые являются частью большей работы, представленной родительским контекстом.

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

Дочерний контекст создается из существующего родительского контекста с помощью таких функций, как context.WithCancel, context.WithDeadline, context.WithTimeout и context.WithValue.

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

parentCtx, cancel := context.WithCancel(context.Background())
defer cancel()

childCtx, childCancel := context.WithTimeout(parentCtx, 10*time.Second)
defer childCancel()

// Здесь childCtx будет отменен либо по истечению 10 секунд, либо когда будет отменен parentCtx


📌 Простой пример: в веб-сервере, обрабатывающем HTTP-запросы, для каждого запроса создается дочерний контекст от основного контекста сервера. Если сервер должен быть остановлен, отмена основного контекста приведет к отмене всех обрабатываемых запросов, что позволяет корректно и быстро завершить работу сервера.
13👍7🥱2
💬 Для чего предназначен буфер в каналах Go?

Буфер в каналах используется для управления потоком данных между горутинами и предоставляет несколько ключевых преимуществ:

✔️ Асинхронная передача данных: буферизированный канал позволяет отправителю передавать данные без немедленного ожидания получателя. Это означает, что горутина-отправитель может продолжать свою работу после помещения данных в буфер канала, не блокируясь до тех пор, пока буфер не заполнится полностью.

✔️ Уменьшение блокировок: в небуферизированных каналах отправитель и получатель должны быть готовы к обмену данными одновременно, что может привести к блокировкам. Буферизированные каналы снижают вероятность таких блокировок, поскольку они позволяют временно хранить данные до их обработки.

✔️ Контроль потока: буферизированные каналы могут использоваться для контроля потока данных в приложении. Размер буфера определяет, сколько данных может быть отправлено без блокировки, что позволяет более тонко настраивать производительность и ресурсоемкость приложения.

✔️ Упрощение некоторых паттернов конкурентности: в некоторых случаях использование буферизированных каналов может упростить реализацию определенных паттернов конкурентности, таких как worker pools или регулирование нагрузки между горутинами.
👍7
🏃 Самоучитель по Go для начинающих. Часть 6. Функции и аргументы. Области видимости. Рекурсия. Defer

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

👉 Читать статью
👉 Часть 1
👉 Часть 2
👉 Часть 3
👉 Часть 4
👉 Часть 5
👍4
💬 Что из себя представляет тип Stringer в Go?

Stringer — это интерфейс, определённый в стандартной библиотеке fmt. Он содержит один метод String() string.

Когда тип реализует этот интерфейс, он может контролировать своё строковое представление. Это особенно полезно, когда необходимо вывести структурированные данные или для логирования.

Простой пример:

type Person struct {
Name string
Age int
}

func (p Person) String() string {
return fmt.Sprintf("%s is %d years old", p.Name, p.Age)
}


Тип Person реализует Stringer, так что каждый раз, когда экземпляр Person выводится с использованием функций из пакета fmt, будет использовано кастомное строковое представление, определённое в методе String().
👍9🥱5
💬 Какие существуют распространенные паттерны конкурентности в Go?

Паттерны конкурентности в Go обычно строятся вокруг горутин и каналов.

Вот несколько основных паттернов конкурентности, которые широко используются в Go:

🔸 Worker pools: подразумевает создание нескольких горутин (воркеров) для выполнения задач из очереди.

🔸 Fan-in (собирает данные из множества источников) и Fan-out (распределяет задачи между несколькими обработчиками).

🔸 Pipeline: организация горутин в серию обработчиков, где каждая горутина выполняет определенную подзадачу. Каждая стадия пайплайна читает из одного канала и пишет в другой, формируя цепочку обработки данных.

🔸 Publish/Subscribe: создание механизма, в котором одни горутины (издатели) публикуют сообщения в канал, а другие горутины (подписчики) читают эти сообщения.

🔸 Context passing: использование пакета context для управления жизненным циклом и отмены горутин. Это особенно полезно в сетевых приложениях и при выполнении запросов к базам данных.

🔸 Errgroup: использование пакета errgroup для параллельного выполнения задач с возможностью обработки ошибок и отмены всех задач при возникновении первой ошибки.

🔸 Select statement: использование оператора select для ожидания нескольких операций с каналами. select позволяет горутине ожидать несколько коммуникационных операций, блокируясь до готовности одной из них.

👉 Подробнее: доклад Go Concurrency Patterns Роба Пайка (слайды) и Advanced Go Concurrency Patterns (слайды) Sameer Ajmani
👍181
💬 Поддерживает ли Go операции инкремента и декремента?

В Go поддерживаются операции инкремента (++) и декремента (--), но есть некоторые особенности:

🔸 В Go операции инкремента и декремента могут использоваться только как самостоятельные операторы. Это означает, что они не могут быть частью более сложных выражений. Например, нельзя использовать: a = b++ или c = ++d.

🔸 Постфиксная форма: в Go поддерживается только постфиксная форма этих операторов (то есть i++ и i--).
👍10🥱4🤔1
💬 Для каких целей в Go может использоваться пустая структура?

☑️ Пустая структура (struct{}{}) не занимает места в памяти. Это делает её идеальной для создания коллекций, где важны только ключи, а значения не нужны.

// Использование для уникального набора значений (set)
uniqueSet := make(map[string]struct{})
uniqueSet["value1"] = struct{}{}
// Проверка наличия значения
_, exists := uniqueSet["value1"]


☑️ Пустые структуры часто используются в каналах для передачи сигналов. Это полезно для синхронизации горутин или передачи сигналов без передачи данных.

done := make(chan struct{})
go func() {
// ...
done <- struct{}{} // Отправка сигнала о завершении
}()
<-done // Ожидание сигнала


☑️ Иногда пустые структуры используются как маркеры в сложных структурах данных или для реализации определённых паттернов проектирования, таких как Singleton или Null Object.

type Singleton struct{}

func (s Singleton) DoSomething() {
// Реализация метода
}

var instance Singleton
instance.DoSomething()
👍231
💬 Почему для использования горутин в Go не требуется помечать родительскую функцию как async, в отличие от некоторых других C-подобный ЯП?

Горутины в Go используются для реализации конкурентности, и их работа базируется на модели «‎общих каналов» вместо «‎общих данных». Это ключевое отличие от моделей асинхронного программирования, используемых в других языках, похожих на C.

В Go, при вызове функции с ключевым словом go, рантайм автоматически запускает эту функцию в новой горутине, позволяя ей выполняться конкурентно относительно вызывающего кода.

Это отличается от модели, используемой в языках, где async/await используется для явного указания асинхронного выполнения. В Go, всё управление горутинами и их взаимодействие скрыто от разработчика и обрабатывается рантаймом, что упрощает работу с конкурентным кодом.
👍21
💬 Какие изменения коснулись цикла for в Go 1.22?

1. Изменение в поведении переменных цикла: в Go 1.21 и ранее, переменные, объявленные в цикле for, создавались один раз и обновлялись при каждой итерации. Это могло привести к ошибкам, когда одна и та же переменная использовалась в замыканиях. Например:

var funcs []func()
for i := 0; i < 3; i++ {
funcs = append(funcs, func() { fmt.Println(i) })
}
for _, f := range funcs {
f() // Выводит "3" три раза, так как все функции ссылаются на одну и ту же переменную i.
}


В Go 1.22, каждая итерация цикла создает новые переменные:

var funcs []func()
for i := 0; i < 3; i++ {
funcs = append(funcs, func(i int) func() {
return func() { fmt.Println(i) }
}(i))
}
for _, f := range funcs {
f() // Выводит "0", "1", "2", так как каждая функция ссылается на свою копию переменной i.
}


2. Циклы for теперь могут итерировать по целым числам: в Go 1.22 добавлена возможность использовать циклы for для итерации по диапазону целых чисел. Например:

package main

import "fmt"

func main() {
for i := range 10 {
fmt.Println(10 - i) // Выводит числа от 10 до 1.
}
}


В этом примере цикл for используется для итерации по целым числам от 0 до 9, и на каждой итерации выводится число, равное 10 минус текущее значение итератора.
👍32
💬 В чем разница между массивами C и срезами Go?

📌 Массивы в C:

1. Статический размер: в C размер массива должен быть известен во время компиляции и не может изменяться во время выполнения. Это означает, что массивы в C являются статическими.

2. Прямой доступ к памяти: массивы в C представляют собой непрерывный блок памяти. Элементы массива хранятся в памяти последовательно, и доступ к ним осуществляется напрямую через указатели и арифметику указателей.

3. Размер и тип: в C размер массива является частью его типа, что означает, что массивы разного размера представляют разные типы данных.

📌 Срезы в Go:

1. Динамический размер: срезы в Go представляют собой динамические, гибкие представления массивов. Срезы могут изменять свой размер во время выполнения, что делает их более гибкими по сравнению с массивами в C.

2. Абстракция над массивами: срез в Go представляет собой структуру, содержащую три компонента: указатель на массив, длину и емкость. Это позволяет срезам предоставлять дополнительную безопасность и удобство по сравнению с прямым использованием массивов.

3. Управление памятью: в Go управление памятью для срезов осуществляется автоматически с помощью сборщика мусора. Это уменьшает риск ошибок, связанных с утечками памяти и неправильным управлением ресурсами.

4. Встроенные функции: в Go существуют встроенные функции для работы со срезами.

📌 Основное отличие между массивами в C и срезами в Go заключается в их гибкости и управлении памятью. Массивы в C статичны и требуют более тщательного управления памятью, в то время как срезы в Go предлагают динамическую структуру с автоматическим управлением памятью и дополнительными удобными функциями для работы с данными.
🥱11👍7
💬 Каким образом расширяется стек горутины в Go?

В Go стек горутины расширяется динамически, используя метод копирования стека. Изначально каждой горутине выделяется небольшой стек, обычно в размере нескольких килобайт. Когда горутина выполняет операции, которые требуют больше памяти стека, чем доступно, Go автоматически расширяет стек вдвое.

Процесс расширения стека начинается с обнаружения, что текущий стек горутины полностью заполнен. В этот момент Go выделяет новый стек, размер которого обычно в два раза больше предыдущего. Затем содержимое старого стека копируется в новый, увеличенный стек.

Важным моментом является обновление всех указателей в стеке. Так как адреса в памяти меняются, Go обновляет все указатели, чтобы они ссылались на новое местоположение в расширенном стеке. После копирования старый стек освобождается.

👉 Подробнее
👍16
💬 Какие проблемы синхронизации могут возникнуть в программе на Go?

• Data race: две или более горутины одновременно обращаются к одной ячейке памяти без какой-либо синхронизации и как минимум одна из них осуществляет запись.

• Deadlock: две или более горутин ожидают друг друга, освобождая ресурсы, и таким образом ни одна из них не может продолжить выполнение.

• Starvation: одна или несколько горутин никогда не получают доступ к ресурсу или к выполнению, потому что другие горутины постоянно захватывают доступ.

• Livelock: горутины активно выполняют операции, но эти операции не приближают их к завершению задачи. Часто это связано с попытками избежать deadlock, которые приводят к бесконечному циклу.
🔥111
💬 Какие изменения коснулись паттернов HTTP-роутинга в стандартной библиотеке Go 1.22?

☑️ Теперь можно регистрировать обработчики для конкретных HTTP-методов, что ограничивает вызовы обработчика только запросами с указанным методом. Паттерны с методами имеют приоритет над соответствующими без метода.

☑️ Паттерны с подстановочными знаками, например /items/{id}, поддерживают сегменты URL-пути. Значение сегмента доступно через метод Request.PathValue. Паттерны, оканчивающиеся на ..., соответствуют всем оставшимся сегментам.

☑️ Паттерны, оканчивающиеся на /, соответствуют всем путям с этим префиксом, а для точного соответствия, включая конечный слэш, используется {$}.

☑️ Если паттерны пересекаются, более конкретный имеет приоритет. Нарушения обратной совместимости контролируются полем GODEBUG httpmuxgo121.

👉 Подробнее
👍10
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.

Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.

Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
💬 Что из себя представляет Compare and swap в Go?

Compare-and-swap (CAS) в Go — это атомарная операция, которая используется для достижения синхронизации. Она проверяет значение некоторой переменной и, если оно соответствует ожидаемому, заменяет его на новое значение. Важной особенностью CAS является то, что весь процесс выполнения — сравнение и замена — атомарен, то есть не может быть прерван или нарушен другими потоками или горутинами.

В Go для работы с атомарными операциями, включая CAS, используется пакет sync/atomic. Примером CAS операции в Go является функция atomic.CompareAndSwapInt32 или atomic.CompareAndSwapInt64.

Эти функции принимают три аргумента: указатель на переменную, старое значение и новое значение. Функция сначала сравнивает текущее значение переменной со старым значением, и если они совпадают, заменяет его на новое значение. Возвращаемое значение — булево, указывающее, была ли произведена замена.

📌 Пример использования atomic.CompareAndSwapInt32:

var value int32 = 100
newValue := int32(200)
oldValue := int32(100)

swapped := atomic.CompareAndSwapInt32(&value, oldValue, newValue)
if swapped {
fmt.Println("Значение было заменено")
} else {
fmt.Println("Значение не было заменено")
}


В этом примере, если начальное значение переменной value равно oldValue (100), то оно будет атомарно заменено на newValue (200).
👍7