Тип 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 механизм сборки мусора называется 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
👍3🔥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
👍2
В Go каналы (
chan) можно закрывать с помощью close(channel), чтобы показать, что больше не будет отправляться данных. Как закрыть канал?
ch := make(chan int)
close(ch) // Закрываем канал
Полный пример
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
for i := 1; i <= 3; i++ {
ch <- i // Отправляем данные
}
close(ch) // Закрываем канал
}()
for val := range ch { // Читаем пока канал не закроется
fmt.Println(val)
}
fmt.Println("Канал закрыт, чтение завершено")
}
Выход
1
2
3
Канал закрыт, чтение завершено
Используем
val, ok := <-ch: -
ok == true → канал открыт, есть данные. -
ok == false → канал закрыт. package main
import "fmt"
func main() {
ch := make(chan int)
close(ch)
val, ok := <-ch
fmt.Println("val:", val, "ok:", ok) // val: 0 ok: false
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
HTTP-запрос включает:
- Стартовую строку: метод (GET, POST), путь (/api), версия (HTTP/1.1)
- Заголовки (headers): информация о клиенте, типах данных, авторизации и т.д.
- Пустая строка: разделитель между заголовками и телом
- Тело (body): данные запроса (не всегда есть — например, у GET нет)
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Карты (maps) представляют собой ассоциативные массивы, которые связывают ключи с соответствующими значениями. Работа с картами включает получение и запись значений, и Go предоставляет удобный синтаксис для этих операций. Рассмотрим особенности синтаксиса получения и записи значений в карты.
Для этого используется синтаксис индексирования
value := myMap[key]
Пример
package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}
value := myMap["Alice"]
fmt.Println("Alice:", value) // Alice: 25
}
Для этого используется синтаксис двойного присваивания
value, exists := myMap[key]
Пример
package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}
value, exists := myMap["Charlie"]
if exists {
fmt.Println("Charlie:", value)
} else {
fmt.Println("Charlie not found")
}
}
Для этого используется синтаксис индексирования:
myMap[key] = value
Пример
package main
import "fmt"
func main() {
myMap := map[string]int{}
// Добавление значений
myMap["Alice"] = 25
myMap["Bob"] = 30
fmt.Println("Map:", myMap) // Map: map[Alice:25 Bob:30]
// Обновление значения
myMap["Alice"] = 26
fmt.Println("Updated Map:", myMap) // Updated Map: map[Alice:26 Bob:30]
}
Для этого используется встроенная функция
delete:delete(myMap, key)
Пример
package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}
// Удаление значения по ключу
delete(myMap, "Alice")
fmt.Println("Map after deletion:", myMap) // Map after deletion: map[Bob:30]
}
Если ключ отсутствует в карте, при попытке получения значения будет возвращено нулевое значение типа значения карты. Например, для карты
map[string]int это будет 0.package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
}
value := myMap["Bob"] // Ключ "Bob" отсутствует
fmt.Println("Value:", value) // Value: 0
}
Нельзя записывать значения в
nil карту. Это приведет к панике времени выполнения.package main
func main() {
var myMap map[string]int // nil карта
myMap["Alice"] = 25 // Вызовет панику: runtime error: assignment to entry in nil map
}
Порядок итерации по карте не определен и может различаться между разными запусками программы.
package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
"Carol": 35,
}
for key, value := range myMap {
fmt.Printf("%s: %d\n", key, value)
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Если у метода ресивер с *, это означает, что метод работает с указателем на объект, а значит:
- изменения внутри метода повлияют на оригинальный объект;
- метод может модифицировать поля структуры;
- вызов возможен как на указателе, так и на значении (Go сам "разыменует").
Такой метод можно вызывать и на value, и на pointer — Go сделает автоматическую конвертацию.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2
Да, между SSL (Secure Sockets Layer) и TLS (Transport Layer Security) есть отличия. TLS является улучшенной и более безопасной версией SSL.
SSL 1.0: Никогда не был выпущен публично из-за серьезных уязвимостей.
SSL 2.0: Выпущен в 1995 году, но вскоре был признан небезопасным из-за множества уязвимостей.
SSL 3.0: Выпущен в 1996 году, значительно улучшил безопасность, но со временем также был признан устаревшим из-за уязвимостей (например, POODLE-атака).
TLS 1.0: Выпущен в 1999 году как обновление SSL 3.0. Включает исправления безопасности и улучшения.
TLS 1.1: Выпущен в 2006 году с дополнительными защитами от некоторых атак.
TLS 1.2: Выпущен в 2008 году, поддерживает современные алгоритмы шифрования и хеширования.
TLS 1.3: Выпущен в 2018 году, значительно улучшена безопасность и производительность, упрощен процесс установки соединения.
SSL: Поддерживает более старые и менее безопасные алгоритмы шифрования.
TLS: Поддерживает более современные и безопасные алгоритмы шифрования. TLS 1.3 исключает поддержку устаревших алгоритмов и предлагает только современные безопасные алгоритмы.
SSL: Более сложный процесс рукопожатия, включающий несколько шагов, что делает его уязвимым для некоторых атак.
TLS: Улучшенный процесс рукопожатия, включая использование HMAC (Hash-based Message Authentication Code) для обеспечения целостности сообщения. TLS 1.3 значительно упрощает и ускоряет процесс рукопожатия.
SSL: Использует комбинацию MD5 и SHA-1 для целостности данных, что не так безопасно по современным стандартам.
TLS: Использует HMAC с SHA-256 и другими современными алгоритмами для обеспечения целостности данных.
SSL: Меньше возможностей для управления сеансами.
TLS: Включает улучшенные механизмы для управления сеансами, такие как возобновление сеансов, что позволяет экономить время и ресурсы при повторных подключениях.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Тип string в Go — это последовательность байтов, закодированных в UTF-8.
Он реализован как структура:
- указатель на массив байтов;
- длина строки.
Строки неизменяемы. Любая операция, которая кажется «изменением», на самом деле создаёт новую строку.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Нет, строки (
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
👍1
- UInt — беззнаковое целое число, только 0 и положительные значения.
UInt полезен, если ты точно знаешь, что число не может быть отрицательным (например, размер массива). Однако арифметические операции между Int и UInt требуют явного преобразования.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Составной индекс (Composite Index) — это индекс, который создаётся сразу на нескольких колонках таблицы базы данных. Он помогает ускорить поиск и сортировку данных, особенно если запросы используют условия по нескольким полям.
Если часто выполняются запросы с фильтрацией по нескольким колонкам (
WHERE col1 = X AND col2 = Y), составной индекс ускоряет их выполнение.Если запросы используют
ORDER BY col1, col2, индекс помогает избежать дополнительной сортировки.Без индекса СУБД вынуждена выполнять полный перебор (Full Table Scan), что занимает больше времени.
Он строится по нескольким колонкам и фактически представляет собой отсортированную структуру данных. Например, в PostgreSQL или MySQL создаётся так:
CREATE INDEX idx_name ON users (last_name, first_name);
Теперь база данных будет использовать индекс для запросов:
SELECT * FROM users WHERE last_name = 'Иванов' AND first_name = 'Петр';
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1