Protocol buffers Protobuf:尝试添加';缩放因子';作为.proto文件的元数据

Protocol buffers Protobuf:尝试添加';缩放因子';作为.proto文件的元数据,protocol-buffers,Protocol Buffers,我试图(错误地)使用.proto定义向我的所有标量值添加一个缩放因子,以便通信双方可以自行决定在内部使用以美分、浮点数或小数为单位的货币值。在这一点上,我想以一个整数结束。不是两个整数(value和scalingFactor,或者value和nanos) 如果我可以自由地在字段级别添加一些元数据,将其放在[]之间,它将如下所示: syntax = "not valid proto3...."; message Product1 { int

我试图(错误地)使用
.proto
定义向我的所有标量值添加一个
缩放因子
,以便通信双方可以自行决定在内部使用以美分、浮点数或小数为单位的货币值。在这一点上,我想以一个整数结束。不是两个整数(
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]
    }
# 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];
}
最后我想给出一个定义,就像Product2所描述的那样(当然不是有效的)。这样双方都可以从
.proto
定义中获得
缩放因子。然后在他们自己的代码中使用
scalingFactor
。有些人可能会在JavaScript中将价格转换为
十进制
,或者在C中以美分表示(例如,一个名为
price
的结构,其中int32表示
(以美分表示),int32表示
比例
(例如-2表示.01))

有没有一个明显的方法可以做到这一点?理想情况下,它很简单

根据答案更新: 现在,我意识到,从帕斯迪亚布洛的反应来看,我自己既不清楚,甚至怀疑自己。 不清楚的部分:如果
价格
为2.50美元,
重量
为7000kg,我想在所有情况下通过电线传输
250
7
。我不希望protobuf为我处理缩放。更重要的是,我想了解如何将传输的值进行缩放以使代码可用

疑问:我不确定我是否希望在我自己的代码中同时使用生成的类。我认为protobuf更多的只是一种传输机制。然后根据传输的值或要传输的值再次创建我自己的变量。

看起来您想在代码中将
权重设置为
7
,然后让protobuf根据
proto
文件中指定的比例,在在线消息中神奇地插入
7000

如果是这样的话,我同意,这看起来很像误用:-)

不幸的是,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));
//应该在早期完成一次,并存储在某个地方。
auto priceScaler=(PriceScale::PRICE\u SCALE\u DIV==0)
? 1.0*价格刻度::价格刻度
:1.0/价格刻度::价格刻度
自动重量秤=(重量秤::重量秤
? 1.0*重量秤::重量秤
:1.0/重量秤::重量秤
//构造消息。
protoMsg.set_id(42);
protoMsg.set_product_name(“链轮”);
protoMsg.set_price(静态_cast(实际价格*价格定标器));
protoMsg.设置重量(静态重量(实际重量*称重器));
并且,在提取值时:

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

auto actualPrice = protoMsg.price() / priceScaler;
auto actualWeight = static_cast<uint32_t>(protoMsg.weight() / weightScaler);
//与发送方一样,应该已经创建了scaler变量。
自动实际价格=protoMsg.price()/priceScaler;
自动实际重量=静态重量(protoMsg.weight()/weightScaler);

将自定义元数据添加到字段和消息中是相当常见的,可以使用。它们看起来像这样:

    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]
    }
# 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没有扩展名)


但是,您应该知道,这完全是元数据,对消息的序列化方式没有影响。编译后的程序将在构建注释时看到注释的值。如果您有两个使用此原型定义的二进制文件,它们将使用编译每个二进制文件时存在的注释的任何值-更改这样的比例因子将非常复杂,因为它会更改字段的语义。这对你来说可能是个问题,也可能不是。

啊!问题不在于双方都要扩大规模。因此,7000kg的连线值为7,2.50美元的连线值为250,我甚至不认为协议缓冲区会对我进行缩放。更重要的是,我希望两端的代码能够从.proto文件中导出缩放因子。因此,不必硬编码,在传输之前必须将十进制数乘以100。让我用你的输入更新这个问题。我现在明白为什么它不是那么简单了。。。(感谢您提供的缩放因子枚举。比使用负数更好。)