解决由于C++而在Google protobuf中解决枚举字段命名限制的解决方案

won*_*hee 15 c++ java enums serialization protocol-buffers

您可能知道,当您使用全局范围或相同的消息在Google protobuf中定义枚举时,如果枚举是兄弟,则无法将枚举字段名称定义为相同.

即使您要使用proto文件生成Java代码,protoc也会抱怨它,并且不会生成包含以下消息的任何代码.

"XXX" is already defined in "your.package.name".
Note that enum values use C++ scoping rules, meaning that enum values are siblings of their type,
not children of it. 
Therefore, "XXX" must be unique within "your.package.name", not just within "your_enum_name".
Run Code Online (Sandbox Code Playgroud)

所以,这意味着你应该做的事情

  1. 用消息包装碰撞的枚举.
    • 优点:嗯...... protoc不会失败?
    • 缺点:生成代码将有一个额外的静态包装类,这样会稍微增加SerDes成本+命名似乎足够长.例如,CURRENCY.NAMESPACE(包装器消息名称).USD

要么

  1. 使用字段的前缀,所以如果您的冲突字段名称是UNKNOWN并且它是CURRENCY,那么它将是CURRENCY.CURRENCY_UNKNOWN或类似的东西.
    • 优点:简单
    • 缺点:与#1一样丑陋,与现有的没有任何前缀的枚举字段命名不一致.

要么

  1. 只是不要使用Enum.使用字符串类型.
    • 优点:简单,不需要像UNKNOWN = 1那样定义回退枚举字段作为默认值.
    • 缺点:失去enum的好处.

似乎C++ 11支持没有这个问题的更好的枚举,但遗憾的是最新的protoc不支持它,我们不能简单地要求其他消费者切换他们的一方使用C++,如果他们不使用它.

因此,它将选择较差的解决方案而不是最佳解决方案,并且可能我们将在此时使用#2.有没有人有相同的经验,告诉我你的解决方案是什么,它是如何结束的?

Ken*_*rda 13

现有代码中的主流解决方案是选项(2):为每个枚举名称指定与其类型对应的前缀.这也有助于减少与宏的冲突.它很冗长,但与建议的其他选项不同,它没有运行时开销,并且为阅读代码的人创建了最少的混淆.

(FWIW,Cap'n Proto通过使用C++ 11枚举类来避免这个问题.由于它会破坏现有代码,因此protobufs不太可能这样做.)

(披露:我是Cap'n Proto的作者以及Google的大部分开源Protobuf代码.)