15 вопросов с собеседований Golang из LinkedIn Assessment — подробные пояснения
Недавно я наткнулся на оценку LinkedIn Golang, интригующую возможность для разработчиков получить значок, демонстрирующий их знание языка (этот значок не только демонстрирует ваши навыки, но и помогает вам выделиться из толпы на конкурентном рынке труда).
Я нашёл вопросы в тесте довольно интересными, и я уже писал о некоторых из них ранее, так как они дают ценную информацию о различных аспектах языка программирования Go.
1. Что нужно, чтобы две функции были одного типа?
Если мы хотим, чтобы две функции в Go считались одним типом, они должны иметь одинаковую сигнатуру функции .
Это просто означает, что они должны иметь соответствующие параметры (количество, типы) и возвращаемые значения.
2. Что возвращает функция len(), если ей передаётся строка в кодировке UTF-8?
Вот вам небольшая идея: в Go строки на самом деле представляют собой последовательности байтов. Это означает, что когда вы передаёте строку в кодировке UTF-8 функции len(), она считает байты, а не символы:
3. Каково значение Read?
Идентификатор iota в Go — интересная функция — она представляет целочисленное значение, которое начинается с 0 и увеличивается на 1 для каждого элемента в блоке const.
4. Как вы скажете go test вывести запущенные тесты?
При использовании команды go test вы можете включить флаг -v ("verbose") для более подробного вывода.
Запустив go test с флагом -v, вы увидите название каждого теста, его результат (ПРОШЕЛ или НЕ ПРОШЕЛ) и продолжительность теста по мере его выполнения:
5. Что делает блок sync.Mutex, пока он заблокирован?
В Go a sync.Mutex служит механизмом взаимного исключения, гарантируя, что только одна горутина может одновременно получить доступ к критическому разделу кода.
Фраза « любое чтение или запись переменной, которую он блокирует » соответствует нашему пониманию, поскольку мы используем a sync.Mutex для защиты доступа к общим переменным.
6. Каков идиоматический способ приостановить выполнение текущей области до тех пор, пока не будет возвращено произвольное количество подпрограмм?
Если у вас была возможность изучить мою статью о пакете Go Sync, вы, возможно, помните, что сначала я использовал функцию time.Sleep, прежде чем перейти к более эффективному sync.WaitGroup:
In sync.WaitGroupGo — это удобный инструмент, который позволяет вам дождаться завершения группы горутин, прежде чем приступить к выполнению.
Он работает с использованием простого счётчика и эффективно блокирует текущую область действия до тех пор, пока все рабочие горутины не завершат свои задачи, а счётчик WaitGroup не достигнет нуля.
7. Каков побочный эффект использования time.After в утверждении select?
Если вы не знакомы с time.After, это функция в пакете Go time, которая возвращает набор каналов для отправки текущего времени после указанной продолжительности.
Обычно она используется в операторах select для реализации тайм-аутов или задержек. Например, представьте, что вы ждёте 3 секунды, прежде чем вывести что-то на экране:
Теперь поговорим о побочном эффекте.
Для кратковременных time.After периодов это может не иметь большого значения, но рассмотрим сценарий, в котором тайм-аут установлен на 1 час, а работа завершается до истечения времени ожидания. В этой ситуации таймер всё ещё задерживается в памяти:
Как следствие, горутина, созданная с помощью , time.After не завершится, пока не истечёт полный час, даже если операция завершится раньше.
8. Какие ограничения есть на тип var для компиляции i := myVal.(int)?
В контексте утверждения типа i := myVal.(int) переменная myVal должна быть типом интерфейса для успешной компиляции кода.
Однако использование её таким образом может быть рискованным и неэффективным, так как это может вызвать панику во время выполнения, если myVal это не тип int. Чтобы более изящно справиться с этой ситуацией, лучше использовать форму утверждения типа с двумя значениями, которая обеспечивает резервный механизм:
9. Как правильно передать это как тело запроса HTTP POST?
Чтобы отправить данные в виде тела запроса HTTP POST, важно знать тип содержимого. Поскольку это необработанный текст, мы будем использовать тип содержимого «текст/обычный». Функция http.Post требует в io.Reader качестве тела, а не строку или байты:
Интерфейс Reader определяется следующим образом:
Чтобы выполнить требования, мы преобразуем тело в буфер, реализующий этот интерфейс:
Таким образом, правильный способ отправки данных в виде HTTP-запроса POST:
10. Каким должно быть идиоматическое имя для интерфейса с одним методом и сигнатурой Save() error?
Основываясь на эффективном соглашении об именах Go для интерфейсов, интерфейсы с одним методом обычно именуются путём добавления суффикса «-er» или аналогичной модификации к имени метода, что приводит к таким существительным агента, как Reader, Writer, Formatterи CloseNotifier..
В этом случае идиоматическое название интерфейса будет Saver .
О, возможно, вы также сталкивались с интерфейсом Stringer(), который определяется следующим образом:
Это уловка, когда вы передаёте значение, реализующее интерфейс, Stringer таким функциям, как fmt.Println() или fmt.Printf(), метод String() автоматически вызывается для получения строкового представления значения.
11. Какова чувствительность к регистру по умолчанию для функции JSON Unmarshal?
Функция JSON Unmarshal в Go по умолчанию нечувствительна к регистру. Однако это поведение можно переопределить с помощью тегов JSON. Что происходит, когда есть два поля, такие как «title» и «Title»?
Давайте рассмотрим это на примере, чтобы понять, почему сначала не учитывается регистр:
В этом примере поле Title имеет явный тег поля json:"Title", предписывающий функции json.Unmarshal сопоставлять поле JSON «Title» (с учётом регистра) с полем структуры Title. Поле SubTitle не имеет тега поля, поэтому оно будет использовать поведение по умолчанию без учёта регистра, чтобы сопоставить поле «subtitle» JSON с полем структуры SubTitle.
Это связано с тем, что encoding/json пакет использует резервный механизм во время демаршалинга:
- Сначала он ищет точное совпадение между именами полей JSON и именами полей или тегами структуры.
- Если он не находит точного совпадения, он возвращается к линейному поиску без учёта регистра (который может быть дорогостоящим для больших наборов данных).
12. Где полезен встроенный метод recover?
Встроенный метод recover действительно полезен в отложенных функциях , но не рекомендуется вызывать его напрямую с помощью ключевого слова defer.
13. В чём разница между time пакетами Time.Sub() и методами Time.Add()?
Основное различие между методами Time.Add()и Time.Sub()в пакете time заключается в их параметрах и возвращаемых значениях. Time.Add() принимает параметр Duration и возвращает значение Time, а Time.Sub() принимает параметр Time и возвращает Duration.
Причина в том, что он Time.Add() может обрабатывать отрицательные аргументы, эффективно функционируя как операция вычитания. Следовательно, не имеет смысла иметь другой метод Time.Sub(), который также принимает файлы Duration.
Методы Time.Add() и Time.Sub() служат разным целям и имеют разные сигнатуры для конкретных вариантов использования:
Как показано в этом примере, Time.Add() используется для добавления или вычитания продолжительности из значения времени, а Time.Sub() используется для вычисления продолжительности между двумя значениями времени.
14. Каков риск использования нескольких тегов полей в одной структуре?
Основная проблема с использованием нескольких тегов полей в одной структуре заключается в том, что это может привести к тесной связи между различными уровнями вашего приложения . Чтобы проиллюстрировать эту концепцию, давайте рассмотрим пример:
Но что такое « пары разных слоёв»?
В этом примере структура Post имеет два тега поля для каждого поля: json и bson. Эти теги могут использоваться для различных целей, таких как отправка HTTP-ответов (с помощью json) и обработка демаршалинга MongoDB (с помощью bson).
Когда используется несколько таких тегов, уровень ответа HTTP (веб-сервер) и уровень хранения (MongoDB) становятся тесно связанными. Если вы хотите изменить title, например, на shortTitle, вам потребуется обновить как ответ HTTP (что также может повлиять на клиентов, обрабатывающих ответ), так и хранилище MongoDB.
Важно отметить, что использование нескольких тегов полей таким образом не является неправильным по своей сути.
15. Если вы перебираете карту в цикле for range, в каком порядке будет осуществляться доступ к парам ключ:значение?
При переборе карты с использованием цикла for range в Go порядок доступа к парам ключ-значение не обязательно соответствует какой-либо конкретной последовательности и не обязательно соответствует порядку вставки:
В результате вы можете столкнуться с разными порядками каждый раз, когда перебираете одну и ту же карту. Такое поведение связано с реализацией карт в Go как хэш-карт, что приводит к недетерминированному порядку итераций.