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

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

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

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

Наши каналы: https://t.iss.one/proglibrary/9197
Download Telegram
💬В Go есть особенность, связанная с неиспользуемыми переменными и импортами. В чем она заключается?

🔻Особенность в том, что если в коде есть неиспользуемая локальная переменная, такой код не скомпилируется. Например:

package main

import "fmt"

func main() {
x := 10
fmt.Println("Hello, World!")
}

Компилятор выдаст ошибку: x declared but not used

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

package main

import "errors"

func doSomething() (int, error) {
return 42, errors.New("an error occurred")
}

func main() {
doSomething() // Это допустимо
result, err := doSomething()
// Это вызовет ошибку, так как result и err не используются
}

🔻Неиспользуемый импорт: если мы импортируем пакет, но не используем его в коде:

package main

import "math"

func main() {
// Ничего не делаем
}


Компилятор выдаст ошибку: "math" imported and not used.

❗️Это правило не касается неиспользуемых параметров функций и глобальных переменных. Этот код скомпилируется:

package main

import "fmt"

var globalVar int

func greet(name string, age int) {
fmt.Println("Hello,", name)
}

func main() {
greet("Alice", 25)
fmt.Println("Hello, World!")
}
👍103
💬Как с помощью стандартной библиотеки создать простой веб-сервер на 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)
http.ListenAndServe(":8080", nil)
}


1⃣Импортируем необходимые пакеты: fmt и net/http
2⃣Определяем функцию обработчика helloHandler, которая будет отвечать на все HTTP-запросы сообщением "Hello, World!"
3⃣В main регистрируем наш обработчик с помощью http.HandleFunc для корневого пути ("/")
4⃣И, наконец, запускаем веб-сервер на порту 8080 с помощью http.ListenAndServe

👉 Когда мы запустим код и перейдем по адресу https://localhost:8080, увидим сообщение "Hello, World!".

📌Либо еще проще:

package main

import "net/http"

func main() {
port := ":8080"
handler := http.FileServer(http.Dir("."))
http.ListenAndServe(port, handler)
}


📌Это что-то вроде python -m SimpleHTTPServer <port>, только на Go.

🚀 Кстати, недавно Eli Bendersky написал простой статический файловый сервер с поддержкой HTTP и HTTPS. Может быть полезен для локального тестирования веб-приложений.
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍4
💬Что из себя представляет тип данных rune в Go?

🔸В современном мире невозможно работать только со строками, состоящими исключительно из ASCII-символов. Везде используются нестандартные знаки, отличные от латиницы языки и эмодзи. Для работы с такими Unicode-символами в Go представлен тип данных rune.

🔸Руна в Go представляет собой тип, который является псевдонимом для int32. Он используется для представления Unicode-кода символа.

🔸Если использовать конструкцию for range, строка автоматически будет преобразована в []rune, то есть обход будет по Unicode-символам.

📌Примеры:

1. Объявление и инициализация руны:

var r rune = 'A'

2. Преобразование строки в срез рун:

s := "Привет"
runes := []rune(s)


3. Итерация по рунам в строке:

for _, r := range "Привет" {
fmt.Printf("%c ", r)
}

// Вывод: П р и в е т


4. Обратное преобразование среза рун в строку:

runes := []rune{'П', 'р', 'и', 'в', 'е', 'т'}
s := string(runes) // "Привет"

5. Получение Unicode-кода руны:

r := 'A'
code := int32(r)
// 65


6. Проверка длины строки в рунах:

s := "Привет"
length := utf8.RuneCountInString(s)
// 6
👍113
💬Отличается ли обработка ошибок в Go от других ЯП? Если да, то чем?

🔺Обработка ошибок в Go существенно отличается от других ЯП и имеет некоторые ключевые особенности:

1. Явная обработка ошибок: в Go нет механизма исключений, как во многих других языках. Вместо этого функции, которые могут вызвать ошибку, обычно возвращают значение ошибки как один из своих возвращаемых результатов.

2. Множественные возвращаемые значения: функции часто возвращают результат (или результаты) и ошибку. Это позволяет легко проверять наличие ошибки после каждого вызова функции.

val, err := someFunction()
if err != nil {
// обработка ошибки
}


3. Кастомные типы ошибок: с помощью пакета errors можно создавать кастомные типы ошибок. Это дает возможность добавить дополнительную информацию к ошибке или создать проверяемые типы ошибок.

4. Добавление дополнительного контекста к ошибке: начиная с Go 1.13, были добавлены функции errors.Is, errors.As и fmt.Errorf для обертывания ошибок, что позволяет сохранить исходную ошибку и добавить дополнительный контекст.

func DoSomething() error {
if err := someOperation(); err != nil {
return fmt.Errorf("someOperation failed: %w", err)
}
return nil
}


5. Нет "finally": так как в Go нет исключений, нет и блока finally. Очистка ресурсов или другие завершающие действия обычно выполняются с использованием defer.

6. panic и recover: хотя Go предпочитает явную обработку ошибок, существуют механизмы panic и recover для обработки исключительных ситуаций. Однако их рекомендуется использовать осторожно и в основном для обработки действительно неожиданных ошибок, таких как выход за границы массива.
👍5🔥4
💬Что из себя представляют мьютексы в Go и какие типы мьютексов бывают?

📌Mutex означает mutual exclusion (взаимное исключение) и является способом защиты критической секции (critical section) программы. Мьютексы — один из наиболее распространенных примитивов синхронизации.

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

📌Стандартная библиотека Go предоставляет два типа мьютексов для синхронизации доступа к общим ресурсам:

1⃣ sync.Mutex — стандартный мьютекс, который предоставляет эксклюзивную блокировку (exclusive lock). Только одна горутина может захватить мьютекс и получить доступ к общему ресурсу.

package main

import (
"fmt"
"sync"
)

var count int
var mu sync.Mutex

func increment() {
mu.Lock()
count++
mu.Unlock()
}

func main() {
var wg sync.WaitGroup

for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
increment()
wg.Done()
}()
}

wg.Wait()
fmt.Println(count)
}


🔹Здесь мы используем sync.Mutex для обеспечения безопасности при инкременте глобальной переменной count из множества горутин.

2⃣ sync.RWMutex — концептуально то же самое, что и Mutex. Тем не менее, RWMutex дает вам немного больше контроля над памятью.

🔸Он предоставляет доступ к критической секции произвольному количеству читателей и не более, чем одному писателю. При этом, если есть писатель, то читателей нет.

package main

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

var cache = make(map[string]string)
var mu sync.RWMutex

func set(key string, value string) {
mu.Lock()
cache[key] = value
mu.Unlock()
}

func get(key string) string {
mu.RLock()
defer mu.RUnlock()
return cache[key]
}

func main() {
set("name", "John")

var wg sync.WaitGroup

for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
fmt.Println(get("name"))
wg.Done()
}()
}

time.Sleep(1 * time.Second)
set("name", "Doe")

wg.Wait()
}


🔹Здесь мы используем sync.RWMutex для обеспечения безопасного доступа к кэшу. Множество горутин может одновременно читать из кэша, но только одна горутина может писать в кэш в данный момент времени.
🔥7👍4
💬В Go есть такое понятие, как «затенение» (англ. shadowing) переменной. Что оно из себя представляет?

🔹В Go происходит «затенение», когда переменная, объявленная во внутренней области видимости, имеет то же имя, что и переменная во внешней области видимости.

🔹В результате внутренняя переменная «затеняет» внешнюю, делая её недоступной в своей области видимости.

📌Пример:

package main

import (

"fmt"
)

func main() {
x := 10

if true {
x := 5 // здесь происходит затенение внешней переменной x
fmt.Println(x) // выводит 5, т. к. используется внутренняя переменная x
}

fmt.Println(x) // выводит 10, т. к. используется внешняя переменная x
}

🔹«Затенение» может быть особенно запутывающим, когда оно происходит с результатами функций, такими как err. Например, часто в Go вы можете видеть следующий код:

value, err := someFunction()
if err != nil {

// обработка ошибки
}

// ...

value2, err := anotherFunction() // здесь может произойти «затенение», если использовать := вместо =
if err != nil {
// обработка ошибки
}

Если вы случайно используете := вместо =, когда присваиваете результат anotherFunction(), вы создадите новую переменную err, которая «затенит» внешнюю переменную err. Это может привести к тому, что ошибки будут проигнорированы или обработаны неправильно.

📌Как обнаружить shadowing в коде? Есть не сколько способов: использовать встроенные инструменты Go или линтеры.

1. go vet -shadow ./...
2. golangci-lint run --enable shadow
3.
$ go get -u golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
$ go vet -vettool=$(which shadow)
👍13🔥11
💬Как можно оптимизировать использование памяти в Go, особенно при работе с большими структурами данных?

📌Для оптимизации использования памяти в Go необходимо выполнять некоторые рекомендации, в частности:

1. Избегать глобальных переменных: глобальные переменные остаются в памяти на протяжении всего времени выполнения программы. Используйте их, когда это действительно необходимо.

2. Использовать правильные типы данных: например, вместо использования int для небольших чисел можно использовать int8/int16 и т. д., в зависимости от диапазона значений.

3. sync.Pool: если в программе часто создаются и удаляются большие объекты, мы можем использовать sync.Pool для их повторного использования.

4. Ленивая инициализация: инициализировать сложные структуры данных или большие массивы желательно только тогда, когда они действительно нужны.

5. Использовать указатели на структуры: вместо передачи копии структуры мы можем передать указатель на нее. Важно знать, что это правило работает не всегда и не везде (подробнее можно прочитать здесь).

6. Срезы vs массивы: срезы могут менять свой размер и динамически выделять память. Если размер данных известен, лучше использовать массив.

7. Освобождать ресурсы: временные большие структуры данных, которые больше не нужны, следует явно освобождать, присваивая им значение nil, чтобы сборщик мусора мог быстрее их убрать.

8. Использовать буферизацию: буферизированный ввод/вывод или буферизированные каналы могут сократить количество выделений и освобождений памяти.

9. Оптимизировать структуры: структуры в Go выровнены по памяти. Переупорядочивание полей структуры может уменьшить ее размер.
👍10
💬Что из себя представляют примитивы синхронизации в контексте Go?

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

🔸sync.Mutex: основной примитив блокировки для исключения одновременного доступа к данным.

🔸sync.RWMutex: разрешает множественное чтение или одну операцию записи в текущий момент времени.

🔸sync.WaitGroup: используется для ожидания завершения группы горутин.

🔸sync.Once: гарантирует, что функция будет вызвана только один раз, несмотря на количество вызовов.

🔸sync.Cond: предоставляет механизм для блокирования горутины, пока не будет выполнено некоторое условие. Не так давно Расс Кокс отменил предложение удалить данные тип в будущей версии Go.

☝️Каналы в Go хоть и не являются примитивами синхронизации в традиционном понимании, они играют ключевую роль в синхронизации и координации горутин в Go.
👍5
💬Go — язык программирования, который отлично подходит для разработки облачных приложений. Что облачные технологии и облачные приложения из себя представляют теоретически?

📌Так звучат определения по мнению Cloud Native Computing Foundation:

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

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

📝Исходя из этого, облачные приложения — больше, чем просто приложения, которые работают в облаке. Они также должны отвечать некоторым требованиям/атрибутам:

👉Масштабируемость — способность показывать ожидаемое поведение в условиях значительных колебаний спроса вверх и вниз.
👉Слабая связанность — свойство системы и стратегия проектирования, согласно которой компоненты системы знают лишь самый минимум о любых других компонентах.
👉Устойчивость — способность системы восстанавливаться после ошибок и сбоев.
👉Управляемость — простота (или ее отсутствие), с которой можно изменить поведение системы для обеспечения безопасности, бесперебойной работы и соответствия меняющимся требованиям.
👉Наблюдаемость — способность определения внутреннего состояния системы по наблюдаемым результатам.
👍9
💬 Что такое data race (гонка данных) в контексте Go?

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

📌Race Condition (состояние гонки) — более широкое понятие, чем гонка данных. Оно описывает ситуацию, когда поведение программы зависит от относительного порядка выполнения операций. Гонка данных — один из видов состояний гонки, но не единственный.

Пример гонки данных, которая может привести к сбоям и повреждению памяти:

func main() {
c := make(chan bool)
m := make(map[string]string)
go func() {
m["1"] = "a" //
Первый конфликтный доступ
c <- true
}()

m["2"] = "b" // Второй конфликтный доступ
<-c
for k, v := range m {
fmt.Println(k, v)
}
}


❗️Чтобы помочь диагностировать такие ошибки, Go включает встроенный детектор гонок данных. Для его использования добавьте флаг -race в команду go:

$ go test -race mypkg
$ go run -race mysrc.go
$ go build -race mycmd
$ go install -race mypkg

📌Переменная окружения GORACE устанавливает параметры детектора гонок данных, например:

$ GORACE="log_path=/tmp/race/report Strip_path_prefix=/my/go/sources/" go test -race

👉 Подробнее
🔥7👍4
💬Что из себя представляет пустой идентификатор в контексте языка Go?

📌Пустой идентификатор "_" в Go действует как своего рода анонимный заполнитель. Его можно использовать как любой другой идентификатор в объявлении, но с ним не будет связано никакое значение.

👉Несколько примеров:

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

value, _ := someFunction()

2. Игнорирование элементов в range: когда перебираются элементы среза или типа map, и нам нужен только ключ или только значение.

for k, _ := range myMap {
fmt.Println(k)
}


for _, v := range mySlice {
fmt.Println(v)
}


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

import _ "image/png"

4. Игнорирование переменных в множественном присваивании:

_, y := getCoordinates()

5. Игнорирование ошибок. Хотя так делать не рекомендуется, пустой идентификатор можно использовать для игнорирования ошибок.

result, _ := strconv.Atoi("123")

6. Использование в анонимных структурах: когда создается анонимная структура, и нам не нужно давать имя одному из ее полей.

person := struct {
Name string
_ int
}{"Alice", 30}


☝️Пустой идентификатор является полезным инструментом в Go и его можно безопасно использовать на практике, но злоупотреблять им точно не стоит, особенно когда речь идет об игнорировании ошибок.
👍9🔥3
💬Что из себя представляют анонимные функции и замыкания в Go?

🔸Функции в Go — обычные значения, с которыми можно работать так же, как с любыми другими объектами: они имеют типы, их можно присваивать переменным и даже передавать и возвращать другим функциям.

🔸Функции могут создаваться внутри других функций как анонимные функции, которые можно вызывать, передавать или использовать иным способом как любые другие функции. Анонимная функция — функция, которой не назначено имя.

🔸Особенностью Go является доступность состояния внешней функции из анонимных функций, даже после ее завершения. Фактически это позволяет определять замыкания. Замыкание — вложенная функция, сохраняющая доступ к переменным внешней функции даже после завершения последней.

📌Возьмем функцию incrementor. Она имеет состояние в виде переменной i и возвращает анонимную функцию, которая увеличивает значение перед возвратом. Можно сказать, что возвращаемая функция «замкнута» на переменной i.

func incrementer() func() int {
i := 0


return func() int {
i++

return i
}
}


📌Вызов incrementor создаст свою локальную копию i и вернет новую анонимную функцию, увеличивающую значение этой копии. Последующие вызовы incrementor будут создавать новые копии i:

func main() {
increment := incrementer()
fmt.Println(increment())
// 1
fmt.Println(increment())
// 2
fmt.Println(increment())
// 3

newIncrement := incrementer()
fmt.Println(newIncrement())
// 1
}
🔥16👍1
💬Как проверить тип переменной во время выполнения программы в Go?

📌Оператор switch — лучший способ проверить тип переменной во время выполнения. Каждый switch содержит по крайней мере один оператор case, который действует как условный оператор, и default case, который выполняется, если ни один из блоков case не является истинным.

👉 Например, мы можем создать swich, который проверяет, содержит ли значение интерфейса i тип int или string:

func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Double %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know type %T!\n", v)
}
}

func main() {
do(21)
do("hello")
do(true)
}


👉 Результат:
Double 21 is 42
"hello" is 5 bytes long
I don't know type bool!
👍9
💬Что такое стек и как его реализовать с помощью Go?

📌Стек — тип данных, представляющий собой список элементов, организованных по принципу LIFO (last in — first out, «последним пришёл — первым вышел»).

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

📌Главный принцип работы стека — данные, которые попали в стек недавно, используются первыми. Чем раньше попал — тем позже используется. После использования элемент стека исчезает, и верхним становится следующий элемент.

📌Три основные операции над стеком:
🔸push — добавление элемента
🔸pop — удаление верхнего элемента
🔸peek — возвращение последнего элемента, не удаляя его.

👉 В Go стек можно реализовать с помощью среза:

type Stack struct {
items []int
}

func (s *Stack) Push(item int) {
s.items = append(s.items, item)
}

func (s *Stack) Pop() int {

if len(s.items) == 0 {
panic("Stack is empty!")
}


item := s.items[len(s.items)-1]

s.items = s.items[:len(s.items)-1]

return item
}

func (s *Stack) Peek() int {
if len(s.items) == 0 {
panic("Stack is empty!")
}

return s.items[len(s.items)-1]
}

func (s *Stack) IsEmpty() bool {
return len(s.items) == 0
}

func (s *Stack) Size() int {
return len(s.items)
}

Мы использовали срез для хранения элементов стека. Метод Push добавляет элемент на верх стека, метод Pop извлекает его, а метод Peek позволяет посмотреть верхний элемент без его извлечения. Также мы использовали проверку стека на наличие элементов.
👍11
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

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

Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.

Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
💬Как поменять местами значения двух переменных без временной переменной? Очень простой вопрос, который может быть задан на собесе.

1️⃣Пример с использованием сложения и вычитания:

a := 5
b := 3


a = a + b // a становится 8
b = a - b // b становится 5
a = a - b // a становится 3

Таким образом, a и b меняются значениями без использования временной переменной.

2️⃣Пример с использованием XOR (исключающего ИЛИ):

a := 5 // 0101 в двоичной системе
b := 3 // 0011 в двоичной системе

a = a ^ b // a становится 6 (0110)
b = a ^ b // b становится 5 (0101)
a = a ^ b // a становится 3 (0011)

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

3️⃣Пример с реализацией простой функции

func main() {
fmt.Println(swap())
}

func swap() []int {
a, b := 15, 10
b, a = a, b
return []int{a, b}
}
👍14👏3
💬Реализуйте функцию, которая принимает срез целых чисел и переворачивает его без использования временного среза.

📌Простой, но достаточно эффективный способ:

func reverse(sw []int) {
for a, b := 0, len(sw)-1; a < b; a, b = a+1, b-1 {
sw[a], sw[b] = sw[b], sw[a]
}
}

func main() {
x := []int{3, 2, 1}
reverse(x)
fmt.Println(x)
}


// [1 2 3]

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

func reverseRecursive(sw []int, start, end int) {
if start >= end {
return
}
sw[start], sw[end] = sw[end], sw[start]
reverseRecursive(sw, start+1, end-1)
}

func main() {
x := []int{3, 2, 1}
reverseRecursive(x, 0, len(x)-1)
fmt.Println(x)
}


// [1 2 3]
👍4
Самые полезные каналы для программистов в одной подборке!

Сохраняйте себе, чтобы не потерять 💾

🔥Для всех

Библиотека программиста — новости, статьи, досуг, фундаментальные темы
Книги для программистов
IT-мемы
Proglib Academy — тут мы рассказываем про обучение и курсы

🐘PHP

Библиотека пхпшника
Вакансии по PHP, Symfony, Laravel
Библиотека PHP для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по PHP — код, квизы и тесты

🐍Python

Библиотека питониста
Вакансии по питону, Django, Flask
Библиотека Python для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по Python — код, квизы и тесты

Java

Библиотека джависта — полезные статьи по Java, новости и обучающие материалы
Библиотека Java для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по Java — код, квизы и тесты
Вакансии для java-разработчиков

👾Data Science

Библиотека Data Science — полезные статьи, новости и обучающие материалы
Библиотека Data Science для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по Data Science — код, квизы и тесты
Вакансии по Data Science, анализу данных, аналитике, искусственному интеллекту

🦫Go

Библиотека Go разработчика — полезные статьи, новости и обучающие материалы по Go
Библиотека Go для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по Go — код, квизы и тесты
Вакансии по Go

🧠C++

Библиотека C/C++ разработчика — полезные статьи, новости и обучающие материалы по C++
Библиотека C++ для собеса — тренируемся отвечать на каверзные вопросы во время интервью и технического собеседования
Библиотека задач по C++ — код, квизы и тесты
Вакансии по C++

💻Другие профильные каналы

Библиотека фронтендера
Библиотека шарписта
Библиотека мобильного разработчика
Библиотека хакера
Библиотека devops’a
Библиотека тестировщика

💼Каналы с вакансиями

Вакансии по фронтенду, джаваскрипт, React, Angular, Vue
Вакансии по C#, .NET, Unity Вакансии по PHP, Symfony, Laravel
Вакансии по DevOps & SRE
Вакансии для мобильных разработчиков
Вакансии по QA тестированию
InfoSec Jobs — вакансии по информационной безопасности

📁Чтобы добавить папку с нашими каналами, нажмите 👉сюда👈

🤖Также у нас есть боты:
Бот с IT-вакансиями
Бот с мероприятиями в сфере IT

Мы в других соцсетях:
🔸VK
🔸YouTube
🔸Дзен
🔸Facebook
🔸Instagram
👍1
💬Что из себя представляет пакет cgo и для чего он предназначен?

📌Cgo позволяет создавать пакеты Go, вызывающие код на C. С его помощью мы можем вызывать функции C напрямую из кода на Go и наоборот.

📌Это полезно, когда у нас есть библиотеки на C, которые мы хотим использовать в Go-проекте, или когда нам требуется взаимодействовать с системными вызовами на более низком уровне.

📌Основные особенности cgo:
1. Позволяет встраивать код на C прямо в исходники Go.
2. Автоматически обрабатывает преобразования типов между Go и C.
3. Важно быть осторожным с управлением памятью, так как Go имеет сборщик мусора, а C — нет.

📌Рассмотрим простой пример

package rand

/*
#include <stdlib.h>
*/
import "C"

func Random() int {
return int(C.random())
}

func Seed(i int) {
C.srandom(C.uint(i))
}


Пакет rand импортирует "C", где "C" — это «псевдопакет», специальное имя, интерпретируемое cgo как ссылка на пространство имен C.

Пакет rand содержит четыре ссылки на пакет C: вызовы C.random и C.srandom, преобразование C.uint(i) и оператор импорта. Функция Random вызывает функцию random стандартной библиотеки C и возвращает результат. В C функция random возвращает значение типа C long, которое cgo представляет как тип C.long. Его нужно преобразовать в тип Go, прежде чем он сможет быть использован кодом Go за пределами этого пакета, используя обычное преобразование типов Go.

Функция Seed делает обратное. Она принимает обычный Go int, преобразует его в тип C unsigned int и передает его функции C srandom.

Если импорту "C" сразу предшествует комментарий, этот комментарий, называемый преамбулой, используется в качестве заголовка при компиляции частей пакета C. Преамбула может содержать любой код на C, включая объявления и определения функций и переменных. Затем они могут быть переданы из кода Go, как если бы они были определены в пакете "C". Могут использоваться все имена, объявленные в преамбуле, даже если они начинаются со строчной буквы.

👉 Подробнее
6👍5
💬Go — императивный или декларативный? В чем разница между двумя подходами?

📌Go является императивным ЯП. Разница между императивными и декларативными языками программирования заключается в подходе к описанию того, как и что программа должна делать:

1️⃣Императивный подход: в императивных ЯП мы описываем, как решить задачу, шаг за шагом. Мы предоставляем последовательность команд/инструкций для достижения определенного результата.

📌Характерные черты:

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

2️⃣ Декларативный подход: в декларативных ЯП мы описываем, что хотим получить, но не указываем конкретные шаги, как это сделать. Вместо этого система или интерпретатор решает, как лучше достичь желаемого результата. Примеры декларативных языков или технологий включают SQL (для запросов к базам данных) и HTML (для описания структуры веб-страниц).
👍8