Дополнительный блок ({ ... }) внутри функции используется для:
- ограничения области видимости переменных;
- создания временной логической области, например, для вложенного вычисления;
- контроля жизни переменной, чтобы освободить её как можно раньше (особенно в длинных функциях или при работе с ресурсами)
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥3
Карты (maps) предоставляют несколько основных функций и операций для работы с ними. Эти функции позволяют добавлять, удалять, получать значения и проверять наличие ключей в карте.
Для этого используется ключевое слово
map, после которого указываются типы ключей и значений.var myMap map[string]int
Это можно сделать с помощью функции
make или литерала карты.// Инициализация с помощью make
myMap = make(map[string]int)
// Инициализация с помощью литерала карты
myMap = map[string]int{
"Alice": 25,
"Bob": 30,
}
Для этого используется синтаксис индексирования.
myMap["Charlie"] = 35
myMap["Alice"] = 26 // обновление значения по ключу "Alice"
Для этого используется синтаксис индексирования.
age := myMap["Alice"]
fmt.Println(age) // 26
Чтобы проверить это можно использовать двойное присваивание.
age, exists := myMap["David"]
if exists {
fmt.Println("Age of David:", age)
} else {
fmt.Println("David not found")
}
Для этого используется встроенная функция
delete.delete(myMap, "Bob")
Для этого используется цикл
for range.for key, value := range myMap {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}Пример
package main
import (
"fmt"
)
func main() {
// Инициализация карты с помощью литерала
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}
// Добавление нового элемента
myMap["Charlie"] = 35
// Обновление существующего элемента
myMap["Alice"] = 26
// Извлечение значения по ключу
age := myMap["Alice"]
fmt.Println("Age of Alice:", age) // 26
// Проверка существования ключа
age, exists := myMap["David"]
if exists {
fmt.Println("Age of David:", age)
} else {
fmt.Println("David not found")
}
// Удаление элемента
delete(myMap, "Bob")
// Итерация по карте
for key, value := range myMap {
fmt.Printf("Key: %s, Value: %d\n", key, value)
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Это интерфейс, содержащий метод Close() error, который сигнализирует об освобождении ресурсов, например, файлов или соединений. Если объект реализует Closer, его можно безопасно завершить, вызвав Close, что предотвращает утечки ресурсов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6🤔2
В многопоточных (параллельных) программах горутины (goroutines) могут одновременно изменять одни и те же данные. Если не синхронизировать доступ, это приведёт к гонке данных (data race), когда несколько потоков читают/пишут одно и то же значение одновременно.
Используется для блокировки критической секции кода, чтобы в один момент только одна горутина могла изменять данные.
package main
import (
"fmt"
"sync"
)
var (
counter int
mutex sync.Mutex
)
func increment(wg *sync.WaitGroup) {
defer wg.Done()
mutex.Lock() // Блокируем доступ
counter++ // Изменяем данные
mutex.Unlock() // Разблокируем доступ
}
func main() {
var wg sync.WaitGroup
for i := 0; i < 1000; i++ {
wg.Add(1)
go increment(&wg)
}
wg.Wait()
fmt.Println("Итоговый счетчик:", counter) // 1000
}
Позволяет нескольким горутинам читать данные одновременно, но блокирует запись.
var (
data int
mutex sync.RWMutex
)
func readData(wg *sync.WaitGroup) {
defer wg.Done()
mutex.RLock() // Разрешаем чтение
fmt.Println("Читаем данные:", data)
mutex.RUnlock()
}
func writeData(wg *sync.WaitGroup) {
defer wg.Done()
mutex.Lock() // Блокируем на запись
data++
mutex.Unlock()
}
Позволяет дождаться завершения всех горутин без блокировки данных.
var wg sync.WaitGroup
wg.Add(2) // Ожидаем 2 горутины
go func() {
defer wg.Done()
fmt.Println("Горутина 1 завершилась")
}()
go func() {
defer wg.Done()
fmt.Println("Горутина 2 завершилась")
}()
wg.Wait() // Ждём завершения всех горутин
fmt.Println("Все горутины завершены")
Атомарные операции быстрее мьютексов и гарантируют безопасное обновление переменных без гонок данных.
import "sync/atomic"
var counter int64
func incrementAtomic() {
atomic.AddInt64(&counter, 1) // Атомарное увеличение
}
В Go рекомендуется избегать блокировок и использовать каналы для передачи данных между горутинами.
package main
import "fmt"
func main() {
ch := make(chan int) // Канал для передачи данных
go func() {
ch <- 42 // Отправляем данные
}()
data := <-ch // Получаем данные
fmt.Println("Получено:", data)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Обобщённо, "recover" означает стратегию, при которой система или компонент не падает окончательно, а пытается вернуть управление, залогировать ошибку или выполнить корректную очистку.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Структуры (struct) представляют собой агрегированные типы данных, которые позволяют объединять несколько различных типов данных под одним именем. Они служат для моделирования объектов и хранения связанных данных, предоставляя удобный способ управления сложными данными.
Определяются с использованием ключевого слова
struct. В структуре могут быть поля различных типов.package main
import "fmt"
// Определение структуры Person
type Person struct {
Name string
Age int
}
func main() {
// Создание экземпляра структуры
var p Person
p.Name = "Alice"
p.Age = 30
fmt.Println("Name:", p.Name)
fmt.Println("Age:", p.Age)
}
Существует несколько способов инициализации структур.
package main
import "fmt"
// Определение структуры Person
type Person struct {
Name string
Age int
}
func main() {
// Инициализация с использованием литерала структуры
p := Person{Name: "Bob", Age: 25}
fmt.Println("Name:", p.Name)
fmt.Println("Age:", p.Age)
}
Инициализация по умолчанию
package main
import "fmt"
// Определение структуры Person
type Person struct {
Name string
Age int
}
func main() {
// Инициализация по умолчанию (поля будут нулевыми значениями)
var p Person
fmt.Println("Name:", p.Name) // Пустая строка
fmt.Println("Age:", p.Age) // 0
}
Могут содержать другие структуры в качестве полей, что позволяет моделировать более сложные данные.
package main
import "fmt"
// Определение структур Address и Person
type Address struct {
City string
State string
}
type Person struct {
Name string
Age int
Address Address
}
func main() {
// Инициализация структуры с вложенной структурой
p := Person{
Name: "Charlie",
Age: 40,
Address: Address{
City: "New York",
State: "NY",
},
}
fmt.Println("Name:", p.Name)
fmt.Println("Age:", p.Age)
fmt.Println("City:", p.Address.City)
fmt.Println("State:", p.Address.State)
}
Могут быть ассоциированы со структурами, что позволяет добавлять функциональность к структурам.
package main
import "fmt"
// Определение структуры Person
type Person struct {
Name string
Age int
}
// Метод для структуры Person
func (p Person) Greet() {
fmt.Printf("Hello, my name is %s and I am %d years old.\n", p.Name, p.Age)
}
func main() {
p := Person{Name: "David", Age: 35}
p.Greet()
}
Позволяют логически объединять связанные данные в один тип.
Позволяют моделировать реальные объекты и их свойства.
Использование структур делает код более организованным и понятным.
Могут иметь методы, что позволяет добавлять функциональность и поведение объектам.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
2. Ёмкость (cap): максимальное количество элементов, которые слайс может вместить без перевыделения памяти.
3. При добавлении элементов с помощью append длина увеличивается, а если она превышает ёмкость, выделяется новый блок памяти с удвоенной ёмкостью.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Слайсы являются ссылочными типами, поэтому простое присваивание одного слайса другому создаст новую ссылку на тот же подлежащий массив. Если вы хотите создать копию слайса с независимым подлежащим массивом, можно использовать встроенную функцию
copy или методы, такие как использование append.Создает побайтовую копию элементов из одного слайса в другой.
package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
// Создаем новый слайс той же длины, что и оригинал
copySlice := make([]int, len(original))
// Копируем элементы из оригинального слайса в новый
copy(copySlice, original)
// Изменяем элемент в копии
copySlice[0] = 100
fmt.Println("Оригинал:", original) // Выводит: Оригинал: [1 2 3 4 5]
fmt.Println("Копия:", copySlice) // Выводит: Копия: [100 2 3 4 5]
}
Использование функции
inal)
Чтобы создать новый слайс с копированными элементами.
package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
// Копируем элементы из оригинального слайса в новый слайс
copySlice := append([]int(nil), original...)
// Изменяем элемент в копии
copySlice[0] = 100
fmt.Println("Оригинал:", original) // Выводит: Оригинал: [1 2 3 4 5]
fmt.Println("Копия:", copySlice) // Выводит: Копия: [100 2 3 4 5]
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🤔1
Singleton гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к нему.
Характеристики:
- Ленивая инициализация (создаётся при первом вызове).
- Применяется для объектов, которые должны быть уникальны: логгеры, конфигурация, доступ к БД.
- В Go реализуется через глобальные переменные и sync.Once для потокобезопасной инициализации.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
В Go для проверки работы горутины часто используют каналы. Они позволяют передавать данные между горутинами и могут использоваться для сигнализации о состоянии выполнения горутины.
Горутина может отправлять сигнал (например,
true) в канал, чтобы уведомить о своем завершении.func worker(done chan bool) {
fmt.Println("Работа началась...")
time.Sleep(2 * time.Second) // Имитация работы
fmt.Println("Работа завершена!")
done <- true // Отправляем сигнал в канал
}
func main() {
done := make(chan bool)
go worker(done) // Запускаем горутину
// Ожидаем сигнал завершения
<-done
fmt.Println("Основной поток: горутина завершена")
}Горутина может отправлять данные в канал, чтобы сигнализировать о прогрессе выполнения.
func worker(progress chan int) {
for i := 1; i <= 5; i++ {
fmt.Printf("Шаг %d выполнен\n", i)
progress <- i // Отправляем номер шага в канал
time.Sleep(500 * time.Millisecond) // Имитация работы
}
close(progress) // Закрываем канал после завершения работы
}
func main() {
progress := make(chan int)
go worker(progress) // Запускаем горутину
// Считываем данные из канала
for step := range progress {
fmt.Printf("Получен сигнал: шаг %d завершен\n", step)
}
fmt.Println("Все шаги выполнены!")
}Если важно знать, работает ли горутина, но при этом нужно ограничить ожидание, используется оператор
select с тайм-аутом.func worker(status chan string) {
time.Sleep(2 * time.Second) // Имитация работы
status <- "Горутина завершена"
}
func main() {
status := make(chan string)
go worker(status)
select {
case msg := <-status:
fmt.Println(msg)
case <-time.After(1 * time.Second): // Тайм-аут 1 секунда
fmt.Println("Горутина работает слишком долго")
}
}Закрытие канала может служить сигналом того, что горутина завершила свою работу.
func worker(done chan struct{}) {
fmt.Println("Горутина работает...")
time.Sleep(2 * time.Second)
fmt.Println("Горутина завершена!")
close(done) // Закрываем канал
}
func main() {
done := make(chan struct{})
go worker(done)
// Проверяем, когда канал закроется
<-done
fmt.Println("Основной поток: горутина завершила работу")
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1