Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2
HTTP (HyperText Transfer Protocol) — это протокол, используемый для передачи данных в интернете.
Год выпуска: 1991
Особенности
Первая версия HTTP, очень простая. Поддерживала только GET-запросы. Отсутствие заголовков, только один объект мог быть передан в ответ на запрос.
Использование:
В настоящее время практически не используется.
Год выпуска: 1996
Особенности
Введены методы запроса, такие как GET, POST и HEAD. Поддержка заголовков для метаданных. Каждый запрос/ответ требует нового соединения, что делает передачу данных менее эффективной.
Использование
Исторически важен, но также почти не используется в современных приложениях.
Год выпуска: 1997
Особенности
Поддержка устойчивых (persistent) соединений, что позволяет повторное использование одного соединения для нескольких запросов/ответов. Введены дополнительные методы запросов, такие как OPTIONS, PUT, DELETE, TRACE и CONNECT. Поддержка chuncked transfer encoding для передачи данных по частям. Улучшена работа с кэшированием и аутентификацией.
Использование
Широко используется и в настоящее время, хотя многие системы переходят на HTTP/2.
Год выпуска: 2015
Особенности
Бинарный протокол, что улучшает производительность и уменьшает количество ошибок. Поддержка мультиплексирования, что позволяет отправлять несколько запросов через одно соединение одновременно, уменьшая задержки. Сжатие заголовков, что уменьшает объем передаваемых данных. Серверное push-сообщение (server push), позволяющее серверу отправлять данные клиенту до того, как он их запросит.
Использование
Быстро набирает популярность благодаря улучшенной производительности и эффективности.
Год выпуска: 2022 (черновая версия в 2020)
Особенности
Основан на протоколе QUIC, который работает поверх UDP, а не TCP. Поддержка улучшенного мультиплексирования и быстрого установления соединений. Лучшая устойчивость к потерям пакетов и более высокая скорость передачи данных по сравнению с HTTP/2.
Использование
Внедрение продолжается, но многие крупные интернет-компании, такие как Google и Facebook, уже активно используют HTTP/3.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Замыкание (closure) — это функция, которая захватывает переменные из внешней области видимости и продолжает использовать их даже после выхода из этой области.
Замыкание «помнит» окружение, в котором оно было создано, и может работать с ним как с локальным контекстом.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Нет, карты (maps) в Go не являются потокобезопасными по умолчанию. Использование карты в нескольких горутинах без должной синхронизации может привести к состояниям гонки, некорректным данным и паникам. Давайте рассмотрим более детально, почему это так и как можно обеспечить потокобезопасность при работе с картами в многопоточной среде.
Карты в Go разработаны для обеспечения высокой производительности при использовании в однопоточных сценариях. Если несколько горутин одновременно пытаются читать и изменять карту, возникает конкуренция за доступ к данным, что может привести к следующим проблемам:
Одновременный доступ к карте из нескольких горутин может привести к состояниям гонки, когда порядок выполнения операций непредсказуем.
Одновременное изменение структуры карты, например добавление или удаление элементов, может вызвать панику в программе.
Самый распространенный способ синхронизации доступа к карте — использование
sync.Mutex
. Мьютексы позволяют заблокировать доступ к карте на время чтения или записи.package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
m := make(map[string]int)
var wg sync.WaitGroup
write := func(key string, value int) {
mu.Lock()
m[key] = value
mu.Unlock()
}
read := func(key string) int {
mu.Lock()
defer mu.Unlock()
return m[key]
}
wg.Add(2)
go func() {
defer wg.Done()
write("key1", 42)
}()
go func() {
defer wg.Done()
fmt.Println(read("key1"))
}()
wg.Wait()
}
Если в вашей программе чаще происходят операции чтения, чем записи, можно использовать
sync.RWMutex
, который позволяет нескольким горутинам читать данные одновременно, но обеспечивает эксклюзивный доступ для записи.package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.RWMutex
m := make(map[string]int)
var wg sync.WaitGroup
write := func(key string, value int) {
mu.Lock()
m[key] = value
mu.Unlock()
}
read := func(key string) int {
mu.RLock()
defer mu.RUnlock()
return m[key]
}
wg.Add(2)
go func() {
defer wg.Done()
write("key1", 42)
}()
go func() {
defer wg.Done()
fmt.Println(read("key1"))
}()
wg.Wait()
}
Go предоставляет специальную структуру
sync.Map
, которая изначально создана для безопасного использования в многопоточной среде. Она автоматически обеспечивает синхронизацию операций.package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
m.Store("key1", 42)
}()
go func() {
defer wg.Done()
value, _ := m.Load("key1")
fmt.Println(value)
}()
wg.Wait()
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
HTTP/3, работающий на основе QUIC, обеспечивает быструю передачу данных поверх UDP. Для его использования в Go можно применять библиотеки вроде quic-go, позволяющие интегрировать поддержку HTTP/3.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Один из полезных паттернов, который я использовал в реальном проекте на Go — это Worker Pool (пул воркеров).
Этот паттерн помогает ограничить количество горутин при обработке задач, чтобы не перегружать систему.
В моём проекте был сервис, который обрабатывал тысячи файлов параллельно. Если запускать новую горутину на каждый файл, то память быстро заканчивалась, и сервер "умирал".
Решение: вместо создания тысяч горутин я использовал Worker Pool с фиксированным числом воркеров (например, 5), которые брали задачи из очереди.
Есть канал задач (
jobs
). Есть пул воркеров (
workers
), которые читают задачи из канала. Каждый воркер обрабатывает одну задачу и берёт следующую.
package main
import (
"fmt"
"sync"
"time"
)
// Количество воркеров
const workerCount = 5
// Воркер, который берет задачи из канала и обрабатывает их
func worker(id int, jobs <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for job := range jobs {
fmt.Printf("Worker %d processing job %d\n", id, job)
time.Sleep(time.Second) // Имитация обработки
}
}
func main() {
jobs := make(chan int, 10)
var wg sync.WaitGroup
// Запускаем воркеров
for i := 1; i <= workerCount; i++ {
wg.Add(1)
go worker(i, jobs, &wg)
}
// Отправляем задачи в канал
for j := 1; j <= 10; j++ {
jobs <- j
}
close(jobs) // Закрываем канал, чтобы воркеры знали, что задачи кончились
wg.Wait() // Ждём завершения всех воркеров
fmt.Println("Все задачи обработаны")
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊3👍1🤔1
Оконные функции (window functions) — это SQL-функции, которые выполняются по строкам с учётом контекста «окна» (группы строк).
Примеры использования:
- Нумерация (ROW_NUMBER())
- Скользящие суммы/средние (SUM() OVER(...))
- Сравнение соседних строк (LAG(), LEAD())
- Ранжирование (RANK())
Они позволяют делать аналитику прямо в SQL, без подзапросов и группировок.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Это система мониторинга и оповещения с открытым исходным кодом, разработанная для сбора и анализа метрик с серверов, приложений и других компонентов инфраструктуры.
позволяет отслеживать производительность, загрузку CPU, память, сетевой трафик и другие параметры.
использует модель pull (запрашивает данные у сервисов), а не push (как, например, Graphite). Это удобнее для управления и отказоустойчивости.
поддерживает кастомные метрики, которые можно интегрировать в своё приложение.
позволяет настроить уведомления при достижении критических значений.
помогает анализировать тренды и предсказывать возможные сбои.
легко развертывается в облаке, Kubernetes, Docker и других средах.
собирают данные.
опрашивает эти экспортеры по HTTP (pull-модель).
(язык запросов) используется для анализа данных.
или другие инструменты визуализируют метрики.
отправляет уведомления (Slack, Email, Telegram и др.).
Для интеграции в Go-приложение можно использовать пакет
prometheus/client_golang
package main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var httpRequests = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
)
func handler(w http.ResponseWriter, r *http.Request) {
httpRequests.Inc() // Увеличиваем счетчик запросов
w.Write([]byte("Hello, Prometheus!"))
}
func main() {
// Регистрируем метрику
prometheus.MustRegister(httpRequests)
// Эндпоинт для сбора метрик
http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
2. Через make: slice := make([]int, length, capacity), где length — длина, а capacity — ёмкость.
3. Пустой слайс: var slice []int.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Forwarded from easyoffer
Ура, друзья! Изиоффер переходит в публичное бета-тестирование!
🎉 Что нового:
🟢 Анализ IT собеседований на основе 4500+ реальных интервью
🟢 Вопросы из собеседований с вероятностью встречи
🟢 Видео-примеры ответов на вопросы от Senior, Middle, Junior грейдов
🟢 Пример лучшего ответа
🟢 Задачи из собеседований
🟢 Тестовые задания
🟢 Примеры собеседований
🟢 Фильтрация всего контента по грейдам, компаниям
🟢 Тренажер подготовки к собеседованию на основе интервальных повторений и флеш карточек
🟡 Тренажер "Реальное собеседование" с сценарием вопросов из реальных собеседований (скоро)
🟢 Автоотклики на HeadHunter
🟢 Закрытое сообщество easyoffer
💎 Акция в честь открытия для первых 500 покупателей:
🚀 Скидка 50% на PRO тариф на 1 год (15000₽ → 7500₽)
🔥 Акция уже стартовала! 👉 https://easyoffer.ru/pro
🎉 Что нового:
💎 Акция в честь открытия для первых 500 покупателей:
🚀 Скидка 50% на PRO тариф на 1 год (
🔥 Акция уже стартовала! 👉 https://easyoffer.ru/pro
Please open Telegram to view this post
VIEW IN TELEGRAM
Нет, строки (
string
) в Go неизменяемы (immutable). Это значит, что нельзя просто изменить один символ в строке. Строка в Go — это байтовый срез (
[]byte
), но неизменяемый. Когда вы создаёте строку s := "hello"
Ошибка при попытке изменения символа напрямую
s := "hello"
s[0] = 'H' // Ошибка: cannot assign to s[0]
Поскольку строка неизменяема, вам нужно создать новую строку с заменённым символом.
Способ 1: Преобразовать в
[]byte
(для ASCII-строк) Если строка содержит только английские буквы и символы ASCII, её можно преобразовать в
[]byte
, заменить символ и создать новую строку. package main
import "fmt"
func main() {
s := "hello"
b := []byte(s) // Преобразуем в изменяемый []byte
b[0] = 'H' // Меняем первый символ
s = string(b) // Преобразуем обратно в строку
fmt.Println(s) // "Hello"
}
Способ 2: Преобразовать в
[]rune
(для Unicode)Если строка содержит русские буквы, эмодзи или другие многобайтовые символы, используйте
[]rune
. package main
import "fmt"
func main() {
s := "привет"
r := []rune(s) // Преобразуем в []rune (массив символов)
r[0] = 'П' // Меняем первый символ
s = string(r) // Преобразуем обратно в строку
fmt.Println(s) // "Привет"
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Горутины и потоки (треды) в традиционном понимании операционных систем — это две различные концепции параллельного выполнения кода, каждая из которых имеет свои особенности и преимущества. Вот ключевые различия между ними.
Горутины — это легковесные "зеленые" потоки, управляемые Go runtime. Они не являются потоками операционной системы, и Go runtime отвечает за их планирование и выполнение на доступных физических потоках. Это позволяет создавать тысячи и даже миллионы горутин в рамках одного приложения с относительно небольшими затратами памяти и CPU.
Треды — это потоки выполнения, управляемые непосредственно операционной системой. Каждый тред занимает значительно больше ресурсов, чем горутина, особенно в плане памяти и времени на создание и управление. Треды более подходят для задач, требующих высокой вычислительной мощности и прямого взаимодействия с операционной системой.
Горутины потребляют гораздо меньше памяти по сравнению с тредами. Например, стек горутины начинается с нескольких килобайт, что значительно уменьшает затраты при масштабировании.
Треды требуют большего количества памяти для каждого стека, обычно начиная от нескольких сотен килобайт до мегабайтов. Это ограничивает количество потоков, которые могут быть активными одновременно без значительного увеличения затрат на ресурсы.
Горутины могут масштабироваться до большого количества параллельных задач благодаря меньшим требованиям к ресурсам и управлению со стороны runtime Go.
Треды ограничены в масштабируемости физическими ресурсами системы и более высокими затратами на управление.
Горутины имеют намного более эффективный контекст переключения, так как Go runtime оптимизирован для работы с большим количеством горутин и их переключением.
Треды терпят большие затраты времени на переключение контекста, так как операционной системе требуется больше времени для управления потоками.
package main
import (
"fmt"
"time"
)
func say(text string) {
for i := 0; i < 5; i++ {
fmt.Println(text)
time.Sleep(time.Millisecond * 500)
}
}
func main() {
go say("Hello")
say("World")
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Линтеры интегрируются в IDE или CI/CD пайплайны. Например, golangci-lint используется для анализа Go-кода.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Это неизменяемые последовательности байтов, обычно представляющие текст в кодировке UTF-8. Работа с ними в Go основывается на использовании встроенных функций, методов стандартной библиотеки и специальных типов данных.
Самый простой способ объединить строки — использовать оператор
+
или функцию fmt.Sprintf
.package main
import "fmt"
func main() {
s1 := "Привет"
s2 := "Мир"
result := s1 + ", " + s2 + "!"
fmt.Println(result) // Привет, Мир!
// Через fmt.Sprintf
formatted := fmt.Sprintf("%s, %s!", s1, s2)
fmt.Println(formatted) // Привет, Мир!
}
Функция
len
возвращает длину строки в байтах, а не в символах.package main
import "fmt"
func main() {
str := "Привет"
fmt.Println(len(str)) // 12, так как кириллические символы занимают 2 байта
}
Строки можно обойти как в виде байтов, так и в виде рун (Unicode символов).
package main
import (
"fmt"
"unicode/utf8"
)
func main() {
str := "Привет"
// Итерация по байтам
for i := 0; i < len(str); i++ {
fmt.Printf("Байт: %x\n", str[i])
}
// Итерация по символам (рунам)
for _, runeValue := range str {
fmt.Printf("Символ: %c\n", runeValue)
}
// Количество рун
fmt.Println("Количество символов:", utf8.RuneCountInString(str))
}
Так как строки неизменяемы, для извлечения подстроки используется срез (
slice
).package main
import "fmt"
func main() {
str := "Привет, Мир!"
substring := str[8:] // С 8-го байта до конца
fmt.Println(substring) // Мир!
}
Функции
strings.Split
и strings.Join
из пакета strings
позволяют разбивать строку на части или объединять части в строку.package main
import (
"fmt"
"strings"
)
func main() {
str := "apple,banana,cherry"
// Разделение строки
parts := strings.Split(str, ",")
fmt.Println(parts) // [apple banana cherry]
// Объединение строк
joined := strings.Join(parts, " | ")
fmt.Println(joined) // apple | banana | cherry
}
Для поиска подстроки можно использовать
strings.Contains
, strings.Index
или strings.HasPrefix/strings.HasSuffix
. Для замены — strings.Replace
.package main
import (
"fmt"
"strings"
)
func main() {
str := "Go — это круто!"
// Поиск подстроки
fmt.Println(strings.Contains(str, "круто")) // true
fmt.Println(strings.Index(str, "это")) // 4
// Замена подстроки
newStr := strings.Replace(str, "круто", "отлично", 1)
fmt.Println(newStr) // Go — это отлично!
}
Стандартная библиотека предоставляет функции для изменения регистра строки:
strings.ToLower
и strings.ToUpper
.package main
import (
"fmt"
"strings"
)
func main() {
str := "Hello, Go!"
fmt.Println(strings.ToUpper(str)) // HELLO, GO!
fmt.Println(strings.ToLower(str)) // hello, go!
}
Удаление пробелов или других символов с начала/конца строки выполняется с помощью
strings.Trim
, strings.TrimSpace
и других функций.package main
import (
"fmt"
"strings"
)
func main() {
str := " Hello, Go! "
fmt.Println(strings.TrimSpace(str)) // "Hello, Go!"
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🤔1
- Документо-ориентированная база данных.
- Хранит данные в формате BSON (похож на JSON).
- Подходит для гибкой схемы или её отсутствия.
- Хороша для быстрого прототипирования и хранения неструктурированных данных.
PostgreSQL:
- Реляционная СУБД с жёсткой схемой.
- Использует таблицы и SQL-запросы.
- Сильная поддержка транзакций, связей, индексов и сложных запросов.
Mongo — для гибкости и масштабируемости, Postgres — для структурированных и строгих данных.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Это интерфейс, который не содержит методов. Поскольку интерфейсы в Go определяют поведение, которое тип должен реализовать, пустой интерфейс, не имеющий методов, автоматически реализуется всеми типами. Это делает пустой интерфейс универсальным контейнером для значений любого типа.
Пустой интерфейс может содержать значение любого типа, потому что все типы в Go автоматически реализуют пустой интерфейс.
Пустой интерфейс широко используется для создания обобщенных (generic) структур данных, функций и методов, которые могут работать с данными любых типов.
Пустой интерфейс может использоваться для хранения значений различных типов в одной переменной.
package main
import "fmt"
func main() {
var i interface{}
i = 42
fmt.Println(i) // Output: 42
i = "hello"
fmt.Println(i) // Output: hello
i = true
fmt.Println(i) // Output: true
}
Пустой интерфейс позволяет создавать функции, которые могут принимать параметры любого типа.
package main
import "fmt"
func printValue(v interface{}) {
fmt.Println(v)
}
func main() {
printValue(42)
printValue("hello")
printValue(true)
}
Пустой интерфейс используется для создания структур данных, которые могут хранить значения различных типов.
package main
import "fmt"
func main() {
var values []interface{}
values = append(values, 42, "hello", true)
for _, v := range values {
fmt.Println(v)
}
}
Пустой интерфейс используется для обработки данных различных типов, например, при парсинге JSON.
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsonData := `{"name": "Alice", "age": 30}`
var result map[string]interface{}
json.Unmarshal([]byte(jsonData), &result)
fmt.Println(result)
}
При работе с пустым интерфейсом часто возникает необходимость проверить тип хранимого значения и привести его к конкретному типу. Это можно сделать с помощью утверждения типа (
type assertion
) или конструкции switch
.Утверждение типа позволяет проверить и преобразовать значение пустого интерфейса к конкретному типу.
package main
import "fmt"
func main() {
var i interface{} = "hello"
s, ok := i.(string)
if ok {
fmt.Println("String:", s) // Output: String: hello
} else {
fmt.Println("Not a string")
}
n, ok := i.(int)
if ok {
fmt.Println("Integer:", n)
} else {
fmt.Println("Not an integer")
}
}
Конструкция
switch
позволяет обрабатывать значения различных типов, хранящиеся в пустом интерфейсе.package main
import "fmt"
func printType(i interface{}) {
switch v := i.(type) {
case string:
fmt.Println("String:", v)
case int:
fmt.Println("Integer:", v)
case bool:
fmt.Println("Boolean:", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}
func main() {
printType("hello") // Output: String: hello
printType(42) // Output: Integer: 42
printType(true) // Output: Boolean: true
printType(3.14) // Output: Unknown type: float64
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
Кэширование помогает:
- Ускорить доступ к часто используемым данным.
- Снизить нагрузку на сервер или БД.
- Сократить сетевой трафик и задержки.
- Обеспечить плавную работу при временных перебоях внешних сервисов.
Кэш может быть в памяти, на диске, на клиенте, в браузере или на уровне CDN.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
В Go обычный
map
не потокобезопасен. Если несколько горутин одновременно записывают в map
, возникнет ошибка "fatal error: concurrent map writes". Решение: использовать синхронизацию через
sync.Mutex
, sync.RWMutex
или sync.Map
. Блокируем доступ на запись и чтение через
sync.Mutex
. package main
import (
"fmt"
"sync"
)
type SafeMap struct {
mu sync.Mutex
m map[string]int
}
func (s *SafeMap) Set(key string, value int) {
s.mu.Lock() // Блокируем доступ
defer s.mu.Unlock()
s.m[key] = value
}
func (s *SafeMap) Get(key string) int {
s.mu.Lock() // Блокируем на чтение
defer s.mu.Unlock()
return s.m[key]
}
func main() {
safeMap := SafeMap{m: make(map[string]int)}
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
safeMap.Set(fmt.Sprintf("key%d", i), i)
}(i)
}
wg.Wait()
fmt.Println("Готово:", safeMap.Get("key5")) // Получаем значение без гонок данных
}
sync.RWMutex
позволяет нескольким горутинам читать одновременно, но блокирует запись. type SafeMap struct {
mu sync.RWMutex
m map[string]int
}
func (s *SafeMap) Set(key string, value int) {
s.mu.Lock() // Блокируем только на запись
defer s.mu.Unlock()
s.m[key] = value
}
func (s *SafeMap) Get(key string) int {
s.mu.RLock() // Разрешаем множественное чтение
defer s.mu.RUnlock()
return s.m[key]
}
sync.Map
из стандартной библиотеки уже потокобезопасен, но работает немного медленнее обычного map
из-за внутренних механизмов. package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Map
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
m.Store(i, i*10) // Потокобезопасная запись
}(i)
}
wg.Wait()
val, ok := m.Load(5) // Потокобезопасное чтение
if ok {
fmt.Println("Значение:", val)
}
}
Использование канала (`chan`) вместо `map`
Вместо
map
можно передавать данные через канал (chan
), если логика позволяет. package main
import (
"fmt"
)
func main() {
ch := make(chan map[string]int, 1)
ch <- make(map[string]int)
go func() {
m := <-ch
m["key"] = 42
ch <- m
}()
m := <-ch
fmt.Println(m["key"]) // 42
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2