Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Горутины в Go являются легковесными потоками управления, которые позволяют выполнять параллельные задачи более эффективно по сравнению с потоками операционной системы. Их ключевые преимущества включают:
Горутины потребляют значительно меньше памяти и ресурсов по сравнению с потоками ОС. Каждая горутина стартует с размером стека порядка 2 КБ, тогда как поток ОС требует гораздо большего размера стека (обычно несколько мегабайт).
Горутины управляются встроенным планировщиком Go, а не планировщиком ОС. Планировщик Go распределяет выполнение горутин по доступным потокам ОС, используя концепцию "M:N" (много горутин на несколько потоков).
Создание, синхронизация и управление горутинами намного проще благодаря встроенным средствам Go, таким как каналы (
channels
) и sync
-пакет. В то время как работа с потоками ОС требует дополнительных усилий для синхронизации (мьютексы, условные переменные и т.д.).Стек горутины автоматически увеличивается или уменьшается в зависимости от потребностей, что позволяет эффективно использовать память.
Синтаксис и использование горутин интуитивно понятны. Для запуска достаточно добавить
go
перед вызовом функции:package main
import (
"fmt"
"time"
)
func sayHello() {
for i := 0; i < 5; i++ {
fmt.Println("Hello")
time.Sleep(100 * time.Millisecond)
}
}
func main() {
go sayHello() // Запускаем горутину
fmt.Println("World")
time.Sleep(1 * time.Second) // Даем горутине время завершиться
}
Горутины позволяют эффективно использовать современные многоядерные процессоры благодаря встроенной конкурентной модели и поддержке параллелизма.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2❤1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Концепции объектно-ориентированного программирования (ООП) реализованы несколько иначе, чем в традиционных ООП-языках, таких как Java или C++. Не использует классы, наследование и полиморфизм на основе классов в привычном понимании. Вместо этого он применяет интерфейсы, структуры и встраивание для достижения гибкости и мощи ООП.
Основной способ организации и капсуляции данных — это структуры (
structs
). Структуры объединяют данные в одну сущность, но в отличие от классов, они не включают определение методов внутри себя. Вместо этого методы определяются отдельно и ассоциируются со структурой через определение получателя метода.type Person struct {
Name string
Age int
}
func (p Person) Greet() string {
return "Hello, my name is " + p.Name
}
Реализуется через интерфейсы. Интерфейс — это набор сигнатур методов. Тип считается реализующим интерфейс, если он имеет все методы, указанные в интерфейсе. Важной особенностью интерфейсов в Go является то, что типы могут удовлетворять интерфейсам неявно, без специального объявления.
type Greeter interface {
Greet() string
}
func GreetSomeone(g Greeter) {
fmt.Println(g.Greet())
}
Один из способов реализации композиции — встраивание структур. Можно встроить одну структуру в другую, что позволяет делегировать часть работы встроенной структуре.
type Employee struct {
Person
Position string
}
func (e Employee) Work() string {
return e.Name + " is working as a " + e.Position
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
2. Через функцию make: s := make([]int, length, capacity).
3. Срезав массив: s := array[start:end].
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3
Это ситуация, когда несколько горутин (или потоков) находятся в состоянии ожидания друг друга, из-за чего выполнение программы останавливается. В Go deadlock может произойти при неправильной работе с каналами, мьютексами и другими механизмами синхронизации.
Если несколько горутин используют блокировки (например, через мьютексы), убедитесь, что все они захватывают их в одном и том же порядке.
func main() {
var mu1, mu2 sync.Mutex
go func() {
mu1.Lock()
defer mu1.Unlock()
mu2.Lock()
defer mu2.Unlock()
}()
go func() {
mu2.Lock()
defer mu2.Unlock()
mu1.Lock()
defer mu1.Unlock()
}()
}
Каналы должны всегда иметь возможность отправки и получения данных. Если одна сторона (отправитель или получатель) заблокирована навсегда, возникает deadlock.
func main() {
ch := make(chan int)
ch <- 42 // Deadlock, так как никто не читает из канала
}
Каналы нужно закрывать только со стороны отправителя, и только тогда, когда больше не будет отправок данных. Неправильное закрытие или отсутствие закрытия может привести к проблемам, включая deadlock.
ch := make(chan int)
close(ch) // Закрыт слишком рано
ch <- 42 // Паника
Иногда deadlock происходит, если горутина ждет сама себя.
func main() {
ch := make(chan int)
ch <- 1
fmt.Println(<-ch) // Никогда не выполнится
}
Go позволяет избегать блокировок с помощью механизма тайм-аутов и оператора
select
. Если операция занимает слишком много времени, можно выполнить альтернативное действие.func main() {
ch := make(chan int)
select {
case data := <-ch:
fmt.Println("Получены данные:", data)
case <-time.After(1 * time.Second):
fmt.Println("Тайм-аут, завершение")
}
}
Go предоставляет утилиту
go run -race
, которая помогает выявлять гонки данных и другие проблемы, связанные с синхронизацией.go run -race main.go
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👾2
Ключи в map (карте) должны обладать определенными свойствами, чтобы быть допустимыми и корректно работать с хеш-таблицей. Важно понимать, что ключи должны поддерживать операцию сравнения и быть хешируемыми.
Ключи должны поддерживать операцию сравнения с использованием оператора
==
. Это необходимо для проверки равенства ключей при выполнении операций вставки, поиска и удаления в карте.Ключи должны быть хешируемыми. Это значит, что для ключей должна существовать функция, которая преобразует их в хеш-код. Хеш-код используется для определения позиции ключа в хеш-таблице.
Булевый тип (bool)
m := map[bool]string{
true: "Yes",
false: "No",
}
Целочисленные типы (int, int8, int16, int32, int64, а также их беззнаковые эквиваленты uint, uint8, uint16, uint32, uint64)
m := map[int]string{
1: "One",
2: "Two",
}
Числа с плавающей точкой (float32, float64)
m := map[float64]string{
1.1: "One point one",
2.2: "Two point two",
}
Строки (string)
m := map[string]int{
"Alice": 25,
"Bob": 30,
}
Составные типы (структуры, массивы), при условии, что все их поля также поддерживают сравнение с помощью оператора ==
type Key struct {
FirstName string
LastName string
}
m := map[Key]int{
{"Alice", "Smith"}: 1,
{"Bob", "Johnson"}: 2,
}
slice
)Срезы не поддерживают операцию сравнения с использованием оператора
==
(только сравнение с nil
).map
)Карты не поддерживают операцию сравнения.
func
)Функции не поддерживают операцию сравнения.
package main
import "fmt"
type Person struct {
FirstName string
LastName string
}
func main() {
// Создаем карту с ключами типа Person
m := make(map[Person]int)
// Вставляем значения в карту
m[Person{"Alice", "Smith"}] = 25
m[Person{"Bob", "Johnson"}] = 30
// Выводим значения из карты
fmt.Println(m[Person{"Alice", "Smith"}]) // Выводит: 25
fmt.Println(m[Person{"Bob", "Johnson"}]) // Выводит: 30
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
В Go дополнительный блок фигурных скобок
{}
в функции используется для ограничения области видимости переменных и улучшения читаемости кода. Это позволяет временно вводить переменные или выполнять локальные операции без влияния на остальную часть функции.Переменные, объявленные внутри блока
{}
, видимы только в пределах этого блока. Это полезно для временных переменных, которые не должны "загрязнять" основную область видимости функции.func processData() {
{
value := 42
fmt.Println("Внутренний блок, value =", value) // value доступна только здесь
}
// fmt.Println(value) // Ошибка: value не определена за пределами блока
}
С помощью блоков можно явно управлять временем жизни переменных, таких как файлы, соединения или буферы. Это особенно важно для ресурсов, которые необходимо закрыть или освободить.
func readFile() {
{
file, err := os.Open("example.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close() // Закроется при выходе из блока
// Работа с файлом
fmt.Println("Чтение файла")
}
// Здесь файл уже закрыт
}
В больших функциях дополнительный блок позволяет логически разделить код на части, делая его более понятным.
func main() {
{
// Работа с настройками
config := loadConfig()
fmt.Println("Конфигурация загружена:", config)
}
{
// Работа с данными
data := fetchData()
fmt.Println("Данные получены:", data)
}
}
Можно использовать дополнительные блоки для изоляции сложных кусков кода и последующего их упрощения.
func calculate() int {
result := 0
{
a := 10
b := 20
result = a + b
}
return result
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
В Go строки представляют собой неизменяемые последовательности байтов, и операция сложения строк (
+
) приводит к созданию новой строки, которая является конкатенацией двух или более исходных строк. Когда вы складываете строки, Go создает новую строку, содержащую все символы исходных строк, соединенных друг за другом. Исходные строки при этом остаются неизменными.
s1 := "Hello"
s2 := "World"
result := s1 + " " + s2
fmt.Println(result) // Output: Hello World
Так как строки в Go неизменяемы, результирующая строка создается заново, а память для нее выделяется в куче или на стеке, в зависимости от размера и контекста.
Сложение строк через оператор
+
может быть неэффективным при множественных операциях, так как каждый раз создается новая строка, а старые промежуточные результаты удаляются сборщиком мусора.result := ""
for i := 0; i < 5; i++ {
result += "Go"
}
fmt.Println(result) // Output: GoGoGoGoGo
Если требуется объединить много строк, рекомендуется использовать
strings.Builder
. Это более эффективный способ, так как Builder
работает с буфером и избегает лишних аллокаций.import "strings"
func main() {
var builder strings.Builder
for i := 0; i < 5; i++ {
builder.WriteString("Go")
}
fmt.Println(builder.String()) // Output: GoGoGoGoGo
}
Go строки поддерживают Unicode, поэтому сложение строк корректно работает с многобайтовыми символами.
s1 := "Привет"
s2 := "Мир"
result := s1 + " " + s2
fmt.Println(result) // Output: Привет Мир
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Это структура данных, которая используется для хранения и поиска пар "ключ-значение". Обеспечивают быстрый доступ к данным по ключу, обычно с константным временем доступа в среднем случае. Основой работы хэш-таблицы является хеш-функция, которая преобразует ключ в индекс, по которому хранится значение.
Функция, которая принимает ключ и преобразует его в индекс массива, называемого "хэш-таблицей". Хорошая хеш-функция распределяет ключи равномерно по хэш-таблице, минимизируя количество коллизий.
Массив фиксированного размера, где каждый элемент называется "корзиной" (bucket). Корзина может содержать одно или несколько значений.
Ситуация, когда два разных ключа хешируются в один и тот же индекс. Коллизии решаются с помощью различных методов, таких как цепочки (chaining) или открытая адресация (open addressing).
Хеш-функция вычисляет индекс для данного ключа. Значение помещается в соответствующую корзину по этому индексу. Если возникает коллизия, используется метод разрешения коллизий.
Хеш-функция вычисляет индекс для ключа. Корзина по этому индексу проверяется на наличие значения. Если значение найдено, оно возвращается; если нет, возвращается индикатор отсутствия значения.
Хеш-функция вычисляет индекс для ключа. Значение удаляется из соответствующей корзины. При необходимости корректируются ссылки или структура данных для разрешения коллизий.
Среднее время доступа к элементу составляет O(1).
Обеспечивает простой интерфейс для вставки, поиска и удаления данных.
Требуют дополнительных механизмов для разрешения, что может усложнить реализацию.
Эффективность хэш-таблицы зависит от качества хеш-функции.
При увеличении количества элементов может потребоваться перераспределение и увеличение размера таблицы, что временно снижает производительность.
package main
import "fmt"
func main() {
// Создание карты
myMap := make(map[string]int)
// Вставка значений
myMap["Alice"] = 25
myMap["Bob"] = 30
// Поиск значений
value, exists := myMap["Alice"]
if exists {
fmt.Println("Alice:", value) // Alice: 25
} else {
fmt.Println("Alice not found")
}
// Удаление значений
delete(myMap, "Alice")
_, exists = myMap["Alice"]
if !exists {
fmt.Println("Alice has been deleted") // Alice has been deleted
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
1. Добавление одного элемента: slice = append(slice, element).
2. Добавление нескольких элементов: slice = append(slice, elements...).
3. Слияние с другим слайсом: slice = append(slice, otherSlice...).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
В 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
👍4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Оператор "квадратные скобки" (
[]
) при применении к строке используется для доступа к отдельным байтам в этой строке. Строки представлены как последовательности байтов, и оператор []
позволяет получить байт по указанному индексу. package main
import (
"fmt"
)
func main() {
str := "hello"
// Получаем байт по индексу
firstByte := str[0]
// Выводим байт и его символ
fmt.Printf("Первый байт: %d\n", firstByte) // Выводит: 104
fmt.Printf("Первый символ: %c\n", firstByte) // Выводит: h
}
В этой строке кода мы получаем байт, расположенный по индексу
0
в строке str
. В данном случае это байт, соответствующий символу 'h'.firstByte := str[0]
Здесь мы выводим байт в виде целого числа. Поскольку символ 'h' имеет ASCII-код 104, вывод будет
104
.fmt.Printf("Первый байт: %d\n", firstByte)
Мы также можем вывести байт как символ, используя формат
%c
. Это отобразит символ 'h'.fmt.Printf("Первый символ: %c\n", firstByte)
Важно понимать, что строки являются последовательностями байтов, а не символов. Это означает, что доступ по индексу с помощью
[]
дает байт, а не руну (rune). Если строка содержит многобайтовые символы (например, символы Unicode), то доступ по индексу может вернуть только один из байтов, составляющих символ.package main
import (
"fmt"
)
func main() {
str := "Привет"
// Получаем байт по индексу
firstByte := str[0]
// Выводим байт и его символ
fmt.Printf("Первый байт: %d\n", firstByte) // Выводит: 208
fmt.Printf("Первый символ: %c\n", firstByte) // Выводит: � (неполный символ)
}
Для корректной работы с многобайтовыми символами (рунами) в строках используется преобразование строки в срез рун
package main
import (
"fmt"
)
func main() {
str := "Привет"
// Преобразуем строку в срез рун
runes := []rune(str)
// Получаем руну по индексу
firstRune := runes[0]
// Выводим руну и её символ
fmt.Printf("Первая руна: %d\n", firstRune) // Выводит: 1055 (код Unicode для 'П')
fmt.Printf("Первый символ: %c\n", firstRune) // Выводит: П
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Массивы представляют собой фиксированную последовательность элементов одного типа. Являются основополагающей структурой данных, на базе которой строятся более сложные структуры, такие как слайсы. Рассмотрим, как устроены массивы, их особенности, а также сравнение с другими структурами данных.
Размер массива задается при его объявлении и не может изменяться во время выполнения программы.
Все элементы массива имеют один и тот же тип.
В отличие от слайсов, массивы хранят свои элементы в непрерывном блоке памяти.
С указанием типа элементов и фиксированного размера. Это объявление создает массив из пяти целых чисел, инициализированных нулями.
var arr [5]int
Массивы могут быть инициализированы при объявлении
arr := [5]int{1, 2, 3, 4, 5}
Можно также инициализировать массив частично, оставив остальные элементы равными нулям:
arr := [5]int{1, 2}
Осуществляется с использованием индексов, начиная с 0
fmt.Println(arr[0]) // 1
arr[1] = 10
fmt.Println(arr[1]) // 10
Фиксирована и задается при его объявлении. Ее можно получить с помощью функции
len
fmt.Println(len(arr)) // 5
При присваивании одного массива другому копируются все элементы:
arr1 := [5]int{1, 2, 3, 4, 5}
arr2 := arr1
arr2[0] = 10
fmt.Println(arr1) // [1 2 3 4 5]
fmt.Println(arr2) // [10 2 3 4 5]
При этом копируется весь массив:
func modifyArray(a [5]int) {
a[0] = 10
}
arr := [5]int{1, 2, 3, 4, 5}
modifyArray(arr)
fmt.Println(arr) // [1 2 3 4 5]
Массивы имеют фиксированный размер, тогда как слайсы динамичны.
Массивы могут быть более производительными для небольших коллекций данных из-за отсутствия накладных расходов на управление динамическими данными.
Использование массивов
package main
import (
"fmt"
)
func main() {
// Объявление и инициализация массива
arr := [5]int{1, 2, 3, 4, 5}
// Доступ к элементам
fmt.Println("First element:", arr[0]) // First element: 1
// Изменение элементов
arr[1] = 10
fmt.Println("Modified array:", arr) // Modified array: [1 10 3 4 5]
// Длина массива
fmt.Println("Length of array:", len(arr)) // Length of array: 5
// Копирование массива
arr2 := arr
arr2[0] = 20
fmt.Println("Original array:", arr) // Original array: [1 10 3 4 5]
fmt.Println("Copied array:", arr2) // Copied array: [20 10 3 4 5]
// Передача массива в функцию
modifyArray(arr)
fmt.Println("Array after modifyArray call:", arr) // Array after modifyArray call: [1 10 3 4 5]
}
func modifyArray(a [5]int) {
a[0] = 10
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4