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 кода

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

📎 Статья

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Мышление программиста Go и скиллы управления кибер-инцидентами в борьбе с диабетом

Статья о человеке, которому Go помогает справляться с диабетом.
Если вкратце, то парень использует Go и распределённую систему микросервисов, чтобы отслеживать уровень инсулина и сахара в крови и т.д.
Параллельно в статье рассказывается про такие инструменты как Prometheus, Grafana, PagerDuty, так что можно узнать много полезного.

📎 Статья

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Немного о записи в файл с помощью Go

В Go можно писать в файлы без использования буферов, что означает, что каждая операция записи в файл приводит к записи на диск. Это поведение отличается от многих других языков программирования, где операции ввода-вывода буферизуются по дефолту для улучшения производительности.
Если вы хотите использовать буферизованный ввод-вывод, вы должны явно использовать пакет bufio для создания буферизованных объектов чтения и записи.

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

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

📎 Здесь обсуждение проблемы записи в файл на Go, примеры кода на Python и C, очень полезно

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Как понять, что канал Go закрыт для записи?

Сразу перейдём к примеру. Закрытый канал не блокируется на чтение. Вот, тут довольно наглядно:
Loop:
for {
select {
case val, ok :=<- someChan:
if !ok {
// канал закрыт
break Loop
}
// получены данные, работа с val
default:
// канал пуст, что-то делать
}
}

Здесь, ok будет истиной только для открытого канала. Но при закрытии по каналу будут приходить пустые сообщения постоянно и ok будет ложью.

Однако вышеприведённая конструкция оптимальна только если нужно выполнять действие в default-ветке. Т.е. что-то делать, когда сообщений нет. Есть более простая и понятная конструкция
for val := range someChan {
// получено сообщение
}
// канал закрыт

В этом случае канал читается, используя for-range. Когда канал будет закрыт и из него будет прочитано последнее сообщение, произойдёт выход из цикла.


Запись

Запись в закрытый канал вызывает панику.
Дизайн приложения должен быть таким, что сторона создающая канал, его же и закрывает и пишет в него то же она. Более того, в этих случая рекомендуется, что б функция возвращала канал только для чтения
func run () <-chan string {
c := make(chan string)
// [...]
}



recover()

Конечно можно в отложенном вызове вызвать recover(), чтобы подавить панику. Но это в корне неправильно.

@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
👣 Разрабы 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