Хобрук: Ваш путь к мастерству в программировании

Protobuf: попытка добавить «коэффициент масштабирования» в качестве метаданных в файл .proto

Я пытаюсь (ошибочно??) использовать определение .proto, чтобы добавить scalingFactor ко всем моим скалярным значениям, чтобы обе стороны, которые общаются, могли решить для себя, использовать ли внутри денежные значения в центах, числах с плавающей запятой или десятичных дробях. В этом я хочу получить только целое число, идущее по проводу. Не два целых числа (например, value и scalingFactor или value и nanos).

Если бы у меня была возможность просто добавить некоторые метаданные на уровне поля, поместив их между [], это выглядело бы так:

    syntax = "not valid proto3....";
    
    message Product1 {
      int32 id = 1;
      string productName = 2;
      int32 priceInCents = 3
      int32 weightInTons = 4
    }
    message Product2 {
      int32 id = 1;
      string productName = 2;
      int32 price = 3 [scalingFactor = .01]
      int32 weight = 4 [scalingFactor = 1000]
    }

Я хотел бы закончить с определением, как оно описано (но, конечно, недействительно) для Product2. Таким образом, обе стороны могут получить scalingFactor из определения .proto. А затем использовать этот scalingFactor в своем собственном коде. Некоторые могут преобразовать цену в decimal в JavaScript или оставить ее в центах в C (например, структура с именем price с int32 для value (в центах) и int32 для scale (например, -2 представляет .01))

Есть ли очевидный способ сделать это? В идеале просто.

ОБНОВЛЕНИЕ на основе ответа:

I now realise by paxdiablo's reaction that I was both unclear and maybe even in doubt myself.

Неясная часть: если price составляет 2,50 доллара США, а weight составляет 7000 кг, я хочу передавать 250 и 7 по проводам во всех случаях. Чего я не искал, так это того, чтобы protobuf справился с масштабированием за меня. Дело в том, что я хотел иметь контекст того, как масштабируются передаваемые значения, чтобы они стали доступными для кода.

Сомнение: я не уверен, что хочу использовать сгенерированные классы в своем собственном коде с обеих сторон. Я видел протобуф больше как транспортный механизм. И снова создайте свои собственные переменные на основе переданных значений или значений, которые необходимо передать.

16.08.2020

Ответы:


1

Похоже, вы хотите установить weight в 7 в своем коде, а затем protobuf волшебным образом вставит 7000 в передаваемое по сети сообщение, основываясь на масштабе, указанном в файле proto.

Если это так, я согласен, это очень похоже на злоупотребление :-)

К сожалению, protobuf этого не делает. Вы должны либо масштабировать значение самостоятельно, чтобы правильное значение передавалось по проводу на другую сторону, либо добавить еще одно поле с масштабированием, чтобы другая сторона могла это исправить.

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

В противном случае обе стороны не смогут договориться о масштабе.


Если, с другой стороны, вам нужно что-то в файле protobuf, в котором только что указан масштаб, вы можете использовать для этого enum, что-то вроде:

// Scale factors to use, extract either MUL or DIV, one needs 
// to be zero, the other is an actual multiplier/divisor.

enum PriceScale {
    PRICE_SCALE_DIV = 0;
    PRICE_SCALE_MUL = 100;     // 2.50 goes over wire as 250.
}
enum WeightScale {
    WEIGHT_SCALE_MUL = 0;
    WEIGHT_SCALE_DIV = 1000;   // 7000 goes over wire as 7.
}
message Product2 {
  int32 id = 1;
  string product_name = 2;
  int32 price = 3;
  int32 weight = 4;
}

но вам все равно придется вручную масштабировать значения, отправляемые по сети, как на отправляющей, так и на принимающей стороне. Это также, вероятно, не предполагаемый вариант использования для перечислений. Мы используем этот трюк для хранения констант в файлах proto, чтобы наш код мог получить к ним доступ (в частности, некоторые строки имеют ограничения по длине, которые мы хотим применить).

Для реального масштабирования вам нужно будет сделать что-то вроде этого на отправляющей стороне:

// Should be done once early on, and stored somewhere.

auto priceScaler = (PriceScale::PRICE_SCALE_DIV == 0)
    ? 1.0 * PriceScale::PRICE_SCALE_MUL
    : 1.0 / PriceScale::PRICE_SCALE_DIV
auto weightScaler = (WeightScale::WEIGHT_SCALE_DIV == 0)
    ? 1.0 * WeightScale::WEIGHT_SCALE_MUL
    : 1.0 / WeightScale::WEIGHT_SCALE_DIV

// Construct message.

protoMsg.set_id(42);
protoMsg.set_product_name("sprocket");
protoMsg.set_price(static_cast<uint32_t>(actualPrice * priceScaler));
protoMsg.set_weight(static_cast<uint32_t>(actualWeight * weightScaler));

И при извлечении значений:

// As with sender, scaler variables should have been created.

auto actualPrice = protoMsg.price() / priceScaler;
auto actualWeight = static_cast<uint32_t>(protoMsg.weight() / weightScaler);
16.08.2020
  • Ах! Проблема не в масштабировании с обеих сторон. Таким образом, значение по сети будет равно 7 за 7000 кг и 250 за 2,50 доллара, и я даже не думал, что буфер протокола сделает масштабирование за меня. Я хочу, чтобы код на обоих концах мог получить коэффициент масштабирования из файла .proto. Таким образом, вам не нужно жестко кодировать, что вы должны умножать десятичное число на 100 перед его передачей. Позвольте мне обновить вопрос с вашим вкладом. Теперь я понимаю, почему это не так просто... (И спасибо за enum для коэффициентов масштабирования. Лучше, чем использовать отрицательное число. ) 16.08.2020

  • 2

    Добавление пользовательских метаданных в поля и сообщения довольно распространено и может быть выполнено с помощью параметров поля< /а>. Они будут выглядеть примерно так:

    # scaling_factor.proto
    syntax = "proto2";
    import "google/protobuf/descriptor.proto";
    
    package my_options;
    
    extend .google.protobuf.FieldOptions {
      optional float scaling_factor = 12345;
    }
    
    
    # product.proto
    syntax = "proto3";
    import "scaling_factor.proto";
    
    message Product2 {
      (...)
      int32 price = 3 [(my_options.scaling_factor) = .01];
      int32 weight = 4 [(my_options.scaling_factor) = 1000];
    }
    

    На каждом языке есть API, которые позволяют получить параметры для определенных полей. Обратите внимание, что расширение поля должно быть определено в файле proto2 (proto3 не имеет расширений).

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

    20.08.2020
    Новые материалы

    Статическая типизация в TypeScript: основы Typescript
    Понимание статической типизации TypeScript, расширенный набор JavaScript, был разработан Microsoft в 2012 году для устранения некоторых ограничений JavaScript. Одним из его основных предложений..

    Как использовать SAAS на благо вашего бизнеса
    В деловом мире SAAS (программное обеспечение как услуга) становится все более популярным. И неудивительно, почему — SAAS предоставляет ряд преимуществ для предприятий любого размера. Вот лишь..

    Приложения случайного блуждания, часть 1 (статистика + машинное обучение)
    Смещенное случайное блуждание при динамической перколяции (arXiv) Автор: Себастьян Андрес , Нина Гантерт , Доминик Шмид , Перла Сузи Аннотация: мы изучаем смещенные случайные..

    Интеллектуальная масштабируемая обработка видео в реальном времени в Azure
    1. Введение В этом руководстве создается сквозной проект для интеллектуальной масштабируемой обработки видео в реальном времени в Azure. При этом создается возможность обнаруживать граффити и..

    Варианты использования положительной изотропной кривизны, часть 6 (машинное обучение)
    Четыре-орбифолды с положительной изотропной кривизной (arXiv) Автор : Хун Хуан Аннотация: Мы доказываем следующий результат: Пусть (X,g0) — полное связное 4-многообразие с равномерно..

    Внутри эпистатических сетей
    Регуляция нейронных сетей для лучшего прогнозирования ландшафтов биологической пригодности Сопоставьте свой индуктивный уклон с областью вашей проблемы Всем алгоритмам машинного обучения..

    Создание полноценного интерфейса командной строки с использованием Python | Расширенный Python
    Создание полноценного интерфейса командной строки с использованием Python — Advanced Python Чтобы изучить расширенные функции языка программирования, вам следует попробовать создать..