序列化时 Protobuf 默认与 "missing required fields"
Protobuf defaults vs. "missing required fields" when serializing
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
很明显,尽管在初始化时有默认值,但它只需要触及每个字段。对我来说,拥有默认值的要点之一是只需要有人更新非默认字段(或他们需要更改的那些字段),因此这种自行设置的方法是一个非常遗憾的解决方案。
将字段标记为 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
,后者递归地将每个字段设置为自身。这似乎是一个丑陋的 hack,所以我将打开下面的问题。
问题:有没有办法创建 ProtoBuf 消息实例并且"convince"每个已经初始化为默认的字段实际上不是一个错误?
这是按预期工作的。 required
表示 "the writer must explicitly fill in this field, not use the default"。如果您想要一个允许作者保留其默认值的字段,那么您需要 optional
。这实际上是 required
和 optional
之间的 仅 区别,因此根本没有理由将 required
与默认值一起使用。可以说,如果 required
字段定义了默认值,Protobuf 编译器应该会引发错误,但我当时并没有考虑实施该限制。
(FWIW,required
长期以来一直被认为 a misfeature 并已在 Protobuf v3 中删除。)
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
很明显,尽管在初始化时有默认值,但它只需要触及每个字段。对我来说,拥有默认值的要点之一是只需要有人更新非默认字段(或他们需要更改的那些字段),因此这种自行设置的方法是一个非常遗憾的解决方案。
将字段标记为 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
,后者递归地将每个字段设置为自身。这似乎是一个丑陋的 hack,所以我将打开下面的问题。
问题:有没有办法创建 ProtoBuf 消息实例并且"convince"每个已经初始化为默认的字段实际上不是一个错误?
这是按预期工作的。 required
表示 "the writer must explicitly fill in this field, not use the default"。如果您想要一个允许作者保留其默认值的字段,那么您需要 optional
。这实际上是 required
和 optional
之间的 仅 区别,因此根本没有理由将 required
与默认值一起使用。可以说,如果 required
字段定义了默认值,Protobuf 编译器应该会引发错误,但我当时并没有考虑实施该限制。
(FWIW,required
长期以来一直被认为 a misfeature 并已在 Protobuf v3 中删除。)