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
加入频道
👣 Разрабы Go отвечают на вопросы

Среди заданных вопросов много интересных, типо:
— можно ли с Go и HTMX делать fullstack-приложения
— в чём отличие между namespace в других ЯП и package в Go
— как обстоят дела с Dependency Injection в Go
— и ещё несколько других

Отличное видео, помогает узнать об актуальных задачах, которые решаются с помощью Go и не только
Рекомендую)

📎 Youtube

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Возможный вопрос на собесе: rune и byte — в чём разница?

rune - это 32-х битный тип, представляющий юникодные символы в кодировке UTF-32 aka UCS-4.

byte - это универсальный 8-битный тип.

rune используется для работы с не-ASCII символами в строках. Есть встроенное приведение []rune для типа string, которое парсит строку из UTF-8 (представление с переменной длиной байтов) в представление с фиксированной длиной байтов.

В случае не-ASCII строк разница между []byte(str) и []rune(str) разительна. Строка Привет, мир!:
Байты:  [208 159 209 128 208 184 208 178 208 181 209 130 44 32 208 188 208 184 209 128 33]
Руны: [1055 1088 1080 1074 1077 1090 44 32 1084 1080 1088 33]


Приведение []rune(string) эквивалентно вот такой функции:
func ToRunes(bytes []byte) []rune {
result := []rune{}
for i := 0; i < len(bytes); {
r, size := utf8.DecodeRune(bytes[i:])
result = append(result, r)
i += size
}
return result
}


📎На картинке текст программы с преобразованием Привет, мир! в руны и обратно

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 В чём суть реализации уязвимости c помощью перестановки defer response.Body.Close()

▶️Итак, есть такой обработчик, и реализация уязвимости связана с тем, что тело ответа закрывается до проверки ошибки.
func HandleRequest(client http.Client, request *http.Request)
(*http.Response, error) {
response, err := client.Do(request)
defer response.Body.Close()
if err != nil {
return nil, err
}
}

А теперь вопрос: почему это должно работать, ведь тело всё равно закрыто, не зависимо до проверки или после?

Известно, что полное отсутствие строки defer response.Body.Close() приводит к гарантированным проблемам, но как протестировать вышеупомянутую уязвимость?


▶️Суть в следующем: defer response.Body.Close() означает, что response.Body.Close() должно быть выполнено в точке выхода из функции. Ни о каком закрытии тела до проверки ошибки речь не идёт.

Проблема здесь в другом — в случае ошибки response может быть nil, и выполнение отложенной инструкции в ветке if err != nil {... return ...} в таком случае приведет к панике из-за обращения к нулевому указателю.
panic: runtime error: invalid memory address or nil pointer dereference


А вот собственно и код:
package main

import (
"fmt"
"io"
"net/http"
"net/url"
"os"
)

func main() {
client := http.Client{}
url, _ := url.Parse("https://no.such.host")
request := &http.Request{
Method: "GET",
URL: url,
}

response, err := client.Do(request)
defer response.Body.Close()
if err != nil {
fmt.Fprintf(os.Stderr, "Request failed: %s\n", err.Error())
}

io.Copy(os.Stdout, response.Body)

}


Как-то так

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Сверхполезный сайт со всей теорией по Go

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

Вопросы с собеседований связанные с Golang
├── Общие вопросы
├── Хеш-мапы
├── Интерфейсы
├── Пакеты
├── Типы данных
├── Defer
├── Примитивы синхронизации
├── Планировщик
├── Строки
├── Массивы и слайсы
├── Дженерики
├── Горутины
├── Конструкции
├── Гонка данных
├── Структуры
├── Контекст
├── Ошибки / Panic
└── Указатели

Вопросы с собеседований связанные с Linux
├── Файловая система
└── Сигналы, процессы

Вопросы по инфраструктуре
└── Базы данных (реляционные)

🖥 GitHub

📎 Учебник

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Как в Golang проверить, содержит ли массив значение?

▶️Итак вопрос: как проверить, есть ли значение в массиве Go?

Есть функция strings.Contains, но она проверяет есть ли строка в строке, не массив. Есть ли функция для этого, или надо писать свою?


▶️Сразу к сути: если массив не отсортирован, то есть функция slices.IndexFunc
// искать индекс элемента target
idx := slices.IndexFunc(someSlice, func (elt E) { return elt == target })
if idx >= 0 { /* найден */ }


Но это реально тривиальная функция:
func IndexFunc[E any](s []E, f func(E) bool) int {
for i := range s {
if f(s[i]) {
return i
}
}
return -1
}


Если же массив отсортирован, то есть функция поиска делением пополам slices.BinarySearch - ищет для типов, для которых определено сравнение <. В общем случае есть поиск по отсортированному слайсу с компаратором slices.BinarySearchFunc

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Поговорим про пользовательские типы в Go

В Go можно объявить алиас на существующий тип данных для выразительности и абстракции.

Например, тип byte из модуля "строки" — это алиас uint8. Алиас объявляется через ключевое слово type:
type NumCount int

func main() {
nc := NumCount(len([]int{1, 2, 3}))

fmt.Println(nc) // 3
}


Алиас можно конвертировать в оригинальный тип и обратно:
type errorCode string

func main() {
ec := errorCode("internal")

fmt.Println(ec) // internal

fmt.Println(string(ec)) // internal
}


Также у алиасов могут быть методы. Объявление метода происходит так же, как и со структурами:
type counter int


// передается указатель, чтобы можно было изменить состояние счетчика "c"
func (c *counter) inc() {
*c++
}

func main() {
c := counter(0)
(&c).inc() // передается указатель на счетчик &c, так как функция "inc()" работает с указателями
(&c).inc()

fmt.Println(c) // 2
}


@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Анонимные поля структур, грамматика Go

1️⃣Есть такая вещь как анонимные поля структуры. В каких случаях они используются?
// A struct with four anonymous fields of type T1, *T2, P.T3 and *P.T4
struct {
T1 // field name is T1
*T2 // field name is T2
P.T3 // field name is T3
*P.T4 // field name is T4
x, y int // field names are x and y
}


2️⃣Что обозначают вот эти строчки, которые, в контексте, можно увидеть тут:
StructType     = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] .
AnonymousField = [ "*" ] TypeName .
Tag = string_lit .

Эти строки имеют отношение к граматикам, которые использует компилятор? Для чего эта информаия прописана в документации?

3️⃣Зачем в структуре объявлять поле вида _. Как его можно использовать?
// A struct with 6 fields.
struct {
x, y int
u float32
_ float32 // padding
A *[]int
F func()
}



Что ж, давайте разберёмся со всеми вопросами:

1️⃣Это один из способов реализации композиции в Go. Пример:
type commonWidget struct {
width, height int
}

func (w *commonWidget) setHeight(height int) { w.height = height }
func (w *commonWidget) setWidth(width int) { w.width = width }

type button struct {
commonWidget
text string
}

type input struct {
commonWidget
type_ string
}

Здесь тип commonWidget описывает общие для всех виджетов поля и методы. Путём включения, типы button и input получают как нужные поля, так и методы, с ними работающие.

2️⃣Да, это формальное описание грамматики. Прописана потому что это не просто документация, а *формальная спецификация* языка. По сути, стандарт. Go с самого начала разрабатывался как спецификация, по которой делались два разных компилятора, gc и gccgo. Благодаря тому, что есть спецификация, когда два этих компилятора чем-то различаются, можно понять, кто "не прав". В свою очередь, различия в имплементации компиляторов часто указывают на неполноту спецификации.

3️⃣Например, чтобы "растянуть" структуру до нужного размера, например чтобы передать её в код на C, который ожидает структуру определённого размера. Либо чтобы сделать смещение более заметным.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Как преобразовать punycode в unicode?

Какой пакет/либу/функцию можно использовать для преобразования url строки из punicode в unicode.
Т.е. задача: xn--go -uedfq ——> Go топ. И наоборот


В этом нам поможет idna, сперва ставим пакет локально:
go get golang.org/x/net/idna

Не забываем настроить переменную среды %GOPATH. После этого мы сможем спокойно импортировать пакет в проект:
package main

import (
"fmt"
"golang.org/x/net/idna"
)

var p *idna.Profile

func main() {
p = idna.New()
fmt.Println(p.ToUnicode("xn--go -uedfq"))
}

// Go топ


Вот такие дела

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Простой сервер с поддержкой REST API на языке Go

Создание простого сервера с поддержкой REST API на языке Go можно выполнить с использованием стандартной библиотеки net/http. Поехали!

Определим структуру User и создадим веб-сервер:
package main

import (
"encoding/json"
"log"
"net/http"
"strconv"
"sync"
)

type User struct {
ID int `json:"id"`
Name string `json:"name"`
}

var (
users = make(map[int]User)
mu sync.Mutex
idSeq int
)

func createUser(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()

idSeq++
user := User{ID: idSeq}

if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

users[user.ID] = user

w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
}

func getUser(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.URL.Path[len("/users/"):])
if err != nil {
http.Error(w, "Invalid user ID", http.StatusBadRequest)
return
}

mu.Lock()
defer mu.Unlock()

user, ok := users[id]
if !ok {
http.NotFound(w, r)
return
}

json.NewEncoder(w).Encode(user)
}

func main() {
http.HandleFunc("/users", createUser)
http.HandleFunc("/users/", getUser)

log.Println("Starting server on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}


Этот код запускает HTTP-сервер на порту 8080. Он обрабатывает два запроса:

POST/users: Создает нового пользователя. Ожидает JSON с именем пользователя в теле запроса.

GET/users/{id}: Возвращает данные пользователя по его ID.

Для тестирования сервера вы можете использовать инструменты вроде curl или postman. Например, для создания пользователя:
curl -X POST -H "Content-Type: application/json" -d '{"name":"John Doe"}' http://localhost:8080/users


И для получения пользователя по ID:
curl http://localhost:8080/users/1


@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Неплохой ролик по чистой архитектуре на Go

Держите годный контент 🔥
О чём вообще речь в этом видео?

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

Демонстрируется реализация чистой архитектуры в коде на примере продакшн-сервиса, который Артур создал ранее.

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

Подчёркивается, что все слои зависят от бизнес-логики, а бизнес-логика не зависит ни от чего; объясняется, как использовать интерфейсы для передачи данных между слоями.

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

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 5 способов писать эффективный код на Go: от названий переменных до архитектуры

Держите отличную статью, где разработчики из YADRO описывают best-practices в Go-разработке

О чём статья?
Статья предлагает советы по повышению эффективности разработки на языке программирования Go.

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

Обсуждается автоматическое создание документации с помощью специальных утилит, таких как Swagger.

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

А также, конечно, освещается тема правильной архитектуры, включая разделение кода на пользовательские кейсы, глаголы и существительные и много всего ещё — должно быть полезно

📎 Статья

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Простое переподключение к БД в Go

При разработке web-сервисов, которые должны работать в режиме 24/7, в не последнюю очередь важно правильно работать с ресурсами лежащими за рамками кода, такие как обращение к другим сервисам или работа с базой данных. О последних мы и поговорим.

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

Ниже приведет пример как это можно сделать простой реконнет к БД работая с Go. Мы используем pgx реализацию Go клиента для Postgres, которая предоставляет различные плюшки.
package main

import (
"context"
"fmt"
"log"
"time"
"github.com/jackc/pgx"
)

type DatabaseInstance struct {
conn *pgx.Conn
connConfig pgx.ConnConfig
maxConnectAttempts int
}

func NewConn(uri string, maxAttempts int) (*DatabaseInstance, error) {
connConfig, err := pgx.ParseURI(uri)
if err != nil {
return nil, err
}
instance := DatabaseInstance{}
instance.connConfig = connConfig
instance.maxConnectAttempts = maxAttempts
return &instance, err
}

func (db *DatabaseInstance) reconnect() (*pgx.Conn, error) {
conn, err := pgx.Connect(db.connConfig)
if err != nil {
return nil, fmt.Errorf("unable to connection to database: %v", err)
}
if err = conn.Ping(context.Background()); err != nil {
return nil, fmt.Errorf("couldn't ping postgre database: %v", err)
}
return conn, err
}

func (db *DatabaseInstance) GetConn() *pgx.Conn {
var err error
if db.conn == nil {
if db.conn, err = db.reconnect(); err != nil {
log.Fatalf("%s", err)
}
}

if err = db.conn.Ping(context.Background()); err != nil {
attempt := 0
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for range ticker.C {
if attempt >= db.maxConnectAttempts {
log.Fatalf("connection failed after %d attempt\n", attempt)
}
attempt++
log.Println("reconnecting...")
db.conn, err = db.reconnect()
if err == nil {
return db.conn
}
log.Printf("connection was lost. Error: %s. Waiting for 5 sec...\n", err)
}
}
return db.conn
}

Код довольно прост: мы перед взятием соединения пингуем БД, если этого не удалось сделать, то ждём 5 секунд и пытаемся снова.

Подобное решение подойдет не всем! Так как перед каждым запросом осуществляется опрос БД, что создает огромный оверхед и подобное решение лучше использовать в сервисах, которые редко ходят с базу. Для сервисов которые постоянно работают с БД лучше использовать пулы соединений. Но даже работая через пулы, код остается полезным, внеся небольшие изменения можно использовать его при первоначальном соединении с базой, это особенно полезно в работе с docker-compose (старых версий), где сервис мог запуститься раньше базы.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Представляем планировщик Go: вы никогда не смотрели на горутины с этой стороны

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

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

Планировщик Go привязывает M горутин к N потокам ядра, формируя модель M:N

Конкурентность и параллельность используются для описания различных типов исполнения задач.

Горутины не используются единожды и добавляются в исполняемую очередь процессора

Поток ОС может создавать новые горутины, если все потоки заблокированы

Планировщик Go участвует в связывании горутин с потоками и исполнении задач

Network Poller является компонентом рантайма Go и служит для исполнения запросов связанных с сетью

📎 Статья

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Годное видео об особенностях Go 1.22

Для тех, у кого руки ещё не дошли до свежей февральской версии Go — держите годное видео от разраба из Авито, рассказывает про некоторые нововведения и всё такое

В частности про:
изменения в поведении циклов for и в синтаксисе итераций по целым числам

новый синтаксис для итерации по функциям, который пока скрыт и требует сборки с специальной переменной

про функцию split из пакета strings, позволяющую разделить строку на части

про функцию для получения случайного целого числа из пакета rand

и ещё о многих других особенностях

📎 Видео

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