Golang | Вопросы собесов @easy_golang Channel on Telegram

Golang | Вопросы собесов

@easy_golang


Cайт easyoffer.ru
Реклама @easyoffer_adv
ВП @easyoffer_vp

Тесты t.me/+MVqzqT6ZzFFhYjhi
Задачи t.me/+MURwpbl6Nq9kYzJi
Вакансии t.me/+mX_RBWjiMTExODUy

Golang | Вопросы собесов (Russian)

Присоединяйтесь к каналу 'Golang | Вопросы собесов', чтобы успешно подготовиться к собеседованиям по языку программирования Golang. Канал @easy_golang предлагает широкий выбор тестов, задач и информацию о вакансиях для тех, кто интересуется работой с Golang.

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

Не упустите возможность быть в курсе последних трендов и развивать свои профессиональные навыки. Присоединяйтесь к каналу 'Golang | Вопросы собесов' прямо сейчас и станьте экспертом в области программирования на Golang!

Golang | Вопросы собесов

12 Feb, 16:10


🤔 Как тесты и TDD влияют на организацию кода?

1. Четкость структуры:
- Код становится модульным и более читаемым.
2. Меньшая связность:
- Компоненты проектируются так, чтобы их можно было легко тестировать независимо.
3. Предсказуемость изменений:
- Тесты помогают выявлять ошибки при рефакторинге.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

12 Feb, 09:10


🤔 Что такое структура (stuct) в Go Зачем они нужны?

Структуры (struct) представляют собой агрегированные типы данных, которые позволяют объединять несколько различных типов данных под одним именем. Они служат для моделирования объектов и хранения связанных данных, предоставляя удобный способ управления сложными данными.

🚩Определение структуры

Определяются с использованием ключевого слова struct. В структуре могут быть поля различных типов.
package main

import "fmt"

// Определение структуры Person
type Person struct {
Name string
Age int
}

func main() {
// Создание экземпляра структуры
var p Person
p.Name = "Alice"
p.Age = 30

fmt.Println("Name:", p.Name)
fmt.Println("Age:", p.Age)
}


🚩Инициализация структур

Существует несколько способов инициализации структур.
package main

import "fmt"

// Определение структуры Person
type Person struct {
Name string
Age int
}

func main() {
// Инициализация с использованием литерала структуры
p := Person{Name: "Bob", Age: 25}
fmt.Println("Name:", p.Name)
fmt.Println("Age:", p.Age)
}


Инициализация по умолчанию
package main

import "fmt"

// Определение структуры Person
type Person struct {
Name string
Age int
}

func main() {
// Инициализация по умолчанию (поля будут нулевыми значениями)
var p Person
fmt.Println("Name:", p.Name) // Пустая строка
fmt.Println("Age:", p.Age) // 0
}


🚩Вложенные структуры

Могут содержать другие структуры в качестве полей, что позволяет моделировать более сложные данные.
package main

import "fmt"

// Определение структур Address и Person
type Address struct {
City string
State string
}

type Person struct {
Name string
Age int
Address Address
}

func main() {
// Инициализация структуры с вложенной структурой
p := Person{
Name: "Charlie",
Age: 40,
Address: Address{
City: "New York",
State: "NY",
},
}

fmt.Println("Name:", p.Name)
fmt.Println("Age:", p.Age)
fmt.Println("City:", p.Address.City)
fmt.Println("State:", p.Address.State)
}


🚩Методы структур

Могут быть ассоциированы со структурами, что позволяет добавлять функциональность к структурам.
package main

import "fmt"

// Определение структуры Person
type Person struct {
Name string
Age int
}

// Метод для структуры Person
func (p Person) Greet() {
fmt.Printf("Hello, my name is %s and I am %d years old.\n", p.Name, p.Age)
}

func main() {
p := Person{Name: "David", Age: 35}
p.Greet()
}



🟠Организация данных
Позволяют логически объединять связанные данные в один тип.
🟠Моделирование объектов
Позволяют моделировать реальные объекты и их свойства.
🟠Повышение читаемости и поддерживаемости кода
Использование структур делает код более организованным и понятным.
🟠Методы и функциональность
Могут иметь методы, что позволяет добавлять функциональность и поведение объектам.

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

12 Feb, 07:00


Все новости из мира программирования на этом канале @umnyiprogrammist

Подписывайтесь, чтобы не упустите ничего важного

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

11 Feb, 16:10


🤔 Какие типы мьютексов предоставляет stdlib?

1. sync.Mutex:
- Базовый мьютекс для блокировки доступа к разделяемым данным.
2. sync.RWMutex:
- Поддерживает несколько потоков чтения одновременно, но блокирует запись.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

11 Feb, 09:10


🤔 Зачем нужен Prometheus?

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

🚩Почему нужен Prometheus?

🟠Мониторинг состояния системы
позволяет отслеживать производительность, загрузку CPU, память, сетевой трафик и другие параметры.
🟠Автоматический сбор метрик
использует модель pull (запрашивает данные у сервисов), а не push (как, например, Graphite). Это удобнее для управления и отказоустойчивости.
🟠Гибкость в сборе данных
поддерживает кастомные метрики, которые можно интегрировать в своё приложение.
🟠Продвинутая система алертинга
позволяет настроить уведомления при достижении критических значений.
🟠Хранение исторических данных
помогает анализировать тренды и предсказывать возможные сбои.
🟠Масштабируемость
легко развертывается в облаке, Kubernetes, Docker и других средах.

🚩Как работает Prometheus?

🟠Экспортеры метрик
собирают данные.
🟠Prometheus
опрашивает эти экспортеры по HTTP (pull-модель).
🟠PromQL
(язык запросов) используется для анализа данных.
🟠Grafana
или другие инструменты визуализируют метрики.
🟠Alertmanager
отправляет уведомления (Slack, Email, Telegram и др.).

🚩Пример использования в Go-приложении

Для интеграции в Go-приложение можно использовать пакет prometheus/client_golang
package main

import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

var httpRequests = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
)

func handler(w http.ResponseWriter, r *http.Request) {
httpRequests.Inc() // Увеличиваем счетчик запросов
w.Write([]byte("Hello, Prometheus!"))
}

func main() {
// Регистрируем метрику
prometheus.MustRegister(httpRequests)

// Эндпоинт для сбора метрик
http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/", handler)

http.ListenAndServe(":8080", nil)
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

10 Feb, 20:14


Ищу работу пол года

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

Честно говоря, искать работу полгода — это нонсенс. Очевидно, что человек делает что-то не так. Главная ошибка, которую совершают многие, — это создание иллюзии поиска работы.

То есть человек вроде бы ищет работу, но делает это неэффективно, тратя время на нецелевые действия. Например:

Просматривает вакансии перед откликом.
Пытается понять, подходит ли он под вакансию. Если считает, что не подходит — не откликается.
Пишет сопроводительные письма (иногда даже уникальные под каждую вакансию).
Заполняет анкеты, проходит тесты.

Все эти действия отнимают время, но не приводят к результату.

Почему это не работает?

HR-менеджер не может вручную отсмотреть 2000 откликов, оценить каждое резюме и прочитать сопроводительные письма. Поэтому компании используют ATS-системы (системы автоматического подбора), которые анализируют резюме и определяют процент его соответствия вакансии.

Что делать, чтобы повысить шансы?

1️⃣ Добавить ключевые навыки в резюме — и в основной текст, и в теги. Возьмите их с easyoffer.ru

2️⃣ Убрать нерелевантный опыт, оставить только подходящий.

3️⃣ Оформить опыт так, чтобы он выглядел релевантным. Если у вас его нет, укажите проекты, стажировки или другой опыт, который можно представить как работу от 1 года. Если опыт слишком большой, сузьте его до 6 лет.

4️⃣ Откликаться на все вакансии без разбору. Если вы Junior, не ищите только стажер или Junior-вакансии — пробуйте везде. Не отказывайте себе сами, пусть это решит HR

5️⃣ Сделать резюме публичным, потому что HR-менеджеры часто ищут кандидатов не только среди откликов, но и в базе резюме.

6️⃣ Используйте ИИ по минимуму – ATS-системы считывают это и помечают "сгенерировано ИИ"

‼️ Главное правило: чем больше откликов — тем выше шанс получить оффер. Делайте резюме удобным для ATS-систем, и вас заметят.

1. Посмотрите видео о том как я вывел свою резюме в Топ1 на HH
2. Посмотрите видео как я нашел первую работу
3. Прочитайте этот кейс про оптимизацию резюме

Если прям вообще тяжело.

Создайте несколько разных резюме. Создайте 2, 3 да хоть 10 резюме. Настройте авто-отлики и ждите приглашения на собесы.

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

Golang | Вопросы собесов

10 Feb, 16:10


🤔 Можно ли использовать один и тот же буфер []byte в нескольких горутинах?

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


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

10 Feb, 09:10


🤔 В чем отличия http 1.1 и http 2?

Это версии протокола HTTP, каждая из которых имеет свои особенности и улучшения по сравнению с предыдущими версиями. Важные различия между этими версиями включают следующие аспекты:

🚩Мультиплексирование

🟠HTTP/1.1
Поддерживает одновременное открытие нескольких TCP соединений (обычно 6-8), что позволяет загружать несколько ресурсов параллельно. Однако каждое соединение может обрабатывать только один запрос за раз, что приводит к задержкам из-за блокировки очереди (head-of-line blocking).

🟠HTTP/2
Вводит мультиплексирование, позволяющее отправлять множество запросов и ответов асинхронно через одно единственное TCP соединение. Это значительно уменьшает задержки и улучшает производительность при загрузке страниц с большим количеством ресурсов.

🚩Бинарный протокол

🟠HTTP/1.1
Является текстовым протоколом, что означает, что запросы и ответы форматируются в виде читаемого текста.

🟠HTTP/2
Бинарный протокол, который делает передачу данных более эффективной и менее подверженной ошибкам в синтаксическом анализе. Бинарный формат упрощает реализацию парсеров и уменьшает размер передаваемых данных.

🚩Сжатие заголовков

🟠HTTP/1.1
Заголовки передаются без сжатия, что может привести к значительному объему передаваемых данных, особенно если одни и те же заголовки отправляются повторно с каждым запросом.

🟠HTTP/2
Использует механизм сжатия заголовков HPACK, который уменьшает избыточность заголовков, сжимая их перед отправкой. Это особенно эффективно для повторяющихся запросов к одним и тем же серверам.

🚩Приоритизация запросов

🟠HTTP/1.1
Не поддерживает приоритизацию запросов, из-за чего браузеры должны использовать эвристики для управления приоритетами ресурсов.

🟠HTTP/2
Поддерживает явную приоритизацию запросов, позволяя клиенту указывать приоритет обработки ресурсов, что делает загрузку страниц более эффективной.

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

09 Feb, 16:10


🤔 Что такое starvation/голодание?

Голодание (starvation) — ситуация, когда горутина или процесс не получают доступа к ресурсу из-за приоритета других задач. Причины:
1. Неправильное управление приоритетами.
2. Частое использование долгих блокировок (например, приоритетная блокировка RWMutex для записи).
Результат: одни задачи постоянно выполняются, другие блокируются бесконечно.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

09 Feb, 09:10


🤔 Что такое iota?

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

🚩Основные характеристики

🟠Инициализация с нуля
Начинает счет с 0 в каждой новой группе констант.
🟠Автоматическое увеличение
Каждое последующее использование iota в одной группе констант увеличивает его значение на 1.
🟠Повторное использование
При каждом новом объявлении константного блока iota сбрасывается до 0.

package main

import "fmt"

const (
A = iota // 0
B // 1
C // 2
)

func main() {
fmt.Println(A) // Вывод: 0
fmt.Println(B) // Вывод: 1
fmt.Println(C) // Вывод: 2
}


Использование его для создания битовых флагов
package main

import "fmt"

const (
Flag1 = 1 << iota // 1 << 0 = 1
Flag2 // 1 << 1 = 2
Flag3 // 1 << 2 = 4
Flag4 // 1 << 3 = 8
)

func main() {
fmt.Println(Flag1) // Вывод: 1
fmt.Println(Flag2) // Вывод: 2
fmt.Println(Flag3) // Вывод: 4
fmt.Println(Flag4) // Вывод: 8
}


Сброс его в новом блоке
package main

import "fmt"

const (
X = iota // 0
Y // 1
)

const (
Z = iota // 0 (новый блок констант, iota сбрасывается)
W // 1
)

func main() {
fmt.Println(X) // Вывод: 0
fmt.Println(Y) // Вывод: 1
fmt.Println(Z) // Вывод: 0
fmt.Println(W) // Вывод: 1
}


🚩Комплексное использование

Можно использовать в выражениях и совместно с другими константами для создания более сложных последовательностей.
package main

import "fmt"

const (
_ = iota // пропускаем 0
KB = 1 << (10 * iota) // 1 << 10 = 1024
MB // 1 << 20 = 1048576
GB // 1 << 30 = 1073741824
)

func main() {
fmt.Println("KB:", KB) // Вывод: KB: 1024
fmt.Println("MB:", MB) // Вывод: MB: 1048576
fmt.Println("GB:", GB) // Вывод: GB: 1073741824
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

08 Feb, 23:42


Привет, ребята!
1,5 года я учился на программиста, а сайт easyoffer.ru стал моим пет-проектом. Я создавал его, потому что:
а) нужно было добавить хоть какой-нибудь проект в резюме
б) подготовиться к прохождению собесов

И всё получилось! Благодаря еasyoffer я успешно прошёл собеседование и устроился Python Junior-разработчиком на удаленку с зарплатой 115 тысяч рублей.

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

По-этому я с самого начала заложил в проект минимальную бизнес-модель, на случай, если сайт начнёт набирать трафик. Я предложил пользователям полный доступ к сайту в обмен на подписку на Telegram-каналы. Это позволяло развивать аудиторию, а в будущем — зарабатывать на рекламе.

Результат превзошёл ожидания!
С момента запуска easyoffer посетило 400 тысяч человек. А когда доход с рекламы превысил мою зарплату программиста, я принял решение уйти с работы и полностью посвятить себя разработке новой версии сайта.

Вот так, зайдя в IT, через 4 месяца вышел через свой же пет-проект. Мне очень повезло

Уже год я работаю над easyoffer 2.0.
Это будет более масштабный и качественной новый проект:
– Появится тренажер
– Появятся задачи из собесов
– Фильтрация контента по грейдам
и еще очень много фич, о которых я расскажу позже.

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

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

Golang | Вопросы собесов

08 Feb, 16:10


🤔 Чем отличается RW мьютекс от обычного?

1. RWMutex (Read-Write Mutex):
- Позволяет нескольким горутинам одновременно читать данные (RLock/RUnlock).
- Запись (Lock/Unlock) блокирует всех, включая читателей.
2. Обычный Mutex:
- Полностью блокирует доступ, независимо от операции (чтение или запись).
RWMutex эффективнее для операций с преобладанием чтения.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

08 Feb, 09:10


🤔 Какие есть особенности синтаксиса получения и записи значений в map?

Карты (maps) представляют собой ассоциативные массивы, которые связывают ключи с соответствующими значениями. Работа с картами включает получение и запись значений, и Go предоставляет удобный синтаксис для этих операций. Рассмотрим особенности синтаксиса получения и записи значений в карты.

🚩Получение значений

🟠Простое получение значения по ключу
Для этого используется синтаксис индексирования
value := myMap[key]


Пример
package main

import "fmt"

func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}

value := myMap["Alice"]
fmt.Println("Alice:", value) // Alice: 25
}


🟠Проверка существования ключа
Для этого используется синтаксис двойного присваивания
value, exists := myMap[key]


Пример
package main

import "fmt"

func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}

value, exists := myMap["Charlie"]
if exists {
fmt.Println("Charlie:", value)
} else {
fmt.Println("Charlie not found")
}
}


🚩Запись значений

🟠Добавление или обновление значения
Для этого используется синтаксис индексирования:
myMap[key] = value


Пример
package main

import "fmt"

func main() {
myMap := map[string]int{}

// Добавление значений
myMap["Alice"] = 25
myMap["Bob"] = 30

fmt.Println("Map:", myMap) // Map: map[Alice:25 Bob:30]

// Обновление значения
myMap["Alice"] = 26
fmt.Println("Updated Map:", myMap) // Updated Map: map[Alice:26 Bob:30]
}


🟠Удаление значений из карты
Для этого используется встроенная функция delete:
delete(myMap, key)


Пример
package main

import "fmt"

func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}

// Удаление значения по ключу
delete(myMap, "Alice")
fmt.Println("Map after deletion:", myMap) // Map after deletion: map[Bob:30]
}


🟠Подводные камни и особенности

🟠Отсутствие ключа
Если ключ отсутствует в карте, при попытке получения значения будет возвращено нулевое значение типа значения карты. Например, для карты map[string]int это будет 0.
        package main

import "fmt"

func main() {
myMap := map[string]int{
"Alice": 25,
}

value := myMap["Bob"] // Ключ "Bob" отсутствует
fmt.Println("Value:", value) // Value: 0
}


🟠Запись в неинициализированную карту
Нельзя записывать значения в nil карту. Это приведет к панике времени выполнения.
        package main

func main() {
var myMap map[string]int // nil карта
myMap["Alice"] = 25 // Вызовет панику: runtime error: assignment to entry in nil map
}


🟠Итерация по карте
Порядок итерации по карте не определен и может различаться между разными запусками программы.
        package main

import "fmt"

func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
"Carol": 35,
}

for key, value := range myMap {
fmt.Printf("%s: %d\n", key, value)
}
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

07 Feb, 16:10


🤔 Как объединить по смыслу Map и Мьютексы?

Для безопасного использования карты (Map) в многопоточном окружении:
1. Создайте карту и мьютекс как пару.
2. Заблокируйте мьютекс перед доступом к карте, разблокируйте после.
3. Используйте sync.Map, если не хотите вручную управлять блокировками.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

07 Feb, 09:10


🤔 Что такое репликация?

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

🚩Цели

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

🟠Распределение нагрузки
Может помочь распределить запросы чтения между несколькими узлами, тем самым уменьшая нагрузку на один сервер и улучшая время отклика в приложениях.

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

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

🚩Типы

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

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

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

06 Feb, 16:10


🤔 Что известно о sync.Map?

Это потокобезопасная структура данных для одновременного доступа из нескольких горутин:
1. Не требует мьютексов для чтения/записи.
2. Оптимизирован для сценариев с частым чтением и редкой записью.
3. Поддерживает методы Load, Store, Delete, Range.
Подходит для кэшей и других сценариев, где производительность важнее.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

06 Feb, 09:10


🤔 Зачем нужна Grafana?

Grafana — это инструмент для визуализации и мониторинга данных. Он позволяет строить дашборды (панели) с графиками, метриками и алертами, получая данные из различных источников (Prometheus, InfluxDB, Loki, MySQL и других).

🚩Основные возможности Grafana

🟠Визуализация данных
создание графиков, таблиц, гистограмм и других визуальных представлений.
🟠Мониторинг в реальном времени
отслеживание метрик серверов, баз данных, контейнеров и микросервисов.
🟠Гибкость источников данных
поддерживает Prometheus, Elasticsearch, MySQL, PostgreSQL и десятки других.
🟠Настраиваемые алерты
оповещения (email, Slack, Telegram) при достижении критических значений.
🟠Дашборды для DevOps
удобный интерфейс для анализа производительности систем.

🚩Зачем нужна Grafana?

🟠Для мониторинга серверов и приложений
Можно отслеживать загрузку CPU, RAM, количество запросов в базе, ошибки и задержки API.

🟠Для DevOps и SRE
Позволяет наблюдать за работой Kubernetes, Docker, CI/CD-пайплайнов и микросервисов.

🟠Для бизнес-аналитики
Может использоваться для отображения KPI, продаж, конверсий и других данных.

🟠Для алертов и оповещений
Если сервер падает или нагрузка превышает порог – Grafana уведомит команду.

🚩Пример использования Grafana с Prometheus

Устанавливаем Prometheus и Grafana
Добавляем Prometheus как источник данных в Grafana
Создаём дашборд с метриками, например
Количество HTTP-запросов
Время ответа сервера
Количество активных соединений
http_requests_total{job="web_service"}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

05 Feb, 16:10


🤔 Зачем нужны WaitGroup?

WaitGroup синхронизирует выполнение нескольких горутин:
1. Добавляет счетчик с количеством ожидаемых горутин.
2. Горутины уменьшают счетчик вызовом Done() после завершения.
3. Ожидание завершения всех горутин выполняется через Wait().
Используется для управления параллельными задачами и предотвращения преждевременного завершения программы.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

05 Feb, 09:10


🤔 Какие функции у map?

Карты (maps) предоставляют несколько основных функций и операций для работы с ними. Эти функции позволяют добавлять, удалять, получать значения и проверять наличие ключей в карте.

🚩Основные операции

🟠Объявление карты
Для этого используется ключевое слово map, после которого указываются типы ключей и значений.
var myMap map[string]int


🟠Инициализация карты
Это можно сделать с помощью функции make или литерала карты.
// Инициализация с помощью make
myMap = make(map[string]int)

// Инициализация с помощью литерала карты
myMap = map[string]int{
"Alice": 25,
"Bob": 30,
}


🟠Добавление и обновление элементов
Для этого используется синтаксис индексирования.
myMap["Charlie"] = 35
myMap["Alice"] = 26 // обновление значения по ключу "Alice"


🟠Извлечение значения по ключу
Для этого используется синтаксис индексирования.
age := myMap["Alice"]
fmt.Println(age) // 26


🟠Проверка существования ключа
Чтобы проверить это можно использовать двойное присваивание.
age, exists := myMap["David"]
if exists {
fmt.Println("Age of David:", age)
} else {
fmt.Println("David not found")
}


🟠Удаление элемента
Для этого используется встроенная функция delete.
delete(myMap, "Bob")


🟠Итерация по карте
Для этого используется цикл for range.
for key, value := range myMap {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}


Пример
package main

import (
"fmt"
)

func main() {
// Инициализация карты с помощью литерала
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}

// Добавление нового элемента
myMap["Charlie"] = 35

// Обновление существующего элемента
myMap["Alice"] = 26

// Извлечение значения по ключу
age := myMap["Alice"]
fmt.Println("Age of Alice:", age) // 26

// Проверка существования ключа
age, exists := myMap["David"]
if exists {
fmt.Println("Age of David:", age)
} else {
fmt.Println("David not found")
}

// Удаление элемента
delete(myMap, "Bob")

// Итерация по карте
for key, value := range myMap {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

04 Feb, 16:10


🤔 Что известно про аналог default в select?

Select с default позволяет немедленно выполнять код, если нет доступных каналов. Это полезно для обработки задач без блокировки:
- Выполняет действие, если нет данных для чтения/записи.
- Используется для таймаутов, проверки состояния или фоновых операций.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

04 Feb, 09:10


🤔 Какие сущности есть в планировщике?

Планировщик задач (Scheduler) управляет выполнением процессов и горутин (в случае Go). В контексте операционных систем и языков программирования, таких как Golang, планировщик отвечает за распределение вычислительных ресурсов.

🟠G (Goroutine) – Горутинa
Это легковесный поток, который выполняет код. В отличие от ОС-потоков, она не требует большого количества памяти и управляется рантаймом Go.
Включает стек, контекст выполнения, а также статус (ждёт, выполняется, завершена).
Переключается между потоками ОС прозрачно для разработчика.
Можно создать десятки тысяч горутин без значительных затрат памяти.
go func() {
fmt.Println("Привет из горутины!")
}()


🟠M (Machine) – Операционный поток
M (Machine) представляет собой реальный поток ОС (kernel thread), на котором выполняются горутины.
Соответствует потокам ОС (pthread в Linux, Windows Thread в Windows).
Может одновременно выполнять только одну горутину.
Количество M зависит от GOMAXPROCS, но обычно Go создаёт столько потоков, сколько ядер в системе.
runtime.GOMAXPROCS(4) // Использовать 4 ядра процессора


🟠P (Processor) – Планировщик (Scheduler)
Это сущность, которая отвечает за распределение горутин (G) между потоками (M).
P управляет очередью горутин и раздаёт их потокам (M).
По умолчанию количество P равно количеству GOMAXPROCS.
Горутину нельзя выполнить без доступного P.
[Processor P1] ----> [Machine M1] ----> Выполняет горутины G1, G2
[Processor P2] ----> [Machine M2] ----> Выполняет горутины G3, G4


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

03 Feb, 16:10


🤔 Что следует помнить при работе с мьютексами?

1. Избегайте длительной блокировки: Держите мьютекс заблокированным только на время выполнения критической секции.
2. Всегда разблокируйте мьютекс: Используйте defer для автоматического вызова Unlock.
3. Не вызывать блокировки в неправильном порядке: Избегайте взаимной блокировки (deadlock).
4. Используйте минимальное количество мьютексов: Чем больше мьютексов, тем выше вероятность ошибок.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

03 Feb, 09:10


🤔 Что такое составной индекс?

Составной индекс (Composite Index) — это индекс, который создаётся сразу на нескольких колонках таблицы базы данных. Он помогает ускорить поиск и сортировку данных, особенно если запросы используют условия по нескольким полям.

🚩Зачем нужен составной индекс?

🟠Оптимизация запросов
Если часто выполняются запросы с фильтрацией по нескольким колонкам (WHERE col1 = X AND col2 = Y), составной индекс ускоряет их выполнение.
🟠Ускорение сортировки
Если запросы используют ORDER BY col1, col2, индекс помогает избежать дополнительной сортировки.
🟠Снижение нагрузки на сервер
Без индекса СУБД вынуждена выполнять полный перебор (Full Table Scan), что занимает больше времени.

🚩Как работает составной индекс?

Он строится по нескольким колонкам и фактически представляет собой отсортированную структуру данных. Например, в PostgreSQL или MySQL создаётся так:
CREATE INDEX idx_name ON users (last_name, first_name);


Теперь база данных будет использовать индекс для запросов:
SELECT * FROM users WHERE last_name = 'Иванов' AND first_name = 'Петр';


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

02 Feb, 16:10


🤔 Способы поиска проблем производительности на проде

Используйте метрики и мониторинг (Prometheus, Grafana), профилирование (pprof) и логирование медленных операций. Инструменты анализа нагрузки, такие как JMeter, помогут выявить узкие места.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

02 Feb, 09:10


🤔 Go — императивный или декларативный?

Go — это императивный язык программирования.

🚩Почему Go императивный?

Императивное программирование означает, что программист явно указывает шаги, которые необходимо выполнить для достижения результата. Код в Go представляет собой последовательность команд, изменяющих состояние программы.
package main

import "fmt"

func main() {
sum := 0
for i := 1; i <= 5; i++ {
sum += i // Явно изменяем переменную sum
}
fmt.Println("Сумма:", sum)
}


🚩Декларативные элементы в Go

Хотя Go — это в первую очередь императивный язык, в нем есть элементы декларативного подхода. Например:
🟠Функциональные элементы
map, filter через срезы и функции высшего порядка.
🟠Структурированность кода
интерфейсы позволяют писать код, в котором детали реализации скрыты (инкапсуляция).
🟠Go concurrency (goroutines, channels)
вместо явного управления потоками, мы декларируем взаимодействие через каналы.

package main

import "fmt"

func mapSlice(slice []int, f func(int) int) []int {
result := make([]int, len(slice))
for i, v := range slice {
result[i] = f(v) // Декларативное применение функции к элементам
}
return result
}

func main() {
nums := []int{1, 2, 3, 4, 5}
squared := mapSlice(nums, func(n int) int { return n * n })
fmt.Println(squared) // [1 4 9 16 25]
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

01 Feb, 16:10


🤔 Как можно измерить использование памяти?

Используйте runtime.ReadMemStats для получения данных о памяти или pprof для профилирования, чтобы выявить функции с высоким потреблением ресурсов. Профили можно анализировать через CLI или визуализировать.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

01 Feb, 09:10


🤔 Почему пустой интерфейс можно привести к любому типу?

В Go пустой интерфейс interface{} является особым типом, который может содержать значение любого типа. Это связано с тем, что в Go любой тип реализует пустой интерфейс, поскольку в нем нет методов, которые нужно реализовать.

🚩Пустой интерфейс

Поскольку пустой интерфейс не требует реализации каких-либо методов, любой тип в Go автоматически реализует этот интерфейс. Это делает пустой интерфейс универсальным контейнером для значений любых типов.
type interface{} interface {}


🚩Внутреннее представление интерфейсов в Go

🟠Type
Типа конкретного значения
🟠Value
Самого значения

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

🚩Приведение пустого интерфейса к конкретному типу

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

Присваивание значений пустому интерфейсу
package main

import "fmt"

func main() {
var i interface{}
i = 42
fmt.Println(i) // 42

i = "hello"
fmt.Println(i) // hello
}


Утверждение типа (Type Assertion)
package main

import "fmt"

func main() {
var i interface{} = "hello"

// Утверждение типа с проверкой
s, ok := i.(string)
if ok {
fmt.Println("String:", s)
} else {
fmt.Println("Not a string")
}

// Утверждение типа без проверки
// Это вызовет панику, если тип не соответствует
s = i.(string)
fmt.Println("String:", s)
}


Использование switch для проверки типа
package main

import "fmt"

func printType(i interface{}) {
switch v := i.(type) {
case string:
fmt.Println("String:", v)
case int:
fmt.Println("Integer:", v)
case bool:
fmt.Println("Boolean:", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}

func main() {
printType("hello")
printType(42)
printType(true)
printType(3.14)
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

31 Jan, 16:10


🤔 Как можно описать принцип работы lock-free?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

31 Jan, 09:10


🤔 Сравни, как реализован ООП в Go и C#?

Объектно-ориентированное программирование (ООП) в Go и C# реализовано с использованием различных подходов и парадигм, отражающих философию и дизайн каждого языка.

🚩Go

🟠Классы и объекты
Используются структуры (struct).
type Person struct {
Name string
Age int
}

func (p *Person) Greet() {
fmt.Printf("Hello, my name is %s\n", p.Name)
}


🟠Наследование
Используется композиция вместо наследования.
type Employee struct {
Person
Position string
}


🟠Инкапсуляция
Модификаторы доступа на уровне пакета (экспортируемые и неэкспортируемые поля).
type Person struct {
name string // неэкспортируемое поле
Age int // экспортируемое поле
}


🟠Полиморфизм
Реализуется через интерфейсы.
type Greeter interface {
Greet()
}

type Person struct {
Name string
}

func (p *Person) Greet() {
fmt.Printf("Hello, my name is %s\n", p.Name)
}


🚩C#

🟠Классы и объекты
Используются классы.
public class Person {
public string Name { get; set; }
public int Age { get; set; }

public void Greet() {
Console.WriteLine($"Hello, my name is {Name}");
}
}


🟠Наследование
Поддерживается классическое наследование.
public class Employee : Person {
public string Position { get; set; }
}


🟠Инкапсуляция
Модификаторы доступа (public, private, protected).
public class Person {
private string name;
public int Age { get; set; }
}


🟠Полиморфизм
Через виртуальные методы и интерфейсы.
public class Person {
public virtual void Greet() {
Console.WriteLine("Hello!");
}
}

public class Employee : Person {
public override void Greet() {
Console.WriteLine("Hello, I am an employee!");
}
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

30 Jan, 16:10


🤔 Что известно о lock-free концепции?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

30 Jan, 09:10


🤔 Что такое NAT?

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

🚩Основные типы

🟠Статический NAT (Static NAT):
Фиксированный сопоставление: Один внутренний IP-адрес сопоставляется с одним внешним IP-адресом. Используется, когда необходимо, чтобы устройство в локальной сети всегда было доступно под одним и тем же публичным IP-адресом. Например Веб-сервер, который должен быть доступен из интернета под фиксированным IP-адресом.

🟠Динамический NAT (Dynamic NAT):
Внутренние IP-адреса сопоставляются с пулом внешних IP-адресов. Когда внутреннее устройство инициирует соединение с интернетом, ему временно присваивается один из доступных внешних IP-адресов. Например, локальная сеть с большим количеством устройств, где не требуется фиксированный внешний IP-адрес для каждого устройства.

🟠Преобразование адресов и портов (PAT, Port Address Translation), также известный как Маскарадинг (Masquerading):
Несколько внутренних IP-адресов могут использовать один внешний IP-адрес, но различаются по номерам портов. Каждый внутренний IP-адрес и порт сопоставляется с уникальным внешним портом. Например, Домашние или офисные сети, где множество устройств выходят в интернет через один публичный IP-адрес.

🚩Зачем нужен

🟠Сохранение IP-адресов:
IPv4-адресов недостаточно для всех устройств, и NAT позволяет использовать один публичный IP-адрес для множества устройств.

🟠Безопасность:
Внутренние IP-адреса не видны извне, что усложняет потенциальным злоумышленникам попытки атак на внутренние устройства.

🟠Управление подключениями:
NAT позволяет администрировать и контролировать сетевой трафик, предоставляя возможности для управления доступом и приоритизацией трафика.

🚩Принцип работы

🟠Инициирование соединения:
Когда устройство в локальной сети (например, компьютер с IP-адресом 192.168.1.10) инициирует соединение с устройством в интернете, NAT изменяет исходящий IP-адрес и порт на внешний IP-адрес маршрутизатора и уникальный номер порта.

🟠Ответный трафик:
Когда ответный пакет возвращается, NAT использует таблицу сопоставлений, чтобы определить, к какому внутреннему устройству направить пакет, и изменяет внешний IP-адрес и порт обратно на внутренний IP-адрес и порт.

🚩Пример работы PAT

1⃣Внутренний компьютер с IP-адресом 192.168.1.10 и портом 12345 инициирует соединение.
2⃣NAT изменяет это на внешний IP-адрес 203.0.113.1 и порт 54321.
3⃣Ответный пакет от сервера приходит на IP-адрес 203.0.113.1 и порт 54321.
4⃣NAT преобразует это обратно в 192.168.1.10:12345 и отправляет пакет внутреннему компьютеру.

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

29 Jan, 16:10


🤔 Как тестировать распределённую систему?

Тестировать распределённую систему можно через симуляцию нагрузки с помощью инструментов вроде Apache JMeter или Locust, проверку устойчивости к отказам (chaos engineering), и мониторинг метрик в реальном времени.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

29 Jan, 09:10


🤔 Как можно откопировать слайс?

Слайсы являются ссылочными типами, поэтому простое присваивание одного слайса другому создаст новую ссылку на тот же подлежащий массив. Если вы хотите создать копию слайса с независимым подлежащим массивом, можно использовать встроенную функцию copy или методы, такие как использование append.

🚩Способы копирования слайса

🟠Использование функции `copy`
Создает побайтовую копию элементов из одного слайса в другой.
package main

import "fmt"

func main() {
original := []int{1, 2, 3, 4, 5}

// Создаем новый слайс той же длины, что и оригинал
copySlice := make([]int, len(original))

// Копируем элементы из оригинального слайса в новый
copy(copySlice, original)

// Изменяем элемент в копии
copySlice[0] = 100

fmt.Println("Оригинал:", original) // Выводит: Оригинал: [1 2 3 4 5]
fmt.Println("Копия:", copySlice) // Выводит: Копия: [100 2 3 4 5]
}


Использование функции
inal)   


Чтобы создать новый слайс с копированными элементами.
package main

import "fmt"

func main() {
original := []int{1, 2, 3, 4, 5}

// Копируем элементы из оригинального слайса в новый слайс
copySlice := append([]int(nil), original...)

// Изменяем элемент в копии
copySlice[0] = 100

fmt.Println("Оригинал:", original) // Выводит: Оригинал: [1 2 3 4 5]
fmt.Println("Копия:", copySlice) // Выводит: Копия: [100 2 3 4 5]
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

28 Jan, 16:10


🤔 Как проверить тип переменной в среде выполнения?

Можно использовать встроенную функцию reflect.TypeOf() из пакета reflect для определения типа переменной.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

28 Jan, 09:10


🤔 Как завершить много горутин?

Завершение множества горутин требует организованного подхода, так как управление ими не предоставляет прямых средств для их остановки. Основные практики включают использование каналов для сигнализации о необходимости завершения, контекстов для управления временем выполнения и ограничениями, а также синхронизации с помощью sync.WaitGroup. Вот каждый из этих методов.

🚩Использование каналов для управления горутинами

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

import (
"fmt"
"sync"
"time"
)

func worker(stopCh <-chan struct{}, wg *sync.WaitGroup, id int) {
defer wg.Done()
for {
select {
case <-stopCh:
fmt.Printf("Worker %d stopping\n", id)
return
default:
// выполнение полезной работы
fmt.Printf("Worker %d working\n", id)
time.Sleep(time.Second)
}
}
}

func main() {
var wg sync.WaitGroup
stopCh := make(chan struct{})

// запуск горутин
for i := 0; i < 3; i++ {
wg.Add(1)
go worker(stopCh, &wg, i)
}

// остановка горутин после 3 секунд
time.Sleep(3 * time.Second)
close(stopCh) // отправка сигнала всем горутинам остановиться
wg.Wait() // ожидание завершения всех горутин
}


🟠Использование пакета context

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

import (
"context"
"fmt"
"sync"
"time"
)

func worker(ctx context.Context, wg *sync.WaitGroup, id int) {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Printf("Worker %d stopping\n", id)
return
default:
// выполнение полезной работы
fmt.Printf("Worker %d working\n", id)
time.Sleep(time.Second)
}
}
}

func main() {
var wg sync.WaitGroup
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)

// запуск горутин
for i := 0; i < 3; i++ {
wg.Add(1)
go worker(ctx, &wg, i)
}

wg.Wait() // ожидание завершения всех горутин
cancel() // убедиться, что все ресурсы освобождены
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

27 Jan, 16:10


🤔 Есть отличия между SSL и TLS?

Да, TLS безопаснее и быстрее, поддерживает более современные криптографические алгоритмы и протоколы, в отличие от устаревшего SSL, который более подвержен уязвимостям.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

27 Jan, 09:10


🤔 Для чего используют индексы?

Это целочисленные значения, которые используются для доступа к элементам упорядоченных структур данных. В контексте Go индексы чаще всего применяются для работы со строками, массивами, срезами, а также картами (косвенно, через ключи).

🚩Для чего нужны индексы?

🟠Доступ к элементам по их позиции
Индексы позволяют обращаться к конкретным элементам массива, строки или среза. Например, если у нас есть массив чисел, индекс указывает, какой именно элемент извлечь.

🟠Навигация внутри коллекций
С помощью индексов можно перебирать элементы массива, строки или среза, например, используя циклы.

🟠Изменение значений (если структура изменяема)
В изменяемых структурах данных, таких как срезы или массивы, индекс позволяет присвоить новое значение конкретному элементу.

🟠Оптимизация поиска
Индексы упрощают и ускоряют доступ к данным, потому что доступ осуществляется за O(1) (константное время) в массивах или срезах.

🟠Индексы в строках
В строках индексы используются для доступа к конкретным байтам.
package main

import "fmt"

func main() {
str := "Привет"

fmt.Println(str[0]) // 208 (байт, не символ!)
fmt.Printf("%c\n", str[0]) // П (символ, представленный первым байтом UTF-8)
}


🟠Индексы в массивах и срезах
В массивах и срезах индексы используются для извлечения и изменения значений
package main

import "fmt"

func main() {
arr := [5]int{10, 20, 30, 40, 50}

fmt.Println(arr[2]) // 30

// Изменение значения по индексу
arr[2] = 100
fmt.Println(arr) // [10 20 100 40 50]
}


🟠Как использовать индексы в циклах
Обычно индексы используются для итерации по элементам коллекции с помощью цикла for.
package main

import "fmt"

func main() {
nums := []int{10, 20, 30, 40, 50}

for i, v := range nums {
fmt.Printf("Индекс: %d, Значение: %d\n", i, v)
}
}


🟠Индексы и подстроки
Индексы полезны для извлечения подстрок с использованием срезов:
package main

import "fmt"

func main() {
str := "Привет, Мир!"

fmt.Println(str[8:12]) // Мир
}


🚩Ошибки работы с индексами

🟠Выход за границы
Если попытаться обратиться к элементу по индексу, который выходит за пределы коллекции, Go выдаст runtime panic:
   package main

func main() {
nums := []int{1, 2, 3}
fmt.Println(nums[5]) // panic: runtime error: index out of range
}


🟠Работа с многобайтовыми символами в строках
Если неверно учитывать байтовое представление символов UTF-8, можно получить некорректный результат.

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

26 Jan, 16:10


🤔 Что такое TLS?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

26 Jan, 09:10


🤔 В чем разница процесса и потока в рамках операционной системы?

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

🚩Процесс

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

🚩Поток (Thread)

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

🚩Основные различия

🟠Изоляция
Процессы изолированы друг от друга, в то время как потоки делят состояние и ресурсы внутри одного процесса.

🟠Память
Каждый процесс имеет собственное адресное пространство, в то время как все потоки внутри процесса делят его адресное пространство.

🟠Создание и управление
Создание нового процесса более ресурсоемко, чем создание потока внутри существующего процесса.

🟠Взаимодействие
Взаимодействие между процессами требует использования межпроцессного взаимодействия (IPC), такого как сокеты, разделяемая память, очереди сообщений и т. д. Потоки внутри процесса могут общаться друг с другом напрямую через общую память.

🟠Надежность и безопасность
Ошибка в одном процессе обычно не влияет на другие процессы, но ошибка в одном потоке может привести к сбою всего процесса.

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

25 Jan, 16:10


🤔 Что такое SSL?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

25 Jan, 09:10


🤔 Как можно оперировать строками?

Это неизменяемые последовательности байтов, обычно представляющие текст в кодировке UTF-8. Работа с ними в Go основывается на использовании встроенных функций, методов стандартной библиотеки и специальных типов данных.

🟠Конкатенация строк
Самый простой способ объединить строки — использовать оператор + или функцию fmt.Sprintf.
package main

import "fmt"

func main() {
s1 := "Привет"
s2 := "Мир"
result := s1 + ", " + s2 + "!"
fmt.Println(result) // Привет, Мир!

// Через fmt.Sprintf
formatted := fmt.Sprintf("%s, %s!", s1, s2)
fmt.Println(formatted) // Привет, Мир!
}


🟠Получение длины строки
Функция len возвращает длину строки в байтах, а не в символах.
package main

import "fmt"

func main() {
str := "Привет"
fmt.Println(len(str)) // 12, так как кириллические символы занимают 2 байта
}


🟠Итерация по строке
Строки можно обойти как в виде байтов, так и в виде рун (Unicode символов).
package main

import (
"fmt"
"unicode/utf8"
)

func main() {
str := "Привет"

// Итерация по байтам
for i := 0; i < len(str); i++ {
fmt.Printf("Байт: %x\n", str[i])
}

// Итерация по символам (рунам)
for _, runeValue := range str {
fmt.Printf("Символ: %c\n", runeValue)
}

// Количество рун
fmt.Println("Количество символов:", utf8.RuneCountInString(str))
}


🟠Извлечение подстроки
Так как строки неизменяемы, для извлечения подстроки используется срез (slice).
package main

import "fmt"

func main() {
str := "Привет, Мир!"
substring := str[8:] // С 8-го байта до конца
fmt.Println(substring) // Мир!
}


🟠Разделение и объединение строк
Функции strings.Split и strings.Join из пакета strings позволяют разбивать строку на части или объединять части в строку.
package main

import (
"fmt"
"strings"
)

func main() {
str := "apple,banana,cherry"

// Разделение строки
parts := strings.Split(str, ",")
fmt.Println(parts) // [apple banana cherry]

// Объединение строк
joined := strings.Join(parts, " | ")
fmt.Println(joined) // apple | banana | cherry
}


🟠Поиск и замена подстроки
Для поиска подстроки можно использовать strings.Contains, strings.Index или strings.HasPrefix/strings.HasSuffix. Для замены — strings.Replace.
package main

import (
"fmt"
"strings"
)

func main() {
str := "Go — это круто!"

// Поиск подстроки
fmt.Println(strings.Contains(str, "круто")) // true
fmt.Println(strings.Index(str, "это")) // 4

// Замена подстроки
newStr := strings.Replace(str, "круто", "отлично", 1)
fmt.Println(newStr) // Go — это отлично!
}


🟠Преобразование регистра
Стандартная библиотека предоставляет функции для изменения регистра строки: strings.ToLower и strings.ToUpper.
package main

import (
"fmt"
"strings"
)

func main() {
str := "Hello, Go!"
fmt.Println(strings.ToUpper(str)) // HELLO, GO!
fmt.Println(strings.ToLower(str)) // hello, go!
}


🟠Тримминг строки
Удаление пробелов или других символов с начала/конца строки выполняется с помощью strings.Trim, strings.TrimSpace и других функций.
package main

import (
"fmt"
"strings"
)

func main() {
str := " Hello, Go! "
fmt.Println(strings.TrimSpace(str)) // "Hello, Go!"
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

24 Jan, 16:10


🤔 Опишите плюсы и минусы микросервисной архитектуры.

Плюсы: масштабируемость, гибкость в разработке и развертывании, изоляция ошибок.
Минусы: сложность разработки, взаимодействия сервисов, управление данными и отладка.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

23 Jan, 16:10


🤔 Чем отличается микросервис от монолита?

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


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

23 Jan, 09:10


🤔 Что такое Go?

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

🚩Основные характеристики

🟠Компиляция и скорость
Go — компилируемый язык, обеспечивающий высокую производительность.
🟠Простота
Язык избегает избыточности, улучшая читаемость кода.
🟠Сборка мусора
Автоматическое управление памятью.
🟠Конкурентность
Встроенные средства для работы с параллельными вычислениями, такие как горутины и каналы.
🟠Стандартная библиотека
Широкий набор инструментов и библиотек.

🚩Пример простого приложения

Простого веб-сервера:
package main

import (
"fmt"
"net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}

func main() {
http.HandleFunc("/", helloHandler)
fmt.Println("Starting server on :8080")
http.ListenAndServe(":8080", nil)
}


🚩Основные концепции

🟠Горутины
Легковесные потоки для параллельных вычислений.
go func() {
fmt.Println("Hello from a goroutine!")
}()


🟠Каналы
Средства обмена данными между горутинами.
ch := make(chan int)
go func() {
ch <- 42
}()
value := <-ch
fmt.Println(value)


🟠Интерфейсы
Абстракция поведения без привязки к реализации.
type Stringer interface {
String() string
}


🟠Пакеты
Организация кода для управления и повторного использования.
package mypackage

import "fmt"

func MyFunction() {
fmt.Println("Hello from mypackage")
}


🚩Применение Go

Go используется для серверного ПО, облачных сервисов, микросервисов, инструментов командной строки и систем с высокой производительностью. Известные проекты на Go включают Kubernetes, Docker, Prometheus, а также Google, Dropbox и Netflix.

🚩Плюсы и минусы

Высокая производительность
Быстро компилируемый язык.
Простота и читаемость
Минимум синтаксического шума.
Конкурентность
Простые механизмы параллельных вычислений.
Богатая библиотека
Широкий набор встроенных инструментов.
Ограниченные обобщения
Ранее отсутствовали, добавлены в Go 1.18.
Нет исключений
Используется управление ошибками через возвращаемые значения.

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

22 Jan, 16:10


🤔 Что такое РПС?

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


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

22 Jan, 11:29


📺 Уникальная база IT собеседований

370+ реальных собеседований на программиста, тестировщика, аналитика и прочие IT профы.

Есть собесы от ведущих компаний: Сбер, Яндекс, ВТБ, Тинькофф, Озон, Wildberries и т.д.

🎯 Переходи по ссылке и присоединяйся к базе, чтобы прокачать свои шансы на успешное трудоустройство!

Golang | Вопросы собесов

22 Jan, 09:10


🤔 Почему нельзя брать ссылку на значение, хранящееся по ключу в map?

Нельзя напрямую взять ссылку на значение, хранящееся по ключу в карте (map), из-за особенностей реализации карт и управления памятью. Рассмотрим подробнее, почему это так.

🚩Причины, почему нельзя брать ссылку на значение в карте

🟠Внутреннее устройство карты (map)
Карты реализованы на основе хеш-таблиц. Внутреннее устройство карты предполагает, что значения могут перемещаться в памяти при выполнении операций, таких как добавление или удаление элементов. Хеш-таблица может перераспределять (реорганизовывать) свои внутренние структуры для оптимизации доступа к элементам. Это может происходить, например, когда карта увеличивается в размере.

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

🚩Демонстрация проблемы

Здесь попытка взять ссылку на значение из карты могла бы привести к проблемам
package main

import "fmt"

func main() {
m := map[string]int{"a": 1, "b": 2}

// Нельзя делать так:
// p := &m["a"]

// Вместо этого можно работать с копией значения
value := m["a"]
p := &value

fmt.Println("Value:", *p) // 1

// Изменение карты
m["c"] = 3

// Ссылка на значение в карте могла бы стать недействительной
// fmt.Println("Value after map change:", *p)
}


🚩Правильные способы работы со значениями карты

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

🟠Работа с копией значения
Получить значение из карты и сохранить его в переменную.
value := m["a"]   


🟠Изменение значения в карте
Если необходимо изменить значение в карте, его нужно сначала извлечь, изменить, а затем снова записать в карту.
value := m["a"]
value = value + 10
m["a"] = value


🟠Использование указателей в качестве значений
В некоторых случаях можно использовать указатели в качестве значений карты, чтобы можно было изменять значения через указатели.
   package main

import "fmt"

func main() {
m := map[string]*int{"a": new(int), "b": new(int)}
*m["a"] = 1
*m["b"] = 2

// Теперь можно брать указатели на значения
p := m["a"]
fmt.Println("Value:", *p) // 1

// Изменение значения через указатель
*p = 42
fmt.Println("Updated Value:", *m["a"]) // 42
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

21 Jan, 16:10


🤔 Что такое хеш-функция?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

21 Jan, 09:10


🤔 Как устроен массив в Go?

Массивы представляют собой фиксированную последовательность элементов одного типа. Являются основополагающей структурой данных, на базе которой строятся более сложные структуры, такие как слайсы. Рассмотрим, как устроены массивы, их особенности, а также сравнение с другими структурами данных.

🚩Основные характеристики

🟠Фиксированный размер
Размер массива задается при его объявлении и не может изменяться во время выполнения программы.
🟠Тип элементов
Все элементы массива имеют один и тот же тип.
🟠Непосредственное хранение данных
В отличие от слайсов, массивы хранят свои элементы в непрерывном блоке памяти.

🟠Объявление массива
С указанием типа элементов и фиксированного размера. Это объявление создает массив из пяти целых чисел, инициализированных нулями.
var arr [5]int


🟠Инициализация массива
Массивы могут быть инициализированы при объявлении
arr := [5]int{1, 2, 3, 4, 5}


Можно также инициализировать массив частично, оставив остальные элементы равными нулям:
arr := [5]int{1, 2}


🟠Доступ к элементам
Осуществляется с использованием индексов, начиная с 0
fmt.Println(arr[0]) // 1
arr[1] = 10
fmt.Println(arr[1]) // 10


🟠Длина массива
Фиксирована и задается при его объявлении. Ее можно получить с помощью функции len
fmt.Println(len(arr)) // 5


🟠Копирование массива
При присваивании одного массива другому копируются все элементы:
arr1 := [5]int{1, 2, 3, 4, 5}
arr2 := arr1
arr2[0] = 10
fmt.Println(arr1) // [1 2 3 4 5]
fmt.Println(arr2) // [10 2 3 4 5]


🟠Передача массива в функции
При этом копируется весь массив:
func modifyArray(a [5]int) {
a[0] = 10
}

arr := [5]int{1, 2, 3, 4, 5}
modifyArray(arr)
fmt.Println(arr) // [1 2 3 4 5]


🚩Сравнение

🟠Размер
Массивы имеют фиксированный размер, тогда как слайсы динамичны.

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

🟠Гибкость: Слайсы более гибки благодаря динамическому изменению размера и доступным методам.

Использование массивов
package main

import (
"fmt"
)

func main() {
// Объявление и инициализация массива
arr := [5]int{1, 2, 3, 4, 5}

// Доступ к элементам
fmt.Println("First element:", arr[0]) // First element: 1

// Изменение элементов
arr[1] = 10
fmt.Println("Modified array:", arr) // Modified array: [1 10 3 4 5]

// Длина массива
fmt.Println("Length of array:", len(arr)) // Length of array: 5

// Копирование массива
arr2 := arr
arr2[0] = 20
fmt.Println("Original array:", arr) // Original array: [1 10 3 4 5]
fmt.Println("Copied array:", arr2) // Copied array: [20 10 3 4 5]

// Передача массива в функцию
modifyArray(arr)
fmt.Println("Array after modifyArray call:", arr) // Array after modifyArray call: [1 10 3 4 5]
}

func modifyArray(a [5]int) {
a[0] = 10
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

20 Jan, 16:10


🤔 Что такое массив (array)?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

20 Jan, 09:10


🤔 Что возвращает оператор "квадратные скобки" для строки ?

Оператор "квадратные скобки" ([]) при применении к строке используется для доступа к отдельным байтам в этой строке. Строки представлены как последовательности байтов, и оператор [] позволяет получить байт по указанному индексу.

package main

import (
"fmt"
)

func main() {
str := "hello"

// Получаем байт по индексу
firstByte := str[0]

// Выводим байт и его символ
fmt.Printf("Первый байт: %d\n", firstByte) // Выводит: 104
fmt.Printf("Первый символ: %c\n", firstByte) // Выводит: h
}


🚩Объяснение

1⃣Доступ к байту
В этой строке кода мы получаем байт, расположенный по индексу 0 в строке str. В данном случае это байт, соответствующий символу 'h'.
firstByte := str[0]   


2⃣Вывод байта в числовом формате
Здесь мы выводим байт в виде целого числа. Поскольку символ 'h' имеет ASCII-код 104, вывод будет 104.
fmt.Printf("Первый байт: %d\n", firstByte)   


3⃣Вывод байта как символа
Мы также можем вывести байт как символ, используя формат %c. Это отобразит символ 'h'.
fmt.Printf("Первый символ: %c\n", firstByte)   


🚩Работа с Unicode

Важно понимать, что строки являются последовательностями байтов, а не символов. Это означает, что доступ по индексу с помощью [] дает байт, а не руну (rune). Если строка содержит многобайтовые символы (например, символы Unicode), то доступ по индексу может вернуть только один из байтов, составляющих символ.
package main

import (
"fmt"
)

func main() {
str := "Привет"

// Получаем байт по индексу
firstByte := str[0]

// Выводим байт и его символ
fmt.Printf("Первый байт: %d\n", firstByte) // Выводит: 208
fmt.Printf("Первый символ: %c\n", firstByte) // Выводит: � (неполный символ)
}


Для корректной работы с многобайтовыми символами (рунами) в строках используется преобразование строки в срез рун
package main

import (
"fmt"
)

func main() {
str := "Привет"

// Преобразуем строку в срез рун
runes := []rune(str)

// Получаем руну по индексу
firstRune := runes[0]

// Выводим руну и её символ
fmt.Printf("Первая руна: %d\n", firstRune) // Выводит: 1055 (код Unicode для 'П')
fmt.Printf("Первый символ: %c\n", firstRune) // Выводит: П
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

19 Jan, 16:10


🤔 Что такое хэш-таблица?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

19 Jan, 09:10


🤔 Через какой канал возможна проверка работы горутины?

В Go для проверки работы горутины часто используют каналы. Они позволяют передавать данные между горутинами и могут использоваться для сигнализации о состоянии выполнения горутины.

🚩Основные способы проверки работы горутины через каналы

🟠Односторонний канал для завершения горутины
Горутина может отправлять сигнал (например, true) в канал, чтобы уведомить о своем завершении.
func worker(done chan bool) {
fmt.Println("Работа началась...")
time.Sleep(2 * time.Second) // Имитация работы
fmt.Println("Работа завершена!")
done <- true // Отправляем сигнал в канал
}

func main() {
done := make(chan bool)

go worker(done) // Запускаем горутину

// Ожидаем сигнал завершения
<-done
fmt.Println("Основной поток: горутина завершена")
}


🟠Канал для передачи промежуточных результатов
Горутина может отправлять данные в канал, чтобы сигнализировать о прогрессе выполнения.
func worker(progress chan int) {
for i := 1; i <= 5; i++ {
fmt.Printf("Шаг %d выполнен\n", i)
progress <- i // Отправляем номер шага в канал
time.Sleep(500 * time.Millisecond) // Имитация работы
}
close(progress) // Закрываем канал после завершения работы
}

func main() {
progress := make(chan int)

go worker(progress) // Запускаем горутину

// Считываем данные из канала
for step := range progress {
fmt.Printf("Получен сигнал: шаг %d завершен\n", step)
}
fmt.Println("Все шаги выполнены!")
}


🟠Тайм-ауты и проверка работы через `select`
Если важно знать, работает ли горутина, но при этом нужно ограничить ожидание, используется оператор select с тайм-аутом.
func worker(status chan string) {
time.Sleep(2 * time.Second) // Имитация работы
status <- "Горутина завершена"
}

func main() {
status := make(chan string)

go worker(status)

select {
case msg := <-status:
fmt.Println(msg)
case <-time.After(1 * time.Second): // Тайм-аут 1 секунда
fmt.Println("Горутина работает слишком долго")
}
}


🟠Закрытие канала как индикатор завершения
Закрытие канала может служить сигналом того, что горутина завершила свою работу.
func worker(done chan struct{}) {
fmt.Println("Горутина работает...")
time.Sleep(2 * time.Second)
fmt.Println("Горутина завершена!")
close(done) // Закрываем канал
}

func main() {
done := make(chan struct{})

go worker(done)

// Проверяем, когда канал закроется
<-done
fmt.Println("Основной поток: горутина завершила работу")
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

18 Jan, 16:10


🤔 Как можно добавить элементы в слайс?

Используйте функцию append:
1. Добавление одного элемента: slice = append(slice, element).
2. Добавление нескольких элементов: slice = append(slice, elements...).
3. Слияние с другим слайсом: slice = append(slice, otherSlice...).


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

18 Jan, 09:10


🤔 Что такое хэш-таблица?

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

🚩Основные компоненты

🟠Хеш-функция
Функция, которая принимает ключ и преобразует его в индекс массива, называемого "хэш-таблицей". Хорошая хеш-функция распределяет ключи равномерно по хэш-таблице, минимизируя количество коллизий.

🟠Хэш-таблица
Массив фиксированного размера, где каждый элемент называется "корзиной" (bucket). Корзина может содержать одно или несколько значений.

🟠Коллизии
Ситуация, когда два разных ключа хешируются в один и тот же индекс. Коллизии решаются с помощью различных методов, таких как цепочки (chaining) или открытая адресация (open addressing).

🚩Принцип работы

🟠Вставка
Хеш-функция вычисляет индекс для данного ключа. Значение помещается в соответствующую корзину по этому индексу. Если возникает коллизия, используется метод разрешения коллизий.

🟠Поиск
Хеш-функция вычисляет индекс для ключа. Корзина по этому индексу проверяется на наличие значения. Если значение найдено, оно возвращается; если нет, возвращается индикатор отсутствия значения.

🟠Удаление
Хеш-функция вычисляет индекс для ключа. Значение удаляется из соответствующей корзины. При необходимости корректируются ссылки или структура данных для разрешения коллизий.

🚩Плюсы и минусы

Быстрый доступ
Среднее время доступа к элементу составляет O(1).
Простота использования
Обеспечивает простой интерфейс для вставки, поиска и удаления данных.
Коллизии
Требуют дополнительных механизмов для разрешения, что может усложнить реализацию.
Зависимость от хеш-функции
Эффективность хэш-таблицы зависит от качества хеш-функции.
Перераспределение
При увеличении количества элементов может потребоваться перераспределение и увеличение размера таблицы, что временно снижает производительность.

package main

import "fmt"

func main() {
// Создание карты
myMap := make(map[string]int)

// Вставка значений
myMap["Alice"] = 25
myMap["Bob"] = 30

// Поиск значений
value, exists := myMap["Alice"]
if exists {
fmt.Println("Alice:", value) // Alice: 25
} else {
fmt.Println("Alice not found")
}

// Удаление значений
delete(myMap, "Alice")
_, exists = myMap["Alice"]
if !exists {
fmt.Println("Alice has been deleted") // Alice has been deleted
}
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

17 Jan, 16:10


🤔 Как проверить слайс на пустоту?

Проверить длину слайса: len(slice) == 0. Nil-слайс также будет считаться пустым, так как его длина равна нулю.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

17 Jan, 09:10


🤔 Что будет если сложить строки?

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

🚩Что произойдет при сложении строк?

🟠Создание новой строки
Когда вы складываете строки, Go создает новую строку, содержащую все символы исходных строк, соединенных друг за другом. Исходные строки при этом остаются неизменными.
s1 := "Hello"
s2 := "World"
result := s1 + " " + s2
fmt.Println(result) // Output: Hello World


🟠Новая строка размещается в памяти
Так как строки в Go неизменяемы, результирующая строка создается заново, а память для нее выделяется в куче или на стеке, в зависимости от размера и контекста.

🚩Особенности сложения строк в Go

🟠Эффективность
Сложение строк через оператор + может быть неэффективным при множественных операциях, так как каждый раз создается новая строка, а старые промежуточные результаты удаляются сборщиком мусора.
result := ""
for i := 0; i < 5; i++ {
result += "Go"
}
fmt.Println(result) // Output: GoGoGoGoGo


🟠Использование `strings.Builder` для оптимизации
Если требуется объединить много строк, рекомендуется использовать strings.Builder. Это более эффективный способ, так как Builder работает с буфером и избегает лишних аллокаций.
   import "strings"

func main() {
var builder strings.Builder
for i := 0; i < 5; i++ {
builder.WriteString("Go")
}
fmt.Println(builder.String()) // Output: GoGoGoGoGo
}


🚩Особенности Unicode

Go строки поддерживают Unicode, поэтому сложение строк корректно работает с многобайтовыми символами.
s1 := "Привет"
s2 := "Мир"
result := s1 + " " + s2
fmt.Println(result) // Output: Привет Мир


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

16 Jan, 16:10


🤔 Можно ли добавлять элементы в nil-слайс?

Да, в nil-слайс можно добавлять элементы с помощью append, так как он автоматически выделяет память для нового массива.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

16 Jan, 09:10


🤔 Зачем используется дополнительный блок фигурных скобок в функции?

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

🚩Зачем это нужно

🟠Ограничение области видимости переменных
Переменные, объявленные внутри блока {}, видимы только в пределах этого блока. Это полезно для временных переменных, которые не должны "загрязнять" основную область видимости функции.
func processData() {
{
value := 42
fmt.Println("Внутренний блок, value =", value) // value доступна только здесь
}
// fmt.Println(value) // Ошибка: value не определена за пределами блока
}


🟠Управление временем жизни ресурсов
С помощью блоков можно явно управлять временем жизни переменных, таких как файлы, соединения или буферы. Это особенно важно для ресурсов, которые необходимо закрыть или освободить.
func readFile() {
{
file, err := os.Open("example.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close() // Закроется при выходе из блока

// Работа с файлом
fmt.Println("Чтение файла")
}
// Здесь файл уже закрыт
}


🟠Локализация кода для улучшения читаемости
В больших функциях дополнительный блок позволяет логически разделить код на части, делая его более понятным.
func main() {
{
// Работа с настройками
config := loadConfig()
fmt.Println("Конфигурация загружена:", config)
}

{
// Работа с данными
data := fetchData()
fmt.Println("Данные получены:", data)
}
}


🟠Проверка и тестирование отдельных блоков
Можно использовать дополнительные блоки для изоляции сложных кусков кода и последующего их упрощения.
func calculate() int {
result := 0
{
a := 10
b := 20
result = a + b
}
return result
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

15 Jan, 16:10


🤔 Что такое nil-слайс и чем отличается

Это слайс, который не ссылается на массив. Он отличается от пустого слайса, который ссылается на массив нулевой длины, но также имеет len и cap равные нулю.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

15 Jan, 09:10


🤔 Какое свойство должно быть у ключа в Map?

Ключи в map (карте) должны обладать определенными свойствами, чтобы быть допустимыми и корректно работать с хеш-таблицей. Важно понимать, что ключи должны поддерживать операцию сравнения и быть хешируемыми.

🚩Свойства ключей

🟠Сравнимость
Ключи должны поддерживать операцию сравнения с использованием оператора ==. Это необходимо для проверки равенства ключей при выполнении операций вставки, поиска и удаления в карте.

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

🚩Допустимые типы ключей

Булевый тип (bool)
  m := map[bool]string{
true: "Yes",
false: "No",
}


Целочисленные типы (int, int8, int16, int32, int64, а также их беззнаковые эквиваленты uint, uint8, uint16, uint32, uint64)
  m := map[int]string{
1: "One",
2: "Two",
}


Числа с плавающей точкой (float32, float64)
  m := map[float64]string{
1.1: "One point one",
2.2: "Two point two",
}


Строки (string)
  m := map[string]int{
"Alice": 25,
"Bob": 30,
}


Составные типы (структуры, массивы), при условии, что все их поля также поддерживают сравнение с помощью оператора ==
  type Key struct {
FirstName string
LastName string
}

m := map[Key]int{
{"Alice", "Smith"}: 1,
{"Bob", "Johnson"}: 2,
}


🚩Недопустимые типы ключей

🟠Срезы (slice)
Срезы не поддерживают операцию сравнения с использованием оператора == (только сравнение с nil).
🟠Карты (map)
Карты не поддерживают операцию сравнения.
🟠Функции (func)
Функции не поддерживают операцию сравнения.

package main

import "fmt"

type Person struct {
FirstName string
LastName string
}

func main() {
// Создаем карту с ключами типа Person
m := make(map[Person]int)

// Вставляем значения в карту
m[Person{"Alice", "Smith"}] = 25
m[Person{"Bob", "Johnson"}] = 30

// Выводим значения из карты
fmt.Println(m[Person{"Alice", "Smith"}]) // Выводит: 25
fmt.Println(m[Person{"Bob", "Johnson"}]) // Выводит: 30
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

14 Jan, 16:10


🤔 Что такое zero-value и какое оно у слайса?

Это nil. Такой слайс имеет длину и ёмкость равные нулю и не ссылается на какой-либо массив.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

14 Jan, 09:10


🤔 Как избежать deadlock?

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

🚩Чтобы избежать deadlock, нужно следовать этим принципам

🟠Грамотно проектировать порядок блокировок
Если несколько горутин используют блокировки (например, через мьютексы), убедитесь, что все они захватывают их в одном и том же порядке.
func main() {
var mu1, mu2 sync.Mutex

go func() {
mu1.Lock()
defer mu1.Unlock()

mu2.Lock()
defer mu2.Unlock()
}()

go func() {
mu2.Lock()
defer mu2.Unlock()

mu1.Lock()
defer mu1.Unlock()
}()
}


🟠Не блокировать каналы навсегда
Каналы должны всегда иметь возможность отправки и получения данных. Если одна сторона (отправитель или получатель) заблокирована навсегда, возникает deadlock.
func main() {
ch := make(chan int)
ch <- 42 // Deadlock, так как никто не читает из канала
}


🟠Закрывайте каналы правильно
Каналы нужно закрывать только со стороны отправителя, и только тогда, когда больше не будет отправок данных. Неправильное закрытие или отсутствие закрытия может привести к проблемам, включая deadlock.
ch := make(chan int)
close(ch) // Закрыт слишком рано
ch <- 42 // Паника


🟠Избегайте ситуаций с ожиданием себя
Иногда deadlock происходит, если горутина ждет сама себя.
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch) // Никогда не выполнится
}


🟠Использовать тайм-ауты и селекторы
Go позволяет избегать блокировок с помощью механизма тайм-аутов и оператора select. Если операция занимает слишком много времени, можно выполнить альтернативное действие.
func main() {
ch := make(chan int)

select {
case data := <-ch:
fmt.Println("Получены данные:", data)
case <-time.After(1 * time.Second):
fmt.Println("Тайм-аут, завершение")
}
}


🟠Используйте инструменты анализа
Go предоставляет утилиту go run -race, которая помогает выявлять гонки данных и другие проблемы, связанные с синхронизацией.
go run -race main.go


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

13 Jan, 16:10


🤔 Как можно создать слайс?

1. С помощью литерала: s := []int{1, 2, 3}.
2. Через функцию make: s := make([]int, length, capacity).
3. Срезав массив: s := array[start:end].


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

10 Jan, 16:10


🤔 Зачем `append` возвращает слайс

append возвращает слайс, чтобы учесть возможное перераспределение памяти при добавлении элементов. Новый слайс может ссылаться на другой массив, если исходного размера недостаточно, поэтому важно использовать возвращаемое значение.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

10 Jan, 09:10


🤔 Как работать со слайсами?

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

🚩Что это такое?

Это динамическая последовательность элементов одного типа, которая предоставляет доступ к части или всем элементам массива без копирования данных. Он содержит три компонента:
Указатель на массив.
Длина (количество элементов в слайсе).
Ёмкость (максимальное количество элементов, которые могут быть включены в слайс без перераспределения памяти).

🚩Почему они нужны?

Слайсы позволяют работать с массивами более гибко:
🟠Динамическая длина
В отличие от массивов, длина слайса может изменяться.
🟠Передача данных
Слайсы можно передавать в функции и возвращать из них, не копируя данные.
🟠Удобство работы
Предоставляют множество встроенных функций для работы с последовательностями данных.

🚩Создать слайс можно несколькими способами:

Из массива
    arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // слайс содержит элементы {2, 3, 4}


Используя make
slice := make([]int, 5)  // создаёт слайс длиной и ёмкостью 5, заполненный нулями    


Литерал слайса
slice := []int{1, 2, 3, 4, 5}    


🚩Основные операции

Доступ к элементам
fmt.Println(slice[0])  // выводит первый элемент слайса    


Изменение элементов
slice[1] = 10  // изменяет второй элемент слайса    


Добавление элементов
slice = append(slice, 6, 7)  // добавляет элементы 6 и 7 к слайсу    


Срезка (slicing)
newSlice := slice[1:3]  // создаёт новый слайс с элементами с 1-го по 3-й    


Рассмотрим пример функции, которая добавляет элемент в слайс и возвращает новый слайс
package main

import "fmt"

func main() {
nums := []int{1, 2, 3}
nums = append(nums, 4) // добавление элемента
fmt.Println(nums) // выводит [1, 2, 3, 4]
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

10 Jan, 07:14


🧠 Machine Learning — авторский канал, где собрана вся база по ИИ и машинному обучению.

Senior разработчик AI-алгоритмов и автономных агентов, разбирает гайды, редкую литературу и код топовых моделей машинного обучения и искусственного интеллекта.

В 2025 году ИИ выйдет на совершенно новый уровень тот, кто не успеет за прогрессом - отстанет, а кто разберется - сорвет куш.

Стоит
подписаться: t.me/ai_machinelearning_big_data

Golang | Вопросы собесов

09 Jan, 16:10


🤔 Какие функции у Map?

1. Добавление элемента: map[key] = value.
2. Получение элемента: value, ok := map[key] — возвращает значение и флаг существования.
3. Удаление элемента: delete(map, key).
4. Итерация: for key, value := range map.
5. Проверка существования: с помощью ok из выражения value, ok := map[key].


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

09 Jan, 12:55


📊 Реклама в сети телеграм каналов easyoffer
✈️ Для заказа пишите @easyoffer_adv

easyoffer
Backend

Python | Вопросы
Python | Удалёнка
Python | LeetCode
Python | Тесты

Frontend | Вопросы
Frontend | Удалёнка
JavaScript | LeetCode
Frontend | Тесты

Java | Вопросы
Java | Удалёнка
Java | LeetCode
Java | Тесты

Тестировщик | Вопросы
Тестировщик | Удалёнка
Тестировщик | Тесты

Data Science | Вопросы
Data Science | Удалёнка
Data Science | Тесты

C# | Вопросы
C# | Удалёнка
C# | LeetCode
C# | Тесты

C/C++ | Вопросы
C/C++ | Удалёнка
C/C++ | LeetCode
C/C++ | Тесты

Golang | Вопросы
Golang | Удалёнка
Golang | LeetCode
Golang | Тесты

DevOps | Вопросы
DevOps | Удалёнка
DevOps | Тесты

PHP | Вопросы
PHP | Удалёнка
PHP | LeetCode
PHP | Тесты

Kotlin | Вопросы
Kotlin | Удалёнка
Kotlin | LeetCode
Kotlin | Тесты

Swift | Вопросы
Swift | Удалёнка
Swift | LeetCode
Swift | Тесты

📊 Реклама в сети телеграм каналов easyoffer
✈️ Для заказа пишите @easyoffer_adv

Golang | Вопросы собесов

09 Jan, 09:10


🤔 Как устроен массив в Go?

Массивы представляют собой фиксированную последовательность элементов одного типа. Являются основополагающей структурой данных, на базе которой строятся более сложные структуры, такие как слайсы. Рассмотрим, как устроены массивы, их особенности, а также сравнение с другими структурами данных.

🚩Основные характеристики

🟠Фиксированный размер
Размер массива задается при его объявлении и не может изменяться во время выполнения программы.
🟠Тип элементов
Все элементы массива имеют один и тот же тип.
🟠Непосредственное хранение данных
В отличие от слайсов, массивы хранят свои элементы в непрерывном блоке памяти.

🟠Объявление массива
С указанием типа элементов и фиксированного размера. Это объявление создает массив из пяти целых чисел, инициализированных нулями.
var arr [5]int


🟠Инициализация массива
Массивы могут быть инициализированы при объявлении
arr := [5]int{1, 2, 3, 4, 5}


Можно также инициализировать массив частично, оставив остальные элементы равными нулям:
arr := [5]int{1, 2}


🟠Доступ к элементам
Осуществляется с использованием индексов, начиная с 0
fmt.Println(arr[0]) // 1
arr[1] = 10
fmt.Println(arr[1]) // 10


🟠Длина массива
Фиксирована и задается при его объявлении. Ее можно получить с помощью функции len
fmt.Println(len(arr)) // 5


🟠Копирование массива
При присваивании одного массива другому копируются все элементы:
arr1 := [5]int{1, 2, 3, 4, 5}
arr2 := arr1
arr2[0] = 10
fmt.Println(arr1) // [1 2 3 4 5]
fmt.Println(arr2) // [10 2 3 4 5]


🟠Передача массива в функции
При этом копируется весь массив:
func modifyArray(a [5]int) {
a[0] = 10
}

arr := [5]int{1, 2, 3, 4, 5}
modifyArray(arr)
fmt.Println(arr) // [1 2 3 4 5]


🚩Сравнение

🟠Размер
Массивы имеют фиксированный размер, тогда как слайсы динамичны.

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

🟠Гибкость: Слайсы более гибки благодаря динамическому изменению размера и доступным методам.

Использование массивов
package main

import (
"fmt"
)

func main() {
// Объявление и инициализация массива
arr := [5]int{1, 2, 3, 4, 5}

// Доступ к элементам
fmt.Println("First element:", arr[0]) // First element: 1

// Изменение элементов
arr[1] = 10
fmt.Println("Modified array:", arr) // Modified array: [1 10 3 4 5]

// Длина массива
fmt.Println("Length of array:", len(arr)) // Length of array: 5

// Копирование массива
arr2 := arr
arr2[0] = 20
fmt.Println("Original array:", arr) // Original array: [1 10 3 4 5]
fmt.Println("Copied array:", arr2) // Copied array: [20 10 3 4 5]

// Передача массива в функцию
modifyArray(arr)
fmt.Println("Array after modifyArray call:", arr) // Array after modifyArray call: [1 10 3 4 5]
}

func modifyArray(a [5]int) {
a[0] = 10
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

08 Jan, 16:10


🤔 Как быстро можно что-то найти, если искать по индексу в слайсе и в Map?

В слайсе поиск по индексу имеет сложность O(1), так как элементы хранятся последовательно в памяти.
В Map поиск по ключу в среднем имеет сложность O(1) благодаря хешированию, но может ухудшиться до O(n) при большом количестве коллизий.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

08 Jan, 09:10


🤔 Как работает append в слайсе ?

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

🚩Как он работает

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

Синтаксис
slice = append(slice, elem1, elem2, ...)


Пример использования
package main

import "fmt"

func main() {
// Создаем слайс из 3 целых чисел
slice := []int{1, 2, 3}

// Добавляем один элемент
slice = append(slice, 4)

// Добавляем несколько элементов
slice = append(slice, 5, 6, 7)

// Выводим слайс
fmt.Println(slice) // Выводит: [1 2 3 4 5 6 7]
}


🚩Объяснение работы

1⃣Начальный слайс
Создаем слайс с тремя элементами [1, 2, 3].
slice := []int{1, 2, 3}   


2⃣Добавление одного элемента
Добавляем элемент 4 к слайсу. Теперь слайс содержит [1, 2, 3, 4].
slice = append(slice, 4)   


3⃣Добавление нескольких элементов
Добавляем элементы 5, 6, и 7. Теперь слайс содержит [1, 2, 3, 4, 5, 6, 7].
slice = append(slice, 5, 6, 7)   


4⃣Вывод слайса
Выводим слайс, который содержит [1, 2, 3, 4, 5, 6, 7].
fmt.Println(slice)   


Работа с емкостью и длиной
package main

import "fmt"

func main() {
slice := []int{1, 2, 3}
fmt.Printf("Before append: len=%d cap=%d %v\n", len(slice), cap(slice), slice)

slice = append(slice, 4)
fmt.Printf("After append: len=%d cap=%d %v\n", len(slice), cap(slice), slice)

slice = append(slice, 5, 6, 7)
fmt.Printf("After multiple appends: len=%d cap=%d %v\n", len(slice), cap(slice), slice)
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

07 Jan, 16:10


🤔 Как правильно объявлять Map?

1. Инициализация: используйте make для создания карты, например, make(map[string]int).
2. Литералы: для статических данных можно использовать литералы, например, map[string]int{"key": 1}.
3. Всегда проверяйте существование элемента с помощью value, ok := map[key], чтобы избежать ошибок доступа к несуществующим ключам.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

07 Jan, 09:10


🤔 Как устроен слайс в Go ?

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

🚩Структура

🟠Указатель на базовый массив
Указатель на первый элемент массива, на который ссылается слайс.
🟠Длина (length)
Количество элементов, доступных в слайсе.
🟠Емкость (capacity)
Максимальное количество элементов, которое может содержать слайс без перераспределения памяти.

🚩Внутреннее устройство

Можно представить в виде структуры
type slice struct {
ptr *ElementType // Указатель на базовый массив
len int // Длина
cap int // Емкость
}


🟠Слайс из массива
Можно создать из массива, указав диапазон элементов:
package main

import "fmt"

func main() {
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // Слайс содержит элементы с индексами 1, 2, 3
fmt.Println(slice) // [2 3 4]
}


🟠Слайс с использованием функции make
Позволяет создать слайс определенной длины и емкости:
package main

import "fmt"

func main() {
slice := make([]int, 3, 5) // Слайс длиной 3 и емкостью 5
fmt.Println(slice) // [0 0 0]
}


🟠Доступ к элементам слайса
Осуществляется так же, как и к элементам массива:
package main

import "fmt"

func main() {
slice := []int{1, 2, 3, 4, 5}
fmt.Println(slice[0]) // 1
slice[1] = 10
fmt.Println(slice) // [1 10 3 4 5]
}


🚩Основные операции с ними

🟠Добавление элементов
Для этого используется функция append
package main

import "fmt"

func main() {
slice := []int{1, 2, 3}
slice = append(slice, 4, 5) // Добавляем элементы 4 и 5 в конец слайса
fmt.Println(slice) // [1 2 3 4 5]
}


🟠Извлечение подмножества слайса (slicing)
Можно создавать новые слайсы на основе существующих
package main

import "fmt"

func main() {
slice := []int{1, 2, 3, 4, 5}
subSlice := slice[1:4] // Слайс содержит элементы с индексами 1, 2, 3
fmt.Println(subSlice) // [2 3 4]
}


🟠Копирование слайсов
Для этого используется функция copy
package main

import "fmt"

func main() {
src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src)
fmt.Println(dst) // [1 2 3]
}


🚩Динамическое изменение длины и емкости

Могут автоматически изменять свою емкость при добавлении новых элементов с помощью append. Когда емкость текущего массива недостаточна для добавления новых элементов, создается новый массив с большей емкостью, в который копируются существующие элементы.
package main

import "fmt"

func main() {
slice := make([]int, 3, 5)
fmt.Println("Before append:", slice, "Len:", len(slice), "Cap:", cap(slice))

slice = append(slice, 1, 2, 3)
fmt.Println("After append:", slice, "Len:", len(slice), "Cap:", cap(slice))

slice = append(slice, 4)
fmt.Println("After another append:", slice, "Len:", len(slice), "Cap:", cap(slice))
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

06 Jan, 16:10


🤔 Как думаешь, будут ли Map ordered?

Нет, в большинстве языков (например, Go) Map не гарантирует порядка хранения элементов.
1. Хранение данных зависит от хеширования ключей, что делает порядок непредсказуемым.
2. Если нужен упорядоченный Map, используйте структуру, где порядок задаётся вручную, например, с помощью slice.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

06 Jan, 09:10


🤔 Что такое zero-value и какое оно у слайса ?

Концепция "нулевого значения" (zero-value) означает значение по умолчанию, которое получает переменная при ее объявлении, если она не была инициализирована явно. Нулевые значения зависят от типа данных переменной.

🟠int
0
🟠float64
0.0
🟠bool
false
🟠string
""
🟠указатели, интерфейсы, функции, каналы, карты, слайсы
nil

🚩Нулевое значение (zero-value) для слайса

Является nil. Это означает, что слайс, объявленный, но не инициализированный явно, указывает на nil и имеет длину и емкость равные нулю.
Нулевое значение для слайса
package main

import "fmt"

func main() {
var slice []int // Объявление слайса без инициализации
fmt.Println(slice) // []
fmt.Println(len(slice)) // 0
fmt.Println(cap(slice)) // 0
fmt.Println(slice == nil) // true
}


🚩Работа с нулевым значением

Можно работать так же, как и с обычным слайсом. Например, можно добавлять элементы с помощью функции append, и это будет работать корректно.
Использование append с nil-слайсом
package main

import "fmt"

func main() {
var slice []int // nil-слайс

// Добавление элемента в nil-слайс
slice = append(slice, 1)
fmt.Println(slice) // [1]
fmt.Println(len(slice)) // 1
fmt.Println(cap(slice)) // 1
fmt.Println(slice == nil) // false (теперь слайс больше не nil)
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

05 Jan, 16:10


🤔 Как со слайсами работать?

1. Инициализация: через литералы ([]int{1, 2, 3}) или с помощью make (make([]int, length, capacity)).
2. Добавление элементов: используйте функцию append для увеличения слайса.
3. Копирование: создавайте новый слайс и копируйте данные с помощью функции copy.
4. Избегание изменения оригинала: будьте осторожны с передачей слайсов, так как они передаются по ссылке.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

05 Jan, 09:10


🤔 Что будет, если подставить переменную в массив?

Массивы и слайсы могут использоваться для хранения последовательности элементов одного типа. Когда вы "подставляете" переменную в массив или слайс, вы просто присваиваете значение этой переменной одному из элементов массива или слайса.

Пример с массивом
package main

import "fmt"

func main() {
// Создаем массив из 5 целых чисел
var arr [5]int

// Создаем переменную и присваиваем ей значение
x := 10

// Подставляем переменную в массив
arr[0] = x

// Выводим массив
fmt.Println(arr) // Выводит: [10 0 0 0 0]
}


🚩Объяснение

1⃣Создание массива
Это создает массив arr из 5 целых чисел, все элементы которого инициализируются значением 0.
var arr [5]int   


2⃣Создание переменной
Создаем переменную x и присваиваем ей значение 10.
x := 10   


3⃣Присваивание значения элементу массива
Присваиваем значение переменной x первому элементу массива arr.
arr[0] = x   


4⃣Вывод массива
Выводит содержимое массива, показывая, что первый элемент массива теперь равен 10, а остальные элементы остаются нулями.
fmt.Println(arr)   


Пример со слайсом
package main

import "fmt"

func main() {
// Создаем слайс из 3 целых чисел
slice := make([]int, 3)

// Создаем переменную и присваиваем ей значение
x := 20

// Подставляем переменную в слайс
slice[1] = x

// Выводим слайс
fmt.Println(slice) // Выводит: [0 20 0]
}


🚩Объяснение

1⃣Создание слайса
Это создает слайс slice из 3 целых чисел, все элементы которого инициализируются значением 0.
slice := make([]int, 3)   


2⃣Создание переменной
Создаем переменную x и присваиваем ей значение 20.
x := 20   


3⃣Присваивание значения элементу слайса
Присваиваем значение переменной x второму элементу слайса slice.
slice[1] = x   


4⃣Вывод слайса
Выводит содержимое слайса, показывая, что второй элемент слайса теперь равен 20, а остальные элементы остаются нулями.
fmt.Println(slice)   


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

04 Jan, 16:10


🤔 Что будет в Map, если не делать make или short assign?

Если Map не инициализировать с помощью make или :=, она будет nil.
1. Попытка записи в неинициализированный Map вызовет ошибку времени выполнения (panic).
2. Инициализация обязательна для корректной работы с Map.


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

04 Jan, 09:10


🤔 Как можно создать слайс?

🟠Создание слайса с использованием литералов
Позволяют создать и инициализировать слайс одновременно
package main

import "fmt"

func main() {
slice := []int{1, 2, 3, 4, 5}
fmt.Println(slice) // [1 2 3 4 5]
}


🟠Создание слайса с использованием функции make
Позволяет создать слайс определенной длины и емкости
package main

import "fmt"

func main() {
slice := make([]int, 3) // Создаем слайс длиной 3 и емкостью 3
fmt.Println(slice) // [0 0 0]

sliceWithCapacity := make([]int, 3, 5) // Создаем слайс длиной 3 и емкостью 5
fmt.Println(sliceWithCapacity) // [0 0 0]
}


🟠Создание слайса на основе массива
Указав подмножество элементов массива
package main

import "fmt"

func main() {
arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // Слайс содержит элементы с индексами 1, 2 и 3
fmt.Println(slice) // [2 3 4]
}


🟠Создание слайса на основе другого слайса (Slicing)
Указав подмножество элементов существующего слайса
package main

import "fmt"

func main() {
slice := []int{1, 2, 3, 4, 5}
subSlice := slice[1:4] // Новый слайс содержит элементы с индексами 1, 2 и 3
fmt.Println(subSlice) // [2 3 4]
}


🟠Создание пустого слайса
Длина и емкость которого равны нулю
package main

import "fmt"

func main() {
var emptySlice []int // Пустой слайс
fmt.Println(emptySlice, len(emptySlice), cap(emptySlice)) // [] 0 0

emptySlice = append(emptySlice, 1) // Добавление элемента
fmt.Println(emptySlice) // [1]
}


🟠Создание слайса с использованием среза от существующего слайса
Указывая начальный и конечный индекс (исключительно)
package main

import "fmt"

func main() {
original := []int{1, 2, 3, 4, 5}
newSlice := original[:3] // Слайс содержит элементы с индексами 0, 1, 2
fmt.Println(newSlice) // [1 2 3]

anotherSlice := original[2:] // Слайс содержит элементы с индекса 2 до конца
fmt.Println(anotherSlice) // [3 4 5]
}


Использование всех методов
package main

import "fmt"

func main() {
// Создание слайса с использованием литерала
sliceLiteral := []int{1, 2, 3, 4, 5}
fmt.Println("Slice literal:", sliceLiteral)

// Создание слайса с использованием make
sliceMake := make([]int, 3) // Длина 3, емкость 3
fmt.Println("Slice make:", sliceMake)

sliceMakeWithCapacity := make([]int, 3, 5) // Длина 3, емкость 5
fmt.Println("Slice make with capacity:", sliceMakeWithCapacity)

// Создание слайса на основе массива
arr := [5]int{1, 2, 3, 4, 5}
sliceFromArray := arr[1:4] // Элементы с индексами 1, 2, 3
fmt.Println("Slice from array:", sliceFromArray)

// Создание слайса на основе другого слайса
sliceFromSlice := sliceLiteral[2:5] // Элементы с индексами 2, 3, 4
fmt.Println("Slice from slice:", sliceFromSlice)

// Создание пустого слайса
var emptySlice []int
fmt.Println("Empty slice:", emptySlice, len(emptySlice), cap(emptySlice))

// Добавление элемента в пустой слайс
emptySlice = append(emptySlice, 10)
fmt.Println("After append:", emptySlice)
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

03 Jan, 16:10


🤔 Какое свойство должно быть у ключа в Map?

Ключи должны быть уникальными и поддерживать операцию сравнения на равенство.
1. В большинстве языков, ключи должны быть сравниваемыми типами (например, числа, строки, указатели).
2. Использование нестабильных или изменяемых ключей может привести к некорректной работе Map.


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

03 Jan, 09:10


🤔 Как можно откопировать слайс?

Слайсы являются ссылочными типами, поэтому простое присваивание одного слайса другому создаст новую ссылку на тот же подлежащий массив. Если вы хотите создать копию слайса с независимым подлежащим массивом, можно использовать встроенную функцию copy или методы, такие как использование append.

🚩Способы копирования слайса

🟠Использование функции `copy`
Создает побайтовую копию элементов из одного слайса в другой.
package main

import "fmt"

func main() {
original := []int{1, 2, 3, 4, 5}

// Создаем новый слайс той же длины, что и оригинал
copySlice := make([]int, len(original))

// Копируем элементы из оригинального слайса в новый
copy(copySlice, original)

// Изменяем элемент в копии
copySlice[0] = 100

fmt.Println("Оригинал:", original) // Выводит: Оригинал: [1 2 3 4 5]
fmt.Println("Копия:", copySlice) // Выводит: Копия: [100 2 3 4 5]
}


Использование функции
inal)   


Чтобы создать новый слайс с копированными элементами.
package main

import "fmt"

func main() {
original := []int{1, 2, 3, 4, 5}

// Копируем элементы из оригинального слайса в новый слайс
copySlice := append([]int(nil), original...)

// Изменяем элемент в копии
copySlice[0] = 100

fmt.Println("Оригинал:", original) // Выводит: Оригинал: [1 2 3 4 5]
fmt.Println("Копия:", copySlice) // Выводит: Копия: [100 2 3 4 5]
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

02 Jan, 16:10


🤔 Что такое retail release?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

02 Jan, 09:10


🤔 Что возвращает оператор "квадратные скобки" для строки ?

Оператор "квадратные скобки" ([]) при применении к строке используется для доступа к отдельным байтам в этой строке. Строки представлены как последовательности байтов, и оператор [] позволяет получить байт по указанному индексу.

package main

import (
"fmt"
)

func main() {
str := "hello"

// Получаем байт по индексу
firstByte := str[0]

// Выводим байт и его символ
fmt.Printf("Первый байт: %d\n", firstByte) // Выводит: 104
fmt.Printf("Первый символ: %c\n", firstByte) // Выводит: h
}


🚩Объяснение

1⃣Доступ к байту
В этой строке кода мы получаем байт, расположенный по индексу 0 в строке str. В данном случае это байт, соответствующий символу 'h'.
firstByte := str[0]   


2⃣Вывод байта в числовом формате
Здесь мы выводим байт в виде целого числа. Поскольку символ 'h' имеет ASCII-код 104, вывод будет 104.
fmt.Printf("Первый байт: %d\n", firstByte)   


3⃣Вывод байта как символа
Мы также можем вывести байт как символ, используя формат %c. Это отобразит символ 'h'.
fmt.Printf("Первый символ: %c\n", firstByte)   


🚩Работа с Unicode

Важно понимать, что строки являются последовательностями байтов, а не символов. Это означает, что доступ по индексу с помощью [] дает байт, а не руну (rune). Если строка содержит многобайтовые символы (например, символы Unicode), то доступ по индексу может вернуть только один из байтов, составляющих символ.
package main

import (
"fmt"
)

func main() {
str := "Привет"

// Получаем байт по индексу
firstByte := str[0]

// Выводим байт и его символ
fmt.Printf("Первый байт: %d\n", firstByte) // Выводит: 208
fmt.Printf("Первый символ: %c\n", firstByte) // Выводит: � (неполный символ)
}


Для корректной работы с многобайтовыми символами (рунами) в строках используется преобразование строки в срез рун
package main

import (
"fmt"
)

func main() {
str := "Привет"

// Преобразуем строку в срез рун
runes := []rune(str)

// Получаем руну по индексу
firstRune := runes[0]

// Выводим руну и её символ
fmt.Printf("Первая руна: %d\n", firstRune) // Выводит: 1055 (код Unicode для 'П')
fmt.Printf("Первый символ: %c\n", firstRune) // Выводит: П
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

01 Jan, 16:10


🤔 Что такое heap object?

Это объект, размещённый в куче, где память выделяется динамически. Такие объекты хранятся до тех пор, пока на них есть ссылки, и освобождаются автоматически, когда ссылки удаляются (через сборщик мусора или ARC).

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

01 Jan, 09:10


🤔 Какое свойство должно быть у ключа в Map?

Ключи в map (карте) должны обладать определенными свойствами, чтобы быть допустимыми и корректно работать с хеш-таблицей. Важно понимать, что ключи должны поддерживать операцию сравнения и быть хешируемыми.

🚩Свойства ключей

🟠Сравнимость
Ключи должны поддерживать операцию сравнения с использованием оператора ==. Это необходимо для проверки равенства ключей при выполнении операций вставки, поиска и удаления в карте.

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

🚩Допустимые типы ключей

Булевый тип (bool)
  m := map[bool]string{
true: "Yes",
false: "No",
}


Целочисленные типы (int, int8, int16, int32, int64, а также их беззнаковые эквиваленты uint, uint8, uint16, uint32, uint64)
  m := map[int]string{
1: "One",
2: "Two",
}


Числа с плавающей точкой (float32, float64)
  m := map[float64]string{
1.1: "One point one",
2.2: "Two point two",
}


Строки (string)
  m := map[string]int{
"Alice": 25,
"Bob": 30,
}


Составные типы (структуры, массивы), при условии, что все их поля также поддерживают сравнение с помощью оператора ==
  type Key struct {
FirstName string
LastName string
}

m := map[Key]int{
{"Alice", "Smith"}: 1,
{"Bob", "Johnson"}: 2,
}


🚩Недопустимые типы ключей

🟠Срезы (slice)
Срезы не поддерживают операцию сравнения с использованием оператора == (только сравнение с nil).
🟠Карты (map)
Карты не поддерживают операцию сравнения.
🟠Функции (func)
Функции не поддерживают операцию сравнения.

package main

import "fmt"

type Person struct {
FirstName string
LastName string
}

func main() {
// Создаем карту с ключами типа Person
m := make(map[Person]int)

// Вставляем значения в карту
m[Person{"Alice", "Smith"}] = 25
m[Person{"Bob", "Johnson"}] = 30

// Выводим значения из карты
fmt.Println(m[Person{"Alice", "Smith"}]) // Выводит: 25
fmt.Println(m[Person{"Bob", "Johnson"}]) // Выводит: 30
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

31 Dec, 16:10


🤔 Какая ссылка производительнее: unowned или weak?

unowned ссылка производительнее, так как она не увеличивает счётчик ссылок объекта. Однако unowned нужно использовать осторожно, так как она приводит к крашу, если объект уже деинициализирован. weak безопаснее, но добавляет небольшую накладную из-за проверки на nil.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

31 Dec, 09:10


🤔 Зачем нужны линтеры (linters)?

Линтеры (linters) нужны для обеспечения качества и чистоты кода, повышения его читаемости и поддержки, а также для предотвращения ошибок на ранних этапах разработки.

🚩Основные причины

🟠Обнаружение ошибок на ранних этапах
Линтеры анализируют код и обнаруживают синтаксические ошибки, неинициализированные переменные, неправильные типы данных и другие потенциальные проблемы еще до запуска программы.

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

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

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

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

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

🚩Примеры использования линтеров

🟠Использование линтера для Go

1⃣Установка golint
go install golang.org/x/lint/golint@latest


2⃣Пример кода example.go
package main

import "fmt"

func main() {
fmt.Println("Hello, world!")
}


3⃣Запуск golint
golint example.go


🟠Использование линтера для JavaScript

1⃣Установка ESLint
npm install eslint --save-dev


2⃣Инициализация конфигурации ESLint
npx eslint --init


3⃣Пример кода example.js
function hello() {
console.log("Hello, world!");
}

hello();


4⃣Запуск ESLint
npx eslint example.js


🚩Плюсы

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

Сокращение времени на отладку
Раннее обнаружение ошибок позволяет сократить время на отладку и тестирование, улучшая производительность команды.

Снижение количества багов
Линтеры обнаруживают потенциальные ошибки до запуска кода, что снижает вероятность появления багов в продакшене.

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

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

30 Dec, 16:10


🤔 Кто последний может обработать кнопку в иерархии вьюшек?

Последним кнопку в иерархии вьюшек может обработать корневой объект, например, UIApplication или основной ViewController. Это происходит, если события не обработаны дочерними вьюшками, и они передаются вверх по цепочке обработчиков.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

30 Dec, 09:10


🤔 Что такое линтеры (linters)?

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

🚩Основные функции линтеров

🟠Проверка стиля кода
Линтеры проверяют, соответствует ли код стилевым рекомендациям и стандартам, таким как использование отступов, именование переменных и форматирование.

🟠Поиск ошибок
Линтеры могут обнаруживать потенциальные ошибки, такие как неиспользуемые переменные, неправильные типы данных, неинициализированные переменные и другие проблемы.

🟠Обеспечение соответствия стандартам
Линтеры помогают поддерживать код в соответствии с общепринятыми стандартами и лучшими практиками, что улучшает читаемость и поддержку кода.

🟠Улучшение качества кода
Линтеры могут указывать на участки кода, которые можно улучшить, например, упростить сложные конструкции или оптимизировать производительность.

🚩Примеры линтеров для различных языков

🟠Go
golint: Проверяет стиль кода на соответствие рекомендациям Go.
gofmt: Автоматически форматирует код в соответствии со стандартами Go.
staticcheck: Более мощный инструмент, который находит ошибки, неэффективные конструкции и другие проблемы.

🟠JavaScript/TypeScript
ESLint: Очень мощный и настраиваемый линтер для JavaScript и TypeScript
JSHint: Инструмент для выявления ошибок и потенциальных проблем в JavaScript-коде.

🟠Python
Pylint: Линтер для Python, который проверяет стиль кода, ищет ошибки и предлагает улучшения.
flake8: Комбинированный инструмент, который включает в себя проверки на стиль, ошибки и другие проблемы.

🟠Java
Checkstyle: Инструмент для проверки стиля кода Java.
PMD: Находит потенциальные ошибки, неиспользуемый код и другие проблемы в коде Java.

🚩Пример использования линтера в Go

1⃣Установка golint
go install golang.org/x/lint/golint@latest


2⃣Создайте файл example.go
package main

import "fmt"

func main() {
fmt.Println("Hello, world!")
}


3⃣Запустите golint
golint example.go


🚩Пример использования линтера в JavaScript

1⃣Установка ESLint
npm install eslint --save-dev


2⃣Инициализация конфигурации ESLint
npx eslint --init


3⃣Создайте файл example.js
function hello() {
console.log("Hello, world!");
}

hello();


Запустите ESLint:
npx eslint example.js


🚩Плюсы

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

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

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

Обучение и развитие
Использование линтеров помогает разработчикам учиться и развиваться, узнавая о лучших практиках и стандартах кода.

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

29 Dec, 16:10


🤔 Как будут реализованы опциональные функции в протоколах?

Опциональные функции в протоколах помечаются с помощью атрибута @objc optional. Класс, который реализует такой протокол, может либо реализовать функцию, либо проигнорировать её.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

29 Dec, 09:10


🤔 Что такое CI/CD?

Это практика автоматизации разработки, тестирования и развертывания программного обеспечения. Цель CI/CD — повысить скорость, частоту и надежность релизов, снижая риски и улучшая качество кода. Давайте разберем, что означает каждый компонент CI/CD и как они работают вместе.

🚩Основные компоненты

🟠Continuous Integration (CI)
Процесс регулярного объединения изменений кода из разных источников в общую кодовую базу. Обнаружение и устранение проблем на ранних стадиях разработки. Разработчики часто интегрируют свой код в общий репозиторий (например, несколько раз в день). Каждый коммит запускает автоматическую сборку и тестирование, чтобы убедиться, что изменения не сломали существующий код.
Инструменты: Jenkins, GitLab CI, Travis CI, CircleCI.

🟠Continuous Delivery (CD)
Практика, при которой код всегда готов к развертыванию в продакшен, но развертывание может требовать ручного вмешательства. Обеспечение готовности кода к релизу в любой момент времени. После успешного прохождения всех этапов CI, код автоматически продвигается к этапам развертывания на различные среды (staging, production). Требует минимального ручного вмешательства для выпуска новой версии.
Инструменты: Spinnaker, Bamboo, Jenkins.

🟠Continuous Deployment
Расширение Continuous Delivery, где каждое изменение, прошедшее все этапы тестирования, автоматически развертывается в продакшен. Полная автоматизация развертывания, минимизация времени между коммитом и доставкой кода пользователям. После успешного прохождения всех этапов CI и CD, изменения автоматически развертываются в продакшен без ручного вмешательства.
Инструменты: Jenkins, GitLab CI/CD, CircleCI, AWS CodePipeline.

🚩Пример использования

🟠Настройка Jenkins
Установите и настройте Jenkins на сервере.
Создайте новый pipeline проект в Jenkins.

🟠Создание Jenkinsfile:
В корне вашего репозитория создайте файл Jenkinsfile, который описывает этапы вашего CI/CD процесса.
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'go build -v'
}
}
stage('Test') {
steps {
sh 'go test -v ./...'
}
}
stage('Deploy') {
steps {
sh 'echo "Deploying to production"'
// Ваши команды для развертывания
}
}
}
}


🟠Запуск Pipeline
Коммиты в репозиторий автоматически запускают Pipeline, выполняющий сборку, тестирование и развертывание.

🚩Плюсы

Быстрое обнаружение ошибок
Автоматическое тестирование каждого изменения кода помогает быстро обнаруживать и устранять ошибки.
Повышение качества кода
Регулярное объединение кода и тестирование улучшают качество и стабильность кода.
Быстрое и надежное развертывание
Автоматизация развертывания минимизирует человеческие ошибки и ускоряет выпуск новых версий.
Упрощение обратной связи
Быстрая интеграция изменений позволяет разработчикам получать обратную связь о качестве кода в реальном времени.

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

28 Dec, 16:10


🤔 Как пишутся Unit тесты со стандартным пакетом testing?

Тесты пишутся в файлах с суффиксом _test.go, а функции тестов имеют сигнатуру func TestXxx(t *testing.T). Для запуска тестов используется команда go test, которая автоматически находит и выполняет тесты. Пакет testing предоставляет методы для логирования, проверки условий и обработки ошибок в тестах.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

28 Dec, 09:10


🤔 Как создавать и импортировать пакеты?

Создание и импортирование пакетов в Go является важной частью организации кода и управления зависимостями. Давайте рассмотрим, как создать пакет, как его структурировать и как импортировать и использовать в других файлах.

🚩Создание пакета

🟠Создание структуры проекта
Создайте папку для вашего проекта и внутри нее создайте папку для вашего пакета.
myproject/
main.go
mypackage/
mypackage.go


🟠Определение пакета
В файле mypackage.go определите пакет с именем mypackage и добавьте функции, которые вы хотите экспортировать.
Файл mypackage/mypackage.go
package mypackage

import "fmt"

// Экспортируемая функция (имя начинается с заглавной буквы)
func PrintHello() {
fmt.Println("Hello from mypackage")
}

// Неэкспортируемая функция (имя начинается с маленькой буквы)
func privateFunction() {
fmt.Println("This is a private function")
}


🚩Импортирование и использование пакета

🟠Импортирование пакета в `main.go`
Чтобы использовать функции из вашего пакета mypackage в файле main.go, нужно импортировать этот пакет.
Файл main.go
package main

import (
"mypackage" // Импортируем наш пакет
)

func main() {
mypackage.PrintHello() // Вызов экспортируемой функции из пакета mypackage
// mypackage.privateFunction() // Это вызовет ошибку, так как функция не экспортируется
}


🟠Запуск программы
Перейдите в корневую папку вашего проекта (myproject) и выполните команду
go run main.go


Вы должны увидеть выво
Hello from mypackage


🟠Именованные импорты
Иногда может потребоваться импортировать пакет под другим именем. Это может быть полезно для сокращения длинных имен пакетов или для избежания конфликтов имен.
Пример с именованным импортом:
Файл main.go:
package main

import (
"fmt"
mp "mypackage" // Импортируем mypackage под именем mp
)

func main() {
mp.PrintHello() // Используем алиас для вызова функции из пакета
}


🟠Пустой импорт
Пустой импорт используется для выполнения побочных эффектов, таких как инициализация или регистрация пакетов, без явного использования их функций.
Пример пустого импорта
import (
_ "some/package" // Импортируем пакет только для его инициализации
)


🚩Модули и управление зависимостями

Для управления зависимостями в Go используется система модулей. Она позволяет указать зависимости вашего проекта и их версии.

🟠Инициализация модуля
Для создания нового модуля выполните команду
go mod init myproject


🟠Добавление зависимостей
Когда вы импортируете внешний пакет, Go автоматически добавляет его в ваш файл go.mod.

🚩Полный пример

1⃣Структура проекта
myproject/
go.mod
main.go
mypackage/
mypackage.go


2⃣Файл mypackage/mypackage.go
package mypackage

import "fmt"

func PrintHello() {
fmt.Println("Hello from mypackage")
}


3⃣Файл main.go
package main

import (
"mypackage"
)

func main() {
mypackage.PrintHello()
}


4⃣Инициализация модуля и запуск
cd myproject
go mod init myproject
go run main.go


5⃣Вы должны увидеть вывод
Hello from mypackage


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

27 Dec, 16:10


🤔 Что такое интеграционные тесты?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

27 Dec, 09:10


🤔 Что такое пакеты (package) в Go?

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

🚩Основные концепции пакетов

🟠Определение пакета
Каждый файл Go начинается с объявления пакета, к которому он принадлежит. Например, package main или package fmt.

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

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

🟠Публичные и приватные члены
Имена, которые начинаются с заглавной буквы, являются экспортируемыми (доступными из других пакетов). Имена, которые начинаются с маленькой буквы, являются неэкспортируемыми (доступны только внутри пакета).

🚩Пример использования пакетов

🟠Создание пакета
Файл mypackage/mypackage.go
package mypackage

import "fmt"

// Экспортируемая функция
func PrintHello() {
fmt.Println("Hello from mypackage")
}

// Неэкспортируемая функция
func privateFunction() {
fmt.Println("This is a private function")
}


🟠Использование пакета
Файл main.go
package main

import (
"mypackage"
)

func main() {
mypackage.PrintHello() // Output: Hello from mypackage
// mypackage.privateFunction() // Ошибка: неэкспортируемая функция
}


🚩Импорт нескольких пакетов

В Go можно импортировать несколько пакетов в одном блоке.
package main

import (
"fmt"
"mypackage"
)

func main() {
fmt.Println("Using multiple packages")
mypackage.PrintHello()
}


🚩Именованные импорты

Иногда необходимо импортировать пакеты с другим именем для избежания конфликтов или для удобства. Это делается с помощью именованных импортов.
package main

import (
"fmt"
mp "mypackage"
)

func main() {
fmt.Println("Using aliased package")
mp.PrintHello()
}


🚩Пустой импорт

Пустой импорт используется, когда нужно выполнить инициализацию пакета, но не использовать его явно. Это часто используется для регистрации драйверов или других побочных эффектов.
import (
_ "some/package"
)


🚩Структура проекта с пакетами

Проекты на Go часто организуются в виде нескольких пакетов, где каждый пакет выполняет определенную роль. Типичная структура проекта может выглядеть следующим образом:
myproject/
main.go
mypackage/
mypackage.go
anotherpackage/
anotherpackage.go


Файл main.go
package main

import (
"mypackage"
"anotherpackage"
)

func main() {
mypackage.PrintHello()
anotherpackage.DoSomething()
}


Файл anotherpackage/anotherpackage.go
package anotherpackage

import "fmt"

func DoSomething() {
fmt.Println("Doing something in anotherpackage")
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

26 Dec, 16:10


🤔 Что такое Unit тесты?

Unit тесты проверяют отдельные, изолированные части кода (модули, функции или методы) на корректность их работы. Они обеспечивают уверенность в том, что каждая часть системы работает как ожидается независимо от остальных. Это основа для выявления багов на ранних этапах разработки.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

26 Dec, 09:10


🤔 Какие основные отличия есть у Go перед языками Java, Python?

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

🟠Компиляция и выполнение
Go: Компилируемый язык, компилируется в машинный код, что обеспечивает высокую производительность и быстрое время выполнения.
Java: Компилируется в байт-код, который выполняется на виртуальной машине Java (JVM). Это обеспечивает переносимость, но может добавлять накладные расходы.
Python: Интерпретируемый язык, что делает его менее производительным по сравнению с компилируемыми языками.

🟠Простота и лаконичность
Go: Разработан для простоты и читаемости, минимизирует синтаксическую сложность, избегает избыточности.
Java: Сложный и многословный синтаксис, требует больше кода для выполнения тех же задач.
Python: Простой и читаемый синтаксис, который делает его легким для изучения и использования.

🟠Управление памятью
Go: Автоматическая сборка мусора, но с управляемыми задержками для обеспечения высокой производительности.
Java: Автоматическая сборка мусора на JVM, что может приводить к задержкам в критических приложениях.
Python: Автоматическая сборка мусора с использованием подсчета ссылок и циклического сборщика мусора.

🟠Конкурентность и параллелизм
Go: Встроенная поддержка конкурентности через горутины и каналы, легковесные потоки с низкими накладными расходами.
Java: Многопоточность с использованием потоков, сложное управление потоками и синхронизацией.
Python: Поддержка многопоточности, но ограниченная глобальной блокировкой интерпретатора (GIL), что затрудняет использование многопоточности для параллельных вычислений.

🟠Статическая и динамическая типизация
Go: Статически типизированный язык, ошибки типа обнаруживаются на этапе компиляции, что повышает надежность кода.
Java: Статически типизированный язык, что позволяет обнаруживать ошибки типа на этапе компиляции.
Python: Динамически типизированный язык, типы проверяются во время выполнения, что может приводить к ошибкам времени выполнения.

🟠Интерфейсы и наследование
Go: Использует интерфейсы для определения поведения без наследования. Интерфейсы реализуются неявно.
Java: Использует классы и интерфейсы, поддерживает множественное наследование через интерфейсы и одиночное наследование классов.
Python: Поддерживает множественное наследование классов, что может усложнять структуру программы.

🟠Стандартная библиотека
Go: Богатая стандартная библиотека с встроенной поддержкой работы с сетью, веб-серверами и другими задачами.
Java: Широкая стандартная библиотека с обширной поддержкой различных API и утилит.
Python: Обширная стандартная библиотека, особенно сильная в области научных вычислений, обработки данных и веб-разработки.

🟠Экосистема и инструменты
Go: Современные и мощные инструменты для сборки, тестирования и профилирования. Простая система управления зависимостями.
Java: Зрелая экосистема с множеством фреймворков и инструментов (например, Maven, Gradle, Spring).
Python: Обширная экосистема пакетов и библиотек (например, pip, virtualenv, Django).

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

25 Dec, 09:10


🤔 Что такое Go?

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

🚩Основные характеристики

🟠Компиляция и скорость
Go — компилируемый язык, обеспечивающий высокую производительность.
🟠Простота
Язык избегает избыточности, улучшая читаемость кода.
🟠Сборка мусора
Автоматическое управление памятью.
🟠Конкурентность
Встроенные средства для работы с параллельными вычислениями, такие как горутины и каналы.
🟠Стандартная библиотека
Широкий набор инструментов и библиотек.

🚩Пример простого приложения

Простого веб-сервера:
package main

import (
"fmt"
"net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}

func main() {
http.HandleFunc("/", helloHandler)
fmt.Println("Starting server on :8080")
http.ListenAndServe(":8080", nil)
}


🚩Основные концепции

🟠Горутины
Легковесные потоки для параллельных вычислений.
go func() {
fmt.Println("Hello from a goroutine!")
}()


🟠Каналы
Средства обмена данными между горутинами.
ch := make(chan int)
go func() {
ch <- 42
}()
value := <-ch
fmt.Println(value)


🟠Интерфейсы
Абстракция поведения без привязки к реализации.
type Stringer interface {
String() string
}


🟠Пакеты
Организация кода для управления и повторного использования.
package mypackage

import "fmt"

func MyFunction() {
fmt.Println("Hello from mypackage")
}


🚩Применение Go

Go используется для серверного ПО, облачных сервисов, микросервисов, инструментов командной строки и систем с высокой производительностью. Известные проекты на Go включают Kubernetes, Docker, Prometheus, а также Google, Dropbox и Netflix.

🚩Плюсы и минусы

Высокая производительность
Быстро компилируемый язык.
Простота и читаемость
Минимум синтаксического шума.
Конкурентность
Простые механизмы параллельных вычислений.
Богатая библиотека
Широкий набор встроенных инструментов.
Ограниченные обобщения
Ранее отсутствовали, добавлены в Go 1.18.
Нет исключений
Используется управление ошибками через возвращаемые значения.

Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

24 Dec, 16:10


🤔 Что такое указатели?

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

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

24 Dec, 09:10


🤔 Как сообщить компилятору, что наш тип реализует интерфейс?

В Go реализация интерфейсов происходит неявно. Это означает, что если тип содержит методы, определенные в интерфейсе, компилятор автоматически считает, что этот тип реализует интерфейс. Вам не нужно явно указывать, что тип реализует интерфейс, как это делается в других языках (например, с использованием ключевого слова implements в Java или implements/inherits в C#).

🟠Проверка на уровне компиляции через явное присваивание
Вы можете создать переменную интерфейсного типа и присвоить ей значение вашего типа. Если тип не реализует интерфейс, компилятор выдаст ошибку.
package main

import "fmt"

// Определение интерфейса
type Stringer interface {
String() string
}

// Определение структуры
type Person struct {
Name string
Age int
}

// Реализация метода String для структуры Person
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

func main() {
// Присваивание переменной интерфейса значения типа Person
var s Stringer = Person{Name: "Alice", Age: 30}
fmt.Println(s.String()) // Output: Alice (30 years old)
}


🟠Использование пустого присваивания для проверки соответствия интерфейсу
Еще один способ проверить соответствие типа интерфейсу — использовать пустое присваивание. Это позволяет выполнять проверку на уровне компиляции без необходимости использовать переменную интерфейса.
package main

// Определение интерфейса
type Stringer interface {
String() string
}

// Определение структуры
type Person struct {
Name string
Age int
}

// Реализация метода String для структуры Person
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

// Пустое присваивание для проверки соответствия интерфейсу
var _ Stringer = Person{}

func main() {
// Ваш основной код здесь
}


🟠Использование функции, принимающей интерфейс
Если у вас есть функция, принимающая значение интерфейсного типа, вы можете использовать ее для проверки соответствия типа интерфейсу.
package main

import "fmt"

// Определение интерфейса
type Stringer interface {
String() string
}

// Определение структуры
type Person struct {
Name string
Age int
}

// Реализация метода String для структуры Person
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

// Функция, принимающая интерфейс
func printString(s Stringer) {
fmt.Println(s.String())
}

func main() {
p := Person{Name: "Alice", Age: 30}
printString(p) // Output: Alice (30 years old)
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

23 Dec, 16:10


🤔 Какие циклы есть в Go?

Go поддерживает только цикл for, который можно использовать как:
Классический цикл с условиями (for i := 0; i < 10; i++).
Цикл с проверкой условия (for i < 10).
Бесконечный цикл (for {}), который останавливается вручную через break.


Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

23 Dec, 09:10


🤔 Где следует поместить описание интерфейса?

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

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

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

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

🚩Примеры

🟠Интерфейс в пакете использования
Если интерфейс используется только в одном пакете, его следует определить в этом пакете.
package mypackage

type Stringer interface {
String() string
}

type Person struct {
Name string
Age int
}

func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}


🟠Интерфейс в пакете реализации
Если интерфейс представляет поведение, которое реализуют типы в разных пакетах, его можно определить в пакете, который предоставляет основную функциональность.
package io

type Reader interface {
Read(p []byte) (n int, err error)
}

type Writer interface {
Write(p []byte) (n int, err error)
}


🟠Отдельный пакет для интерфейсов
Если интерфейсы должны быть доступны в нескольких пакетах, можно создать отдельный пакет для них.
package interfaces

type Stringer interface {
String() string
}


🟠Использование интерфейса в других пакетах
Файл main.go
package main

import (
"fmt"
"myproject/interfaces"
)

type Person struct {
Name string
Age int
}

func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

func printString(s interfaces.Stringer) {
fmt.Println(s.String())
}

func main() {
p := Person{Name: "Alice", Age: 30}
printString(p)
}


Ставь 👍 и забирай 📚 Базу знаний

Golang | Вопросы собесов

22 Dec, 16:10


🤔 Расскажи про гарбидж коллектор

Гарбидж-коллектор (сборщик мусора) — это механизм управления памятью, который автоматически освобождает память, занятую объектами, больше не используемыми программой. В языках, таких как Java и Go, сборщик мусора отслеживает объекты, на которые нет ссылок, и периодически удаляет их, освобождая память. Этот процесс помогает предотвращать утечки памяти, хотя иногда может вызвать небольшие паузы в работе программы.

Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний

Golang | Вопросы собесов

22 Dec, 09:10


🤔 Как преобразовать интерфейс к другому типу?

Преобразование интерфейса к другому типу выполняется с помощью утверждения типа (type assertion). Это позволяет проверить, является ли значение, содержащееся в интерфейсной переменной, конкретным типом, и, если да, привести его к этому типу. Утверждение типа может быть выполнено как с проверкой, так и без проверки.

🚩Утверждение типа (Type Assertion)

Синтаксис
value, ok := interfaceValue.(ConcreteType)


interfaceValue — переменная интерфейсного типа. ConcreteType — тип, к которому вы хотите привести значение. value — переменная, которая будет содержать значение типа ConcreteType, если приведение успешно. ok — булевое значение, указывающее, было ли приведение успешным.

🚩Пример утверждения типа с проверкой

Когда вы используете утверждение типа с проверкой, вы получаете два значения: само значение и булевое значение, указывающее, было ли приведение успешным.
package main

import "fmt"

func main() {
var i interface{} = "hello"

// Утверждение типа с проверкой
s, ok := i.(string)
if ok {
fmt.Println("String:", s)
} else {
fmt.Println("Not a string")
}

// Утверждение типа с проверкой
n, ok := i.(int)
if ok {
fmt.Println("Integer:", n)
} else {
fmt.Println("Not an integer")
}
}


🚩Пример утверждения типа без проверки

Когда вы уверены в типе значения, вы можете использовать утверждение типа без проверки. Если тип значения не соответствует ожидаемому, программа вызовет панику.
package main

import "fmt"

func main() {
var i interface{} = "hello"

// Утверждение типа без проверки
s := i.(string)
fmt.Println("String:", s)

// Утверждение типа без проверки, которое вызовет панику
// n := i.(int) // Это вызовет панику, если раскомментировать
// fmt.Println("Integer:", n)
}


🚩Использование `switch` для проверки типа

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

import "fmt"

func printType(i interface{}) {
switch v := i.(type) {
case string:
fmt.Println("String:", v)
case int:
fmt.Println("Integer:", v)
case bool:
fmt.Println("Boolean:", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}

func main() {
printType("hello") // Output: String: hello
printType(42) // Output: Integer: 42
printType(true) // Output: Boolean: true
printType(3.14) // Output: Unknown type: float64
}


🚩Пример использования интерфейсов и утверждения типов

Рассмотрим пример, в котором используется интерфейс fmt.Stringer и утверждение типа для приведения значения к конкретному типу.
package main

import "fmt"

type Person struct {
Name string
Age int
}

// Реализация интерфейса fmt.Stringer
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}

func printValue(i interface{}) {
if str, ok := i.(fmt.Stringer); ok {
fmt.Println("Stringer:", str.String())
} else {
fmt.Println("Not a Stringer")
}
}

func main() {
p := Person{Name: "Alice", Age: 30}
printValue(p) // Output: Alice (30 years old)
printValue("Hello, world!") // Output: Not a Stringer
}


Ставь 👍 и забирай 📚 Базу знаний