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

    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 не должен происходить из разных горутин.
    Ответ написан
    Комментировать