Ответы пользователя по тегу Go
  • Golang protoc grpc gateway, почему возникает ошибка?

    @Wirusnyy-chel
    Без .proto файла на вопрос сложно ответить.

    Вы точно все комманды вызываете:
    1. Нужно сгенерировать гошные структуры
    2. Нужно сгенерировать grpc сервер
    3. Сгенерировать gateway

    Обычный grpc сервер работает? Он в любом случае нужен будет. Если нет, начните с него. Гайдов по простому grpc точно достаточно.

    Если grpc сервер работает то можно переходить к gateway, ознакомьтесь с официальным репозиторием
    https://github.com/grpc-ecosystem/grpc-gateway
    В нем есть примеры в папках example + ссылка на лендинг с документацией
    Ответ написан
    Комментировать
  • Почему код в одном случае работает, а в другом - нет и выдает ошибку?

    @Wirusnyy-chel
    Канал done у вас в обоих случаях не буфферизированый - это значит что для выполнения операции записи в канал должны быть готовы и писатель (ch<-val) и читатель (<-ch).

    В первом варианте у вас писатель готов совершить операцию, но у него нет читателя и этот поток исполнения ставится на паузу, до тех пор, пока не появится читатель, а читатель определён в этом же потоке поэтому его никогда не будет. Программа зависнет и может упасть с ошибкой.
    Это можно поправить сделав канал буфферизированным
    done := make(chan book, 1)


    Второй случай работает, т.к. писатель и читатель в разных потоках и могут дождаться друг друга.
    Ответ написан
    Комментировать
  • Golang PGX как добавлять значения в jsonb?

    @Wirusnyy-chel
    Когда вы указываете
    '{$1}'
    постгрес воспринимает это как просто строку, а не как параметр для вставки.


    Пробовал явно указывать тип $1
    query := `
    UPDATE type
    SET characteristics = jsonb_insert(
    characteristics, '{$1}'::text, '{"type": "$2", "measure": "$3"}'::jsonb
    )
    WHERE id=$4`

    Так тоже ошибка : function jsonb_insert(jsonb, text, jsonb) does not exist

    У функции jsonb_insert сигнатура
    jsonb_insert(target jsonb, path text[], new_value jsonb [, insert_after boolean])
    Поэтому строка `'{$1}'::text'`, должна быть `'{$1}'::text[]'`. (Но и это не совсем поможет)

    Можно преобразовать это следующим образом:
    query := `
        UPDATE type
        SET characteristics = jsonb_insert(
            characteristics, array[$1::text], 
           jsonb_build_object('type', $2, 'measure', '$3')
        )
        WHERE id=$4`
    
      tag, err := conn.Exec(ctx, query,
        c.Name,      // string
        c.Type,      // string
        c.Measure,   // string
        c.ID,        // uint64
      )


    Или позволить pxg самому собрать jsonb:

    query := `
        UPDATE type
        SET characteristics = jsonb_insert(
            characteristics, array[$1::text], $2
        )
        WHERE id=$3`
    
      tag, err := conn.Exec(ctx, query,
        c.Name,      // string
       struct{ // лучше вынести как отдельный тип
         Type string `json:"type"`
         Measure string `json:"measure"`
        }{c.Type, c.Measure}
        c.ID,        // uint64
      )
    Ответ написан
    3 комментария
  • Почему меняется работа RWMutex в зависимости от его расположения в коде?

    @Wirusnyy-chel
    У вас в обоих случаях mutex защищает только от одновременной записи и чтения из переменной. Фактически порядок вывода не зависит от этого мьютекса, можете убедиться в этом если запустите исполнение несколько раз или добавите разные слипы в горутинах чтения и записи.

    Если необходимо синхронизировать потоки записи и чтения лучше использовать каналы.

    Как упражнение на mutex могу предложить следующее:
    Задать структуру с двумя переменными: где значение первой переменной зависит от второй. Если параллельно обновлять и читать значения можно увидеть следующее:
    Без мьютекса чтение может иногда возвращать несогласованное значение между переменными.
    С мьютексом значение при чтении будет всегда согласованным.

    P.S. В вашем примере для синхронизации переменных достаточно обычного мьютекса. RWMutex будет полезен если читателей больше одного.
    Ответ написан
    4 комментария
  • Как в GO написать свою функцию к другим типам?

    @Wirusnyy-chel
    В вашем примере нужно заменить
    var str string
    на
    var str strType
    Ответ написан
    Комментировать
  • Как одновременно прочитать построчно два файла?

    @Wirusnyy-chel
    Из комментариев под вопросом:
    нужно из файла взять подстроку после : и проверить существует ли подстрока из 1 файла в подстроке файла 2(до :) и если она есть, то записать строку в виде: подстрока из 1 файла: подстрока из 2 файла

    размеры файлов до 1гб


    Быстрым будет вариант с мапой из ответа выше, но он будет потреблять достаточно много памяти и ищет только прямые вхождения подстроки 1 в подстроке 2.

    Предлагаю вариант с меньшим потреблением памяти
    file1, err := os.Open(config.First_file)
    if err != nil {
      log.Fatalln("error")
    }
    defer file1.Close()
    file1Scanner := bufio.NewScanner(file1)
    
    file2, err := os.Open(config.Second_file)
    if err != nil {
      log.Fatalln("error")
    }
    defer file2.Close()
    file2Scanner := bufio.NewScanner(file2)
    
    // находим все доступные подстроки из файла 2
    file2SubSrings := make([]string,0)
    for file2Scanner.Scan(){
      file2SubSrings = append(file2SubSrings, strings.Split(file2Scanner.Text(), ":")[0])
    }
    
    for file1Scanner.Scan() {
      file1SubString := strings.Split(file1Scanner.Text(), ":")[1]
      for _, val := range file2SubStrings{
        if strings.Contains(val, file1SubString) {
          log.Println(file1SubString, ":", val)
          break
        }
    }
    
    if err := file1Scanner.Err(); err != nil {
      log.Fatalln(err)
    }
    
    if err := file2Scanner.Err(); err != nil {
      log.Fatalln(err)
    }


    UPD Вариант с параллельностью
    func scanFiles(file1, file2 *bufio.Scanner) {
    	// находим все доступные подстроки из файла 2
    	file2SubStrings := make([]string, 0)
    	for file2.Scan() {
    		file2SubStrings = append(file2SubStrings, strings.Split(file2.Text(), ":")[0])
    	}
    
    	wg := new(sync.WaitGroup)
    	valChan := make(chan string)
    	for i := 0; i < 5; i++ {
    		wg.Add(1)
    		go findIntersections(valChan, file2SubStrings, wg)
    	}
    
    	for file1.Scan() {
    		valChan <- strings.Split(file1.Text(), ":")[1]
    	}
    
    	wg.Wait()
    }
    
    func findIntersections(values chan string, file2SubStrings []string, wg *sync.WaitGroup) {
    	for {
    		file1SubString, ok := <-values
    
    		if !ok {
    			wg.Done()
    			return
    		}
    
    		for _, val := range file2SubStrings {
    			if strings.Contains(val, file1SubString) {
    				log.Println(file1SubString, ":", val)
    				break
    			}
    		}
    	}
    }


    UPD2
    строка из файла 2 - 663624e4aae0164132f10f09fdd9fcd2:liberty_
    строка из файла 1 - scherbakovatd@example.com:663624e4aae0164132f10f09fdd9fcd2
    на выходе должно выйти scherbakovatd@example.com:liberty_

    func scanFiles(file1, file2 *bufio.Scanner) {
    	scanWg := new(sync.WaitGroup)
    	scanWg.Add(2)
    
    	file1SubStrings := make(map[string]string)
    	file2SubStrings := make(map[string]string)
    
    
    	go func() {
    		var substr []string
    		for file1.Scan() {
    			substr = strings.Split(file1.Text(), ":")
    			file1SubStrings[substr[1]] = substr[0]
    		}
    		scanWg.Done()
    	}()
    	
    	go func() {
    		var substr []string 
    		for file2.Scan() {
    			substr = strings.Split(file2.Text(), ":")
    			file2SubStrings[substr[0]] = substr[1]
    		}	
    		scanWg.Done()
    	}()
    	
    	scanWg.Wait()
    	
    	
    	wg := new(sync.WaitGroup)
    	valChan := make(chan struct{k,v string})
    	for i := 0; i < 5; i++ {
    		wg.Add(1)
    		go findIntersections(valChan, file2SubStrings, wg)
    	}
    
    	for k, v := range file1SubStrings {
    		valChan <- struct{ k, v string }{k: k, v: v}
    	}
    
    	wg.Wait()
    }
    
    func findIntersections(file1Values chan struct{ k,v string}, file2 map[string]string, wg *sync.WaitGroup) {
    	for {
    		file1, ok := <-file1Values
    
    		if !ok {
    			wg.Done()
    			return
    		}
    		
    		if file2Value, ok := file2[file1.k];ok {
    			log.Println(file1.k, ":", file2Value)
    		}
    	}
    }
    Ответ написан
  • Linter для Go для выявления переменных без явной инициализации?

    @Wirusnyy-chel
    Идея для проверки очень хорошая, но, судя по всему, такого литера ещё нет. Если найдёте или сами реализуете, пожалуйста отпишитесь.
    Есть близкий по смыслу https://github.com/GaijinEntertainment/go-exhaustruct

    Вариант с регулярной может помочь с реализацией необходимого вам поведения с помощью других линтеров.

    Идея как это реализовать.
    !! Warning похоже на небольшой костыль и сам это поведение не проверял!!
    Линтеры:
    1. Регулярка из ответа выше.
    2. https://github.com/gordonklaus/ineffassign
    3. Проверка на использование директивы nolint
    Алгоритм:
    1. Запрещаете неявную инициализации при помощи регулярки.
    2. Если переменная должна быть инициализирована дальше в коде, ineffassing выдаст ошибку, поэтому добавляем директиву nolint. Если этой инициализации не будет (ошибка которую хотим поймать) - упадёт проверка на использование nolint
    Ответ написан
    1 комментарий
  • Как сжать файл?

    @Wirusnyy-chel
    Если нужно уменьшить размер бинарника который собирается гошкой https://habr.com/ru/company/plesk/blog/532402/

    Если хотите сжимать файлы для пересылки/хранения то перед использованием их нужно распаковать.
    Ответ написан
    Комментировать
  • Как игнорировать ошибку Broken import в редакторе?

    @Wirusnyy-chel
    Вы не совсем корректно используете директиву replace из-за этого редактор пишет ошибку.

    В go вы можете обращаться к пакетам из текущего проекта или из внешнего. Чтобы обращаться к внешним пакетам нужено указать его в go.mod, для текущего проекта это не нужно.

    В вашем примере два пакета example.com/hello и example.com/greetings. Добиться нужного вам поведения можно несколькими способами:

    1. Оба пакета находятся в одном проекте (репозитории)
    Тогда в корневой директории нужно создать go.mod с "module example.com" и все будет работать как вы ожидаете. От файлов go.mod в greetings и hello нужно будет избавиться.

    2. Greetengs внешний проект
    Нужно опубликовать его и получить через go get

    3. Greetengs внешний проект без публикации
    Использовать go workspace
    Ответ написан
    Комментировать