💬 Почему в Go лучше использовать strconv вместо fmt для преобразования в/из строки?
Пакет
Для наглядности рассмотрим простое сравнение производительности:
Процесс рефлексии не «бесплатный», он добавляет как время, так и накладные расходы на память, что может быть довольно значительным, когда мы обрабатываем большие объемы данных или требуется высокая производительность.
Пакет
strconv
специально создан для преобразования строк, что означает, что он оптимизирован именно для них. Для наглядности рассмотрим простое сравнение производительности:
func BenchmarkFmt(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprint(i)
}
}
func BenchmarkStrconv(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = strconv.Itoa(i)
}
}
BenchmarkFmt-8 23821753 50.17 ns/op 16 B/op 2 allocs/op
BenchmarkStrconv-8 100000000 11.47 ns/op 3 B/op 1 allocs/op
strconv.Itoa
значительно быстрее и эффективнее с точки зрения выделения памяти по сравнению с fmt.Sprint
. fmt.Sprint
при этом использует рефлексию, чтобы понять, с каким типом данных работает, и определяет лучший способ форматирования его как строки.Процесс рефлексии не «бесплатный», он добавляет как время, так и накладные расходы на память, что может быть довольно значительным, когда мы обрабатываем большие объемы данных или требуется высокая производительность.
👍20❤3
💬 Что произойдет, если в type switch использовать временную переменную для типа nil? Какой тип будет у этой переменной?
Когда в type switch используется временная переменная для типа nil, тип этой переменной будет таким же, как и тип исходного значения, которое мы проверяем в TypeSwitchGuard. Например, если исходное значение имеет тип any, временная переменная также будет иметь тип any. Это можно проиллюстрировать следующим примером:
В этом примере код не компилируется с ошибкой, указывающей, что переменная типа any не может быть присвоена переменной типа error, так как тип any не реализует метод Error. Это подтверждает, что временная переменная t в случае nil имеет тот же тип, что и x (в данном случае any).
Когда в type switch используется временная переменная для типа nil, тип этой переменной будет таким же, как и тип исходного значения, которое мы проверяем в TypeSwitchGuard. Например, если исходное значение имеет тип any, временная переменная также будет иметь тип any. Это можно проиллюстрировать следующим примером:
var x any
var y error
switch t := x.(type) {
case nil:
y = t // Ошибка компиляции: any does not implement error
}
В этом примере код не компилируется с ошибкой, указывающей, что переменная типа any не может быть присвоена переменной типа error, так как тип any не реализует метод Error. Это подтверждает, что временная переменная t в случае nil имеет тот же тип, что и x (в данном случае any).
❤1
Ответьте на 3 вопроса, чтобы получить вводные занятия к курсу «Алгоритмы и структуры данных»
🔥Получите вводные занятия, ответив на 3 вопроса – https://proglib.io/w/c2161ff4
На вводной части вас ждут:
1. Лекция «Производительность алгоритмов» от руководителя разработки Яндекс.Самокатов
2. Лекция «Итеративные сортировки и линейные сортировки» от аспирант департамента искусственного интеллекта ВШЭ
3. Практические задания после лекций
4. Ссылки на дополнительные материалы для самостоятельного изучения
⚡️ Переходите и начинайте учиться уже сегодня – https://proglib.io/w/c2161ff4
🔥Получите вводные занятия, ответив на 3 вопроса – https://proglib.io/w/c2161ff4
На вводной части вас ждут:
1. Лекция «Производительность алгоритмов» от руководителя разработки Яндекс.Самокатов
2. Лекция «Итеративные сортировки и линейные сортировки» от аспирант департамента искусственного интеллекта ВШЭ
3. Практические задания после лекций
4. Ссылки на дополнительные материалы для самостоятельного изучения
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
💬 Поддерживается ли в Go арифметика указателей как C++ или других языках?
В Go, в отличие от других языков, таких как C++, арифметика указателей не поддерживается напрямую. К примеру, нельзя прибавить или вычесть числа непосредственно у указателя, перемещая его вдоль блока памяти.
Отсутствие арифметики указателей исключает целый класс ошибок, связанных с выходом за границы массива, неправильным обращением к памяти и другими подобными проблемами. Это помогает предотвратить баги и уязвимости, связанные с прямым доступом и изменением адресов памяти.
Для выполнения операций, аналогичных арифметике указателей, в Go можно использовать слайсы, которые обеспечивают безопасный доступ к элементам массива и автоматически управляют размером и ёмкостью.
В Go, в отличие от других языков, таких как C++, арифметика указателей не поддерживается напрямую. К примеру, нельзя прибавить или вычесть числа непосредственно у указателя, перемещая его вдоль блока памяти.
Отсутствие арифметики указателей исключает целый класс ошибок, связанных с выходом за границы массива, неправильным обращением к памяти и другими подобными проблемами. Это помогает предотвратить баги и уязвимости, связанные с прямым доступом и изменением адресов памяти.
Для выполнения операций, аналогичных арифметике указателей, в Go можно использовать слайсы, которые обеспечивают безопасный доступ к элементам массива и автоматически управляют размером и ёмкостью.
🔥1
💬 Когда pointer ресивер предпочтительнее использовать, чем value ресивер в Go?
Первая причина — чтобы метод мог изменить значение, на которое указывает его ресивер.
Вторая — чтобы избежать копирования значения при каждом вызове метода. Это может быть более эффективно, если ресивер, например, является большой структурой.
В примере ниже, оба метода
В общем случае, все методы для данного типа должны использовать либо только
Первая причина — чтобы метод мог изменить значение, на которое указывает его ресивер.
Вторая — чтобы избежать копирования значения при каждом вызове метода. Это может быть более эффективно, если ресивер, например, является большой структурой.
В примере ниже, оба метода
Scale
и Abs
имеют тип ресивера *Vertex
, хотя метод Abs
не должен изменять свой ресивер.
package main
import (
"fmt"
"math"
)
type Vertex struct {
X, Y float64
}
func (v *Vertex) Scale(f float64) {
v.X = v.X * f
v.Y = v.Y * f
}
func (v *Vertex) Abs() float64 {
return math.Sqrt(v.X*v.X + v.Y*v.Y)
}
func main() {
v := &Vertex{3, 4}
fmt.Printf("Before scaling: %+v, Abs: %v\n", v, v.Abs())
v.Scale(5)
fmt.Printf("After scaling: %+v, Abs: %v\n", v, v.Abs())
}
В общем случае, все методы для данного типа должны использовать либо только
pointer
ресивер, либо только value
ресивер, чтобы избежать путаницы и обеспечить согласованность.👍3❤1
⚡️Proglib запускает канал про ИИ для генерации звука
Там мы будем рассказывать про все существующие нейросети, которые генерируют музыку и голос — с пошаговыми инструкциями, инструментами и лайфхаками.
⭐️генерация голоса и музыки
⭐️замена и перевод речи
⭐️распознавание звуков
👉Подписывайтесь!
Там мы будем рассказывать про все существующие нейросети, которые генерируют музыку и голос — с пошаговыми инструкциями, инструментами и лайфхаками.
⭐️генерация голоса и музыки
⭐️замена и перевод речи
⭐️распознавание звуков
👉Подписывайтесь!
💬 Интерфейс и any (interface{}) в Go — это одно и то же? Объясните простыми словами.
Нет, это не одно и то же. Интерфейсы определяют контракты для типов, которые их реализуют.
Нет, это не одно и то же. Интерфейсы определяют контракты для типов, которые их реализуют.
any
— это псевдоним для пустого интерфейса interface{}
. Пустой интерфейс interface{}
может содержать значение любого типа, поскольку он не требует реализации никаких методов.🥱5👍3
💬 Почему crypto/rand в некоторых кейсах предпочтительнее использовать вместо math/rand для генерации ключей в Go?
Когда мы работаем над проектами, связанными с генерацией ключей, будь то для шифрования или для создания уникальных идентификаторов, важны качество и безопасность этих ключей.
Пакет
Даже если мы инициализируем генератор с чем-то вроде текущего времени, уровень непредсказуемости или энтропии будет довольно низким. Это происходит потому, что вариации времени между запусками незначительны.
С другой стороны,
Использование
Опять же, если мы генерируем ключи для целей, не связанных с безопасностью, math/rand вполне подойдет.
Когда мы работаем над проектами, связанными с генерацией ключей, будь то для шифрования или для создания уникальных идентификаторов, важны качество и безопасность этих ключей.
Пакет
math/rand
отлично подходит для генерации псевдослучайных чисел. Но у этого метода есть серьезный недостаток: если кто-то узнает, как генерируются числа (начальное значение seed), он сможет предсказать будущие числа.
import "math/rand"
func Key() string {
// rand.Seed(time.Now().UnixNano()) // deprecated
r := rand.New(rand.NewSource(time.Now().UnixNano()))
buf := make([]byte, 16)
for i := range buf {
buf[i] = byte(r.Intn(256))
}
return fmt.Sprintf("%x", buf)
}
Даже если мы инициализируем генератор с чем-то вроде текущего времени, уровень непредсказуемости или энтропии будет довольно низким. Это происходит потому, что вариации времени между запусками незначительны.
С другой стороны,
crypto/rand
предлагает лучшее решение для генерации чисел, которые криптографически безопасны. Эта библиотека разработана для полной непредсказуемости, используя источники случайности, предоставляемые ОС, которые обычно гораздо сложнее предсказать.
import "crypto/rand"
func Key() string {
buf := make([]byte, 16)
_, err := rand.Read(buf)
if err != nil {
panic(err)
}
return fmt.Sprintf("%x", buf)
}
Использование
crypto/rand
особенно необходимо для операций, таких как шифрование, аутентификация или любой другой контекст, где безопасность имеет критическое значение.Опять же, если мы генерируем ключи для целей, не связанных с безопасностью, math/rand вполне подойдет.
👍11❤4
💬 Когда процесс в Linux может не реагировать на SIGKILL?
🔸 Когда процесс является зомби-процессом, который уже завершился, но не освободил свои ресурсы. Зомби не может принимать сигналы и ожидает, что его родительский процесс считает его статус с помощью системного вызова
🔸 Когда процесс находится в состоянии блокировки. Он выполняет неотменяемый системный вызов, такой как ожидание ввода-вывода или другого события, которое не наступило. Процесс не может завершиться, пока операционная система не вернет его в нормальное состояние.
🔸 Когда процесс является процессом init. Он не получает от ОС сигналов, которые не хочет обрабатывать. Процесс init может игнорировать SIGKILL, так как он является особым процессом, который отвечает за запуск и завершение других процессов.
🔸 Когда процесс является зомби-процессом, который уже завершился, но не освободил свои ресурсы. Зомби не может принимать сигналы и ожидает, что его родительский процесс считает его статус с помощью системного вызова
wait
.🔸 Когда процесс находится в состоянии блокировки. Он выполняет неотменяемый системный вызов, такой как ожидание ввода-вывода или другого события, которое не наступило. Процесс не может завершиться, пока операционная система не вернет его в нормальное состояние.
🔸 Когда процесс является процессом init. Он не получает от ОС сигналов, которые не хочет обрабатывать. Процесс init может игнорировать SIGKILL, так как он является особым процессом, который отвечает за запуск и завершение других процессов.
👍13❤🔥2
Forwarded from Книги для программистов
📖 ТОП-10 книг о том, как правильно построить карьеру в IT
Хотите преуспеть в IT? Ознакомьтесь с нашим списком лучших книг, которые помогут вам выстроить успешную карьеру в этой динамичной отрасли!
Читать статью, чтобы ознакомиться со всеми книгами 👉 https://proglib.io/sh/glq68BCSKj
Хотите преуспеть в IT? Ознакомьтесь с нашим списком лучших книг, которые помогут вам выстроить успешную карьеру в этой динамичной отрасли!
Читать статью, чтобы ознакомиться со всеми книгами 👉 https://proglib.io/sh/glq68BCSKj
👍1
💬 Что такое статическая компиляция/линковка и в чем ее особенности?
Линковка (или компоновка) — это последний этап сборки программы, когда все скомпилированные части кода и библиотеки объединяются в один исполняемый файл. Статически слинкованный исполняемый файл не зависит от наличия других библиотек в системе во время своей работы, так как все необходимые библиотеки встраиваются в итоговый бинарный файл.
Для включения статической компиляции/линковки в Go необходимо установить переменную окружения CGO_ENABLED=0 при сборке (т. е. `CGO_ENABLED=0 go build ...`). Это гарантирует, что все внешние библиотеки, от которых зависит выполнение кода, будут встроены в итоговый бинарный файл. Полученный бинарный файл можно использовать, например, в Docker-образе, основанном на scratch (т.е. не содержащем никаких файлов, чистая файловая система).
Однако, это накладывает некоторые ограничения и привносит особенности, которые необходимо помнить:
1. C-код будет недоступен. Некоторые модули из стандартной библиотеки Go зависят от C-кода, но они не являются критичными.
2. Не будет использоваться системный DNS-резольвер: Go будет использовать собственный DNS-резолвер.
3. Проблемы с проверкой x.509 сертификатов на MacOS: в некоторых случаях проверка x.509 сертификатов может не работать корректно.
Если итоговый бинарный файл планируется использовать в Docker-образе scratch, то также следует учитывать:
1. Корневые SSL/TLS сертификаты: для осуществления HTTP запросов по протоколу HTTPS нашему приложению, в образ нужно будет поместить корневые SSL/TLS сертификаты в
2. Файл временной зоны: для корректной работы с датой и временем необходимо добавить файл временной зоны в
Линковка (или компоновка) — это последний этап сборки программы, когда все скомпилированные части кода и библиотеки объединяются в один исполняемый файл. Статически слинкованный исполняемый файл не зависит от наличия других библиотек в системе во время своей работы, так как все необходимые библиотеки встраиваются в итоговый бинарный файл.
Для включения статической компиляции/линковки в Go необходимо установить переменную окружения CGO_ENABLED=0 при сборке (т. е. `CGO_ENABLED=0 go build ...`). Это гарантирует, что все внешние библиотеки, от которых зависит выполнение кода, будут встроены в итоговый бинарный файл. Полученный бинарный файл можно использовать, например, в Docker-образе, основанном на scratch (т.е. не содержащем никаких файлов, чистая файловая система).
Однако, это накладывает некоторые ограничения и привносит особенности, которые необходимо помнить:
1. C-код будет недоступен. Некоторые модули из стандартной библиотеки Go зависят от C-кода, но они не являются критичными.
2. Не будет использоваться системный DNS-резольвер: Go будет использовать собственный DNS-резолвер.
3. Проблемы с проверкой x.509 сертификатов на MacOS: в некоторых случаях проверка x.509 сертификатов может не работать корректно.
Если итоговый бинарный файл планируется использовать в Docker-образе scratch, то также следует учитывать:
1. Корневые SSL/TLS сертификаты: для осуществления HTTP запросов по протоколу HTTPS нашему приложению, в образ нужно будет поместить корневые SSL/TLS сертификаты в
/etc/ssl/certs
.2. Файл временной зоны: для корректной работы с датой и временем необходимо добавить файл временной зоны в
/etc/timezone
.👍16❤1