ProtoBuf消息上的SerializeToString()方法包含必需的字段,这些字段具有默认值,始终抛出EncodeError
,指出消息缺少那些必需字段。但是,如果我检查字段的值,则会设置所有默认值。例如:
// mymessage.proto
message MyMessage {
required int32 val = 1 [default=18];
}
然后在python:
from mymessage_pb2.py import MyMessage
m = MyMessage()
print m.val # Shows m.val == 18
print m.SerializeToString() # EncodeError
另一方面,如果我这样做:
m.val = m.val
print m.SerializeToString() # No Error
很明显,尽管初始化时有默认值,但它只需要触摸每个字段。对我来说,默认的一个主要观点是只需要有人来更新非默认字段(或者他们需要更改的那些字段),所以这个set-it-to-own方法是一个非常令人遗憾的解决方案。
将字段标记为optional
不是解决方案,因为根据我们的规范,这些字段是合法要求的。
更新:我尝试合作包括MergeFrom和CopyFrom,但都没有奏效。所以我写了这个:
def ActuallyInit(obj):
err = []
obj.IsInitialized(err)
for field in err:
attr = obj.__getattribute__(field)
try:
obj.__setattr__(field, attr)
except:
ActuallyInit(attr)
然后创建一个protobuf对象并将其传递给ActuallyInit
,它以递归方式将每个字段设置为自身。这看起来像是一个丑陋的黑客,所以我将问题留在下面。
问题:有没有办法创建ProtoBuf消息实例并且"说服"它每个已经初始化为默认的字段实际上都不是错误吗?
答案 0 :(得分:7)
这是按预期工作的。 required
表示“作者必须明确填写此字段,而不是使用默认值”。如果您想要允许编写者使用其默认值离开该字段的字段,那么您需要optional
。这实际上是required
和optional
之间的唯一差异,因此没有理由将required
与默认值一起使用。可以说,如果使用默认值定义required
字段,Protobuf编译器应该引发错误,但我当时认为没有实现该限制。
(FWIW,required
一直被视为a misfeature,已在Protobuf v3中删除。)