- Нет классов, используется композиция через структуры и методы.
- Полиморфизм достигается с помощью интерфейсов.
- Наследования нет, встраивание заменяет его.
2. C#:
- Полноценное ООП: классы, наследование, абстракция, интерфейсы.
- Поддержка модификаторов доступа (public, private, protected).
- Разработано для объектно-ориентированной модели с полной поддержкой инкапсуляции и полиморфизма.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
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
👍1
Примитивы — это средства, предотвращающие конфликты между потоками:
- Mutex — взаимное исключение.
- Semaphore — ограничение количества одновременных доступов.
- Spinlock — цикл ожидания без сна.
- RWLock (чтение-запись) — позволяет множественное чтение, но только одну запись.
- Atomic операции — безопасные базовые действия без блокировок.
- Condition variables — ожидание события от другого потока.
- Channel / Queue — для безопасного обмена данными (особенно в Go).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Слайс (
slice) — это динамический массив, который ссылается на часть массива в памяти. В отличие от массивов (array), слайсы могут изменять размер. Слайс в Go — это структура
type SliceHeader struct {
Data uintptr // Указатель на массив в памяти
Len int // Длина слайса (количество элементов)
Cap int // Вместимость (capacity) — сколько элементов может вместить без перевыделения памяти
}Пример структуры слайса
arr := [5]int{1, 2, 3, 4, 5}
s := arr[1:4] // Берём срез от 2-го до 4-го элемента
fmt.Println(s) // [2 3 4]Есть несколько способов создать слайс:
Способ 1: Срез массива
arr := [5]int{10, 20, 30, 40, 50}
s := arr[1:4] // [20 30 40]Способ 2: Использование
make()s := make([]int, 3, 5) // Длина 3, вместимость 5
fmt.Println(s, len(s), cap(s)) // [0 0 0] 3 5
Способ 3: Литерал (инициализация значениями)
s := []int{1, 2, 3}
fmt.Println(s) // [1 2 3]Слайсы можно изменять, используя
append(). s := []int{1, 2, 3}
s = append(s, 4, 5)
fmt.Println(s) // [1 2 3 4 5]Когда
append() увеличивает slice, Go использует оптимизированный алгоритм роста:- Если
cap < 1024, слайс удваивает размер (cap *= 2). - Если
cap >= 1024, рост идёт примерно на 25% (cap += cap / 4). s := []int{}
for i := 0; i < 10; i++ {
s = append(s, i)
fmt.Printf("Len: %d, Cap: %d\n", len(s), cap(s))
}Выход (пример)
Len: 1, Cap: 1
Len: 2, Cap: 2
Len: 3, Cap: 4
Len: 5, Cap: 8
Len: 9, Cap: 16
Так как слайсы хранят ссылку на массив, возможны побочные эффекты.
arr := [5]int{1, 2, 3, 4, 5}
s1 := arr[:3] // [1 2 3]
s2 := arr[2:] // [3 4 5]
s2[0] = 100 // Меняем первый элемент s2
fmt.Println(s1) // [1 2 100] ❗️ s1 тоже изменилсяРешение: используйте
copy() для создания нового массива. s1 := []int{1, 2, 3}
s2 := make([]int, len(s1))
copy(s2, s1) // Копируем данные
s2[0] = 100
fmt.Println(s1) // [1 2 3] ✅ Оригинал не изменилсяСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Тип rune представляет собой alias для типа
int32, предназначенного для хранения Unicode кодовых точек.Строки (
string) являются последовательностями байтов, а не символов. Это означает, что один символ может занимать больше одного байта, особенно если это символ из расширенного набора Unicode.Тип используется для работы с символами, представляемыми одной кодовой точкой Unicode. Это упрощает манипуляции с символами, так как каждая
rune — это отдельный символ, независимо от его длины в байтах.Использование типа
rune делает код более понятным и само-документируемым. Когда в коде виден тип rune, это сразу указывает на то, что переменная предназначена для хранения одного символа, а не целого числа.Создание и инициализация
var r rune = '世'
fmt.Println(r) // Output: 19990
Итерация по строке
s := "Привет, 世界"
for _, r := range s {
fmt.Printf("%c ", r)
}
// Output: П р и в е т , 世 界
Преобразование между
string ито такоеs := "Go"
runes := []rune(s)
fmt.Println(runes) // Output: [71 111]
s2 := string(runes)
fmt.Println(s2) // Output: Go
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
copy? 1. Синтаксис: copy(dst, src).
2. Копируется минимальное количество элементов, равное длине меньшего слайса.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
HAVING — это оператор SQL, который фильтрует результаты после GROUP BY, аналогично WHERE, но работает с агрегатными функциями (COUNT(), SUM(), AVG(), MAX(), MIN()). WHERE фильтрует до GROUP BY (по отдельным строкам). HAVING фильтрует после GROUP BY (по сгруппированным данным). Пример 1: Фильтрация по
HAVINGЗадача: Вывести товары, у которых продано более 10 единиц.
SELECT product, SUM(quantity) as total_sold
FROM sales
GROUP BY product
HAVING SUM(quantity) > 10;
Пример 2: Разница между
WHERE и HAVINGSELECT category, COUNT(*) as total_products
FROM products
WHERE price > 100 -- ❌ Убирает дешёвые товары ДО группировки
GROUP BY category
HAVING COUNT(*) > 5; -- ✅ Оставляет только категории с более 5 товаров
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Линтеры интегрируются в IDE или CI/CD пайплайны. Например, golangci-lint используется для анализа Go-кода.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2🤔1
Стажировки и вакансии для Go разработчиков.
- Вакансии которых нет на джоб-агрегаторах
- Только прямые контакты HR в Telegram
👉 @jobs_go
Пока другие листают джоб-сайты — ты уже пишешь HR в Telegram.
- Вакансии которых нет на джоб-агрегаторах
- Только прямые контакты HR в Telegram
👉 @jobs_go
Пока другие листают джоб-сайты — ты уже пишешь HR в Telegram.
В Go механизм сборки мусора называется Garbage Collector (GC).
Go использует автоматический сборщик мусора с конкурентной, трицветной, инкрементальной стратегией.
выполняется параллельно с работой программы.
объекты помечаются как белые, серые и чёрные.
работает порциями, а не останавливает программу надолго.
мусор, который будет удалён.
те, которые находятся в обработке.
используемые объекты, которые не подлежат удалению.
Чтобы уменьшить нагрузку на GC:
Используйте пул объектов (
sync.Pool). Минимизируйте аллокации в куче (например, используйте
[]byte вместо string, если можно). Ограничивайте долгоживущие объекты, так как они реже сканируются.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Зависит от уровня, но в общем:
- На уровне базы: индексация, query plan, нормализация, кэширование.
- На уровне кода: профилирование, снижение сложности алгоритмов.
- На уровне сети: сжатие, уменьшение количества запросов.
- На уровне архитектуры: кэш, очереди, шардирование, микросервисы, отказ от лишнего состояния.
- На уровне ОС/серверов: тюнинг параметров, балансировка, масштабирование.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Может быть как безопасным, так и небезопасным, в зависимости от контекста и конкретного использования.
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
buffer := make([]byte, 10)
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
buffer[i] = byte(i) // Несколько горутин одновременно модифицируют буфер
}(i)
}
wg.Wait()
fmt.Println("Buffer:", buffer)
}
Если несколько горутин только читают из буфера, это безопасно. Пример безопасного использования:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
buffer := []byte("Hello, World!")
for i := 0; i < len(buffer); i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Printf("buffer[%d]: %c\n", i, buffer[i])
}(i)
}
wg.Wait()
}
Для синхронизации доступа к буферу используйте мьютексы (
sync.Mutex). Это гарантирует, что только одна горутина в данный момент модифицирует буфер.package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var mu sync.Mutex
buffer := make([]byte, 10)
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
mu.Lock()
buffer[i] = byte(i)
mu.Unlock()
}(i)
}
wg.Wait()
fmt.Println("Buffer:", buffer)
}
Если каждая горутина должна работать с независимой копией буфера, создавайте копии для каждой горутины.
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
buffer := []byte("Hello, World!")
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
localBuffer := make([]byte, len(buffer))
copy(localBuffer, buffer)
localBuffer[i] = byte(i)
fmt.Printf("Goroutine %d: %s\n", i, localBuffer)
}(i)
}
wg.Wait()
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
- Rebase «переписывает» историю, перенося коммиты одной ветки поверх другой, будто они создавались последовательно.
Merge — безопаснее и прозрачно показывает, где ветки сливались. Rebase — чище история, но может быть опасен при совместной разработке, особенно на уже опубликованных ветках.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1