Среди заданных вопросов много интересных, типо:
— можно ли с Go и HTMX делать fullstack-приложения
— в чём отличие между namespace в других ЯП и package в Go
— как обстоят дела с Dependency Injection в Go
— и ещё несколько других
Отличное видео, помогает узнать об актуальных задачах, которые решаются с помощью Go и не только
Рекомендую)
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
rune
и byte
— в чём разница?rune
- это 32-х битный тип, представляющий юникодные символы в кодировке UTF-32 aka UCS-4.byte
- это универсальный 8-битный тип.rune
используется для работы с не-ASCII символами в строках. Есть встроенное приведение []rune
для типа string
, которое парсит строку из UTF-8
(представление с переменной длиной байтов) в представление с фиксированной длиной байтов.[]byte(str)
и []rune(str)
разительна. Строка Привет, мир!
:Байты: [208 159 209 128 208 184 208 178 208 181 209 130 44 32 208 188 208 184 209 128 33]
Руны: [1055 1088 1080 1074 1077 1090 44 32 1084 1080 1088 33]
[]rune(string)
эквивалентно вот такой функции:func ToRunes(bytes []byte) []rune {
result := []rune{}
for i := 0; i < len(bytes); {
r, size := utf8.DecodeRune(bytes[i:])
result = append(result, r)
i += size
}
return result
}
Привет, мир!
в руны и обратно@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
func HandleRequest(client http.Client, request *http.Request)
(*http.Response, error) {
response, err := client.Do(request)
defer response.Body.Close()
if err != nil {
return nil, err
}
}
А теперь вопрос: почему это должно работать, ведь тело всё равно закрыто, не зависимо до проверки или после?
Известно, что полное отсутствие строки
defer response.Body.Close()
приводит к гарантированным проблемам, но как протестировать вышеупомянутую уязвимость?defer response.Body.Close()
означает, что response.Body.Close()
должно быть выполнено в точке выхода из функции. Ни о каком закрытии тела до проверки ошибки речь не идёт.Проблема здесь в другом — в случае ошибки
response
может быть nil
, и выполнение отложенной инструкции в ветке if err != nil {... return ...}
в таком случае приведет к панике из-за обращения к нулевому указателю.panic: runtime error: invalid memory address or nil pointer dereference
А вот собственно и код:
package main
import (
"fmt"
"io"
"net/http"
"net/url"
"os"
)
func main() {
client := http.Client{}
url, _ := url.Parse("https://no.such.host")
request := &http.Request{
Method: "GET",
URL: url,
}
response, err := client.Do(request)
defer response.Body.Close()
if err != nil {
fmt.Fprintf(os.Stderr, "Request failed: %s\n", err.Error())
}
io.Copy(os.Stdout, response.Body)
}
Как-то так
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Здесь описывается абсолютно всё, что поможет подготовиться к собеседованию, и даже больше
Вопросы с собеседований связанные с Golang
├── Общие вопросы
├── Хеш-мапы
├── Интерфейсы
├── Пакеты
├── Типы данных
├── Defer
├── Примитивы синхронизации
├── Планировщик
├── Строки
├── Массивы и слайсы
├── Дженерики
├── Горутины
├── Конструкции
├── Гонка данных
├── Структуры
├── Контекст
├── Ошибки / Panic
└── Указатели
Вопросы с собеседований связанные с Linux
├── Файловая система
└── Сигналы, процессы
Вопросы по инфраструктуре
└── Базы данных (реляционные)
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Есть функция
strings.Contains
, но она проверяет есть ли строка в строке, не массив. Есть ли функция для этого, или надо писать свою?slices.IndexFunc
// искать индекс элемента target
idx := slices.IndexFunc(someSlice, func (elt E) { return elt == target })
if idx >= 0 { /* найден */ }
Но это реально тривиальная функция:
func IndexFunc[E any](s []E, f func(E) bool) int {
for i := range s {
if f(s[i]) {
return i
}
}
return -1
}
Если же массив отсортирован, то есть функция поиска делением пополам
slices.BinarySearch
- ищет для типов, для которых определено сравнение <
. В общем случае есть поиск по отсортированному слайсу с компаратором slices.BinarySearchFunc
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Например, тип
byte
из модуля "строки" — это алиас uint8
. Алиас объявляется через ключевое слово type
:type NumCount int
func main() {
nc := NumCount(len([]int{1, 2, 3}))
fmt.Println(nc) // 3
}
type errorCode string
func main() {
ec := errorCode("internal")
fmt.Println(ec) // internal
fmt.Println(string(ec)) // internal
}
type counter int
// передается указатель, чтобы можно было изменить состояние счетчика "c"
func (c *counter) inc() {
*c++
}
func main() {
c := counter(0)
(&c).inc() // передается указатель на счетчик &c, так как функция "inc()" работает с указателями
(&c).inc()
fmt.Println(c) // 2
}
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
// A struct with four anonymous fields of type T1, *T2, P.T3 and *P.T4
struct {
T1 // field name is T1
*T2 // field name is T2
P.T3 // field name is T3
*P.T4 // field name is T4
x, y int // field names are x and y
}
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | AnonymousField) [ Tag ] .
AnonymousField = [ "*" ] TypeName .
Tag = string_lit .
Эти строки имеют отношение к граматикам, которые использует компилятор? Для чего эта информаия прописана в документации?
_
. Как его можно использовать?// A struct with 6 fields.
struct {
x, y int
u float32
_ float32 // padding
A *[]int
F func()
}
Что ж, давайте разберёмся со всеми вопросами:
type commonWidget struct {
width, height int
}
func (w *commonWidget) setHeight(height int) { w.height = height }
func (w *commonWidget) setWidth(width int) { w.width = width }
type button struct {
commonWidget
text string
}
type input struct {
commonWidget
type_ string
}
Здесь тип
commonWidget
описывает общие для всех виджетов поля и методы. Путём включения, типы button
и input
получают как нужные поля, так и методы, с ними работающие.gc
и gccgo
. Благодаря тому, что есть спецификация, когда два этих компилятора чем-то различаются, можно понять, кто "не прав". В свою очередь, различия в имплементации компиляторов часто указывают на неполноту спецификации.@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Wikipedia
Composition over inheritance
software design pattern
url
строки из punicode в unicode.Т.е. задача:
xn--go -uedfq
——> Go топ
. И наоборотidna
, сперва ставим пакет локально:go get golang.org/x/net/idna
Не забываем настроить переменную среды
%GOPATH
. После этого мы сможем спокойно импортировать пакет в проект:package main
import (
"fmt"
"golang.org/x/net/idna"
)
var p *idna.Profile
func main() {
p = idna.New()
fmt.Println(p.ToUnicode("xn--go -uedfq"))
}
// Go топ
Вот такие дела
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Создание простого сервера с поддержкой REST API на языке Go можно выполнить с использованием стандартной библиотеки
net/http
. Поехали!User
и создадим веб-сервер:package main
import (
"encoding/json"
"log"
"net/http"
"strconv"
"sync"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
}
var (
users = make(map[int]User)
mu sync.Mutex
idSeq int
)
func createUser(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()
idSeq++
user := User{ID: idSeq}
if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
users[user.ID] = user
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
}
func getUser(w http.ResponseWriter, r *http.Request) {
id, err := strconv.Atoi(r.URL.Path[len("/users/"):])
if err != nil {
http.Error(w, "Invalid user ID", http.StatusBadRequest)
return
}
mu.Lock()
defer mu.Unlock()
user, ok := users[id]
if !ok {
http.NotFound(w, r)
return
}
json.NewEncoder(w).Encode(user)
}
func main() {
http.HandleFunc("/users", createUser)
http.HandleFunc("/users/", getUser)
log.Println("Starting server on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
8080
. Он обрабатывает два запроса:—
POST/users
: Создает нового пользователя. Ожидает JSON с именем пользователя в теле запроса. —
GET/users/{id}
: Возвращает данные пользователя по его ID.curl
или postman
. Например, для создания пользователя:curl -X POST -H "Content-Type: application/json" -d '{"name":"John Doe"}' http://localhost:8080/users
curl http://localhost:8080/users/1
@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
Держите отличную статью, где разработчики из YADRO описывают best-practices в Go-разработке
О чём статья?
А также, конечно, освещается тема правильной архитектуры, включая разделение кода на пользовательские кейсы, глаголы и существительные и много всего ещё — должно быть полезно
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
package main
import (
"context"
"fmt"
"log"
"time"
"github.com/jackc/pgx"
)
type DatabaseInstance struct {
conn *pgx.Conn
connConfig pgx.ConnConfig
maxConnectAttempts int
}
func NewConn(uri string, maxAttempts int) (*DatabaseInstance, error) {
connConfig, err := pgx.ParseURI(uri)
if err != nil {
return nil, err
}
instance := DatabaseInstance{}
instance.connConfig = connConfig
instance.maxConnectAttempts = maxAttempts
return &instance, err
}
func (db *DatabaseInstance) reconnect() (*pgx.Conn, error) {
conn, err := pgx.Connect(db.connConfig)
if err != nil {
return nil, fmt.Errorf("unable to connection to database: %v", err)
}
if err = conn.Ping(context.Background()); err != nil {
return nil, fmt.Errorf("couldn't ping postgre database: %v", err)
}
return conn, err
}
func (db *DatabaseInstance) GetConn() *pgx.Conn {
var err error
if db.conn == nil {
if db.conn, err = db.reconnect(); err != nil {
log.Fatalf("%s", err)
}
}
if err = db.conn.Ping(context.Background()); err != nil {
attempt := 0
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for range ticker.C {
if attempt >= db.maxConnectAttempts {
log.Fatalf("connection failed after %d attempt\n", attempt)
}
attempt++
log.Println("reconnecting...")
db.conn, err = db.reconnect()
if err == nil {
return db.conn
}
log.Printf("connection was lost. Error: %s. Waiting for 5 sec...\n", err)
}
}
return db.conn
}
Код довольно прост: мы перед взятием соединения пингуем БД, если этого не удалось сделать, то ждём 5 секунд и пытаемся снова.
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Встречайте годный контент!
В этой статье детально и подробно описана работа планировщика Go, разобраны основные моменты, связанные с горутинами
Вот некоторые факты из статьи:
M
горутин к N
потокам ядра, формируя модель M:N
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Для тех, у кого руки ещё не дошли до свежей февральской версии Go — держите годное видео от разраба из Авито, рассказывает про некоторые нововведения и всё такое
В частности про:
split
из пакета strings
, позволяющую разделить строку на частиrand
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Держите полезный ролик, в котором на разные вопросы, связанные с тестированием Go-кода, отвечает разработчик с опытом 8 лет.
О чём говорится в видео?
— Краткое введение в тестирование: что такое тесты и какие виды тестов существуют.
— Должен ли разработчик писать тесты?
— Что такое TDD?
— «Утром код — вечером тесты» или «Утром тесты — вечером код»?
— Какую логику и какие данные нужно тестировать, а когда тесты не нужны.
— Как TDD помогает увеличить скорость и снизить затраты на разработку.
— Забиваете на best practices во время инцидентов? Остановитесь и подумайте.
— Как хорошие тесты становятся документацией к коду.
— Что такое test cases и как они связаны с use cases.
— Как методика TDD влияет на структуру команды и процессы.
— Что такое технический долг.
— Как «постмортем» помогает не воспроизводить одни и те же фейлы.
— Что ещё почитать по про test driven development.
В целом, полезное видео, рекомендую
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM
Интерфейсы в Go — это способ реализации полиморфизма
package main
import (
"math"
"fmt"
)
// Круг.
type Circle struct {
x, y, r float64
}
// Прямоугольник.
type Rectangle struct {
x1, y1, x2, y2 float64
}
// Интерфейс фигуры, которому удовлетворяют все типы, имеющие соответствующий
// метод вычисления площади Area().
type Figure interface {
Area() float64
}
// Реализация интерфейса Figure для Circle.
func (c *Circle) Area() float64 {
return math.Pi * c.r * c.r
}
// Реализация интерфейса Figure для Rectangular.
func (r *Rectangle) Area() float64 {
return math.Abs(r.x2 - r.x1) * math.Abs(r.y2 - r.y1)
}
func main() {
figures := make([]Figure, 0) // Срез фигур.
// Мы можем добавлять в этот срез все, что удовлетворяет интерфейсу
// Figure, несмотря на то, что это элементы разных типов:
figures = append(figures, &Circle{0, 0, 10})
figures = append(figures, &Rectangle{0, 0, 10, 20})
// И теперь мы можем единообразно обрабатывать эти данные разных типов.
for _, figure := range figures {
fmt.Printf("Area of %#v = %f\n", figure, figure.Area())
}
}
$ go run figures.go
Area of &main.Circle{x:0, y:0, r:10} = 314.159265
Area of &main.Rectangle{x1:0, y1:0, x2:10, y2:20} = 200.000000
@golang_interview
Please open Telegram to view this post
VIEW IN TELEGRAM