Golang вопросы собеседований
13.5K subscribers
625 photos
3 videos
1 file
432 links
@notxxx1 - админ

@Golang_google - Golang для разработчиков

@itchannels_telegram - 🔥лучшие из ит

@golangl - chat

@golangtests - golang tests

@golang_jobsgo - go chat jobs

@ai_machinelearning_big_data - AI

@data_analysis_ml

РКН: clck.ru/3FmtKd
加入频道
👣 Fixing For Loops in Go 1.22

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

https://go.dev/blog/loopvar-preview

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Каков порядок перебора map?

Порядок перебора элементов в map в Go является неопределенным и не гарантированным. Это связано с тем, что map внутренне реализован как хэш-таблица, и порядок элементов может меняться при каждой итерации по map.

Если вам требуется определенный порядок элементов, вам необходимо явно сортировать ключи или значения перед их использованием. Например, вы можете сначала извлечь ключи из map в срез (slice), отсортировать этот срез и затем итерироваться по отсортированным ключам для доступа к значениям.

Пример сортировки ключей map перед итерацией:

m := map[string]int{
"banana": 2,
"apple": 1,
"cherry": 3,
}

keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}

sort.Strings(keys)

for _, k := range keys {
fmt.Println(k, m[k])
}

В этом примере мы создаем map с неупорядоченными ключами и значениями. Затем мы извлекаем ключи из map в срез keys, сортируем этот срез с помощью sort.Strings, а затем итерируемся по отсортированным ключам, чтобы получить доступ к соответствующим значениям.

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

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Где следует поместить описание интерфейса: в пакете с реализацией или в пакете, где этот интерфейс используется? Почему?

Описание интерфейса следует помещать в пакете, где этот интерфейс используется, а не в пакете с реализацией. Это согласуется с принципом разделения интерфейса и реализации (Interface Segregation Principle) из принципов SOLID.

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

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

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

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Как вы отсортируете массив структур по алфавиту по полю Name?

Для сортировки массива структур по алфавиту по полю Name в Go, вы можете использовать интерфейс sort.Interface и функцию sort.Sort() из пакета sort.

Вот пример кода, который демонстрирует, как отсортировать массив структур по полю Name:

package main

import (
"fmt"
"sort"
)

type Person struct {
Name string
Age int
}

type ByName []Person

func (a ByName) Len() int { return len(a) }
func (a ByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a ByName) Less(i, j int) bool { return a[i].Name < a[j].Name }

func main() {
people := []Person{
{Name: "Alice", Age: 25},
{Name: "Charlie", Age: 30},
{Name: "Bob", Age: 20},
}

sort.Sort(ByName(people))

for _, person := range people {
fmt.Println(person.Name, person.Age)
}
}
В этом примере мы определяем тип Person для представления структуры человека с полями Name и Age. Затем мы определяем тип ByName, который является срезом структур Person. Мы также реализуем методы Len(), Swap(), и Less() для типа ByName, чтобы он соответствовал интерфейсу sort.Interface.

Затем мы создаем срез структур Person и заполняем его некоторыми значениями. Далее мы вызываем sort.Sort(ByName(people)), чтобы отсортировать срез структур по полю Name. Наконец, мы проходимся по отсортированному срезу и выводим отсортированные значения.

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

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Можно ли использовать один и тот же буфер []byte в нескольких горутинах?

В Go можно использовать один и тот же буфер []byte в нескольких горутинах, но это требует дополнительных мер предосторожности для обеспечения безопасности и избежания гонок данных (data races).

Одним из подходов к безопасному использованию одного буфера []byte в нескольких горутинах является синхронизация доступа к нему с помощью мьютексов или других механизмов синхронизации, таких как sync.RWMutex. Мьютексы позволяют горутинам синхронизировать свой доступ к общему ресурсу и предотвращать одновременную запись или чтение из буфера.

Вот пример использования мьютекса для безопасного доступа к общему буферу []byte:

var bufferMutex sync.Mutex
var buffer []byte

func writeToBuffer(data []byte) {
bufferMutex.Lock()
defer bufferMutex.Unlock()
// Здесь происходит запись в буфер
// ...
}

func readFromBuffer() []byte {
bufferMutex.Lock()
defer bufferMutex.Unlock()
// Здесь происходит чтение из буфера
// ...
return buffer
}

В этом примере мьютекс bufferMutex используется для блокировки доступа к буферу []byte перед его записью или чтением. Это гарантирует, что только одна горутина имеет доступ к буферу в определенный момент времени.

Однако, важно помнить, что использование общего буфера []byte может быть проблематичным, особенно если горутины модифицируют его содержимое. Если горутины выполняют параллельные записи в буфер, могут возникнуть состояния гонки и непредсказуемые результаты. В таких случаях рекомендуется использовать другие механизмы синхронизации, такие как каналы (channels) или пулы буферов, чтобы гарантировать безопасность и предсказуемость работы с данными в многопоточной среде.

В целом, использование одного и того же буфера []byte в нескольких горутинах возможно, но требует осторожности и правильной синхронизации доступа к нему для обеспечения безопасности данных.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Способы поиска проблем производительности на проде?

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

Мониторинг ресурсов: Используйте инструменты мониторинга, такие как системные метрики, мониторинг нагрузки CPU, памяти, диска и сети. Это поможет вам определить, какие ресурсы используются в большей степени и могут быть узкими местами.

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

Логирование: Разместите подробные и информативные логи в вашем приложении. Логирование может помочь идентифицировать узкие места в вашем коде или обнаружить неожиданные события или проблемы использования ресурсов.

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

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

Масштабирование и горизонтальное масштабирование: Если ваше приложение испытывает проблемы с производительностью на проде, рассмотрите возможность масштабирования, как вертикального (увеличение ресурсов на одном сервере) и горизонтального (добавление дополнительных серверов). Это может помочь распределить нагрузку и повысить производительность.

Анализ кода и оптимизация: Просмотрите свой код и ищите возможности для оптимизации. Иногда простые изменения в алгоритмах или структурах данных могут привести к значительному улучшению производительности.

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

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

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

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Сколько времени в минутах займет у вас написание процедуры обращения односвязного списка?

package main

import "fmt"

type Node struct {
Val int
Next *Node
}

func reverseLinkedList(head *Node) *Node {
var prev *Node
curr := head
for curr != nil {
Next := curr.Next
curr.Next = prev
prev = curr
curr = Next
}
return prev
}

// можно сократить curr
// func reverseLinkedList(head *Node) *Node {
// var prev *Node
// for head != nil {
// Next := head.Next
// head.Next = prev
// prev = head
// head = Next
// }
// return prev
// }

// можно сократить Next (через множественное присваивание)
// func reverseLinkedList(head *Node) *Node {
// var prev *Node
// for head != nil {
// head.Next, prev, head = prev, head, head.Next
// }
// return prev
// }

// или создавая новые узлы
// func reverseLinkedList(head *Node) *Node {
// var result *Node
// curr := head
// for curr != nil {
// result = &Node{curr.Val, result}
// curr = curr.Next
// }
// return result
// }

func printLinkedList(head *Node) {
current := head
for current != nil {
fmt.Printf("%d -> ", current.Val)
current = current.Next
}
fmt.Println("nil")
}

func main() {
node1 := &Node{Val: 1}
node2 := &Node{Val: 2}
node3 := &Node{Val: 3}
node4 := &Node{Val: 4}
node5 := &Node{Val: 5}
node1.Next = node2
node2.Next = node3
node3.Next = node4
node4.Next = node5
fmt.Println("Исходный список:")
printLinkedList(node1)
reversedHead := reverseLinkedList(node1)
fmt.Println("Обращенный список:")
printLinkedList(reversedHead)
}


Пишите свое решение в комментариях👇

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
⚽️ Задача: Где приземлится мяч

Сложность: Средняя

Условие задачи: Дан двумерный массив, определяющий короб, а также n-ое количество мячей.

Каждая ячейка данной коробки имеет диагональную перегородку, которая может перенаправлять движение мяча.

- Перегородка ячейки типа "левый верхний угол —> правый нижний угол" имеет представление 1.
- Перегородка ячейки типа "правый верхний угол —> левый нижний угол" имеет представление -1.

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

Необходимо вернуть массив, который будет показывать добрался ли i-ый мяч до дна коробки (интерпретируется 1) или же уткнулся в стену (-1).

Пример:

Ввод:
grid = [[1,1,1,-1,-1],[1,1,1,-1,-1],[-1,-1,-1,1,1],[1,1,1,1,-1],[-1,-1,-1,-1,-1]]
Вывод: [1,-1,-1,-1,-1]
Объяснение: *во вложении

Ввод: grid = [[-1]]
Вывод: [-1]
Объяснение: мяч уткнется в левую стенку коробки

📌 Решение

Пишите свое решение в комментариях👇

@golang_interview
🔘 Полезных функций тестирования: параллельные и бенчмарк тесты.

Параллельные тесты
Параллельные тесты в #golang позволяют выполнять несколько тестов одновременно. Это особенно полезно для тестов, связанных с IO поскольку другие тесты могут выполняться во время периодов ожидания, а значит, вы будете меньше времени ждать выполнения вашего набора тестов.

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

Для этого достаточно пометить тест как параллельный следующим образом: изображение 1.

Бенчмарк-тесты
Бенчмарк-тесты - это отличный способ измерить и оптимизировать эффективность определенных частей кода.

Например, вот два способа конкатенации строки.

С помощью +: изображение 2.

Использование strings.Builder: изображение 3.

Если мы их запустим код, то получим следующий результат:

BenchmarkStringConcat-12 1000000 1200 ns/op BenchmarkStringBuilder-12 5000000 250 ns/op

Это означает, что тест выполнялся за 1000000 и 5000000 итераций, при этом stringConcat затрачивалось 1200 наносекунд на операцию, а strings.Builder - 250. Таким образом, strings.Builder гораздо эффективнее.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🦫Улучшенная маршрутизация HTTP-серверов в Go 1.22

В Go 1.22 ожидается появление расширенного мультиплексора для обработки HTTP в пакете net/http.
Новый мультиплексор позволит сопоставлять шаблоны путей более гибко, что раньше требовало использования сторонних библиотек, таких как gorilla/mux.

Использование нового mux
Если вы когда-либо использовали сторонние пакеты mux/маршрутизаторов для Go (например, gorilla/mux), то использование нового стандартного mux будет простым и привычным. Начните с чтения документации по нему - она краткая и понятная.

Давайте рассмотрим несколько базовых примеров использования. Наш первый пример демонстрирует некоторые из новых возможностей mux по сопоставлению шаблонов:

package main

import (
"fmt"
"net/http"
)

func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /path/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "got path\n")
})

mux.HandleFunc("/task/{id}/", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
fmt.Fprintf(w, "handling task with id=%v\n", id)
})

http.ListenAndServe("localhost:8090", mux)
}


Опытные программисты на Go сразу же заметят две новые особенности:

- В первом обработчике метод HTTP (в данном случае GET) указывается явно в составе шаблона. Это означает, что данный обработчик сработает только для GET-запросов к путям, начинающимся с /path/, а не для других HTTP-методов.

- Во втором обработчике во втором компоненте пути присутствует подстановочный знак - {id}, который ранее не поддерживался. Подстановочный знак будет соответствовать одному компоненту пути, и обработчик сможет получить доступ к найденному значению через метод PathValue запроса.

Поскольку Go 1.22 еще не выпущен, я рекомендую запускать этот пример с gotip. Полный пример кода с инструкциями по его выполнению. Давайте проверим работу этого сервера:

📌 Читать дальше

@golang_interview
Вышел GigaChat нового поколения. Разработчики @gigachat_bot качественно обновили его, изменив свой подход к обучению. Благодаря этому сервис стал лучше отвечать на запросы пользователей — примерно в два раза. При этом GigaChat также запустили в VK, аудитория сервиса уже достигла более 1 млн пользователей.

Попробовать.

@golang_interview
💡 Задача: Количество узлов

Условие: дано дерево (т.е. связный неориентированный граф, не имеющий циклов), состоящее из n узлов с числом от 0 до n - 1 и ровно n - 1 ребер. Корнем дерева является узел 0, и каждый узел дерева имеет метку, которая представляет собой символ нижнего регистра, указанный в строковых метках (т.е. узел с номером i имеет метку labels[i]).

Массив ребер задан на ребрах фермы[i] = [ai, bi], что означает наличие ребра между узлами ai и bi в дереве.

Возвращает массив размера n, где и[i] - количество узлов в поддереве узла земли, которые имеют ту же метку, что и узел i.

Поддерево дерева - это дерево, состоящее из узла в T и всех его дочерних узлов.

Пример:

Ввод:
n = 7, edges = [[0,1],[0,2],[1,4],[1,5],[2,3],[2,6]], labels = "abaedcd"
Вывод: [2,1,1,1,1,1,1]
Объяснение:

Ввод:
n = 4, edges = [[0,1],[1,2],[0,3]], labels = "bbbb"
Вывод: [4,2,1,1]

📌 Решение задачи

Пишите свое решение в комментариях👇

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
6️⃣ Популярных стилей архитектуры API, которые необходимо знать.

1. gRPC — это система удалённого вызова процедур с открытым исходным кодом, в качестве транспорта используется HTTP/2, в качестве языка описания интерфейса — Protocol Buffers. gRPC предоставляет такие функции как аутентификация, двунаправленная потоковая передача и управление потоком, блокирующие или неблокирующие привязки, а также отмена и тайм-ауты. Генерирует кроссплатформенные привязки клиента и сервера для многих языков. Чаще всего используется для подключения служб в микросервисном стиле архитектуры и подключения мобильных устройств и браузерных клиентов к серверным службам.

2. SOAP: Протокол для обмена структурированной информацией при реализации веб-сервисов, известный своими строгими стандартами и форматом сообщений на основе XML.

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

4. Webhook: Механизм взаимодействия в реальном времени, при котором приложение отправляет HTTP POST-запросы на заранее определенный URL-адрес для уведомления и запуска действий в другой системе.

5. REST: Representational State Transfer - архитектурный стиль проектирования сетевых приложений, использующий стандартные методы HTTP (GET, POST, PUT, DELETE) для манипулирования ресурсами.

6. WebSocket: Протокол, обеспечивающий двунаправленную связь между клиентом и сервером в реальном времени через одно долговременное соединение. Идеально подходит для приложений, требующих обновления данных с малой задержкой, таких как чат или игры.

#junior

@golang_interview
FSRouter - это простая библиотека маршрутизатора файловой системы для Go, предназначенная для простой интеграции с большинством библиотек маршрутизаторов http. Она использует соглашение "NextJS" для получения маршрутов непосредственно в виде иерархии файлов директорий.

go get -v -u github.com/aziis98/go-fsrouter

pages/
├── dashboard/[...all].html # => /dashboard/* (useful for SPAs)
└── user/
├── [name].html # => /user/:name
└── [name]/
└── posts/
└── [post].html # => /user/:name/posts/:post


Github

@golang_interview
💡 Задача: Взлом замка

Условие: даётся замок, состоящий из четырёх вращающихся дисков, на каждом из которых имеется 10 цифр: от 0 до 9. При этом за раз можно перемещать только одно колесо и на одно значение.

Изначально замок находится на значении «0000».

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

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

Пример:

Ввод:
deadends = ["0201","0101","0102","1212","2002"], target = "0202"
Вывод:
6
Объяснение:
последовательность, открывающая замок: "0000" -> "1000" -> "1100" -> "1200" -> "1201" -> "1202" -> "0202".

📌 Решение задачи

Пишите свое решение в комментариях👇


@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 K-ый наибольший элемент

Сложность: Лёгкая

Условие задачи: Нужно создать класс по нахождению k-ого наибольшего элемента среди передаваемых значений. k-м считается элемент для отсортированного списка, а не по уникальности значения.

Класс содержит следующие методы:

- KthLargest(int k, int[] nums) иниициализирует класс;
- int add(int val) добавляет элемент в спискок и возвращает k-ый наименьший согласно условию.

Пример:

Ввод:
["KthLargest", "add", "add", "add", "add", "add"]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]

Вывод:
[null, 4, 5, 5, 8, 8]
Объяснение:

KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);
kthLargest.add(3); // return 4
kthLargest.add(5); // return 5
kthLargest.add(10); // return 5
kthLargest.add(9); // return 8
kthLargest.add(4); // return 8


📌 Решение

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🔖 10 алгоритмов для интервью по системному проектированию

📌 Читать

@golang_interview
👣 Задача: Неубывающий подмассив

Условие: Дан целочисленный массив nums, верните все различные возможные неубывающие подпоследовательности данного массива, по крайней мере, с двумя элементами.

Вы можете вернуть ответ в любом порядке.

Пример:
Ввод:
nums = [4,6,7,7]
Вывод: [[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

Ввод: nums = [4,4,3,2,1]
Вывод: [[4,4]]

Решение

Пишите свое решение в комментариях👇

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
🦫10 проектов для изучения Golang в 2023 году

Оптимальный способ освоить Golang — создавать проекты. Исследованиями показано, что учиться лучше на практике, это подтверждается и моим опытом. Вопрос в том, какие именно проекты создавать?

10 идей проектов на Golang для начинающих (с курсами):

1. Создание веб-сервера

Это отличный проект для начала веб-разработки на Golang. Настраивая сервер для обработки HTTP-запросов и отправки ответов обратно клиентам, вы узнаете о маршрутизации, обработке HTTP-методов, парсинге параметров запроса, работе со статическими файлами.

Начните со встроенного пакета net/http, этого надежного каркаса для создания HTTP-серверов. Настроив сервер, добавьте конечные точки для обработки GET-, POST-, PUT- и DELETE-запросов.

2. Создание системы управления книгами YSQL


Это проект для эффективного управления книжными фондами.

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

В целом это отличный проект для создания масштабируемых приложений баз данных, эффективный и простой в сопровождении благодаря Golang и YSQL.

3. Создание «Slackbot» для загрузки файлов

Это проект для загрузки файлов на канал Slack, доступ к каналу получается через его API. Создается приложение Slackbot с настройкой его разрешений, а также сервер для обработки загрузки файлов, который интегрируется со Slackbot.

Ваша команда часто обменивается файлами в Slack? Тогда проект для вас: здесь это делается быстро и легко, не выходя из интерфейса Slack.

4. Создание «AWS Lambda»

📌 Продолжение

@golang_interview