Warning: Undefined array key 0 in /var/www/tgoop/function.php on line 65

Warning: Trying to access array offset on value of type null in /var/www/tgoop/function.php on line 65
308 - Telegram Web
Telegram Web
💬 Для чего в приведенном коде предназначена конструкция "_ struct{}"?

Конструкция _ struct{} используется для предотвращения создания литералов структур без именованных полей при инициализации ProgInfo.

Это значит, что мы не сможем случайно инициализировать ProgInfo без указания имён полей, что может помочь избежать ошибок и повысить читаемость кода, особенно когда структура со временем расширяется новыми полями.

В Go, когда мы инициализируем структуру без указания имён полей, например:


info := ProgInfo{0, 1, 2, 3}


Это называется неименованным или позиционным литералом. Такой способ инициализации может привести к ошибкам, особенно если порядок полей в структуре изменится или будут добавлены новые поля.

Добавление поля _ struct{} делает такую инициализацию невозможной, требуя от разработчика использовать именованные литералы, где каждое значение присваивается конкретному имени поля:


info := ProgInfo{
Flags: 0,
Reguse: 1,
Regset: 2,
Regindex: 3,
}
👍75😁52
⚡️Proglib запускает каналы про нейросети

По каждому направлению отдельно! А именно:

Библиотека нейрозвука — здесь все, связанное с транскрибацией, синтезом речи, ИИ-музыкой
Библиотека нейротекста — классические ИИ-помощники вроде ChatGPT, Gemini, Bing
Библиотека нейровидео — здесь пишем про нашумевшую Sora AI, а также про Runway ML, дипфейки и другие видеотехнологии
Библиотека нейрокартинок — генерируем изображения и рассказываем про Midjourney, DALL-E, Stable Diffusion
⭐️Библиотека робототехники и беспилотников — наконец, тут мы рассказываем не столько про ИИ, сколько про роботов, беспилотные технологии и интернет вещей

И все это — максимально подробно: с пошаговыми инструкциями, промтами, инструментами и лайфхаками.

Подписывайтесь!
💬 В чем разница между методами Time.Sub() и Time.Add() пакета time?

Ключевое отличие между методами Time.Add() и Time.Sub() в пакете time заключается в их параметрах и возвращаемых значениях. Time.Add() принимает параметр Duration и возвращает значение Time, в то время как Time.Sub() принимает параметр Time и возвращает Duration.

💬 Почему они оба не принимают Duration и не возвращают Time?

Причина в том, что Time.Add() может обрабатывать отрицательные аргументы, эффективно выполняя операцию вычитания. Следовательно, не имело бы смысла иметь другой метод Time.Sub(), который также принимает Duration.

Методы Time.Add() и Time.Sub() служат разным целям и имеют различные сигнатуры для обработки конкретных юзкейсов:

package main

import (
"fmt"
"time"
)

func main() {
now := time.Now()

newTime := now.Add(2 * time.Hour)
fmt.Println("Time after 2 hours:", newTime)
newTime = now.Add(-2 * time.Hour)
fmt.Println("Time before 2 hours:", newTime)

duration := newTime.Sub(now)
fmt.Println("Duration newTime to now:", duration)
}


Как показано в примере, Time.Add() используется для добавления или вычитания продолжительности из временного значения, в то время как Time.Sub() используется для вычисления продолжительности между двумя временными значениями.
👍133
💬 Как правильно отправить эти данные в теле HTTP POST запроса?


data := "test data"


Для отправки данных в теле HTTP POST запроса важно знать тип содержимого. Поскольку это сырой текст, мы будем использовать тип содержимого text/plain. Функция http.Post требует io.Reader в качестве тела, а не строки или байтов:


Post(url string, contentType string, body io.Reader) (resp *http.Response, err error)


Интерфейс Reader определен следующим образом:


type Reader interface {
Read(p []byte) (n int, err error)
}


Чтобы соответствовать требованиям, мы преобразуем тело в буфер, который реализует этот интерфейс:


func main() {
data := "test data"

contentType := "text/plain"

body := strings.NewReader(data)
// или
// body := bytes.NewBufferString(data)

resp, err := http.Post("https://example.com", contentType, body)

// ....
}
👍18🤔2
💬 В чем заключается риск использования глобальных переменных, особенно изменяемых?

Глобальные переменные — это те, которые мы размещаем вне функций или методов, доступные для любой части нашего кода для использования и изменения. Часто они приносят больше проблем, чем пользы. Вот почему:

🔹 Отслеживание изменений затруднено: определить, где была изменена переменная featureConfig.NewCheckoutProcessEnabled в вашем приложении, сложно, когда любая часть кода может её изменить.

🔹 Тестирование усложняется: предположим, мы тестируем новый и старый процессы оформления заказа. Если оба теста вмешиваются в один и тот же глобальный featureConfig, мы не сможем тестировать их независимо, не мешая один другому.

🔹 Проблемы с конкурентностью: когда несколько запросов пытаются одновременно читать или изменять featureConfig, это может привести к несоответствиям (состояние гонки).

📌 Что делать? Dependency injection👇

Это метод, при котором мы предоставляем объекту его потребности извне, вместо того чтобы создавать их самостоятельно или брать из глобальных переменных.

Да, этот метод делает вещи немного более сложными, но он также упрощает поддержку кода, его тестирование и поиск ошибок.

С внедрением зависимостей настройка тестов для сценариев с включенными и отключенными функциями становится простой.

Но если наши глобальные переменные не изменяются, не требуют тестирования и должны работать именно так, то в этих ситуациях использование глобальных переменных может быть более предпочтительным.

Также, если мы используем глобальные переменные, которые изменяются во время выполнения, необходимо убедиться, что мы используем техники синхронизации.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
🤔 Context vs структура: следует ли передавать информацию, специфичную для запроса, через context.Context?

HTTP-обработчики могут использовать контекст для управления тайм-аутами запросов или отменой в рамках запроса. Тип Context также позволяет передавать значения (например, идентификатор пользователя, связанный с запросом) другим функциям.

Следует ли использовать этот механизм для передачи информации по цепочке вызовов запроса? Или лучше использовать обычную структуру?

Вот две причины, по которым использование Context для передачи значений может быть плохой идеей:

Значения в Context представляют собой пары ключ/значение, где ключ и значение являются пустыми интерфейсами (т. е. any). Другими словами, значения в контексте — это как мешок со всем подряд. Компилятор не может помочь вам отловить ошибки типов или даже проверить, есть ли информация. Удачи в устранении неполадок 😉

Если вы видите функцию, принимающую параметр Context, вы не можете сказать, что внутри. Если вы видите функцию, которая принимает параметр структуры, вы можете ясно видеть, что данные передаются, и что это за данные.

Но разве doSomething(ctx) не выглядит намного чище, чем doSomething(ctx, someStruct)?

Чистый код сам по себе не является целью. Код не чист только потому, что он короткий. Код чистый, если читатель может ясно видеть, что он делает.

Так context.WithValue() следует избегать?

Значения в контексте могут быть полезны, если они не критичны для бизнес-логики приложения. Например, совершенно нормально передавать идентификаторы запросов для логирования или измерения метрик. Читатель все равно сможет понять логику кода, и если что-то пойдет не так с этим идентификатором, это повлияет только на логирование или метрики приложения, но не на результат запроса.

💡Если данные важны для вашей бизнес-логики, не помещайте их в Context.

#tip
Please open Telegram to view this post
VIEW IN TELEGRAM
👍151
💬 Что необходимо, чтобы две функции считались одного типа?

Чтобы две функции считались одного типа в Go, они должны иметь одинаковую сигнатуру функции.

Это означает, что они должны иметь совпадающие параметры (количество, типы) и возвращаемые значения.


type sigFunc func(a int, b float64) (bool, error)

func functionA(a int, b float64) (bool, error) {
return true, nil
}

func functionB(a int, b float64) (bool, error) {
return false, nil
}

func main() {
var x sigFunc = functionA
x = functionB
print(x)
}
17
💬 Даны n каналов типа chan int. Напишите функцию на Go, которая объединит все данные из этих каналов в один и вернет его.

Для объединения данных из нескольких каналов типа chan int в один канал в Go, можно использовать функцию, которая итерируется по каждому каналу, читает данные и отправляет их в один общий канал.

Это можно реализовать с помощью select внутри горутины для асинхронного чтения из входных каналов. Вот простой пример функции:


package main

import (
"sync"
)

func mergeChannels(channels ...chan int) chan int {
var wg sync.WaitGroup
mergedChannel := make(chan int)

// Функция для чтения данных из канала и отправки их в объединенный канал.
output := func(c chan int) {
for n := range c {
mergedChannel <- n
}
wg.Done()
}

wg.Add(len(channels))
for _, c := range channels {
go output(c)
}

// Закрытие объединенного канала после того, как все данные из входных каналов будут обработаны.
go func() {
wg.Wait()
close(mergedChannel)
}()

return mergedChannel
}

func main() {
// Пример использования функции mergeChannels
c1 := make(chan int)
c2 := make(chan int)

// Запуск примера с фиктивным заполнением каналов
go func() {
for _, n := range []int{1, 2, 3} {
c1 <- n
}
close(c1)
}()
go func() {
for _, n := range []int{4, 5, 6} {
c2 <- n
}
close(c2)
}()

merged := mergeChannels(c1, c2)
for n := range merged {
println(n)
}
}


Этот код определяет функцию mergeChannels, которая принимает переменное количество каналов chan int и возвращает один канал chan int, в который сливаются все входящие данные. Он использует пакет sync для ожидания завершения всех операций передачи данных перед закрытием результирующего канала.
🔥18👍52
💬 Для чего предназначен пакет unsafe в Go?

Пакет unsafe в Go предназначен для выполнения операций, которые выходят за рамки типобезопасного программирования, предоставляемого Go. Это позволяет напрямую работать с памятью.

unsafe используется для оптимизации или для взаимодействия с кодом, написанным на других языках, когда необходимо точное управление размещением и интерпретацией данных в памяти. Однако использование unsafe — это легкий способ выстрелить себе в ногу, поэтому нужно соблюдать определенные правила.

📌 Простой пример:


package main

import (
"fmt"
"reflect"
"unsafe"
)

func stringToBytes(s string) []byte {
// Получаем строковый заголовок
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))

// Преобразуем его в заголовок среза байтов
sliceHeader := reflect.SliceHeader{
Data: stringHeader.Data,
Len: stringHeader.Len,
Cap: stringHeader.Len,
}

// Возвращаем срез, созданный на основе заголовка среза
return *(*[]byte)(unsafe.Pointer(&sliceHeader))
}

func main() {
s := "Hello, World!"
b := stringToBytes(s)

fmt.Println(s) // Выведет: Hello, World!
fmt.Println(b) // Выведет: [72 101 108 108 111 44 32 87 111 114 108 100 33]
}


Пример демонстрирует использование unsafe для прямого преобразования строк в срезы байтов без создания копии данных. Он работает, изменяя способ, которым Go интерпретирует область памяти, занимаемую строкой, трактуя ее как срез байтов.

Это может быть полезно в ситуациях, где необходимо избежать дополнительного копирования данных для повышения производительности, но требуется осторожное обращение, поскольку любые изменения в возвращаемом срезе байтов могут повлиять на исходную строку и наоборот, что нарушает иммутабельность строк в Go и может привести к неопределенному поведению.
👍6🔥31🤔1
Media is too big
VIEW IN TELEGRAM
Что нужно для счастья разработчику на Go? Интересные задачи в продуктовой разработке, когда результат можно буквально «потрогать» в виде сервера, системы хранения данных или планшета? Большое сообщество коллег, с которыми можно развиваться? Или, может, просто комфортное рабочее место — в одном из классных офисов или у себя дома? 
Чтобы не выбирать что-то одно, можно прийти работать в YADRO — компанию-производителя IT-инфраструктуры, пользовательского и телеком-оборудования. На видео один из гоферов компании как раз рассказывает об актуальных задачах и жизни разработчиков в инженерной компании.  
Оставить резюме можно здесь: https://clck.ru/39g5Vz  
Ждут как тимлидов команд разработки, так и начинающих специалистов.

Реклама. ООО «КНС ГРУПП», ИНН 7701411241, www.yadro.com
erid: 2SDnjdLM5ow
🔥5👍31👏1
💡Как тривиально проверить значения интерфейса на nil?

В Go новички часто сталкиваются с проблемой интерфейсных переменных, которым присваивается nil указатель. В таком случае, хотя значение в интерфейсе является nil, сама переменная интерфейса не равна nil.

Пример: создаем переменную x как указатель на int, который по умолчанию nil, и переменную y как пустой интерфейс, который тоже nil по умолчанию. После присваивания x переменной y, интерфейс y уже не является nil, хотя x все еще nil.


var x *int
var y any
y = x


📌 Что вернет y == nil?

Вернет false. Это потому, что интерфейс не просто представляет значение, которое ему присвоено, а действует как контейнер для этого значения.

Для проверки, является ли значение в интерфейсе nil, нужно использовать утверждение типа. Например, для проверки y на nil, используем:


y.(*int) == nil


Это показывает, что интерфейс y не nil, но содержащееся в нем значение — nil. Полный пример здесь.

#tip
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
💬 Даны два канала. В первый пишутся числа. Необходимо, чтобы числа читались из первого по мере поступления, что-то с ними происходило и результат записывался во второй канал. 

Для решения этой задачи можно использовать горутину, которая будет читать числа из первого канала, выполнять некоторую операцию с каждым числом (например, умножать его на 2) и отправлять результат во второй канал.

📌 Вот пример решения на Go:

package main

import (
"fmt"
)

func processNumbers(input <-chan int, output chan<- int) {
for num := range input {
// Пример операции: умножаем число на 2
result := num * 2
output <- result
}
close(output)
}

func main() {
inputChannel := make(chan int)
outputChannel := make(chan int)

go processNumbers(inputChannel, outputChannel)

// Отправляем числа в первый канал
go func() {
for i := 1; i <= 5; i++ {
inputChannel <- i
}
close(inputChannel)
}()

// Читаем результаты из второго канала
for result := range outputChannel {
fmt.Println(result)
}
}


🔹 Функция processNumbers принимает два канала: input для чтения и output для записи. Она читает каждое число из input, умножает его на 2 и отправляет результат в output. После обработки всех чисел она закрывает канал output.
🔹 В функции main, создаются два канала: inputChannel и outputChannel.
🔹 Горутина processNumbers запускается для обработки чисел, передавая ей эти каналы.
🔹 В отдельной горутине числа от 1 до 5 отправляются в inputChannel, после чего канал закрывается.
🔹 В основной горутине читаются и выводятся результаты из outputChannel.
🥱13👍103
💬 Почему Go выбирают для облачной разработки и решения задач DevOps?

☑️ Обширная стандартная библиотека
☑️ Кросс-платформенная компиляция
☑️ Экосистема и инструментарий (управление зависимостями, обработка ошибок, тестирование, профилирование и многое другое)
☑️ Простота и скорость разработки
☑️ Сборка мусора, о которой не надо задумываться
☑️ Строгая типизация
☑️ Встроенная поддержка конкурентности
☑️ Высокая производительность

Пишите в комментарии, если хотите что-то добавить/исправить👇
💬 Почему порядок обхода элементов в map является случайным?

Главная причина — предотвращение зависимости от порядка элементов. При итерации по элементам map, Go специально не гарантирует никакого порядка.

Это сделано, чтобы разработчики не полагались на порядок при написании кода, что могло бы привести к непредсказуемым багам при изменении содержимого мапы.

Случайность порядка обхода напоминает разработчикам о том, что структура данных map не предназначена для хранения элементов в упорядоченном виде.

Внутренняя реализация map в Go предназначена для быстрого доступа, добавления и удаления элементов, а не для поддержания элементов в определенном порядке. Эффективность операций с мапой имеет более высокий приоритет, чем сохранение порядка элементов.
👍12
🧑‍💻 Статьи для IT: как объяснять и распространять значимые идеи

Напоминаем, что у нас есть бесплатный курс для всех, кто хочет научиться интересно писать — о программировании и в целом.

Что: семь модулей, посвященных написанию, редактированию, иллюстрированию и распространению публикаций.

Для кого: для авторов, копирайтеров и просто программистов, которые хотят научиться интересно рассказывать о своих проектах.

👉Материалы регулярно дополняются, обновляются и корректируются. А еще мы отвечаем на все учебные вопросы в комментариях курса.
💬 Как удалить элемент из среза в Go без использования стандартной библиотеки?

👉 Если порядок важен

Чтобы удалить элемент из середины среза и сохранить порядок оставшихся элементов, можно использовать append:


newSlice := append(slice[:index], slice[index+1:]...)


Это объединяет часть среза до удаляемого элемента с частью среза после удаляемого элемента, исключая сам удаляемый элемент, но сохраняя порядок оставшихся элементов.

👉 Если порядок не важен

В случае, когда сохранение исходного порядка элементов не является приоритетом, можно выполнить удаление элемента, заменив его последним элементом среза, а затем уменьшить длину среза. Это эффективнее, так как не требует перемещения элементов:


slice[index] = slice[len(slice)-1]
newSlice := slice[:len(slice)-1]


Этот метод эффективно удаляет элемент, заменяя его последним элементом среза, и уменьшает размер среза, исключая последний элемент.

👉 Удаление из начала или конца

Если элемент для удаления находится в начале или в конце среза, можно просто использовать срезы:

📌 Для удаления первого элемента:


newSlice := slice[1:]


📌 Для удаления последнего элемента:


newSlice := slice[:len(slice)-1]
👍21
💬 Как в Go преобразовать строку в число и обратно, и как обрабатывать возможные ошибки при этих преобразованиях?

В Go для преобразования строки в число и обратно используются функции из пакета strconv. При преобразовании строки в число необходимо учитывать возможные ошибки, так как входная строка может не быть корректно преобразована в числовой формат.

🔹 Преобразование строки в число

Чтобы преобразовать строку в число, можно использовать функции как strconv.Atoi для целых чисел или strconv.ParseFloat для чисел с плавающей точкой.


package main

import (
"fmt"
"strconv"
)

func main() {
// Преобразование строки в целое число
strInt := "123"
intValue, err := strconv.Atoi(strInt)
if err != nil {
fmt.Println("Ошибка преобразования:", err)
} else {
fmt.Println("Целое число:", intValue)
}

// Преобразование строки в число с плавающей точкой
strFloat := "123.45"
floatValue, err := strconv.ParseFloat(strFloat, 64) // 64 указывает на то, что результат будет float64
if err != nil {
fmt.Println("Ошибка преобразования:", err)
} else {
fmt.Println("Число с плавающей точкой:", floatValue)
}
}


🔹 Преобразование числа в строку

Для преобразования числа в строку используется функция strconv.Itoa для целых чисел или fmt.Sprintf для чисел с плавающей точкой или других форматов. Например:


package main

import (
"fmt"
"strconv"
)

func main() {
// Преобразование целого числа в строку
intValue := 123
strInt := strconv.Itoa(intValue)
fmt.Println("Строка:", strInt)

// Преобразование числа с плавающей точкой в строку
floatValue := 123.45
strFloat := fmt.Sprintf("%f", floatValue)
fmt.Println("Строка:", strFloat)
}
🔥7👍31
💬 В каких кейсах используется указатель на структуру в Go?

1. Когда структура передается в функцию по значению, Go создаёт её копию. Чтобы изменения внутри функции отражались на самой структуре, следует передавать указатель на неё.

2. Передача структур через указатели эффективнее по памяти, особенно для больших структур, потому что передается только адрес памяти, а не вся структура.

3. Использование указателей может улучшить производительность программы, снижая накладные расходы на копирование больших структур данных при передаче их между функциями.

4. Указатели на структуры могут быть nil, что позволяет использовать их для реализации опциональных полей или для указания на отсутствие конкретного значения.

5. Структуры могут реализовывать интерфейсы, и указатели на эти структуры могут быть переданы функциям, ожидающим интерфейс. Это позволяет работать с разными типами данных через общий интерфейс.
👍9😁73
2025/07/14 07:27:06
Back to Top
HTML Embed Code: