【问题标题】:How to send boolean value from perl script without converting them into string如何从 perl 脚本发送布尔值而不将它们转换为字符串
【发布时间】:2017-10-07 15:08:48
【问题描述】:

我将一个 Perl 数据结构传递给encode_json,并使用它的返回值作为输入以发布到 RESTful API。

例子:

$data = (input1 => true);
$json_data = encode_json($data);
print $json_data; // Prints: ["input1":"true"]

$url= http://api.example.com/resources/getDataAPI
$headers = {Accept => 'application/json', Authorization => 'Basic ' . encode_base64($username . ':' . $password)};

$client = REST::Client->new();
$client->POST($url,($json_data,$headers));

一切正常。

最近另一位开发人员很少进行输入参数验证检查,REST 严格接受布尔值,不带引号。

我现在需要将我的输入发送为

$data = '["inout1":true]'
$client = REST::Client->new();
$client->POST($url,($data,$headers));

我的所有脚本都失败了,因为使用encode_json 函数将输入数据编码为 JSON 格式。

我可以手动形成 JSON 数据,但输入数据有时会非常庞大​​。无法识别它们并随时修改。

有没有什么方法可以实现不带引号的布尔值传递?

【问题讨论】:

标签: json perl boolean


【解决方案1】:

在 Perl 中直接使用 true 和 false 在 use strict 下会出现语法错误,因为 barewords 是不允许的。

我猜你正在使用JSON 或JSON::XS。那些使用标量引用来表示TRUE 和FALSE。具体来说,\1 和 \0。

$data = ( input1 => \1 );

这里是相关的doc from JSON::XS,它也允许Types::Serializer::True 和Types::Serializer::False:

Types::Serializer 模块中的这些特殊值分别成为 JSON true 和 JSON false 值。如果需要,您也可以直接使用\1 和\0。

还有the doc from JSON,其中JSON::true和JSON::false也可以使用:

这些特殊值分别成为 JSON true 和 JSON false 值。如果需要,您也可以直接使用\1 和\0。


如果您坚持使用不带引号的true,如my $foo = true,您可以创建返回\1 和\0 的子类或常量(实际上是子类)。

use constant false => \0;
sub true () { return \1 } # note the empty prototype

$data = ( input1 => true, input2 => false );

作为Sinan points out in his comment,使用常量会更快,除非您包含一个空原型(子定义中的()),因为这样Perl 可以内联调用。

但在我看来,这不如简单地使用参考文献那么清楚。始终考虑下一个编写此代码的人。

【讨论】:

  • use constant false 创建一个可以内联的子例程,每次都会调用sub true。只要在使用它的代码之前看到原型,就相当于sub true () { \1 }。
  • 谢谢。我不知道。
  • @Borodin 哪个部分?思南说什么,还是我说什么?我也不知道内联(这是一个词吗?!)的事情。现在试试看。
  • 关于内联的事情记录在Constant Functions in perlsub 下,我的意思是关于 JSON 布尔值的引用。我一直用JSON::true和JSON;;false。
  • 我将排在第二位 @Borodin,因为 JSON::true 和 JSON::false 比 \0 和 \1 对代码的未来读者更有帮助。
【解决方案2】:

与simbabque 的答案相反,我真的不认为使用引用作为\1 和\0 在JSON 中生成true 和false 是一个好主意。

JSON module 中的常量不仅仅是为了方便。

如果您使用此类常量,您仍然可以在 Perl 中将它们评估为 true 或 false 值,而在 Perl 中 \0 和 \1 都被评估为 true。

使用这些常量,除了在 Perl 中保留布尔值外,还可以在 JSON 中工作以生成正确的数据。

这是我所说的一个例子:

use 5.010;
use strict;
use warnings;
use JSON qw(encode_json decode_json);

my $data = {
    true_1 => JSON::true,
    true_2 => \1,
    false_1 => JSON::false,
    false_2 => \0,
};

for my $key (sort keys %$data) {
    say "$key value is $data->{$key} and is evaluated as true" if $data->{$key};
    say "$key value is $data->{$key} and is evaluated as false" if not $data->{$key};
}

say encode_json $data;

该代码将输出如下内容:

false_1 value is 0 and is evaluated as false
false_2 value is SCALAR(0x146f39b4c18) and is evaluated as true

true_1 value is 1 and is evaluated as true
true_2 value is SCALAR(0x146f3998918) and is evaluated as true

{"true_2":true,"false_1":false,"false_2":false,"true_1":true}

如您所见,引用 \0 (false_2) 的值在 Perl 中被评估为 true,而设置为 JSON::false 的值仍然是false 在 Perl 评估中。

另外,你可以看到,当打印JSON::true和JSON::false的值时,它们会自动转换为1和0,而\1和\0打印为SCALAR(0x146f3998918)和SCALAR(0x146f39b4c18)。

最后,当转换为JSON 时,两者都能正常工作。但是在 Perl 数据结构中设置应该为假的“真”值(0、空字符串或undef),可能会导致代码的其他部分出现错误,您可能会使用相同的结构和评估布尔字段来做某事。

此外,在开发级别,同行开发人员在使用 JSON::true 和 JSON::false 时更容易理解您正在编码的内容,而不是看到参考为 \1 和 \0 而无法理解如果他/她不熟悉这种 hacky 技巧,那么参考的原因。

如果您真的不想输入额外的 6 个字符,那么您可以在代码顶部执行此操作:

use JSON qw(encode_json decode_json);
sub true () { JSON::true }
sub false () { JSON::false }

然后您可以简单地将它们用作代码中的常量,如下所示:

$data = {
    is_member => true,
    is_suspended => false,
}

虽然,也许常量名称应该全部大写(如TRUE 和FALSE),但这是另一个讨论的主题。

因此,在使用 Perl 和 JSON 时,请始终使用 JSON::true 和 JSON::false。它们将在 Perl 中很好地评估,它们被转换为 JSON 中的正确数据类型,并且它们正确地打印到控制台和文件。 JSON::null 也是如此。

【讨论】:

    猜你喜欢
    • 2012-07-05
    • 2011-02-17
    • 2012-04-02
    • 2021-02-23
    • 1970-01-01
    • 1970-01-01
    • 2018-09-07
    • 1970-01-01
    相关资源
    最近更新 更多