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

如您所知,当您在 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".

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

  1. 用消息包装冲突枚举。
    • 优点:嗯...原型不会失败吗?
    • 缺点:生成代码将有一个额外的静态包装类,这样它会增加SerDes的成本一点点+命名似乎足够长。例如,货币。命名空间(包装器消息名称)。美元

  1. 使用前缀作为字段,因此,如果冲突的字段名称为“未知”并且采用 CURRENCY,则它将是 CURRENCY。CURRENCY_UNKNOWN或类似的东西。
    • 优点:简单
    • 缺点 :与#1一样丑陋,与没有任何前缀的现有枚举字段命名不一致。

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

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

因此,它将选择不那么糟糕的解决方案而不是最佳解决方案,也许我们将在这一点上使用#2。有没有人有同样的经验,告诉我你的解决方案是什么,它是如何结束的?


答案 1

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

(FWIW,Cap'n Proto通过使用C++11枚举类来解决这个问题。protobufs不太可能这样做,因为它会破坏现有的代码。

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


答案 2