在下面的代码中,我有一个绑定到哈希的类。在FETCH
函数中,我正在打印密钥的JSON
编码:
package Example::Tie;
use JSON;
my $json = JSON->new();
sub TIEHASH {
my ($pkg,@list) = @_;
bless { @list }, $pkg;
}
sub FETCH {
my ($tied,$key) = @_;
return $json->encode({key => $key});
}
package Example;
sub new {
my ($pkg,@list) = @_;
my $self = {};
tie %$self, 'Example::Tie', @list;
bless $self, $pkg;
}
package main;
my $exp = Example->new();
print($exp->{0} . "\n");
我得到以下输出:
{"key":"0"}
这导致0
被编码为字符串。有没有办法将它编码成数字呢?
print($exp->{0} . "\n"); # this should print {"key":0}
print($exp->{'0'} . "\n"); # this should print {"key":"0"}
答案 0 :(得分:5)
由于Perl中没有字符串或数字的真实概念,只有标量,这很棘手。 JSON module tries通过查看它编码的值的最后一个上下文来实现它。
Simple Perl标量(任何不是引用的标量)是最难编码的对象:此模块将未定义的标量编码为JSON空值,最后在编码为JSON字符串之前在字符串上下文中使用的标量,以及其他任何数字值:
# dump as number encode_json [2] # yields [2] encode_json [-3.0e17] # yields [-3e+17] my $value = 5; encode_json [$value] # yields [5] # used as string, so dump as string print $value; encode_json [$value] # yields ["5"] # undef becomes null encode_json [undef] # yields [null]
FETCH
中的代码不具体执行此操作。所以它必须在其他地方。
我的猜测是,Perl自动引用哈希键是罪魁祸首。
$exp->{0}; # this should print {"key":0}
$exp->{'0'}; # this should print {"key":"0"}
这两个表达式是等价的。 Perl会自动将{}
内部的哈希(ref)元素中的内容视为引用,并且它们成为字符串。因为这很容易被遗忘,there is best practice总是使用单引号''
。
Perldata says(强调我的):
哈希是由关联的字符串键索引的标量值的无序集合。
这个想法是没有哈希的数字键。如果有数字键,可以订购,然后你有一个数组。
您可以直接使用不带引号的号码FETCH
作为arg来进一步证明。
Example::Tie->FETCH(1);
这将导致
{"key":1}
因此,我得出结论,将tie
与JSON模块一起使用是不可能的,除非您明确尝试将其强制转换为数字。 JSON模块的文档中有一个示例。
您可以通过编号强制类型为数字:
my $x = "3"; # some variable containing a string $x += 0; # numify it, ensuring it will be dumped as a number $x *= 1; # same thing, the choice is yours.
答案 1 :(得分:5)
基本上,@simbabque's answer是正确的。当您的FETCH
获取参数列表时,0
中的$exp->{0}
已经被字符串化,因为哈希键始终是字符串。
当然,如果你向每个参数添加0
以便不加选择地获取,你将会遇到问题。下面,我使用Scalar::Util::looks_like_number来区分数字和字符串,但是,当然,如果您使用"0"
进行尝试,这将无效。这也将转换为0
。
use strict; use warnings;
package Example::Tie;
use JSON;
use Scalar::Util qw( looks_like_number );
my $json = JSON->new;
sub TIEHASH {
my $pkg = shift;
bless { @_ } => $pkg;
}
sub FETCH {
my $tied = shift;
$json->encode({key => looks_like_number($_[0]) ? 0 + $_[0] : $_[0]})
}
package Example;
sub new {
my $pkg = shift;
my $self = {};
tie %$self, 'Example::Tie', @_;
bless $self => $pkg;
}
package main;
my $exp = Example->new;
print "$_\n" for map $exp->{$_}, 0, 'a';