Forwarded from Golang
Мощная шпаргалка по Go, которая покрывает практически все темы
Если пролистать хотя бы по диагонали, есть отличный от нуля шанс пройти собеседование и получить оффер)
Что внутри?
├╼
Компилятор├╼
Пакеты├╼
Функции├╼
Управление памятью├╼
Операторы├╼
Управляющие структуры├╼
Объектноориентированность├╼
Интерфейсы├╼
Обработка ошибок├╼
Горутины (Goroutine)├╼
Проверка управления памятью├╼
Reflect ├╼
Добавление кода C├╼
GUI╰╼
Распределенные системы@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Итак, задача: написать свою фукнцию
sleep
time.After
, вот так:package main
import (
"log"
"time"
)
func sleep(d time.Duration) {
select {
case <-time.After(d):
}
}
func CallSleep() {
log.Println("Do something")
sleep(5 * time.Second)
log.Println("Something else")
}
Но выглядит как-то громоздко, да и вообще.
func sleep2(d time.Duration) time.Time {
ticker := time.Tick(d)
for done := range ticker {
return done
}
return time.Now()
}
func sleep(d time.Duration) {
<-time.After(d)
}
Ну вот, то, что нужно
@Golang_google
Please open Telegram to view this post
VIEW IN TELEGRAM
network_api -> data(UseCase->Repository)
. Так как все
http
хендлеры обрабатываются параллельно, то каким образом корректно протянуть зависимости репозиториев и use_case
объектов в слой network_api
? То есть это будут синглтоны или же их нужно создавать для каждого отдельного request
? Что насчёт доступа к общим ресурсам?
Например,
use_case
при загрузке читает json
-конфигурацию и в дальнейшем к ней обращается по многим путям из слоя nwtwork_api
.Есть какие нибудь best practices?
Если наши данные терпимы к параллельному одновременному доступу — тогда можно не замарачиваться. Если же нельзя одновременно из нескольких потоков обращаться к менеджеру данных — тогда стоит ввести глобальную блокировку. Фактически, такой глобальной блокировкой будет являться единственное соединение к базе данных.
Вот и всё, пожалуй
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Держите полезную статью о тестировании Go-приложений
Что внутри?
ExecuteTest
, передавая контекст и testing.TB
или provider.T
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Но если ты посмотришь это видео, то будешь знать ответы, и во всеоружии встретишь такие вопросы, если они попадутся
Уверен, будет полезно)
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
var _ myInterface = &myImplementation{}
:type T struct{}
var _ I = T{} // Проверка, что T имплеменирует I.
var _ I = (*T)(nil) // Проверка, что *T имплеменирует I.
Обычно это указывают, чтобы ошибки были выявлены уже во время компиляции.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Держите годный контент)
Тут неплохой список тем, которые с большой вероятностью будут обсуждаться на собеседовании + теория по самому важному
Собственно, теория покрывает такие разделы:
├╼
Скалярные├╼
Массив и слайс├╼
Map├╼
Структура╰╼
Интерфейс├╼
Каналы├╼
Горутины├╼
Sync╰╼
ПаттерныУверен, будет полезно) Успешных собеседований
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Держите репозиторий с вопросами по Golang. Здесь вы найдете вопросы, которые могут быть заданы на собеседовании, с подробными разъяснениями и анализом различных corner cases. Представьте, что это ваши билеты на экзамен - вытягивайте билет и готовьтесь!
Здесь затрагиваются самые важные темы Go, в том числе:
• Slices
• Maps
• Указатели
• Goroutines и Channels
• Работа со строками
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
io.Pipe
для создания туннеля между писателем и читателем.// отправляем пользователю ответ с аттачем
//reader, writer := io.Pipe()
writer := new(bytes.Buffer)
err = main.Doc.Save(writer) // метод Документа из unioffice - принимает io.Writer, сохраняет тип Document в zip.
//writer.Close() // для Pipe
...
reader := bytes.NewReader(writer.Bytes())
...
nbytes, err := io.Copy(w, reader) // w это http.ResponseWriter
При запуске эта программа зависает, поэтому приходится использовать промежуточный буфер, как видно из кода. Что здесь не так с использованием Pipe?
Нужно просто вызов
Writer
обернуть в горутину, иначе все блокируется.go func () {
defer writer.Close()
err = main.Doc.Save(writer) // принимает io.Writer
...
}
}()
Вот и всё
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Sub
из пакета time
.func main() {
// В високосном году 2096 будет 366 дней
t1 := Date(2096, 1, 1)
t2 := Date(2097, 1, 1)
days := t2.Sub(t1).Hours() / 24
fmt.Println(days) // 366
}
func Date(year, month, day int) time.Time {
return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
}
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
map
:map[
/dbus-service:map[
org.freedesktop.DBus.Introspectable:map[]
org.freedesktop.DBus.Peer:map[]
org.freedesktop.DBus.Properties:map[]
Basket:map[
Fruit:"Apple"
]
]
При конвертации в
json
значение поле Fruit
"теряется":"/dbus-service":{
"org.freedesktop.DBus.Introspectable":{},
"org.freedesktop.DBus.Peer":{},
"org.freedesktop.DBus.Properties":{},
"Basket":
{
"Fruit":{}
}
}
Для вывода используется это:
fmt.Printf("%v", data)
jsonData, _ := json.Marshal(data)
fmt.Printf("json data: %s", jsonData)
Вопрос на засыпку: почему так происходит с
Fruit
?Marshal
'aлятся у Fruit:"Apple"
."Apple"
— имеет тип данных dbus.Variant
У него нету "публичных" свойств. Неэкспортируемых.
Экспортируемые пишутся с большой буквы.
Неэкспортируемые с маленькой.
Решение: создавать новое дерево
map
'ов с примитивными данными (string
вместо dbus.Variant
) путем рекурсии.@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
array := [104 0 101 0 108 0 108 0 111 0 0 0 0 0 0 0]
. Как перевести его в строку, чтобы она была равна видимым его символам (т.е. string(array[:]) == "hello"
)?package main
import "fmt"
var array = []byte{104, 0, 101, 0, 108, 0, 108, 0, 111, 0, 0, 0, 0, 0, 0, 0}
func main() {
new_array := make([]byte, 0, len(array))
for _, b := range array {
if b == 0 {
continue
}
new_array = append(new_array, b)
}
// 5 - ожидаемая длинна
fmt.Println(len(new_array))
// строка без 0x00
fmt.Println(string(new_array))
}
func btos(c []byte) string {
n := 0
for _, b := range c {
if b == 0 {
continue
}
c[n] = b
n++
}
return string(c[:n])
}
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Необходимо реализовать микросервис для работы с балансом пользователей (зачисление средств, списание средств, перевод средств от пользователя к пользователю, а также метод получения баланса пользователя). Сервис должен предоставлять HTTP API и принимать/отдавать запросы/ответы в формате JSON.
1. Сервис должен предоставлять HTTP API с форматом JSON как при отправке запроса, так и при получении результата.
2. Язык разработки: Go.
3. Фреймворки и библиотеки можно использовать любые.
4. Реляционная СУБД: MySQL или PostgreSQL.
5. Использование docker и docker-compose для поднятия и развертывания dev-среды.
6. Весь код должен быть выложен на Github с Readme файлом с инструкцией по запуску и примерами запросов/ответов (можно просто описать в Readme методы, можно через Postman, можно в Readme curl запросы скопировать, и так далее).
7. Если есть потребность в асинхронных сценариях, то использование любых систем очередей - допускается.
8. При возникновении вопросов по ТЗ оставляем принятие решения за кандидатом.
9. Разработка интерфейса в браузере не требуется. Взаимодействие с API предполагается посредством запросов из кода другого сервиса. Для тестирования можно использовать любой удобный инструмент. Например: в терминале через curl или Postman.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
package cache
import (
"sync"
"time"
)
type Cache struct {
*sync.Map
TTL time.Duration
}
func New(ttl time.Duration) *Cache {
return &Cache{
Map: new(sync.Map),
TTL: ttl,
}
}
func (c *Cache) Store(key, value interface{}) {
c.Map.Store(key, value)
// memory leak?
time.AfterFunc(c.TTL, func() {
c.Map.Delete(key)
})
}
time.Timer
и его методам нет ничего про обязательные деструкторы как у time.Ticker
. При этом в коде выше как минимум 2 проблемы:• Создаётся множество таймеров, что увеличивает потребление ОЗУ и создаёт дополнительную нагрузку на планировщик.
• Если положить значение по ключу дважды, сотрётся оно по истечении первого TTL, а не второго.
И то, и другое можно вылечить, если просто запоминать время установки значения и проходиться по всем значением раз в N миллисекунд, удаляя устаревшие.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
jsonFile, err := os.Open("referenceData/ex.json")
if err != nil {
return err
}
defer jsonFile.Close() // первый defer
byteValue, err := ioutil.ReadAll(jsonFile)
if err != nil {
return err
}
err = json.Unmarshal(byteValue, &exToParse)
if err != nil {
return err
}
jsonFile, err = os.Open("referenceData/di.json") // перезапись jsonFile
if err != nil {
return err
}
defer jsonFile.Close() // нужно ли заново объявлять defer jsonFile.Close()?
byteValue, err = ioutil.ReadAll(jsonFile)
if err != nil {
return err
}
err = json.Unmarshal(byteValue, &diToParse)
if err != nil {
return err
}
Сначала инициализируем переменную не через
var
, а сразу передаём значение. Потом сразу пишем defer jsonFile.Close()
. Потом в этот же файл загружаем другой json, и так же пишем defer jsonFile.Close()
.Вопрос — а нужен ли второй
defer
? По идеи в ОЗУ, после перезаписи, jsonFile
один и тоже, с тем же адресом, но только с другим содержанием.defer
, вычисляются в момент использования defer
. Вот простой пример, где это видно:type T int
func (t T) Close() { fmt.Println(int(t)) }
// ...
t := T(1)
defer t.Close()
t = T(2)
defer t.Close()
// 2
// 1
Вообще, не рекомендуется переиспользовать переменные подобным образом, так как это усложняет понимание текста программы.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM