Golang вопросы собеседований
13.5K subscribers
631 photos
3 videos
1 file
433 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