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
加入频道
Forwarded from Golang
👣 Шпаргалка по Go

Мощная шпаргалка по Go, которая покрывает практически все темы
Если пролистать хотя бы по диагонали, есть отличный от нуля шанс пройти собеседование и получить оффер)

Что внутри?
├╼ Компилятор
├╼ Пакеты
├╼ Функции
├╼ Управление памятью
├╼ Операторы
├╼ Управляющие структуры
├╼ Объектноориентированность
├╼ Интерфейсы
├╼ Обработка ошибок
├╼ Горутины (Goroutine)
├╼ Проверка управления памятью
├╼ Reflect
├╼ Добавление кода C
├╼ GUI
╰╼ Распределенные системы

📎 Cheatsheet

@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Собственная функция sleep

Итак, задача: написать свою фукнцию sleep
🟡Первое, что может прийти в голову — использовать time.After, вот так:
package main

import (
"log"
"time"
)

func sleep(d time.Duration) {
select {
case <-time.After(d):
}
}

func CallSleep() {
log.Println("Do something")
sleep(5 * time.Second)
log.Println("Something else")
}

Но выглядит как-то громоздко, да и вообще.

🟡Второй вариант — сделать так:
func sleep2(d time.Duration) time.Time {
ticker := time.Tick(d)
for done := range ticker {
return done
}
return time.Now()
}


🟡А можно вообще сделать так:
func sleep(d time.Duration) {
<-time.After(d)
}

Ну вот, то, что нужно

@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Golang HTTP синхронизация

▶️Кейс: пишем Restful сервер с использованием патернов network_api -> data(UseCase->Repository).

Так как все http хендлеры обрабатываются параллельно, то каким образом корректно протянуть зависимости репозиториев и use_case объектов в слой network_api? То есть это будут синглтоны или же их нужно создавать для каждого отдельного request?
Что насчёт доступа к общим ресурсам?
Например, use_case при загрузке читает json-конфигурацию и в дальнейшем к ней обращается по многим путям из слоя nwtwork_api.

Есть какие нибудь best practices?


▶️Здесь всё зависит от того, какие требования предъявляются к нашим данным (т.е именно модель данных диктует требования к архитектуре).
Если наши данные терпимы к параллельному одновременному доступу — тогда можно не замарачиваться. Если же нельзя одновременно из нескольких потоков обращаться к менеджеру данных — тогда стоит ввести глобальную блокировку. Фактически, такой глобальной блокировкой будет являться единственное соединение к базе данных.
Вот и всё, пожалуй

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Go, Allure и HTTP, или как тестировать HTTP-сервисы на Go

Держите полезную статью о тестировании Go-приложений
Что внутри?

В статье рассматривается создание библиотеки CUTE для упрощения тестирования HTTP-сервисов на языке Go.

Библиотека CUTE облегчает создание автотестов и упрощает переход на Go, предоставляя возможности для создания HTTP-тестов и реализации проверок.

Ранее в компании Ozon не было подходящих инструментов для тестирования HTTP-сервисов, и библиотека CUTE была создана для решения этой проблемы.

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

Библиотека предоставляет возможности для информирования о тесте, подготовки дополнительных шагов и создания запросов.

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

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

Для создания теста необходимо вызвать ExecuteTest, передавая контекст и testing.TB или provider.T

📎 Статья

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 5 неожиданных вопросов с собеседований по Go

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

📎 YouTube

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Как проверить, имплементирует ли переменная интерфейс?

В Go, реализация интерфейса является неявной, поэтому используется конструкция вида
var _ myInterface = &myImplementation{}:
type T struct{}
var _ I = T{} // Проверка, что T имплеменирует I.
var _ I = (*T)(nil) // Проверка, что *T имплеменирует I.


Обычно это указывают, чтобы ошибки были выявлены уже во время компиляции.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Подборка вопросов для собеседования и немного теории

Держите годный контент)
Тут неплохой список тем, которые с большой вероятностью будут обсуждаться на собеседовании + теория по самому важному

Собственно, теория покрывает такие разделы:

🟡Типы данных
├╼ Скалярные
├╼ Массив и слайс
├╼ Map
├╼ Структура
╰╼ Интерфейс
🟡Сoncurrency
├╼ Каналы
├╼ Горутины
├╼ Sync
╰╼ Паттерны
🟡Планировщик
🟡Управление памятью
🟡Экосистема

Уверен, будет полезно) Успешных собеседований
📎 Вопросы и немного теории

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Подборка популярных вопросов с собеседований на позицию Go-разработчика

Держите репозиторий с вопросами по Golang. Здесь вы найдете вопросы, которые могут быть заданы на собеседовании, с подробными разъяснениями и анализом различных corner cases. Представьте, что это ваши билеты на экзамен - вытягивайте билет и готовьтесь!

Здесь затрагиваются самые важные темы Go, в том числе:
• Slices
• Maps
• Указатели
• Goroutines и Channels
• Работа со строками

🖥 Подборка

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Использование io.Pipe в Golang

▶️Вот пример использования io.Pipe для создания туннеля между писателем и читателем.
// отправляем пользователю ответ с аттачем
//reader, writer := io.Pipe()
writer := new(bytes.Buffer)
err = main.Doc.Save(writer) // метод Документа из unioffice - принимает io.Writer, сохраняет тип Document в zip.
//writer.Close() // для Pipe
...
reader := bytes.NewReader(writer.Bytes())
...
nbytes, err := io.Copy(w, reader) // w это http.ResponseWriter

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


▶️Проблема здесь довольно проста, вы же заметили?
Нужно просто вызов Writer обернуть в горутину, иначе все блокируется.
go func () {
defer writer.Close()
err = main.Doc.Save(writer) // принимает io.Writer
...
}
}()

Вот и всё

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Количество дней между двумя датами в Go

Ну тут всё просто, чтобы вычислить количество дней между 2 датами можно использовать функцию Sub из пакета time.
func main() {
// В високосном году 2096 будет 366 дней
t1 := Date(2096, 1, 1)
t2 := Date(2097, 1, 1)
days := t2.Sub(t1).Hours() / 24
fmt.Println(days) // 366
}

func Date(year, month, day int) time.Time {
return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
}


@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Почему теряются поля при конвертации?

▶️Итак, есть такая структура ответа map:
map[
/dbus-service:map[
org.freedesktop.DBus.Introspectable:map[]
org.freedesktop.DBus.Peer:map[]
org.freedesktop.DBus.Properties:map[]
Basket:map[
Fruit:"Apple"
]
]


При конвертации в json значение поле Fruit "теряется":
"/dbus-service":{
"org.freedesktop.DBus.Introspectable":{},
"org.freedesktop.DBus.Peer":{},
"org.freedesktop.DBus.Properties":{},
"Basket":
{
"Fruit":{}
}
}


Для вывода используется это:
fmt.Printf("%v", data)

jsonData, _ := json.Marshal(data)
fmt.Printf("json data: %s", jsonData)


Вопрос на засыпку: почему так происходит с Fruit?


▶️Ответ: этой ситуации данные не пропадают. Они не Marshal'aлятся у Fruit:"Apple".
"Apple" — имеет тип данных dbus.Variant
У него нету "публичных" свойств. Неэкспортируемых.

Экспортируемые пишутся с большой буквы.
Неэкспортируемые с маленькой.

Решение: создавать новое дерево map'ов с примитивными данными (string вместо dbus.Variant) путем рекурсии.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Массив байтов ⟶ в строку на Go

▶️Задача: имеется массив байтов вида array := [104 0 101 0 108 0 108 0 111 0 0 0 0 0 0 0]. Как перевести его в строку, чтобы она была равна видимым его символам (т.е. string(array[:]) == "hello")?


▶️Ну, тут всё просто, можно сделать так:
package main

import "fmt"

var array = []byte{104, 0, 101, 0, 108, 0, 108, 0, 111, 0, 0, 0, 0, 0, 0, 0}

func main() {
new_array := make([]byte, 0, len(array))
for _, b := range array {
if b == 0 {
continue
}
new_array = append(new_array, b)
}
// 5 - ожидаемая длинна
fmt.Println(len(new_array))
// строка без 0x00
fmt.Println(string(new_array))
}


🟡Или вот, более компактный вариант:
func btos(c []byte) string {
n := 0
for _, b := range c {
if b == 0 {
continue
}
c[n] = b
n++
}
return string(c[:n])
}


@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Тестовое задание на позицию стажёра-бэкендера + разбор

🟡Задача:
Необходимо реализовать микросервис для работы с балансом пользователей (зачисление средств, списание средств, перевод средств от пользователя к пользователю, а также метод получения баланса пользователя). Сервис должен предоставлять HTTP API и принимать/отдавать запросы/ответы в формате JSON.

🟡Требования к сервису:
1. Сервис должен предоставлять HTTP API с форматом JSON как при отправке запроса, так и при получении результата.
2. Язык разработки: Go.
3. Фреймворки и библиотеки можно использовать любые.
4. Реляционная СУБД: MySQL или PostgreSQL.
5. Использование docker и docker-compose для поднятия и развертывания dev-среды.
6. Весь код должен быть выложен на Github с Readme файлом с инструкцией по запуску и примерами запросов/ответов (можно просто описать в Readme методы, можно через Postman, можно в Readme curl запросы скопировать, и так далее).
7. Если есть потребность в асинхронных сценариях, то использование любых систем очередей - допускается.
8. При возникновении вопросов по ТЗ оставляем принятие решения за кандидатом.
9. Разработка интерфейса в браузере не требуется. Взаимодействие с API предполагается посредством запросов из кода другого сервиса. Для тестирования можно использовать любой удобный инструмент. Например: в терминале через curl или Postman.

🖥 GitHub с решением

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Про утечку памяти с time.AfterFunc

▶️Вопрос: будет ли течь память при такой реализации TTL in-memory-кеша (предполагаемый размер кеша — несколько десятков тысяч объектов)?
package cache

import (
"sync"
"time"
)

type Cache struct {
*sync.Map
TTL time.Duration
}

func New(ttl time.Duration) *Cache {
return &Cache{
Map: new(sync.Map),
TTL: ttl,
}
}

func (c *Cache) Store(key, value interface{}) {
c.Map.Store(key, value)
// memory leak?
time.AfterFunc(c.TTL, func() {
c.Map.Delete(key)
})
}



▶️Утечки быть не должно, так как в документации к типу time.Timer и его методам нет ничего про обязательные деструкторы как у time.Ticker. При этом в коде выше как минимум 2 проблемы:

• Создаётся множество таймеров, что увеличивает потребление ОЗУ и создаёт дополнительную нагрузку на планировщик.

• Если положить значение по ключу дважды, сотрётся оно по истечении первого TTL, а не второго.

И то, и другое можно вылечить, если просто запоминать время установки значения и проходиться по всем значением раз в N миллисекунд, удаляя устаревшие.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Нужен ли второй defer file.Close(), после перезаписи переменной?

▶️Итак, есть такой код:
jsonFile, err := os.Open("referenceData/ex.json")
if err != nil {
return err
}
defer jsonFile.Close() // первый defer
byteValue, err := ioutil.ReadAll(jsonFile)
if err != nil {
return err
}

err = json.Unmarshal(byteValue, &exToParse)
if err != nil {
return err
}

jsonFile, err = os.Open("referenceData/di.json") // перезапись jsonFile
if err != nil {
return err
}
defer jsonFile.Close() // нужно ли заново объявлять defer jsonFile.Close()?
byteValue, err = ioutil.ReadAll(jsonFile)
if err != nil {
return err
}

err = json.Unmarshal(byteValue, &diToParse)
if err != nil {
return err
}

Сначала инициализируем переменную не через var, а сразу передаём значение. Потом сразу пишем defer jsonFile.Close(). Потом в этот же файл загружаем другой json, и так же пишем defer jsonFile.Close().

Вопрос — а нужен ли второй defer? По идеи в ОЗУ, после перезаписи, jsonFile один и тоже, с тем же адресом, но только с другим содержанием.


▶️Да, нужен, так как аргументы функции, вызываемой defer, вычисляются в момент использования defer. Вот простой пример, где это видно:
type T int

func (t T) Close() { fmt.Println(int(t)) }

// ...

t := T(1)
defer t.Close()

t = T(2)
defer t.Close()

// 2
// 1

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

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Полезные утилиты Go

Язык Go имеет в своем распоряжении полный набор утилит, выполняемых из командной строки. 99% вы про них знаете, но повторение — мать учения)

go build. Эта утилита компилирует тесты. По необходимости она также скомпилирует зависимости.

Если имя пакета не main, то после того, как вы выполните go build, ничего не скомпилируется. Если вы хотите скомпилировать файл .a в $GOPATH/pkg, Вам вместо этого нужно выполнить go install.

go clean. Эта команда удаляет все файлы, созданные компилятором, включая следующие:
_obj/            // старый каталог object
_test/ // старый каталог test
_testmain.go // старый каталог gotest
test.out // старый каталог test
build.out // старый каталог test
*.[568ao] // объектные файлы

DIR(.exe) // создано go build
DIR.test(.exe) // создано go test -c
MAINFILE(.exe) // создано go build MAINFILE.go

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

go fmt и gofmt. Те из вас, которые работают с C/C++, должны знать, что люди часто дискутируют, какой стиль написания кода лучше: K&R-стиль или ANSI-стиль. Однако же в Go есть только один стиль написания кода, go fmt сделает всю работу за вас. Просто выполните команду go fmt <Имя файла>.go в терминале.

go get. Эта команда служит для установки удаленных пакетов. На данный момент она поддерживает BitBucket, GitHub, Google Code и Launchpad. При запуске этой команды происходят следующие вещи: первая - Go скачивает исходники пакетов, вторая - исполняется go install. Перед использованием этой команды убедитесь, что у вас установлены соответствующие инструменты:
BitBucket (Mercurial Git)
GitHub (git)
Google Code (Git, Mercurial, Subversion)
Launchpad (Bazaar)


Остальные утилиты можно глянуть по ссылке
📎 Ссылка

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM