Ответы пользователя по тегу Go
  • Как через os/exec запустить сторонний exe файл в GoLang?

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

    Несколько примеров:
    path := `c:\Program files\some program\program.exe`
    // аналогично вызову в консоли start "c:\Program files\some data"
    cmd := exec.Command("start", path)
    ......
    
    // аналогично вызову в консоли "c:\Program files\some program\program.exe"
    cmd := exec.Command(path)
    ......
    
    // аналогично вызову в консоли some_prog.exe -flag1 value1 -flag2 value2
    cmd := exec.Command("some_prog.exe", "-flag1", "value1", "-flag2", "value2")
    ......


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

    Кстати, если вам просто нужен полный ответ команды stdout+stderr, можете использовать метод cmd.CombinedOutput(). Он выполнил программу, дождется ее завершения и вернет полностью то, что она писала в консоль.
    Ответ написан
    7 комментариев
  • Как вы решаете проблему циклических импортов?

    orders и payments должны лежать внутри одной модели.
    Если кода много, то можете вынести эти структуры в отдельный пакет, посвященный только внутренним структурам данных, это и будет та самая одна модель.
    пакет structures: типы orders и payments
    пакет orders: импортирует structures
    пакет payments: импортирует structures

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

    Никак не получить, это и не нужно в нормальной ситуации
    Если очень хочется, то можно это сделать через unsafe. Но используя пакет unsafe вы лишаетесь безопасности по памяти.
    Ответ написан
    Комментировать
  • Как провести итерацию функций в map?

    Старайтесь никогда не использовать пустой интерфейс (interface{}), только в самых крайних случаях.
    Тут вам нужно просто изменить тип мапы на map[string][]func(string, interface{})

    Не знаю, почему shortName у вас тоже имеет тип interface{}, его бы изменить на конкретный тип или конкретный интерфейс. Тогда код станет еще понятнее и удобнее.
    Ответ написан
    Комментировать
  • Как ускорить работу кода?

    Для таких целей отлично подходит паттерн "worker pool"
    https://gobyexample.com/worker-pools

    Создаете воркеров столько, сколько параллельно урлов хотите обрабатывать. Отправляете в канал не слайс урлов, а урлы по-одному. Каждый воркер берет из канала свой урл и все они параллельно обрабатывают разные урлы.
    Ответ написан
    1 комментарий
  • При запуске микросервиса выдает ошибку, что делать?

    Проверьте, что хост и порт постгреса правильные.
    Если запускаете в докере, то учтите, что коннект к localhost там не работает, потому что у каждого контейнера свой локалхост.
    Ответ написан
    Комментировать
  • Как правильно определить какой JSON вернулся?

    Успешность обычно проверяют по http-коду ответа.

    Если же сервис сделан так, что код ответа всегда 200, то единственный верный способ будет пытаться анмаршалить оба и смотреть на поля, всё верно.
    Ответ написан
    1 комментарий
  • Почему int при делении int на int с остатком?

    Это не деление с остатком, это целочисленное деление.
    Если делишь одно целое число на другое целое число, работает целочисленная арифметика, потому что го это строго статически типизированный язык.
    Чтобы получить дробное число, нужно явно делить одно число с плавающей точкой на другое.
    package main
    
    import "fmt"
    
    func main() {
    	var some = float64(5) / float64(3)
    	fmt.Println(some)
    	fmt.Printf("%T", some)
    }


    Происходит это потому что компьютер так работает на уровне железа. Если процессору дать команду на деление двух целых, ответом будет целое. Если дать команду на деление двух флоатов — будет флоат.
    В некоторых языках компилятор или интерпретатор берут на себя смелость решать за пользователя, какой ему тип нужен и автоматически включают нужный тип деления в зависимости от ситуации (обычно включается флоат на флоат, как в JS, например). Но это может приводить к ошибкам в некоторых ситуациях.
    Поэтому в го, C, C++ и еще многих других языках (обычно это статически типизированные языки), пользователь должен явно выбирать требуемый тип деления, используя нужные типы переменных.
    Ответ написан
    1 комментарий
  • Go. Что делать, если в коде много схожих друг с другом функций?

    Наоборот, написать общую функцию для таких целей — это хороший способ.
    У вас тут посыл запроса, обработка кода ответа, парсинг. Это всё отлично выносится в общую функцию, которой потом удобно будет пользоваться. Особенно с дженериками, которые добавили в go1.18
    Ответ написан
    2 комментария
  • Как в Golang проверить вхождение строки в строку, но слово целиком?

    Такое делается предварительной токенизацией и потом поиском по токенам.
    Например так:
    https://go.dev/play/p/p5-eLLx1ilr

    С помощью регулярки указываем, какие символы не могут быть внутри слова (\s означает все пробельные символы, а дальше идёт перечисление знаков препинания).
    Потом делаем Split по регулярке, получаем набор токенов (слов), кладём их в мапу для быстрого поиска (можно оставить в массиве, если искать слово надо один раз).

    Если нужна возможность искать фразы (а они содержат пробелы), то индекс уже по-другому придется строить, самый простой способ — после токенизации сделать strings.Join(str, " "), тогда разделитель будет строго пробел на выходе.

    package main
    
    import (
    	"fmt"
    	"regexp"
    )
    
    func main() {
    	tokens := tokenize("something, something1, othersomething")
    
    	fmt.Println(tokens)
    
    	fmt.Println("some", tokens.containsWord("some"))
    	fmt.Println("thing", tokens.containsWord("thing"))
    	fmt.Println("something", tokens.containsWord("something"))
    }
    
    var re = regexp.MustCompile(`[\s,.;"']+`)
    
    type TokenizedString map[string]struct{}
    
    func tokenize(str string) TokenizedString {
    	list := re.Split(str, -1)
    	tokens := make(map[string]struct{}, len(list))
    	for _, token := range list {
    		tokens[token] = struct{}{}
    	}
    	return tokens
    }
    
    func (t TokenizedString) containsWord(word string) bool {
    	_, ok := t[word]
    	return ok
    }
    Ответ написан
    Комментировать
  • Почему не работает отладка для Go в VS Code?

    Судя по тексту ошибки, у вас нет корректного go.mod в корне проекта. Создайте его командой go mod init somename вместо somename принято ставить путь к репозиторию вашего проекта, но можно и просто имя.
    Ответ написан
    4 комментария
  • Как правильно обрабатывать ошибки в go?

    Пример, конечно, очень странный. Не ясно, где применять такую функцию.
    Но матчинг ошибки через Is и вынесение ее в var сделаны правильно.

    Is используем, когда надо проверить, наследована ли ошибка от указанной кастомной ошибки.

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

    https://go.dev/play/p/AGbxpqQKteC
    type CustomError struct {
    	Text     string
    	HttpCode int
    }
    
    func (c *CustomError) Error() string {
    	return c.Text
    }
    
    func main() {
    	err := doSomeStuff()
    	if err != nil {
    		customErr := &CustomError{}
    		if errors.As(err, &customErr) {
    			fmt.Println(customErr.Text, " http code:", customErr.HttpCode)
    		}
    	}
    }
    
    func doSomeStuff() error {
    	return &CustomError{
    		Text:     "please provide a password",
    		HttpCode: 401,
    	}
    }
    Ответ написан
    4 комментария
  • Как добавить запись в JSON файл?

    Вы правильно открываете файл, а потом используете WriteFile, вместо того, чтобы писать в открытый дескриптор файла.
    Правильно будет так:
    func WriteJson(d structs.Bassketball) error {
    	f, err := os.OpenFile("basketball.json", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    	if err != nil {
    		return err
    	}
    	defer f.Close()
    
    	rawJSON, _ := json.Marshal(d)
    	_, err = f.Write(rawJSON)
    	if err != nil {
    		return err
    	}
    
    	return nil
    }
    Ответ написан
    1 комментарий
  • Как установить пакеты в go проект без интернета?

    1. Можете класть их в папку vendor вашего проекта. https://blog.gopheracademy.com/advent-2015/vendor-...
    2. Можете переносить кэш пакетов с другой машины (он лежит в $GOPATH/pkg/mod)
    3. Можете использовать replace в файле go.mod, чтобы указать, где лежит тот или иной пакет. https://go.dev/ref/mod#go-mod-file-replace
    Ответ написан
    Комментировать
  • Как подключитЬся с помощью Golang к другой программе?

    1. Через сетевой протокол на API сторонней программы. (обычно используют JSON RPC, REST, GRPC)
    2. Через вызов клиента другой программы в командной строке из вашего приложения и парсинг вывода.
    3. Вызов функций SDK, предоставленного сторонней программой (обычно через cgo).

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

    Вместо того, чтобы объявлять

    type Forks []struct {
      ForkID           string      `json:"fork_id"`
      Income           float64     `json:"income"`
      Sport            string      `json:"sport"`
    ...............
      AliveSec         int         `json:"alive_sec"`
      ValuingData      ValuingData `json:"valuing_data"`
    }


    Вам нужно объявить тип элемента и тип массива разными типами
    type Fork struct {
      ForkID           string      `json:"fork_id"`
      Income           float64     `json:"income"`
      Sport            string      `json:"sport"`
    ...............
      AliveSec         int         `json:"alive_sec"`
      ValuingData      ValuingData `json:"valuing_data"`
    }
    
    type Forks []Fork


    Тогда сможете сделать так:
    func checkBet(body []byte, v *Fork) {
    ......
    Ответ написан
    1 комментарий
  • Как на GO послать сообщение в Телеграм (канал, лично) проще всего?

    1. Создать телеграм-бота, через @BotFather
    2. Получить в процессе создания токен.
    3. Админ должен нажать start в личке с созданным ботом (иначе бот ему не сможет отправлять сообщения).
    4. Используя библиотеку https://github.com/go-telegram-bot-api/telegram-bot-api послать сообщение админу (нужно знать юзерайди админа).
    Ответ написан
    1 комментарий
  • Можно ли использовать переменную типа string, как название функции и потом вызвать ее?

    Нет, так сделать нельзя, Го не скриптовый язык.

    Но саму функцию в переменную положить можно. И потом вызвать.

    https://go.dev/play/p/dkF1s6ENnjA
    func main() {
    	fn := some
    	fmt.Println(fn())
    	fn = other
    	fmt.Println(fn())
    }
    
    func some() int {
    	return 1
    }
    
    func other() int {
    	return 2
    }
    Ответ написан
    Комментировать
  • Какой тег использовать, что бы получить структуру?

    type Event struct {
        Preview     Image      `json:"preview"`
        Images      []string   `json:"images"`
    }


    Ну или если очень хотите отдельный тип, то:
    type Image string
    Ответ написан
    Комментировать
  • Как добавить заголовки к http запросу при помощи golang?

    Примерно так
    func makeRequest() error {
    	req, err := http.NewRequest(http.MethodGet, "https://habr.com", nil)
    	if err != nil {
    		return err
    	}
    
    	req.Header.Add("User-Agent", "mySuperTestApp v1.0")
    
    	res, err := http.DefaultClient.Do(req)
    	if err != nil {
    		return err
    	}
    	defer res.Body.Close()
    	if res.StatusCode != http.StatusOK {
    		return fmt.Errorf("wrong status code: %d", res.StatusCode)
    	}
    
    	body, err := io.ReadAll(res.Body)
    	if err != nil {
    		return err
    	}
    
    	fmt.Println(string(body))
    	return nil
    }
    Ответ написан
    Комментировать