Библиотека Go для собеса | вопросы с собеседований
6.88K subscribers
220 photos
6 videos
1 file
424 links
Вопросы с собеседований по Go и ответы на них.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/0b524a15

Для обратной связи: @proglibrary_feeedback_bot

Наши каналы: https://t.me/proglibrary/9197
Download Telegram
💬 Почему в Go лучше использовать strconv вместо fmt для преобразования в/из строки?

Пакет strconv специально создан для преобразования строк, что означает, что он оптимизирован именно для них.

Для наглядности рассмотрим простое сравнение производительности:


func BenchmarkFmt(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprint(i)
}
}

func BenchmarkStrconv(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = strconv.Itoa(i)
}
}

BenchmarkFmt-8 23821753 50.17 ns/op 16 B/op 2 allocs/op
BenchmarkStrconv-8 100000000 11.47 ns/op 3 B/op 1 allocs/op


strconv.Itoa значительно быстрее и эффективнее с точки зрения выделения памяти по сравнению с fmt.Sprint. fmt.Sprint при этом использует рефлексию, чтобы понять, с каким типом данных работает, и определяет лучший способ форматирования его как строки.

Процесс рефлексии не «бесплатный», он добавляет как время, так и накладные расходы на память, что может быть довольно значительным, когда мы обрабатываем большие объемы данных или требуется высокая производительность.
👍203
💬 Что произойдет, если в type switch использовать временную переменную для типа nil? Какой тип будет у этой переменной?

Когда в type switch используется временная переменная для типа nil, тип этой переменной будет таким же, как и тип исходного значения, которое мы проверяем в TypeSwitchGuard. Например, если исходное значение имеет тип any, временная переменная также будет иметь тип any. Это можно проиллюстрировать следующим примером:
var x any
var y error

switch t := x.(type) {
case nil:
y = t // Ошибка компиляции: any does not implement error
}

В этом примере код не компилируется с ошибкой, указывающей, что переменная типа any не может быть присвоена переменной типа error, так как тип any не реализует метод Error. Это подтверждает, что временная переменная t в случае nil имеет тот же тип, что и x (в данном случае any).
1
Ответьте на 3 вопроса, чтобы получить вводные занятия к курсу «Алгоритмы и структуры данных»

🔥Получите вводные занятия, ответив на 3 вопроса – https://proglib.io/w/c2161ff4

На вводной части вас ждут:

1. Лекция «Производительность алгоритмов» от руководителя разработки Яндекс.Самокатов

2. Лекция «Итеративные сортировки и линейные сортировки» от аспирант департамента искусственного интеллекта ВШЭ

3. Практические задания после лекций

4. Ссылки на дополнительные материалы для самостоятельного изучения

⚡️Переходите и начинайте учиться уже сегодня – https://proglib.io/w/c2161ff4
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
💬 Поддерживается ли в Go арифметика указателей как C++ или других языках?

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

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

Для выполнения операций, аналогичных арифметике указателей, в Go можно использовать слайсы, которые обеспечивают безопасный доступ к элементам массива и автоматически управляют размером и ёмкостью.
🔥1
💬 Когда pointer ресивер предпочтительнее использовать, чем value ресивер в Go?

Первая причина — чтобы метод мог изменить значение, на которое указывает его ресивер.

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

В примере ниже, оба метода Scale и Abs имеют тип ресивера *Vertex, хотя метод Abs не должен изменять свой ресивер.


package main

import (
"fmt"
"math"
)

type Vertex struct {
X, Y float64
}

func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}

func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func main() {
v := &Vertex{3, 4}
fmt.Printf("Before scaling: %+v, Abs: %v\n", v, v.Abs())
v.Scale(5)
fmt.Printf("After scaling: %+v, Abs: %v\n", v, v.Abs())
}


В общем случае, все методы для данного типа должны использовать либо только pointer ресивер, либо только value ресивер, чтобы избежать путаницы и обеспечить согласованность.
👍31
⚡️Proglib запускает канал про ИИ для генерации звука

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

⭐️генерация голоса и музыки
⭐️замена и перевод речи
⭐️распознавание звуков

👉Подписывайтесь!
💬 Интерфейс и any (interface{}) в Go — это одно и то же? Объясните простыми словами.

Нет, это не одно и то же. Интерфейсы определяют контракты для типов, которые их реализуют.

any — это псевдоним для пустого интерфейса interface{}. Пустой интерфейс interface{} может содержать значение любого типа, поскольку он не требует реализации никаких методов.
🥱5👍3
💬 Почему crypto/rand в некоторых кейсах предпочтительнее использовать вместо math/rand для генерации ключей в Go?

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

Пакет math/rand отлично подходит для генерации псевдослучайных чисел. Но у этого метода есть серьезный недостаток: если кто-то узнает, как генерируются числа (начальное значение seed), он сможет предсказать будущие числа.


import "math/rand"

func Key() string {
// rand.Seed(time.Now().UnixNano()) // deprecated
r := rand.New(rand.NewSource(time.Now().UnixNano()))

buf := make([]byte, 16)

for i := range buf {
buf[i] = byte(r.Intn(256))
}

return fmt.Sprintf("%x", buf)
}


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

С другой стороны, crypto/rand предлагает лучшее решение для генерации чисел, которые криптографически безопасны. Эта библиотека разработана для полной непредсказуемости, используя источники случайности, предоставляемые ОС, которые обычно гораздо сложнее предсказать.


import "crypto/rand"

func Key() string {
buf := make([]byte, 16)

_, err := rand.Read(buf)
if err != nil {
panic(err)
}

return fmt.Sprintf("%x", buf)
}


Использование crypto/rand особенно необходимо для операций, таких как шифрование, аутентификация или любой другой контекст, где безопасность имеет критическое значение.

Опять же, если мы генерируем ключи для целей, не связанных с безопасностью, math/rand вполне подойдет.
👍114
💬 Когда процесс в Linux может не реагировать на SIGKILL?

🔸 Когда процесс является зомби-процессом, который уже завершился, но не освободил свои ресурсы. Зомби не может принимать сигналы и ожидает, что его родительский процесс считает его статус с помощью системного вызова wait.
🔸 Когда процесс находится в состоянии блокировки. Он выполняет неотменяемый системный вызов, такой как ожидание ввода-вывода или другого события, которое не наступило. Процесс не может завершиться, пока операционная система не вернет его в нормальное состояние.
🔸 Когда процесс является процессом init. Он не получает от ОС сигналов, которые не хочет обрабатывать. Процесс init может игнорировать SIGKILL, так как он является особым процессом, который отвечает за запуск и завершение других процессов.
👍13❤‍🔥2
📖 ТОП-10 книг о том, как правильно построить карьеру в IT

Хотите преуспеть в IT? Ознакомьтесь с нашим списком лучших книг, которые помогут вам выстроить успешную карьеру в этой динамичной отрасли!

Читать статью, чтобы ознакомиться со всеми книгами 👉 https://proglib.io/sh/glq68BCSKj
👍1
💬 Что такое статическая компиляция/линковка и в чем ее особенности?

Линковка (или компоновка) — это последний этап сборки программы, когда все скомпилированные части кода и библиотеки объединяются в один исполняемый файл. Статически слинкованный исполняемый файл не зависит от наличия других библиотек в системе во время своей работы, так как все необходимые библиотеки встраиваются в итоговый бинарный файл.

Для включения статической компиляции/линковки в Go необходимо установить переменную окружения CGO_ENABLED=0 при сборке (т. е. `CGO_ENABLED=0 go build ...`). Это гарантирует, что все внешние библиотеки, от которых зависит выполнение кода, будут встроены в итоговый бинарный файл. Полученный бинарный файл можно использовать, например, в Docker-образе, основанном на scratch (т.е. не содержащем никаких файлов, чистая файловая система).

Однако, это накладывает некоторые ограничения и привносит особенности, которые необходимо помнить:

1. C-код будет недоступен. Некоторые модули из стандартной библиотеки Go зависят от C-кода, но они не являются критичными.
2. Не будет использоваться системный DNS-резольвер: Go будет использовать собственный DNS-резолвер.
3. Проблемы с проверкой x.509 сертификатов на MacOS: в некоторых случаях проверка x.509 сертификатов может не работать корректно.

Если итоговый бинарный файл планируется использовать в Docker-образе scratch, то также следует учитывать:

1. Корневые SSL/TLS сертификаты: для осуществления HTTP запросов по протоколу HTTPS нашему приложению, в образ нужно будет поместить корневые SSL/TLS сертификаты в /etc/ssl/certs.
2. Файл временной зоны: для корректной работы с датой и временем необходимо добавить файл временной зоны в /etc/timezone.
👍161