Ответы пользователя по тегу Go
  • Как сделать болле корректно даный цикл?

    Вполне нормальное у вас решение. Разве что можно сделать так:
    func divide(x ...float64) float64 {
      if len(x) == 0 {
        return 0
      }
      if len(x) == 1 {
        return x[0]
      }
      a := x[0]
      for _, v := range x[1:] {
        a /= v
      }
      return a
    }
    Ответ написан
    1 комментарий
  • Можно ли изменять неимпортируемые поля структуры в других пакетах программы?

    Не понял, в чем проблема. Есть у вас пакет cache, внутри тип Cache и функция New

    Так как функция New экспортируемая, вызываете ее из любого пакета и создаете себе экземпляр кэша. Потом этот экземпляр через dependency injection кладете во все нужные вам экземпляры сервисов.
    Ответ написан
    Комментировать
  • Какую технологию выбрать для live трансляции go?

    Проще всего взять за основу ffmpeg, он очень гибкий есть куча примеров, как на его основе делать трансляции через протокол HLS.

    Go тут по сути будет использоваться как оркестратор для запуска ffmpeg и предоставления доступа к hls-кускам видео и плейлистам.

    В свое время ковырял эту связку, в целом так программу для трансляций можно собрать за день.
    Ответ написан
    2 комментария
  • Отправка загруженной фото в боте -> пользователю?

    Есть минимум два способа
    1. Выгрузить фото в файл или s3 и дать на него урл
    2. Выгрузить фото в качестве сырых данных в файл или в память и отправить эти данные другому пользователю через sendPhoto


    Если правильно помню, просто переслать файл-айди не получится, потому что у Телеги файл-айди разный для разных пользователей и ботов.
    Ответ написан
    Комментировать
  • Как использовать GOOS в exec.Command?

    Способ из инета костыльный, по-хорошему нужно делать так:

    cmd := exec.Command("go", "build", ".")
    cmd.Env = os.Environ()
    cmd.Env = append(cmd.Env, "GOOS=windows")
    Ответ написан
    3 комментария
  • Как выйти из go функции, которая в функции?

    Должен подойти такой вариант
    func start() {
    	file, _ := os.ReadFile("./data.txt")
    
    	for _, i := range strings.Split(string(file), "\n") {
    		select {
    		case <-stop:
    			return
    		default:
    			http.Get(Url + i)
    		}
    	}
    }


    На каждой итерации цикла проверяем, было ли сообщение в канал, если не было, обрабатываем очередной урл. Минус в том, что проверяем мы только между обработками урлов. Если обработка одного урла это пара секунд, то все норм.

    Более сложный вариант

    package main
    
    import (
    	"context"
    	"errors"
    	"io/ioutil"
    	"net/http"
    	"strings"
    )
    
    func start() {
    	file, _ := os.ReadFile("./data.txt")
    
    	ctx, cancel := context.WithCancel(context.Background())
    	defer cancel() // контекст обязательно надо отменять в конце
    
    	go func() {
    		select {
    
    		// Отменяем контекст при получении стоп-сигнала
    		case <-stop:
    			cancel()
    
    		// чтобы горутина завершилась по отмене контекста даже если stop не будет
    		case <-ctx.Done():
    		}
    	}()
    
    	for _, i := range strings.Split(string(file), "\n") {
    		err := processUrl(ctx, Url+i)
    		if err != nil {
    			if errors.Is(err, context.Canceled) {
    				return
    			}
    			// обработать ошибку
    		}
    	}
    }
    
    func processUrl(ctx context.Context, finalUrl string) error {
    	req, err := http.NewRequestWithContext(ctx, "GET", finalUrl, nil)
    	if err != nil {
    		return err
    	}
    	res, err := http.DefaultClient.Do(req)
    	if err != nil {
    		return err
    	}
    	defer res.Body.Close() // обязательно, иначе будет утечка
    
    	// обработать ответ
    
    	return nil
    }



    Здесь уже выход будет мгновенный, потому что http-запрос отменится по контексту хоть на середине.
    Ответ написан
  • Почему Go не видит бинарники в GOBIN?

    Го сам никакие пути к бинарникам не ищет, он обращается за этим к операционной системе. Поэтому добавьте вашу папку с бинарниками в переменную окружения PATH вашей ОС.

    GOBIN определяет путь, куда Го будет билдить бинарники, которые устанавливаются через go install. Но он не отвечает за их поиск там.
    Ответ написан
    Комментировать
  • Как в GO написать свою функцию к другим типам?

    Логично, что ругается. Вы объявили метод у типа strType, а переменную создали типа string.

    Нужно делать так:
    package main
    
    func main() {
    	var str strType
    
    	str.Temp()
    }
    
    type strType string
    
    func (s strType) Temp() {
    }
    Ответ написан
    3 комментария
  • Для чего в go.mod добовить зависимости если мы указываем полный путь к ним в коде?

    Для указания версий этих зависимостей. Чтобы бралась не последняя версия, а указанная. Обеспечивает повторяемость релизов и стабильность.
    Ответ написан
    Комментировать
  • Почему env GOPATH больше не имеет значения?

    Раньше все зависимости лежали в GOPATH, но это было неудобно тем, что не было никакого управления этими зависимостями. Нельзя было зафиксировать их конкретные версии и нельзя было для разных проектов сделать разные зависимости, потому что все было в одной центральной папке.
    Потом в го ввели систему модулей:
    https://go.dev/blog/using-go-modules
    https://habr.com/ru/company/otus/blog/503918/

    Теперь в корневой папке каждого проекта есть файл go.mod, который перечисляет зависимости этого проекта и их конкретные версии. Поэтому необходимость в GOPATH отпала, теперь Go при сборке использует модули, указанные в go.mod и не ходит в GOPATH вообще, это намного удобнее.
    Ответ написан
    4 комментария
  • Как зашифровать http запрос?

    Использовать https, тогда можно будет зашифровать в том числе урл.
    Если делать свое шифрование поверх http, то во-первых, это будет сильно сложнее сделать правильно и надежно, во-вторых, не получится зашифровать урл, потому что по стандарту http он должен быть в открытом виде.
    Ответ написан
    Комментировать
  • Как понять от первого элемента в слайсе(capacity)?

    Каждый раз, когда у слайса кончается капасити, го делает переаллокацию данных в памяти, увеличивая капасити и копируя старые данные в новую аллоцированную область. Причем, капасити растет с запасом, чтобы свести количество переаллокаций к минимуму (ибо это дорогая операция). Поэтому это нормальная ситуация, когда капасити становится больше, чем длина. Го вам делает запас на будущее.
    Ответ написан
    2 комментария
  • Как правильно взаимодействовать с каналами?

    То, что в канал данные пишутся медленнее, чем читаются, не должно вызывать никаких проблем при правильном подходе. У вас просто очень странно написан воркер, он на каждое событие запускает горутину и почему-то останавливается, если буфер канала пустой. Воркера надо по-хорошему останавливать, когда канал закрыт, а не пуст.

    Лучше сделать так
    package main
    
    import (
    	"bufio"
    	"fmt"
    	"os"
    	"sync"
    )
    
    func main() {
    	urls := make(chan string)
    	go fillChannel(urls)
    
    	// создаем группу для ожидания, того, что все воркеры завершены
    	wg := &sync.WaitGroup{}
    
    	for i := 0; i < 5; i++ {
    		// при запуске каждого воркера, увеличиваем счетчик в группе на 1
    		wg.Add(1)
    		go requestWorker(urls, wg)
    	}
    
    	// ждем, пока счетчик в группе не будет равен 0
    	wg.Wait()
    }
    
    func requestWorker(channel <-chan string, wg *sync.WaitGroup) {
    	// По завершении воркера счетчик в группе будет уменьшен на 1
    	defer wg.Done()
    	// Заодно пишем сообщение о завершении воркера
    	defer println("Worker stopped")
    
    	// Постоянно читаем из канала новые сообщения
    	// цикл автоматически завершится, когда канал закроется и буфер будет пуст
    	for url := range channel {
    		println(url)
    	}
    }
    
    func fillChannel(channel chan<- string) {
    	file, err := os.Open("data.txt")
    	defer file.Close()
    
    	if err != nil {
    		fmt.Println(err)
    		return
    	}
    
    	fileScanner := bufio.NewScanner(file)
    	fileScanner.Split(bufio.ScanLines)
    
    	for fileScanner.Scan() {
    		channel <- fileScanner.Text()
    	}
    
    	// закрываем канал, когда данные кончились
    	// в го принято, чтобы канал закрывал только тот, кто в него пишет
    	close(channel)
    }



    Этот паттерн называется worker pool. Мы пишем в канал все нужные данные и закрываем канал, когда данные кончились. Благодаря тому, что воркеры читают из канала через range, цикл просто выходит, когда канал закрыт и воркеры завершаются.
    WaitGroup используется для того, чтобы подождать, пока воркеры доработают последние данные.
    Ответ написан
    Комментировать
  • Как в процессе выполнения программы считывать вывод?

    Все гораздо проще. Вы можете сразу в stdout подложить буфер и смотреть в него при необходимости
    cmd := exec.Command("python", "script.py")
    stdoutBuf := bytes.NewBuffer(nil)
    cmd.Stdout = stdoutBuf
    if err := cmd.Run(); err != nil {
    	log.Println(err.Error())
    }
    
    fmt.Println(stdoutBuf.String())


    Или еще проще, если вам нужны и stdout и stderr вместе:
    cmd := exec.Command("python", "script.py")
    res, err := cmd.CombinedOutput()
    if err != nil {
    	log.Fatal(err)
    }
    fmt.Println(string(res))
    Ответ написан
    3 комментария
  • Что не так с потоками?

    Рантайм го расчитан на то, что большинство горутин будут иметь точки блокировок, что логично для веб-сервисов. Когда сервис блокируется на чтении/записи сети/файла, планировщик переключается на другую горутину. Поэтому нет никаких гарантий того, что нагрузка равномерно распределиться, если все горутины будут заняты просто числомолотилками.
    После какой-то версии го (точно не помню номер), завезли вытесняющую многозадачность и теперь планировщик может переключать горутины даже на числомолотилках, но делает он это обычно когда запускается сборка мусора или срабатывает случайный таймер. Поэтому равномерного распределения на таких задачах не ждите, язык просто делался не для этого.
    Ответ написан
    Комментировать
  • Как преобразовать interface в string?

    https://go.dev/play/p/-aB5SS1amav
    package main
    
    import (
    	"fmt"
    	"log"
    )
    
    func main() {
    	code := map[string]interface{}{
    		"test": "test",
    	}
    
    	// извлекаем interface{} из мапы внутри которого строка
    	ifaceStr := code["test"]
    
    	// извлекаем строку из interface{}
    	str, ok := ifaceStr.(string)
    	if !ok {
    		log.Fatal("it's not a string")
    	}
    	fmt.Println(str)
    }


    Но почему бы вам не делать анмаршал в map[string]string сразу? Чтобы не конвертить лишний раз?
    Ответ написан
  • Можно ли использовать значение переменной как название структуры?

    Так делать не стоит, в го это решается другими способами. Вы пытаетесь переносить подход из скриптовых языков в го, так это не работает.
    Ответ написан
  • Как отдавать статику через julienschmidt/httprouter?

    r.Handler("GET", "/", fServer)
    Этот шаблон значит полное совпадение с корнем, поэтому у вас 404 на все вложенные страницы. Чтобы этого избежать сделайте так:

    r.Handler("GET", "/*filepath", fServer)
    Ответ написан
    3 комментария
  • Golang выдает ошибку, что делать?

    Вам компилятор четко пишет
    main redeclared in this block {строка 8 столбец 6 }
    previous declaration at ./hello.go:18:6

    Перевожу: функция main написана несколько раз, второй раз она встречается в файле hello.go на 18 строчке.
    Видимо, у вас в одной папке несколько файлов и в нескольких из них есть функция main. Так делать нельзя, все, что находится в одной папке, го считает одним пакетом.

    Что касается второй ошибки, отправляйтесь изучать основы синтаксиса языка, иначе далеко так не уедете. У вас лишние запятые в конце списка параметров и в конце списка переменных.
    Ответ написан
    7 комментариев
  • Запутался с установкой golang, что делать?

    потом я хотел настроить перменную GOPATH, а там как я понял надо указать путь до ГО и там выбрать папку scr.


    Нет, вы пользуетесь каким-то странный старым руководством. Если из пакетов ставите, то у вас уже всё нужное есть. Никакой GOPATH уже давно прописывать не надо.
    Ответ написан
    Комментировать