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

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Предлагаю не злоупотреблять каналами:
    https://goplay.tools/snippet/a91nAx2wevG

    Ваш тест из вопроса проходит. Корректность теста не смотрел :)
    Ответ написан
    Комментировать
  • Почему не видит пакет race?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Если устанавливали по инструкции с сайта, то удаляйте все что напихали в систему. Потом нужно установить компилятор через менеджер пакетов.
    Например, для debian/ubuntu через apt:
    sudo apt install golang
    Либо через snap:
    sudo snap install go --channel=1.16/stable --classic
    Ответ написан
    Комментировать
  • Как организовать тесты в пакетах вида адаптер?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Проблема в том что эти адаптеры имеют одни и те же методы, делают одно и тоже (но по своему),

    Это заворачивается в интерфейс и тестируете по этому интерфейсу ваши конкретные реализации.
    https://gobyexample.com/interfaces

    пример repo_test.go:
    type Repository interface{
        MethodA() error
        MethodB() error
    }
    
    func TestRedis(t *testing.T) {
         testRepo(t, NewRedis(...))
    }
    
    func TestMongo(t *testing.T) {
         testRepo(t, NewMongo(...))
    }
    
    func testRepo(t *testing.T, repo Repository){
        err := repo.MethodA()
        if err != nil {
            t.Errorf("methodA: %s", err)
        }
    
        err = repo.MethodB()
        if err != nil {
            t.Errorf("methodB: %s", err)
        }
    }


    ... но тут проблема с цикличным импортом (все адаптеры импортируют компоненты из repo).

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

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Никогда не устанавливайте программы вручную в корень системы, как в вашей инструкции. Почти всегда есть готовые пакеты. Лучше уже через докер ставить, лезть в систему - крайний случай.
    (и советую все вернуть как было до ручной установки)

    Го лучше поставить через snap (а вот vscode лучше через deb с сайта):
    sudo snap install go --channel=1.16/stable --classic


    Когда понадобятся другие версии, VScode может сам установить в папку желаемую версию и будет использовать её:
    ctrl+shift+p, вводите Go: Locate Configured Go Tools (или на панели снизу можно найти кнопку).

    Бывает что анализатор может заглючить и перезапуск gopls помогает: ctrl+shift+p, Go: Restart language Server

    И убедитесь, что го расширение установлено в редактор.
    Ответ написан
    Комментировать
  • Есть ли простой способ передать задачу в Go?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Пример замыканий:
    package main
     
    import (
        "fmt"
        "math/rand"
        "time"
    )
     
    type kelvin float64
     
    func measureTemperature(samples int, sensor func() kelvin) { // measureTemperature принимает функцию в качестве второго параметра
        for i := 0; i < samples; i++ {
            k := sensor()
            fmt.Printf("%v° K\n", k)
            time.Sleep(time.Second)
        }
    }
     
    func fakeSensor() kelvin {
        return kelvin(rand.Intn(151) + 150)
    }
     
    func main() {
        measureTemperature(3, fakeSensor) // Передает название функции другой функции
    }

    Источник
    Ответ написан
    2 комментария
  • Как огрганизовать хранение нескольких value в boltdb и поиск по ним?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    И при каждом запросе перебирать каждый элемент, сравнивать по полям структуры с нужными данными?

    bolthold

    Будет ли это быстро когда база вырастит до 10 000 полей.

    Нужно смотреть конкретно в ваших задачах.

    В пользу SQLite можно отнести поддержку sql запросов, что позволяет использовать стандартные подходы к построению базы данных. Например, можно воспользоваться маппером sqlx или gorm.
    Ответ написан
    Комментировать
  • Go под Android?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Из коробки все компилируется:
    GOOS=android GOARCH=arm GOARM=7 go build

    И джавы вообще никакой не надо, как и графической оболочки :)
    Лучше вообще на Го забыть про всякие там новомодные gui - только консоль, только хардкор.

    Если так хочется как можно больше на Го сделать, то решением может быть библитека на нем, а фронт на нативных технологиях: Java/Kotlin или Dart.

    Еще есть вариант в виде привязки к Qt, логику можно писать на Го, графику на QML. Только вот придется весь набор Qt либ тянуть с собой, да и ограничения в лицензировании продукта есть.
    Ответ написан
    7 комментариев
  • Как изменить двумерный массив в for?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    ....  
     for i, _ := range arr {
        arr[i] = append(arr[i], "ddddd")
      }
    ....

    В вашем случае innerArray это срез, который внутри содержит указатель на массив, но когда вы делаете append и при этом size выходит за пределы capacity, то выделяется новый массив и в него добавляется новое значение.

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

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Без регулярных выражений:
    https://play.golang.org/p/SIqQunrMQHI
    import (
    	"strings"
    )
    
    func normalize(s string) string {
    	var sb strings.Builder
    
    	for _, r := range s {
    		switch {
    		case '0' <= r && r <= '9':
    		case r == '+':
    		default:
    			continue
    		}
    		sb.WriteRune(r)
    	}
    
    	return sb.String()
    }


    С регeлярками:
    https://play.golang.org/p/GYzsCTaEa9W
    import (
    	"regexp"
    	"strings"
    )
    var re = regexp.MustCompile(`(?i)[\d\+]+`)
    
    func normalize(s string) string {
    	var sb strings.Builder
    	subs := re.FindAllStringSubmatch(s, -1)
    	
    	for _, sub := range subs {
    		sb.WriteString(sub[0])
    	}
    	
    	return sb.String()
    }


    Или вариант с заменой сиволов:
    var re = regexp.MustCompile(`(?m)[^+\d]`)
    var str = `+999 (99)-999 9999`
    fmt.Println(re.ReplaceAllString(str, ""))


    Версия без регулярок более экономна по ресурсам процессора и памяти, но при изменении паттерна потребует изменения и кода функции.
    Ответ написан
    Комментировать
  • Как сделать обязательным указание одного из двух полей protobuf?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Oneof

    Да и к Go вопрос никак не относится.
    Ответ написан
    Комментировать
  • Нужно составить небольшую программу на GO которая отправляет данные в базу данных PostgreSql?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Если собираетесь изучть SQL, то не советую начинать с использования ORM библиотек.

    Для упрощения работы с sql-запросами в Го есть такие инструменты, которые облегчат жизнь:
    • sqlc - генерирует всю обвязку обращений к БД на основе sql-запросов в виде Го-кода.
    • sqlx (дока с примерами) - библиотека для упрощения работы с запросами. Например, автоматический маппинг из результата в go-структуру.
    Ответ написан
    Комментировать
  • Где почитать про sync/atomic?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Официальная дока:
    https://golang.org/pkg/sync/atomic/

    Первые строчки в гугле со статьями, где все разжевано:
    https://go101.org/article/concurrent-atomic-operat...
    https://gobyexample.ru/atomic-counters.html
    Ответ написан
    Комментировать
  • Golang + Websoket. Как получать изменения от других сервисов?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Еще есть реализация socket.io для golang.

    Но для прокачки скилов я бы все равно порекомендовал кастомную реализацию асинхронного обмена сообщениями поверх WebSocket.

    Также для получения событий (только от сервера к браузеру, он же взаимодействует как обычно по http) еще есть такая технология как Server-sent events. В связке с http2 вообще огонь.
    Ответ написан
    Комментировать
  • Как послать в пул - воркер команду ожидания?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Как мы должны догадаться что такое сессия в вашем понимании? Вы даже не написали, как у вас организован пул воркеров и как ваши воркеры обрабатывают задания.

    Делайте stateless архитектуру и присылайте сессию вместе с заданием.

    Для хранения состояния сессии в Го есть context.Context, который можно отменять (учтите, что придется обарабатывать отмену вручную).
    Ответ написан
    Комментировать
  • Как структурировать http сервер?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Я использую такой подход:
    1) Хендлеры занимаются лишь обработкой входных параметров от клиента, например, извлечение параметров, вывод ошибок пользователю;
    2) Бизнес-логика вынесена в отдельный пакет или класс;
    3) Запросы во внешние хранилища тоже в отдельном пакете;
    4) Передача соединений бд или хранилищ только через контекст с помощью миддлвари.

    Пример структуры проекта:
    | + api
    | - - router.go
    | + models
    | - - modelA.go
    | - - modelB.go
    | + app
    | - - taskA.go
    | - - taskB.go
    | + database
    | - - requests.go
    | main.go

    main.go:
    package main
    import "api"
    func main(){
      ...
      r := api.NewRouter(...)
      http.ListenAndServe(...)
    }


    api/router.go:
    package api
    import (
      "app"
      "models"
    )
    func NewRouter(...) ...{
      // Инициализация роутера, регистрация обработчиков и т.д.
      ...
      return r
    }
    
    func handleEndpointA(w http.ResponseWriter, r *http.Request){
      // Извлечение, валидация параметров.
      // Извлечение соединений БД и друхих хранилищ из контекста.
      // Обработка ошибок.
      ...
      result, err := app.DoTaskA(ctx, db, paramA, paramB)
      ...
      render(w, result)
    }
    
    func handleEndpointB(w http.ResponseWriter, r *http.Request){
      ...
      result, err := app.DoTaskB(ctx, db, paramC)
      ...
      render(w, result)
    }


    app/taskA.go:
    package app
    import(
        "database"
        "models"
    )
    func DoTaskA(ctx, db, paramA, paramB) (result, err){
      // Какие-то манипуляции с параметрами.
      ...
      // Запрос в бд.
      modelA, err := database.RequestA(ctx, db, param)
      ...
      return result, err
    }


    database/requests.go:
    package database
    import (
      "models"
    )
    func RequestA(ctx, db, param) (result, err) {
      // Не забываем поставить таймаут на запрос к БД.
      ctx, cancel = context.WithTimeout(ctx, defaultRequestTimeout)
      defer cancel()
      ...
      result, err := db.DoRequest(ctx, ...)
      ...
      return result, err
    }
    Ответ написан
    Комментировать
  • Как результат кодогенераций сохранить в архив и сразу его отдать?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    https://golang.org/pkg/archive/zip/

    Пример с одним файлом:
    func handle(w http.ResponseWriter, r *http.Request){
    	fileToZip, _ := os.Open("filepath")
    	defer fileToZip.Close()
    
    	// NewWriter returns a new Writer writing a zip file to w.
    	zipWriter := zip.NewWriter(w)
    	defer zipWriter.Close()
    
    	info, _ := fileToZip.Stat()
    
    	header, _ := zip.FileInfoHeader(info)
    
    	// Change to deflate to gain better compression
    	// see http://golang.org/pkg/archive/zip/#pkg-constants
    	header.Method = zip.Deflate
    
    	// CreateHeader adds a file to the zip archive using the provided FileHeader
    	// for the file metadata. 
    	// This returns a Writer to which the file contents should be written.
    	writer, _ := zipWriter.CreateHeader(header)
    	io.Copy(writer, fileToZip)
    }
    Ответ написан
  • Где можно взять пример проекта (1-5 тыс. строк ) на github?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Golang/Gin codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld spec and API.

    https://github.com/gothinkster/golang-gin-realworl...
    Ответ написан
    Комментировать
  • Как в golang написать регулярное выражение эквивалентное php?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    MustCompile и MatchString

    пример
    package main
    
    import (
    	"fmt"
    	"regexp"
    )
    
    func main() {
    	re := regexp.MustCompile(`(gopher){2}`)
    	fmt.Println(re.MatchString("gopher"))
    	fmt.Println(re.MatchString("gophergopher"))
    	fmt.Println(re.MatchString("gophergophergopher"))
    }
    Ответ написан
    Комментировать
  • Архитектура highload websocket проекта?

    WinPooh32
    @WinPooh32
    Stack Overflow answer searching expert
    Из-за особенностей работы сборщика мусора в Go у вас скорее всего возникнут проблемы, если ключи в map'е содержат указатели (включая структуры их содержащие).

    Вот накидал способ хранения сокетов немного в другом виде без указателей в ключах:
    const n = 4 // длина идентификатора комнаты в байтах
    type (
    	noop struct{}
    	WebSocket struct{} // сокет
    
    	Sockets []WebSocket
    	RoomKey [n]byte
    	
    	Index uint32
    
    	Room map[Index] struct{}
    	Rooms map[RoomKey] Room
    )
    
    var sockets = make(Sockets, 0, 2000000)
    var rooms = make(Rooms, 1000)
    var lastSocketRoomKey RoomKey
    
    func insert(ws WebSocket, rk RoomKey){
    	room, _ := rooms[rk]
    	// тут создание комнаты, если ее нет
    	// ...
    	
    	sockets = append(sockets, ws)
    	
    	last := len(sockets) - 1
    	room[Index(last)] = noop{}
      
            // сохраним ключ комнаты последнего сокета
            // чтобы можно было исправить индекс при удалении
            copy(lastSocketRoomKey[:], rk[:])
    }
    
    func remove(i Index, rk RoomKey){
    	// удаляем сокет,
    	// переместив последний в массиве на место удаляемого
    
    	last := len(sockets) - 1
    	sockets[i] = sockets[last]
    	sockets = sockets[:last]
    
    	// удаляем сокет из комнаты
    	room, _ := rooms[rk]
    	delete(room, Index(i))
    
    	// чиним индекс перемещенного сокета
    	roomOfLast := rooms[lastSocketRoomKey]
    	delete(roomOfLast, Index(last))
    	roomOfLast[Index(i)] = noop{}
    }


    Когда вам нужно разослать сообщения, в моем примере доступ к сокету будет происходить примерно так:
    for _, index := range rooms[roomkey]{
         // sockets[index] -- сокет в комнате с roomkey
         
        // т.к. из-за особенности структуры искать сокет в комнате получается невыгодно долго, 
        // придется удалять закрытые сокеты "ленивым" способом во время рассылки, 
        // либо заполнять массив индексов и после уже удалять эти сокеты из общего хранилища
        // функцией remove(index, roomkey)
    }


    Очевидно, что в данном примере доступ к sockets и rooms не должен происходить из разных горутин.
    Ответ написан
    Комментировать