你好!每个人,我都有与此类似的问题:
当列表具有“可选”修饰符时,节俭的C ++服务器将始终将其返回为null / undef。
另外,如果一个可选列表包含的结构,则该结构的任何字段都不能设置为“可选”,否则将返回null / undef值。
删除所有“可选”修饰符后,一切正常。
有人可以告诉我为什么我不能在列表前使用“可选”吗?
这是旧文件:
namespace cpp thrifttest
namespace perl thrifttest
struct Pair {
1: optional string a,
2: optional string b
}
struct Result {
1: optional list<string> strList,
2: optional list<Pair> pairList
}
service Test {
Result listTest()
}
这是C ++代码(服务器):
#include "gen-cpp/Test.h"
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>
#include <iostream>
using namespace std;
using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using boost::shared_ptr;
using namespace ::thrifttest;
class TestHandler : virtual public TestIf {
public:
TestHandler() {
// Your initialization goes here
}
void listTest(Result& _return) {
_return.strList.push_back("Test");
_return.strList.push_back("one level list");
cout << "strList size: " << _return.strList.size() << endl;
Pair pair;
pair.a = "Test";
pair.b = "two level list";
_return.pairList.push_back(pair);
cout << "pairList size: " << _return.pairList.size() << endl;
printf("call listTest\n");
}
};
int main(int argc, char **argv) {
int port = 9595;
shared_ptr<TestHandler> handler(new TestHandler());
shared_ptr<TProcessor> processor(new TestProcessor(handler));
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
server.serve();
return 0;
}
这是perl代码(客户端):
#!/usr/bin/perl
use v5.12;
use warnings;
use autodie;
use utf8;
use Data::Dumper;
use lib 'gen-perl';
use thrifttest::Test;
use thrifttest::Constants;
use thrifttest::Types;
use Thrift;
use Thrift::BinaryProtocol;
use Thrift::Socket;
use Thrift::BufferedTransport;
my $socket = new Thrift::Socket('localhost', 9595);
my $transport = new Thrift::BufferedTransport($socket, 1024, 1024);
my $protocol = new Thrift::BinaryProtocol($transport);
my $client = new thrifttest::TestClient($protocol);
eval {
$transport->open();
my $result = $client->listTest;
say Dumper($result);
$transport->close();
};
say $@ if $@;
C ++服务器输出:
strList size: 2
pairList size: 1
call listTest
perl客户端输出:
$VAR1 = bless( {
'pairList' => undef,
'strList' => undef
}, 'thrifttest::Result' );
PS:我的开发环境是CentOS 7,GCC 4.8.3,Perl 5.16,旧版0.9.3
我错了,这不是一个真正的错误,它只是一些不幸的设计,并不是真正的傻瓜,而是允许用户制作Dumb Things™。问题在于optional
运算符的语义以及如何在C ++中实现它。
假设我们有这个IDL:
struct Xtruct2
{
1: i8 byte_thing,
2: Xtruct struct_thing,
3: i32 i32_thing
}
生成的代码(尤其是write()
方法)如下所示:
uint32_t Xtruct2::write(::apache::thrift::protocol::TProtocol* oprot) const {
//...
xfer += oprot->writeFieldBegin("struct_thing", ::apache::thrift::protocol::T_STRUCT, 2);
xfer += this->struct_thing.write(oprot);
xfer += oprot->writeFieldEnd();
//...
}
如果现在修改IDL并添加说明optional
符:
struct Xtruct2
{
1: i8 byte_thing,
2: optional Xtruct struct_thing,
3: i32 i32_thing
}
生成的代码看起来略有不同:
uint32_t Xtruct2::write(::apache::thrift::protocol::TProtocol* oprot) const {
//...
if (this->__isset.struct_thing) {
xfer += oprot->writeFieldBegin("struct_thing", ::apache::thrift::protocol::T_STRUCT, 2);
xfer += this->struct_thing.write(oprot);
xfer += oprot->writeFieldEnd();
}
//...
}
节俭有三种requiredness的:required
,optional
和默认。如果required
未optional
指定或未指定,则隐式假定使用后者(这就是为什么默认需求没有特殊关键字的原因)。相对于读写这些字段的语义如下:
requiredness write field? read field?
----------------------------------------------------------------------
required always always, must be present
(default) always if present, may be missing
optional only if set if present, may be missing
因此optional
,与默认值相比,更改的是写方法的行为。虽然始终写入默认字段,但optional
仅有条件地写入字段。可以通过__isset
标志来检查该标志,该标志由一个位集组成,每个字段的位数不为1 required
。如果设置了其中的相应位标志__isset
,则可以使用字段值。如果位标志不存在,则字段值尚未初始化,因此不应使用。
到目前为止,这并不是什么大问题。但是有一个陷阱optional
可以解决:默认值和字段可以在C ++中访问和使用,即使未设置位标志(因为它们就在那里)也是如此。在默认情况下,这没什么大不了的:您分配您的值,并且由于始终写入字段,因此基本上不会发生任何不良情况。反序列化字段时,将设置该字段的位标志(请参见生成的代码)。
但是,当您选择加入时,情况发生了变化optional
:现在突然之间,您有责任通过__isset
直接访问或通过生成的setter方法(在我们的情况下为:)正确设置标志。
void Xtruct2::__set_struct_thing(const Xtruct& val) {
this->struct_thing = val;
__isset.struct_thing = true;
}
我的假设是,应该不可能访问尚未设置的可选字段,但事实证明,这似乎是设计使然。我仍然认为设计在这里容易出错。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句