• Почему Go не видит бинарники в GOBIN?

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

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

    Самый простой способ это сделать такой шейдер
    63ce6c21eff31708991280.png

    Потом заанимировать параметр factor у ноды mix
    При factor=0 будет отображаться первая текстура, при factor=1 вторая. В промежуточных значениях текстуры будут плавно смешиваться

    Если нужно чтобы текстура натекала не по всему объекту сразу, а ближе к эффекту на видео, снизу вверх, например, то это уже сложнее. Нужно будет factor брать из третьей градиентной текстуры и анимировать её маппинг по объекту.
    Ответ написан
  • Как в GO написать свою функцию к другим типам?

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

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

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

    Подскажу важные хаки для вашего решения.
    Когда нужно обработать n каких-то задач в m потоков, в го очень хорошо работает паттерн worker pool.
    Суть в том, что создается канал, в одной горутине в него кладутся задачи и как только все задачи будут положены, канал обязательно закрывается.
    Тем временем, запускается m воркеров. Воркер представляет из себя функцию, которая в цикле for читает задачи из канала и выполняет их. Удобство тут в том, что как только канал будет закрыт (и в нем не останется ни одной задачи, если он буферизированный), то все циклы for во всех воркерах завершатся. Поэтому не надо делать отдельный канал и селект для завершения.
    WaitGroup при этом следит, чтобы все воркеры успели доработать до конца (потому что когда канал закрывается, какие-то воркеры еще могут завершать свои последние задачи).

    Шаблон в простом виде прикладываю тут, можете его натянуть на свой случай
    package main
    
    import (
    	"fmt"
    	"sync"
    )
    
    type Task struct {
    	URL string
    	// сюда можно еще добавить нужные данные для задачи
    }
    
    type Result struct {
    	// если нам нужно что-то получать как результат обработки задачи
    	// то можно результат класть сюда
    }
    
    const (
    	workersCount = 5
    )
    
    func main() {
    	tasks := make(chan Task)
    	results := make(chan Result)
    
    	go generateTasks(tasks)
    
    	wg := &sync.WaitGroup{}
    	for i := 0; i < workersCount; i++ {
    		wg.Add(1) // обязательно инкрементим вне воркера, потому что воркер стартует не сразу
    		go worker(tasks, results, wg)
    	}
    
    	go func() {
    		wg.Wait()
    		// wg.Wait пустит нас сюда только когда все воркеры завершатся
    		// а значит, нам можно закрывать канал результатов, потому что результатов больше точно не будет
    		close(results)
    	}()
    
    	for result := range results {
    		// обрабатываем результаты, если нужно
    		// если нам не нужно централизованное место для обработки результатов,
    		// канал results и все, что с ним связано, можно убрать
    		fmt.Println("got result:", result)
    	}
    	// программа завершится как только канал results будет закрыт
    }
    
    func generateTasks(tasks chan<- Task) { // тип chan<- значит, что в переданный сюда канал можно только писать, нельзя читать
    	// тут генерируем наши задачи, читаем их из файла, например
    	for i := 0; i < 20; i++ {
    		tasks <- Task{
    			URL: fmt.Sprintf("http://test.com?i=%d", i),
    		}
    	}
    
    	// как только задачи закончились, закрываем канал
    	// этим мы сигнализируем воркерам, что работы больше нет, можно завершаться
    	close(tasks)
    }
    
    func worker(tasks <-chan Task, results chan<- Result, wg *sync.WaitGroup) {
    	defer wg.Done() // defer позволяет точно не забыть сделать Done() при завершении функции
    	for task := range tasks {
    		fmt.Println(task.URL)
    		var res Result
    		// здесь пишем код, который обрабатывает задачу
    		// генерируем на выходе какой-то результат (если результат нам не нужен, можем это опустить)
    		results <- res
    	}
    }
    Ответ написан
    1 комментарий
  • Почему 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 он должен быть в открытом виде.
    Ответ написан
    Комментировать
  • Подс-жите программу для фоновой 3D-нагрузки видеокарты?

    Это видеокарта экономит энергию, называется опция power mizer, ее можно найти в панели управления нвидия и включить всегда на performance.
    Ответ написан
  • Как понять от первого элемента в слайсе(capacity)?

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

    В любом современном рендерере. Из бесплатных, например, Blender+cycles.
    Ответ написан
    Комментировать
  • Как реализовать такое облако слов?

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

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

    Лучше сделать так
    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 комментария
  • Как понять каррирование и частичное применение функции? В чём их различия?

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

    Что вообще происходит в теле возвращаемой функции?

    Так немного некорректно рассуждать, потому что компилятор может по-разному оптимизировать внутренность функции.

    Но если вам будет проще понять, можно представить, что у нас не Хаскель, а обычный императивный язык. Тогда частичное применение можно эмулировать с помощью замыкания:
    func main() {
    	fmt.Println(sum(1, 2))
    
    	carried := carry(sum, 1)
    	fmt.Println(carried(2))
    }
    
    func sum(a, b int) int {
    	return a + b
    }
    
    func carry(fn func(int, int) int, a int) func(int) int {
    	return func(b int) int {
    		return fn(a, b)
    	}
    }

    https://go.dev/play/p/dp6W3U5bSGq

    То есть, когда вы частично применяете функцию, можете считать, что примененный аргумент сохранился в переменной внутри "обертки", которая возникает вокруг этой функции. В Хаскеле просто это делается очень удобно синтаксически, в отличие от других языков.
    Ответ написан
  • Что не так с потоками?

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