В Go есть несколько способов преобразования строки в число и числа в строку.
Используется пакет
strconv
и функция strconv.Atoi()
или strconv.ParseInt()
. package main
import (
"fmt"
"strconv"
)
func main() {
str := "42"
num, err := strconv.Atoi(str) // Преобразуем строку в int
if err != nil {
fmt.Println("Ошибка:", err)
return
}
fmt.Println("Число:", num) // Выведет: Число: 42
}
Пример 2:
strconv.ParseInt()
(гибкое преобразование) num, err := strconv.ParseInt("1234", 10, 64)
// "1234" → строка, 10 → десятичная система, 64 → int64
if err != nil {
fmt.Println("Ошибка:", err)
} else {
fmt.Println("Число:", num) // 1234
}
Используется
strconv.Itoa()
или strconv.FormatInt()
. num := 42
str := strconv.Itoa(num) // 42 → "42"
fmt.Println("Строка:", str) // "42"
Пример 2:
strconv.FormatInt()
(int64 → строка) num := int64(12345)
str := strconv.FormatInt(num, 10) // 10 — десятичная система
fmt.Println("Строка:", str) // "12345"
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Индексы занимают память и замедляют вставку/обновление. Не стоит индексировать:
- Часто изменяемые поля.
- Поля с высокой избыточностью (например, булевы значения, где 90% значений — true).
- Очень длинные строки (текст, JSONB без надобности).
- Маленькие таблицы, где поиск и так быстрый.
- Поля, по которым не происходит выборок или фильтраций.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Это система мониторинга и оповещения с открытым исходным кодом, разработанная для сбора и анализа метрик с серверов, приложений и других компонентов инфраструктуры.
позволяет отслеживать производительность, загрузку CPU, память, сетевой трафик и другие параметры.
использует модель pull (запрашивает данные у сервисов), а не push (как, например, Graphite). Это удобнее для управления и отказоустойчивости.
поддерживает кастомные метрики, которые можно интегрировать в своё приложение.
позволяет настроить уведомления при достижении критических значений.
помогает анализировать тренды и предсказывать возможные сбои.
легко развертывается в облаке, Kubernetes, Docker и других средах.
собирают данные.
опрашивает эти экспортеры по HTTP (pull-модель).
(язык запросов) используется для анализа данных.
или другие инструменты визуализируют метрики.
отправляет уведомления (Slack, Email, Telegram и др.).
Для интеграции в Go-приложение можно использовать пакет
prometheus/client_golang
package main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var httpRequests = prometheus.NewCounter(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total number of HTTP requests",
},
)
func handler(w http.ResponseWriter, r *http.Request) {
httpRequests.Inc() // Увеличиваем счетчик запросов
w.Write([]byte("Hello, Prometheus!"))
}
func main() {
// Регистрируем метрику
prometheus.MustRegister(httpRequests)
// Эндпоинт для сбора метрик
http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
В реальных проектах часто используются:
- Builder — для конфигурации сложных объектов (например, HTTP-клиентов).
- Factory — для создания сервисов по интерфейсу.
- Singleton — для централизованного логгера или глобальных параметров.
- Также могут применяться Strategy, Adapter, Observer, особенно при построении архитектуры с плагинами, хранилищами, UI-обработкой.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4💊3👍2
В 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
💊3👍2
- Шардирование — горизонтальное распределение данных по разным узлам или серверам. Например, одни пользователи хранятся в одном шарде, другие — в другом.
- Партиционирование — разбиение данных внутри одной базы или таблицы, например по дате, географии или категории. Все данные при этом могут оставаться на одном сервере.
Ключевое отличие: шардирование — про масштабирование инфраструктуры, партиционирование — про организацию данных внутри.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Нет, строки (
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
👍5🔥2💊1
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
ACID — это набор свойств транзакций в базах данных, обеспечивающий надежность и целостность данных.
Транзакция выполняется либо полностью, либо не выполняется вовсе.
Пример: Если при переводе денег со счета A на счет B ошибка произошла на полпути, изменения откатываются.
Данные остаются в правильном состоянии до и после транзакции.
Пример: Если сумма на всех счетах банка должна оставаться неизменной, транзакция не должна нарушить это правило.
Одновременные транзакции не мешают друг другу.
Пример: Два клиента покупают один и тот же товар, но база данных правильно обрабатывает, кто купил первым.
После завершения транзакции изменения сохраняются, даже если система сломается.
Пример: Если заказ оформлен, он не исчезнет при внезапном отключении электричества.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Go использует трассирующий сборщик мусора с метками (mark-and-sweep).
Он проходит в два этапа:
1. Mark — находят все доступные (живые) объекты.
2. Sweep — освобождают недоступные (мертвые) объекты.
GC работает инкрементально и в параллель с приложением, начиная с Go 1.5.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Существуют встроенные функции для преобразования типов, включая преобразование из строки в целое число и наоборот. Для этих целей используются функции из стандартной библиотеки
strconv
. Рассмотрим, как это делается.Для этого используется функция
strconv.Atoi
. Она возвращает два значения: само число и ошибку, если преобразование не удалось.package main
import (
"fmt"
"strconv"
)
func main() {
str := "123"
num, err := strconv.Atoi(str)
if err != nil {
fmt.Println("Error converting string to int:", err)
} else {
fmt.Println("Converted number:", num)
}
}
Для этого используется функция
strconv.Itoa
.package main
import (
"fmt"
"strconv"
)
func main() {
num := 123
str := strconv.Itoa(num)
fmt.Println("Converted string:", str)
}
Важно обрабатывать ошибки при преобразовании типов, особенно при преобразовании строки в целое число, чтобы избежать неожиданных сбоев в программе.
package main
import (
"fmt"
"strconv"
)
func main() {
str := "abc"
num, err := strconv.Atoi(str)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Converted number:", num)
}
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Перед названием метода указывается ресивер — переменная, к которой метод привязан. Он описывается в круглых скобках перед именем метода и указывает, для какого типа метод определён.
Здесь u *User — это ресивер. Он определяет, что метод PrintName относится к типу User, и при вызове будет доступ к его полям.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Размер числа в байтах зависит от его типа данных. В Go есть несколько числовых типов, и каждый занимает определённое количество байтов в памяти.
Можно проверить размер типа с помощью
unsafe.Sizeof()
package main
import (
"fmt"
"unsafe"
)
func main() {
var a int64
var b float64
var c byte // то же самое, что uint8
fmt.Println("int64:", unsafe.Sizeof(a)) // 8
fmt.Println("float64:", unsafe.Sizeof(b)) // 8
fmt.Println("byte:", unsafe.Sizeof(c)) // 1
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Карты (maps) реализованы на основе хеш-таблиц, что обеспечивает быстрый доступ к значениям по ключам. Давайте рассмотрим, как происходит поиск по ключу в карте, и какие этапы включены в этот процесс.
Сначала вычисляется хеш-значение ключа. Функция хеширования преобразует ключ в целое число, которое служит индексом в хеш-таблице.
Хеш-значение используется для доступа к соответствующей "ячейке" или "корзине" (bucket) в хеш-таблице.
Если корзина содержит несколько элементов (из-за коллизий хеширования), Go выполняет линейный поиск среди этих элементов, сравнивая ключи с использованием оператора
==
.Когда вы пытаетесь получить значение по ключу, Go сначала вычисляет хеш-значение этого ключа. Хеш-функция берет ключ (например, строку или целое число) и преобразует его в индекс хеш-таблицы.
Хеш-значение указывает на конкретную корзину в хеш-таблице. Корзина может содержать один или несколько элементов. В случае коллизий (когда несколько ключей хешируются в один и тот же индекс) корзина может содержать связанный список или другой механизм для хранения нескольких элементов.
Если корзина содержит несколько элементов, Go выполняет линейный поиск среди этих элементов. Для каждого элемента в корзине сравнивается ключ с искомым ключом с использованием оператора
==
. Если ключи совпадают, возвращается соответствующее значение. Если ключ не найден, возвращается нулевое значение типа (zero value) и флаг, указывающий на отсутствие ключа.package main
import "fmt"
func main() {
myMap := map[string]int{
"Alice": 25,
"Bob": 30,
}
value, exists := myMap["Alice"]
if exists {
fmt.Println("Alice:", value) // Alice: 25
} else {
fmt.Println("Alice not found")
}
value, exists = myMap["Charlie"]
if exists {
fmt.Println("Charlie:", value)
} else {
fmt.Println("Charlie not found") // Charlie not found
}
}
Даже при хорошей хеш-функции неизбежны коллизии, когда разные ключи хешируются в один и тот же индекс. Эффективно обрабатывает такие случаи, используя корзины для хранения элементов с одинаковыми хеш-значениями.
В среднем, доступ к элементу в карте осуществляется за константное время O(1), что делает карты очень эффективными для поиска по ключу. Однако в худшем случае, при большой нагрузке коллизий, производительность может деградировать до линейного времени O(n).
Карты не являются потокобезопасными. Если одна горутина изменяет карту, в то время как другая горутина читает из нее, это может привести к панике. Для обеспечения потокобезопасности используйте мьютексы или структуру
sync.Map
.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
- Интеграционные тесты проверяют взаимодействие между компонентами, например, работу сервиса с базой или API с внешней системой.
Юнит-тесты дают быструю обратную связь, интеграционные — показывают, как работает система целиком.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Завершение множества горутин требует организованного подхода, так как управление ими не предоставляет прямых средств для их остановки. Основные практики включают использование каналов для сигнализации о необходимости завершения, контекстов для управления временем выполнения и ограничениями, а также синхронизации с помощью
sync.WaitGroup
. Вот каждый из этих методов.Каналы могут использоваться для отправки сигналов горутинам о том, что им следует завершить свою работу. Это один из наиболее часто используемых подходов, так как он прост в реализации и очень эффективен.
package main
import (
"fmt"
"sync"
"time"
)
func worker(stopCh <-chan struct{}, wg *sync.WaitGroup, id int) {
defer wg.Done()
for {
select {
case <-stopCh:
fmt.Printf("Worker %d stopping\n", id)
return
default:
// выполнение полезной работы
fmt.Printf("Worker %d working\n", id)
time.Sleep(time.Second)
}
}
}
func main() {
var wg sync.WaitGroup
stopCh := make(chan struct{})
// запуск горутин
for i := 0; i < 3; i++ {
wg.Add(1)
go worker(stopCh, &wg, i)
}
// остановка горутин после 3 секунд
time.Sleep(3 * time.Second)
close(stopCh) // отправка сигнала всем горутинам остановиться
wg.Wait() // ожидание завершения всех горутин
}
Предоставляет функциональность для передачи контекста внутрь вашей программы, включая сигналы о необходимости завершения работы. Это может быть полезно, если у вас есть иерархия горутин с общим временем выполнения или дополнительными ограничениями.
package main
import (
"context"
"fmt"
"sync"
"time"
)
func worker(ctx context.Context, wg *sync.WaitGroup, id int) {
defer wg.Done()
for {
select {
case <-ctx.Done():
fmt.Printf("Worker %d stopping\n", id)
return
default:
// выполнение полезной работы
fmt.Printf("Worker %d working\n", id)
time.Sleep(time.Second)
}
}
}
func main() {
var wg sync.WaitGroup
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
// запуск горутин
for i := 0; i < 3; i++ {
wg.Add(1)
go worker(ctx, &wg, i)
}
wg.Wait() // ожидание завершения всех горутин
cancel() // убедиться, что все ресурсы освобождены
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
SSL (Secure Sockets Layer) — это протокол, который обеспечивает безопасность передачи данных в интернете, используя шифрование. Он был разработан для защиты данных, передаваемых между клиентом (например, веб-браузером) и сервером (например, веб-сайтом), от перехвата и манипуляций.
Защита данных от перехвата и чтения посторонними лицами путем их шифрования.
Подтверждение подлинности сервера (и иногда клиента) с помощью цифровых сертификатов, что позволяет клиенту убедиться, что он подключен к настоящему серверу.
Проверка того, что данные не были изменены во время передачи, с помощью контрольных сумм и хеш-функций.
Клиент инициирует соединение с сервером, запрашивая защищенное соединение.
Сервер отправляет свой цифровой сертификат, который содержит его публичный ключ и информацию о сервере.
Клиент проверяет сертификат, используя доверенные центры сертификации (CA), чтобы удостовериться в подлинности сервера.
Клиент и сервер используют асимметричное шифрование для обмена ключами сеанса, которые затем используются для симметричного шифрования данных в течение сессии.
Все данные, передаваемые между клиентом и сервером, шифруются с использованием симметричных ключей, обеспечивая безопасность передачи.
При посещении веб-сайта с использованием HTTPS (например, https://example.com), SSL обеспечивает шифрование и безопасность данных, передаваемых между вашим браузером и сервером.
Никогда не был выпущен публично из-за серьезных уязвимостей.
Выпущен в 1995 году, но вскоре был признан небезопасным из-за множества уязвимостей.
Выпущен в 1996 году, значительно улучшил безопасность, но со временем также был признан устаревшим из-за уязвимостей (например, POODLE-атака).
SSL был заменен протоколом TLS, который является его преемником и предлагает улучшенную безопасность. Текущие версии TLS (1.2 и 1.3) используются вместо SSL.
TLS обеспечивает более сильное шифрование, лучшее управление сессионными ключами и устранение уязвимостей, найденных в SSL.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Git — это распределённая система контроля версий, которая позволяет:
- Отслеживать изменения в коде.
- Создавать ветки и экспериментировать без риска.
- Сотрудничать над проектами в команде. Git хранит историю в виде снимков состояний (commit), а не разницы (diff), что делает его быстрым и надёжным.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊4👍2🔥2