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

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

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

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

Наши каналы: https://t.me/proglibrary/9197
Download Telegram
💬Один из частых вопросов на собесах: «Что такое конкурентность в Go?»

Сначала надо вспомнить о таких вещах, как асинхронность и параллельность.

📌Асинхронность говорит о порядке исполнения кода. Вычисления в системе могут идти двумя способами:
— когда код выполняется последовательно — синхронно;
— когда результат выполнения кода доступен не сразу, а через некоторое время в виде некоторого асинхронного (нарушающего обычный порядок выполнения) вызова, — асинхронно.

📌Параллельность в свою очередь говорит о том, что физически происходит несколько процессов одновременно.

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

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

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

Конкурентные вычисления реализуются на одном ядре системы. Примитивы конкурентности в Go:
— горутины;
— каналы;
— мьютексы (объекты Mutex, RWMutex);
— оператор select … case;
— объекты waitGroup, errGroup.

Конкурентность позволяет увеличить скорость обработки данных при наличии ресурсов, если выполнять те же задачи, которые можно выполнять последовательно.
🔥7👍411
💬Что такое ООП и как эта методология реализована в Go?

Это методология, при которой программа рассматривается как набор объектов, взаимодействующих друг с другом. У каждого есть свойства и поведение. Каждый объект является экземпляром определённого класса, а классы образуют иерархию наследования.

Основные принципы ООП:

🔸Абстракция
🔸Инкапсуляция
🔸Наследование
🔸Полиморфизм

📌Но! В Go нет классов, объектов, исключений и шаблонов. Нет иерархии типов, но есть сами типы — то есть возможность описывать свои типы/структуры. Структурные типы (с методами) служат тем же целям, что и классы в других языках.

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

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

📌Инкапсуляция в Go реализована на уровне пакетов. Имена, начинающиеся со строчной буквы, видны только внутри этого пакета (не являются экспортируемыми). И наоборот — все, что начинается с заглавной буквы — доступно извне пакета.
👍4🤔1
💬Что из себя представляют каналы в Go?

Каналы представляют инструменты коммуникации между горутинами.

Технически это конвейер/труба, откуда можно считывать или помещать данные. То есть одна горутина может отправить данные в канал, а другая — считать помещенные в этот канал данные.

📌Для создания канала в Go есть ключевое слово chan. Канал может передавать данные только одного типа.

package main

import "fmt"

func main() {
var c chan int
fmt.Println(c)
}


При простом определении переменной канала она имеет значение nil, то есть по сути канал неинициализирован. Для инициализации применяется функция make().

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

📌Для создания небуферизированного канала вызывается функция make() без указания емкости канала:

var intCh chan int = make(chan int)

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

chanBuf := make(chan bool, 3)

📌С каналом можно произвести 4 действия:

— создать канал;
— записать данные в канал;
— вычесть что-то из канала;
— закрыть канал.

📌Однонаправленные каналы: в Go можно определить канал, как доступный только для отправки данных или только для получения данных.

📌Канал может быть возвращаемым значением функции. Однако следует внимательно подходить к операциям записи и чтения в возвращаемом канале.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥4
💬Какие встроенные типы данных есть в Go?

Go имеет ряд встроенных типов данных, а также он позволяет определять свои типы.

📌Целочисленные типы

▫️int8: представляет целое число от -128 до 127 и занимает в памяти 1 байт (8 бит).
▫️int16: представляет целое число от -32768 до 32767 и занимает в памяти 2 байта (16 бит).
▫️int32: представляет целое число от -2147483648 до 2147483647 и занимает 4 байта (32 бита).
▫️int64: представляет целое число от –9 223 372 036 854 775 808 до 9 223 372 036 854 775 807 и занимает 8 байт (64 бита).
▫️uint8: представляет целое число от 0 до 255 и занимает 1 байт.
▫️uint16: представляет целое число от 0 до 65535 и занимает 2 байта.
▫️uint32: представляет целое число от 0 до 4294967295 и занимает 4 байта.
▫️uint64: представляет целое число от 0 до 18 446 744 073 709 551 615 и занимает 8 байт.
▫️byte: синоним типа uint8, представляет целое число от 0 до 255 и занимает 1 байт.
▫️rune: синоним типа int32, представляет целое число от -2147483648 до 2147483647 и занимает 4 байта.
▫️int: представляет целое число со знаком, которое в зависимости от платформы может занимать либо 4 байта, либо 8 байт. То есть соответствовать либо int32, либо int64.
▫️uint: представляет 32-битные или 64-битные числа без знака (в зависимости от платформы).

📌Числа с плавающей точкой

▫️float32: представляет число с плавающей точкой от 1.4*10-45 до 3.4*1038 (для положительных). Занимает в памяти 4 байта (32 бита)
▫️float64: представляет число с плавающей точкой от 4.9*10-324 до 1.8*10308 (для положительных) и занимает 8 байт.

📌Комплексные числа

▫️complex64: комплексное число, где вещественная и мнимая части представляют числа float32.
▫️complex128: комплексное число, где вещественная и мнимая части представляют числа float64.

📌Тип bool: может иметь одно из двух значений: true (истина) или false (ложь).

📌Строки представлены типом string. В Go строке соответствует строковый литерал, но кроме обычных символов строка может содержать специальные последовательности, которые начинаются с обратного слеша \.

📌Если переменной не присвоено значение, то она имеет значение по умолчанию, которое определено для ее типа. Для числовых типов это число 0, для логического типа — false, для строк — "" (пустая строка).
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍1
💬 В чем отличие между массивами и срезами в Go?

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

▪️Определение массива: [capacity]data_type{element_values}

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

▪️Определение среза: s := []data_type{element1, element2, ...}

▪️Можно также создать срез определенной длины без заполнения элементов коллекции с помощью встроенной функции make():
s := make([]string, 3)

▪️Рассчитать длину массива/среза можно с использованием метода len() с указанием массива/среза в качестве параметра.

▪️Массивы можно разделить на срезы с помощью следующего синтаксиса: [first_index:second_index] или s[:].

▪️В дополнение к базовой функциональности, срезы имеют несколько дополнительных особенностей по сравнению с массивыми. Одна из них — функция append, которая позволяет добавлять элементы в срез.

▪️Чтобы удалить элемент, нужно выделить в срез элементы до/после него, а затем объединить два новых среза в один, не содержащий удаленного элемента: s = append(s[:i], s[i+1:]...).

▪️Поскольку срезы имеют переменную длину, для определения размера этого типа данных метод len() подходит не очень хорошо. Вместо него лучше использовать функцию cap() для определения емкости среза. Данная функция показывает, сколько элементов может содержать срез.

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

▪️Срезы могут быть скопированы с помощью метода copy.
4👍2
💬Что такое пакеты в Go и для чего они нужны?

▫️Каждая программа на Go состоит из пакетов. Файлы, находящиеся в одном каталоге, должны относиться к одному пакету.

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

▫️Согласно соглашению, имя пакета совпадает с последним элементом пути импорта. Например, пакет math/rand состоит из файлов, которые начинаются с оператора package rand.

▫️Импорт пакетов осуществляется с помощью оператора import и позволяет нам вызывать функции, которые не встроены в Go. Некоторые пакеты являются частью стандартной библиотеки Go, а некоторые нужно устанавливать с помощью инструмента go get.

🤔Резюмируя сказанное:

📌Пакет — это механизм
переиспользования кода, при котором файлы помещаются в общий каталог. В начале каждого такого файла объявляется зарезервированное слово
package, а после него указывается имя пакета. В рамках пакета все функции и глобальные переменные видят друг друга.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍2