Ответы пользователя по тегу Go
  • Какую структуру go-сервиса стоит использовать?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Есть еще документ имеющий рекомендательный характер, но не имеющий силы официального руководства https://github.com/golang-standards/project-layout...
    Ответ написан
    Комментировать
  • Как ввернуть нескольких значений одной функцией в printf()?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Так как вы пробуете нельзя. Функции способные принять произвольное количество аргументов, на самом деле принимают один -- слайс. То, что элементы этого слайса можно привести перечислением -- синтаксический сахар.
    Конструкция func1(func2()) работает только в случае если func2() возвращает ровно такие значения и столько, сколько аргументов ожидает func1().
    В вашем случае swap() возвращает два значения, а fmt.Printf() ожидает только один аргумент -- []interface{}
    То есть можно только вот так
    func printTwoValue(x, y string) {
    	fmt.Printf("Цена: %s , ok= %s\n", x, y)
    }
    printTwoValue(swap("1", "2"))

    Работающий код https://go.dev/play/p/z9sFlujsfxd
    Ну или вот так
    func swap(x, y string) []interface{} {
    	return []interface{}{y, x}
    }
    fmt.Printf("Цена: %s , ok= %s\n", swap("1", "2")...)

    Работающий код
    https://go.dev/play/p/46ylXp9Tirv
    Ответ написан
  • Какой размер структуры в Go?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Как уже отмечалось это alignment и его можно посмотреть функцией unsafe.Alignof() https://pkg.go.dev/unsafe#Alignof
    Но не всё потеряно, акробатическими трюками можно бороться за каждый байт) Например:
    type s struct {
    	x int16
    	y int8
    	z int8
    }

    тоже будет занимать 4 байта на распространённых архитектурах. Prooflink https://play.golang.com/p/4AfhDeXDyF-
    Ответ написан
    Комментировать
  • Как проверить наличие пользователя в БД?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    По крайней мере в postgres можно обойтись внутренним механизмом sql, одним запросом:
    db.Prepare("INSERT INTO telegram (chat_id, username, timestamp) VALUES (?, ?, ?) ON CONFLICT (chat_id) DO NOTHING")

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

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Похоже вы пытаетесь использовать Method expressions https://go.dev/ref/spec#Method_expressions И так можно, только нужно:
    var m = map[int]methodPtr{
    	0: (*someStruct).method1,
    }
    Работающий код https://go.dev/play/p/0TqJTmuEGHU
    Правда, на мой взгляд, не очень удобно)
    Ответ написан
    Комментировать
  • Golang PGX как добавлять значения в jsonb?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    А попробуйте []string
    query := `
        UPDATE type
        SET characteristics = jsonb_insert(
            characteristics, '{$1}', '{"type": "$2", "measure": "$3"}'::jsonb
        )
        WHERE id=$4`
    
      tag, err := conn.Exec(ctx, query,
        []string{c.Name},      // Вот здесь попробуйте []string
        c.Type,      // string
        c.Measure,   // string
        c.ID,        // uint64
      )
    Ответ написан
  • Как правильно структурировать проект в Go?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Вам в комментариях уже подсказали https://github.com/golang-standards/project-layout... Но этот документ не имеет официальной поддержки или методической силы. Это только волонтёрская попытка унификации.
    Подход команды разработчиков языка виден в сырцах компилятора и стандартной библиотеки.
    Рекомендованный и однозначно принятый сообществом layout не утверждён.
    Особые свойства есть у папок internal и vendor. Эти папки при сборке рассматриваются тулчейном go иначе чем другие. Особые свойства этих папок отражены в официальной документации.
    Ответ написан
    Комментировать
  • Что выбрать для бэкенда с нуля?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Я, евангелист языка Go) Мне язык нравится и платят неплохо. Go быстрее чем Node.js, быстрее чем PHP.
    Но, хотел бы заметить:
    Вообщем есть проект написанный не мной, на PHP.

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

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    О каких хранимках идёт речь?
    В postgres есть собственная метафора хранимок, скомпилированных и живущих на postgres сервере. В Go пакет стандартной библиотеки sql сделан кросс-sql-движковым и ближайший аналог это sql.Stmt https://pkg.go.dev/database/sql#Stmt (в документации есть примеры кода). Вы можете скомпилировать sql стейтмент единожды в контексте соединения или транзакции и использовать многократно и потоко-безопасно пока жив контекст. Это даёт выигрыш в производительности.
    Если я правильно вопрос)
    Наивный код
    script, err := ioutil.ReadFile("path/to/procedure.sql")
    if err != nil {
        log.Fprintf(os.Stderr, "Error reading SQL script file: %v\n", err)
    }
    stmt, err := db.PrepareContext(context.Background(), string(script)) //компилируем стейтмент как шаблон c плейсхолдерами аргументов
    if err != nil {
    	log.Fatal(err)
    }
    _, err = stmt.ExecContext(ctx, args) //применяем стейтмент к аргументам args... в контексте ctx
    if err != nil {
        log.Fprintf(os.Stderr, "Error executing SQL script: %v\n", err)
    }

    Шаблон (path/to/procedure.sql) может выглядеть так
    SELECT username FROM users WHERE id = ?
    Вопросительный знак ? это плейсхолдер для аргумента
    Ответ написан
    1 комментарий
  • Как провести деструктуризацию?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    То чего вы добиваетесь не идеоматично, паттерн не применяется в рабочем Go коде. Никакой деструктуризации base syntax не предполагает.
    Просто показать возможности языка, ну и для code golfing:
    func Destruct(s any) (e []any) {
    	v := reflect.ValueOf(s)
    	if v.Kind() != reflect.Struct {
    		return nil
    	}
    	for i := 0; i < v.NumField(); i++ {
    		e = append(e, v.Field(i).Interface())
    	}
    	return
    }

    Работающий пример в песочнице https://go.dev/play/p/uk1o-Nl4Ic8
    Ответ написан
    1 комментарий
  • Когда надо использовать goroutines?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Отправлять запросы к БД будет, по всей видимости, интернет сервер/сервис обслуживающий большое количество клиентов. (Или зачем вообще производительность?) Каждого клиента будет обслуживать отдельная goroutine. Эта же рутина и будет в процессе работы делать запросы к БД. Это удобно, это так само получается, так спроектирована стандартная библиотека. При этом определенная оптимизация проводится на уровне стандартной библиотеки https://pkg.go.dev/database/sql. Например, вы можете пре-подготавливать стейтменты и транзакции и выполнять их многократно и потокобезопасно из разных горутин/хендлеров своего сервера. Go драйвер sql обычно поддерживает пулл соединений с движком и переиспользует эти соединения для обслуживания хендлеров. Тут, как бы, разработчика не ставят перед выбором. Всё за нас решили архитекторы стандартной библиотеки Go)
    Ответ написан
    2 комментария
  • Как использовать форк пакета в Го?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Всего две команды:
    подмена
    go mod edit -replace github.com/orig/pkg v1.0.0=github.com/my/fork/pkg v1.0.0

    или на локальный репо
    go mod edit -replace github.com/orig/pkg v1.0.0=/local/path/onyourmachine

    вернуть обратно когда ваш PR закоммитят
    go mod edit -dropreplace  github.com/orig/pkg v1.0.0

    А можно подправить go.mod вручную. В нём должно появиться
    replace github.com/orig/pkg v1.0.0  => github.com/my/fork/pkg v1.0.0

    В исходниках при этом менять импорты не нужно.
    Ответ написан
    1 комментарий
  • Что такое монадическая обработка ошибок?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Errors are values.
    Don't just check errors, handle them gracefully.
    (c) Rob Pike https://go-proverbs.github.io/
    Ответ написан
    Комментировать
  • Как реализовать сравнение кастомных типов в Go?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Есть ещё reflect.deepequal чтобы самому руками интерфейс не реализовывать.
    Ответ написан
    Комментировать
  • Как запросить только несколько полей?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Вам просто не нужно вообще включать answer в Projection. Должно быть достаточно:
    bson.M{
        "tasks": bson.M{
          "balls":  1,
          "description":  1,
        },
    }

    Ну и наоборот, вот так должно работать:
    bson.M{
        "tasks": bson.M{
          "answer":  0,
        },
    }

    Или что хотим включить или что исключить.
    Ответ написан
  • Что интересного полезного можно писать на GO для прокачки как разработчика?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Ответ написан
    Комментировать
  • Как правильнее хранить разные типы в одном поле структуры?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Мне кажется вы с ног на голову... Может быть так?
    type Admin struct {
      Permissions map[string]interface{}
      User
    }
    type Subscriber struct {
      Online        bool
      Status        string
      SubscriptedTo []int
      User
    }
    type User struct {
      ID    int
      Login string
    }
    Ответ написан
    Комментировать
  • Как передать любой тип данных в фильтрации?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    В Go нельзя использовать строковое значение как квалификатор типа. То есть нельзя написать:
    var Type string
    Type = "int"
    var foo Type // так не работает
    var foo "int" // и так не работает

    Из известных мне языков так нигде нельзя.
    В конкретном вашем примере сниппеты похоже на JSON. В Go это парсится примерно так:
    type Message struct {
    		Type string
    		Payload json.RawMessage // разобрать со второго захода
    }
    var message Message
    // первый заход, Payload пока не парсится, остаётся json.RawMessage
    json.Unmarshal(data, message)
    // варианты типа
    switch message.Type {
    		case "string":
    			dst = new(StringPayload) // готовим контейнер для типа string
    		case "int":
    			dst = new(IntPayload) // контейнер для int
    }
    // теперь разбираем Payload в подходящий контейнер
    json.Unmarshal(message.Payload, dst)

    gRPC обычно использует в качестве контейнера для сообщений protobuf. protobuf это строго типизированный язык. Передать на нём generic сообщение вообще вряд ли получится, по крайней мере не видел что бы кто нибудь делал.
    Ответ написан
    Комментировать
  • Как форсировать использование указателя при параметре-интерфейсе в Go?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Просто реализуйте интерфейс только для указателя на структуру
    func (ms *MyStruct) Callme() (string, error)
    Ответ написан
  • Почему горутина так мало весит?

    uvelichitel
    @uvelichitel Куратор тега Go
    habrahabr.ru/users/uvelichitel
    Гуглить greenthreads, user space threads. Такое не только Go умеет. Архитектурно, конкретно Go берёт истоки в Plan9, можно почитать например https://9fans.github.io/plan9port/man/man3/thread.html
    Планировщик user space потоков похож на системный планировщик pthreads. Но в системных потоках, если совсем грубо, при переключении контекста нужно сохранить регистры, стек и кучу(heap). В легковесных user space потоках куча общая для всех. Память для сохранения стека при переключении контекста системный планировщик выделяет сразу с запасом. А планировщик Go runtime выделяет, без запаса, всего 2кб с возможностью роста. (Между прочим много кода и архитектуры в планировщик Go занёс соотечественник -- Дмитрий Вьюков. 2кб вроде его персональная заслуга)
    Ответ написан
    Комментировать