在下面的代码中,我有一个绑定到哈希的类.在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");
Run Code Online (Sandbox Code Playgroud)
我得到以下输出:
{"key":"0"}
Run Code Online (Sandbox Code Playgroud)
这导致0被编码为字符串.有没有办法将其编码为数字?
print($exp->{0} . "\n"); # this should print {"key":0}
print($exp->{'0'} . "\n"); # this should print {"key":"0"}
Run Code Online (Sandbox Code Playgroud)
由于Perl中没有字符串或数字的真实概念,只有标量,这很棘手.该JSON模块试图通过看最后的背景下,编码值是用来做什么的.
简单的Perl标量(任何不是引用的标量)是最难编码的对象:此模块将未定义的标量编码为JSON空值,最后在编码为JSON字符串之前在字符串上下文中使用的标量,以及其他任何内容作为数值:
Run Code Online (Sandbox Code Playgroud)# 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"}
Run Code Online (Sandbox Code Playgroud)
这两个表达式是等价的.Perl会自动将{}for hash(ref)元素内部的内容视为引用,并将它们变为字符串.因为这很容易被遗忘,所以最好总是使用单引号''.
Perldata说(强调我的):
散列是由其关联的字符串键索引的标量值的无序集合.
这个想法是没有哈希的数字键.如果有数字键,可以订购,然后你有一个数组.
您可以通过FETCH直接使用未加引号的数字作为arg 来进一步证明.
Example::Tie->FETCH(1);
Run Code Online (Sandbox Code Playgroud)
这将导致
{"key":1}
Run Code Online (Sandbox Code Playgroud)
因此,我得出结论,使用tieJSON模块无法实现您想要做的事情,除非您明确地尝试将其强制转换为数字.JSON模块的文档中有一个示例.
您可以通过编号强制类型为数字:
Run Code Online (Sandbox Code Playgroud)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.
基本上,@ simbabque的答案很明显.到那时,你FETCH得到参数列表,0in $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';
Run Code Online (Sandbox Code Playgroud)