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
加入频道
👣 Как преобразовать 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
👣 Как писать чистый код на Go, который работает

Держите полезный ролик, в котором на разные вопросы, связанные с тестированием Go-кода, отвечает разработчик с опытом 8 лет.

О чём говорится в видео?
— Краткое введение в тестирование: что такое тесты и какие виды тестов существуют.
— Должен ли разработчик писать тесты?
— Что такое TDD?
— «Утром код — вечером тесты» или «Утром тесты — вечером код»?
— Какую логику и какие данные нужно тестировать, а когда тесты не нужны.
— Как TDD помогает увеличить скорость и снизить затраты на разработку.
— Забиваете на best practices во время инцидентов? Остановитесь и подумайте.
— Как хорошие тесты становятся документацией к коду.
— Что такое test cases и как они связаны с use cases.
— Как методика TDD влияет на структуру команды и процессы.
— Что такое технический долг.
— Как «постмортем» помогает не воспроизводить одни и те же фейлы.
— Что ещё почитать по про test driven development.

В целом, полезное видео, рекомендую
📎 YouTube

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Вопрос с собеседования: зачем нужны интерфейсы в Go?

Интерфейсы в Go — это способ реализации полиморфизма

Проиллюстрировать интерфейсы можно так:
package main

import (
"math"
"fmt"
)

// Круг.
type Circle struct {
x, y, r float64
}

// Прямоугольник.
type Rectangle struct {
x1, y1, x2, y2 float64
}

// Интерфейс фигуры, которому удовлетворяют все типы, имеющие соответствующий
// метод вычисления площади Area().
type Figure interface {
Area() float64
}

// Реализация интерфейса Figure для Circle.
func (c *Circle) Area() float64 {
return math.Pi * c.r * c.r
}

// Реализация интерфейса Figure для Rectangular.
func (r *Rectangle) Area() float64 {
return math.Abs(r.x2 - r.x1) * math.Abs(r.y2 - r.y1)
}

func main() {
figures := make([]Figure, 0) // Срез фигур.

// Мы можем добавлять в этот срез все, что удовлетворяет интерфейсу
// Figure, несмотря на то, что это элементы разных типов:
figures = append(figures, &Circle{0, 0, 10})
figures = append(figures, &Rectangle{0, 0, 10, 20})

// И теперь мы можем единообразно обрабатывать эти данные разных типов.
for _, figure := range figures {
fmt.Printf("Area of %#v = %f\n", figure, figure.Area())
}
}


Результат:
$ go run figures.go
Area of &main.Circle{x:0, y:0, r:10} = 314.159265
Area of &main.Rectangle{x1:0, y1:0, x2:10, y2:20} = 200.000000


@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Указатели на структуры

▶️Итак, вот код:
v1 := Struct{}
v2 := &Struct{}

В чём отличие? Понятно, что во втором случае передается указатель, но когда что нужно использовать?


▶️Первая строка создает новый экземпляр структуры Struct и присваивает его переменной v1. В этом случае переменная v1 будет содержать саму структуру, а не указатель на нее.

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

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

Вот, для наглядности:
type Struct struct {
Value int
}

func main() {
v1 := Struct{} // Создаем структуру
v1.Value = 10 // Изменяем поле Value

v2 := &Struct{} // Создаем указатель на структуру
v2.Value = 20 // Изменяем поле Value через указатель

fmt.Println(v1.Value) // Выводит 10
fmt.Println(v2.Value) // Выводит 20
}


В этом примере мы создаем структуру Struct и изменяем поле Value сначала через саму структуру, а затем через указатель на структуру. Оба вывода будут отличаться, потому что изменения сделанные через указатель на структуру будут отражаться на самой структуре, в то время как изменения, сделанные через саму структуру, не влияют на указатель на нее.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Особенности работы defer

Почему в данной ситуации сначала выводится "Second" и "Third" (хотя они должны идти после "First"), а "Fourth" как раз лишь только после "First"?
Ведь defer должен срабатывать перед закрытием функции, в которой он объявлен.
package main

import "fmt"

func main() {
defer fmt.Println(changePointer())
fmt.Println("First")
}

func changePointer() string {
defer fmt.Println("Third")
fmt.Println("Second")
return "Fourth"
}



Итак, не будем тянуть, сразу к сути.
changePointer() вызывается, потому что это необходимо для получения результата, который может быть использован в fmt.Println(changePointer()).
Функция changePointer выполняется, чтобы получить результат, который возвращается в main, и только после этого запланированные defer — вызовы выполняются.
Вот такие дела

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Простая задача в Go

Итак, суть задания: пользователь вводит произвольную строку в консоль. Считываем это через fmt.Scanln(), тут все понятно.
Далее необходимо вывести True, если строка состоит из цифр и False во всех остальных случаях. Как это можно сделать?


Как вариант проверить строку регуляркой: ^\d*$ или, что аналогично: ^[0-9]*$.
test:="1233455677789900066554436433"
pattern:=`^\d*$`

matched,err:= regexp.Match(pattern,
[]byte(test))

Ну и неплохо бы ещё прикрутить обработку ошибок

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Разработка микросервисов на Go

Согласно Statista, больше 80% организаций со штатом от 5000 сотрудников используют микросервисную архитектуру, или микросервисы. Разработка микросервисов помогает бизнесу масштабироваться, делают приложения надежнее и упрощают кодовую базу. Но подходят они не всем.

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

📎 Статья

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

Итак, реальный кейс: необходимо выяснить язык в строке. Если в ней содержатся кириллические символы, значит она написана на русском языке. Если кириллических символов нет - значит на английском.
Вот первая идея, которая приходит в голову; тут используются регулярные выражения:
import (
"regexp"
)

func main() {
str := "Некая строка c кириллическими символами"
re := regexp.MustCompile("[А-Яа-я]+?") //проверяем на киррилические символы
isRussian := re.MatchString(str)

if isRussian {
...
}
}

Есть ли более эффективный способ узнать, на каком языке написана строка? Языков только два - русский и английский.


Самый быстрый (и он же, самый простой) способ:
func IsEngByLoop(str string) bool {
for i := 0; i < len(str); i++ {
if str[i] > unicode.MaxASCII {
return false
}
}
return true
}

Раз мы уверены, что имеем дело только с 2 языками, то достаточно определить, являются ли все символы строки ASCII символами. Если да, то строка написана на Английском, если нет - то на каком-то другом (в вашем случае, это Русский).
Вот и все дела

📎 Подробнее

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Почему это не вызывает ошибку?

package main
import "fmt"

func main() {
slice := []int{1}
fmt.Println(slice[1:])

}

Мы ведь обращаемся к элементу слайса с индексом 1, которого нет


▶️Итак, лучше 1 раз увидеть (определение поведения слайсов от авторов), чем 100 раз услышать (читать чьи-то интерпретации)

Вот цитата:
"For arrays or strings, the indices are in range if 0 <= low <= high <= len(a), otherwise they are out of range. For slices, the upper index bound is the slice capacity cap(a) rather than the length."
Особенно важно последнее предложение

Ну и небольшой пример для полного понимания:

package main
import "fmt"

func main() {

slice := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
slice1 := slice[5:6]
slice2 := slice1[1:10]
fmt.Println(slice1, slice2, cap(slice2), len(slice2))

}


Подробнее

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