TUI —
Примеры TUI:
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱5👍3❤2👾2😁1
Слайс — это структура из трех полей:
Однако если вы делаете
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤2
Константы могут быть
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Под капотом:
1. Выделяется новый массив с
2.
3. Добавляется новый
4. Возвращается
Четвёртый пункт — это одна из причин, почему важно всегда присваивать результат
append(). Старый слайс может указывать наPlease open Telegram to view this post
VIEW IN TELEGRAM
👍3❤2
sync.WaitGroup — это примитив синхронизации из стандартного пакета sync, предназначенный для WaitGroup использует внутренний счётчик:
• Счётчик увеличивается при
• Уменьшается при
• Когда счётчик достигает нуля —
Пример использования:
func main() {
var wg sync.WaitGroup
numWorkers := 3
wg.Add(numWorkers) // Устанавливаем счётчик равным количеству горутин
for i := 1; i <= numWorkers; i++ {
go worker(i, &wg) // Запускаем горутины
}
wg.Wait() // Блокируемся до завершения всех горутин
fmt.Println("Все горутины завершены")
}Please open Telegram to view this post
VIEW IN TELEGRAM
👍8😁1
Defer гарантированно выполнится при нормальном выходе из функции — это его основное предназначение. Но важно понимать нюансы:
• При обычном return из функции — defer отработает до
• При панике — defer выполнится перед
• При достижении конца функции — все отложенные вызовы выполнятся в
Когда defer НЕ выполнится:
• os.Exit() — немедленно завершает программу, defer'ы
• Фатальные ошибки
•
• Бесконечные
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
wg.Done() используется для сигнализации sync.WaitGroup. Это метод Пример:
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // Гарантированный вызов wg.Done()
time.Sleep(time.Duration(id) * time.Second)
fmt.Printf("Worker %d завершен\n", id)
}Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Пример:
package main
import "fmt"
func main() {
var fib func(n int) int // Объявляем переменную с типом функции
fib = func(n int) int { // Теперь можем ссылаться на fib внутри
if n < 2 {
return n
}
return fib(n-1) + fib(n-2) // Рекурсивный вызов
}
fmt.Println(fib(7)) // Вывод: 13
}
Вложенные функции подходят для задач вроде
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3🤔1🌚1
Горутина завершается
• Через done-канал
done := make(chan struct{})
go func() {
for {
select {
case <-done:
return // выходим из горутины
default:
// делаем работу
}
}
}()
// когда нужно остановить
close(done)• Через context
ctx, cancel := context.WithCancel(context.Background())
go func() {
for {
select {
case <-ctx.Done():
return
default:
// делаем работу
}
}
}()
// когда нужно остановить
cancel()
thread.kill() из других языков.Please open Telegram to view this post
VIEW IN TELEGRAM
😍5🔥3🥱1
Функция
recover() в Go возвращает panic(), если она Пример использования:
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Паника перехвачена:", r) // Вывод: Паника перехвачена: ошибка!
}
}()
panic("ошибка!")
fmt.Println("Этот код не выполнится") // Пропускается
}Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ключ должен быть
== и !=.var m map[string]int // работает
var m map[int]string // работает
var m map[[]byte]int // ошибка компиляции: slice не comparable
var m map[map[string]int]int // ошибка: map не comparable
Что можно использовать как ключ:
• bool
• int, int8, int16, int32, int64
• uint, uint8, uint16, uint32, uint64, uintptr
• float32, float64
• complex64, complex128
• string
• pointer (*T)
• channel (chan T)
• interface — если динамический тип comparable
• struct — если все поля comparable
• array [N]T, если T comparable
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍2
nil-слайс и пустой слайс имеют схожий внешний вид и поведение в большинстве операций, но
Обе формы безопасны:
len, cap дают 0, append работает одинаково, цикл range не выполнится. Разница видна при Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🎉3
В Go
Мапа в Go реализована как хеш-таблица, которая может динамически
Код, который выдаст ошибку
m := map[string]int{"a": 1}
p := &m["a"] // cannot take the address of m["a"]Что делать вместо этого
Хранить указатели в мапе:
m := map[string]*int{}
val := 1
m["a"] = &valИзвлечь значение, изменить, записать обратно:
m := map[string]int{"a": 1}
val := m["a"]
val++
m["a"] = valИспользовать структуры:
type Data struct { value int }
m := map[string]*Data{"a": {1}}
m["a"].value++ // работаетPlease open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3
Согласно документации, анализатор forvar применяется только к
Причина в том, что проблема с
// До Go 1.22 - проблемный код
for _, x := range items {
go func() {
fmt.Println(x) // все горутины видели последнее значение x
}()
}
// Решение до Go 1.22
for _, x := range items {
x := x // создание новой переменной для каждой итерации
go func() {
fmt.Println(x) // теперь каждая горутина видит свое значение
}()
}
В
// Здесь проблемы не было даже до Go 1.22
for i := 0; i < 10; i++ {
go func() {
fmt.Println(i) // каждая итерация имела свой i
}()
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2😁1
Каждый defer добавляет вызов в
runtime.deferreturn Please open Telegram to view this post
VIEW IN TELEGRAM
🥰2
Если выражение состоит из констант, компилятор
const x = 5 * 10 + 3 становится Простые функции встраиваются в
Если код не используется вовсе, то компилятор
Please open Telegram to view this post
VIEW IN TELEGRAM
👾2
() с аргументами в конце для result := func(a, b int) int { return a + b }(3, 5)
fmt.Println(result) // 8Функция создаётся и исполняется сразу.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1😢1
Go предоставляет встроенные инструменты для работы с файловой системой:
Чтение файла
Типичный паттерн: открыть файл через
os.Open(), затем прочитать содержимое построчно с помощью bufio.Scanner:package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
file, err := os.Open("example.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}
Запись и дозапись в файл
Для создания нового файла используйте os.Create(), для дозаписи —
os.OpenFile() с флагами os.O_APPEND|os.O_WRONLY:// Создание и запись
file, err := os.Create("output.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
file.WriteString("Hello, Go!\n")
// Дозапись в существующий файл
file, err := os.OpenFile("output.txt",
os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer file.Close()
file.WriteString("Appended line\n")
Используйте
bufio.Writer для буферизации при записи больших объёмов данных — это значительно ускорит операции ввода-вывода.Please open Telegram to view this post
VIEW IN TELEGRAM
❤2👍1
В цикле
for index, value := range str строка str итерируется по UTF-8 index – байтовый индекс начала value – значение Please open Telegram to view this post
VIEW IN TELEGRAM
Чтобы сохранить
С точки зрения компилятора и поведения программы
any и interface{} Please open Telegram to view this post
VIEW IN TELEGRAM
😢2👍1
Поведение зависит от того, как это влияет на внутренний счётчик.
WaitGroup.Add() принимает любое целое число, включая var wg sync.WaitGroup
wg.Add(5) // счётчик = 5
wg.Add(-2) // счётчик = 3
Если
Add() делает внутренний счётчик отрицательным, то Please open Telegram to view this post
VIEW IN TELEGRAM
👍4