Perl eval Data :: Dumper不一致

时间:2016-03-28 11:19:39

标签: perl serialization deserialization eval data-dumper

我必须在Perl中序列化和反序列化。我知道Data::Dumpereval不适合这项工作,但我不允许在我正在处理的遗留脚本中修改此方面。
以下是使用eval的两种方式( CODE 1 CODE 2 )。
CODE 1 中,哈希在通过eval反序列化之前以字符串形式提供。
CODE 2 中,在通过Dumper反序列化之前,使用eval对哈希进行序列化。

在两个代码示例中,两种尝试反序列化工作的方法之一。为什么反序列化的其他方式不起作用?

代码1

my $r2 = "( 
'w' => {
           'k2' => 5,
           'k1' => 'key',
           'k3' => [
                     'a',
                     'b',
                     2,
                     '3'
                   ]
         },
  'q' => 2 
)"; 

my %z; 
eval "\%z = $r2";          ####### Works. 
print "\%z = [".Data::Dumper::Dumper (\%z)."] "; 

my $answer = eval "$r2";   #### Does NOT work. 
print "\n\nEvaled = [".Dumper($answer)."] "; 

输出

%z = [$VAR1 = {
          'w' => {
                   'k2' => 5,
                   'k1' => 'key',
                   'k3' => [
                             'a',
                             'b',
                             2,
                             '3'
                           ]
                 },
          'q' => 2
        };
]

Evaled = [$VAR1 = 2;
]

但是下面的代码以相反的方式工作:
代码2

my %a = ( "q" =>2, "w"=>{ "k1"=>"key", "k2"=>5, k3=>["a", "b", 2, "3",], }, );  **# Same hash as above example.** 
$Data::Dumper::Terse=1; 
$Data::Dumper::Purity = 1; 
my $r2 = Dumper(\%a); 

my %z; 
eval '\%z = $r2'; 
print "\n\n\%z = [".Dumper(\%z)."] ";         #### Does NOT work. 

my $answer = eval $r2; 
print "\n\nEvaled = [".Dumper($answer)."] ";  ####### Works.

输出

%z = [$VAR1 = {};
]

Evaled = [$VAR1 = {
          'w' => {
                   'k2' => 5,
                   'k1' => 'key',
                   'k3' => [
                             'a',
                             'b',
                             2,
                             '3'
                           ]
                 },
          'q' => 2
        };
]

2 个答案:

答案 0 :(得分:2)

首先,请不要放置导致语法错误的注释(**)。

请注意,您在第一个代码块中提供的字符串产生的数据结构与Dumper函数不同。在第一个块中,您创建了一个哈希,但是您没有将它分配给任何变量。如果是Dumper函数,则会创建匿名哈希,并将其引用传递给$VAR变量。

要使第一个代码生效,您应该将(替换为{以创建匿名哈希,然后将其分配给变量,例如:

my $r2 = "$VAR = { 
    'w' => {
           'k2' => 5,
           'k1' => 'key',
           'k3' => [
                     'a',
                     'b',
                     2,
                     '3'
                   ]
         },
  'q' => 2 
}"; 

答案 1 :(得分:1)

不要使用Data :: Dumper来序列化数据。说完了......

这是标量和列表上下文的问题。在第二个评估中,您有:

my $answer = ...;

由于您要分配标量,因此在标量上下文中评估右侧。这意味着eval处于标量上下文中。该值是:

(
'w' => {
           'k2' => 5,
           'k1' => 'key',
           'k3' => [
                     'a',
                     'b',
                     2,
                     '3'
                   ]
         },
  'q' => 2
)

这看起来像一个列表,但它实际上是标量上下文中的逗号运算符。评估左侧,丢弃结果,并返回右侧。因此,my $x = ( 'left', 'right' )会将right分配给$xWhat is the difference between a list and an array?中的perlfaq4涵盖了这一点。

在您的问题中,您会看到$r获得值2。这是逗号链中最右边的值,因此这是您在标量上下文中获得的值。将其更改为其他值(可能是'duck'),这就是您将获得的值:

my $r2 = "(
    'w' => {
               'k2' => 5,
             },
      'q' => 'duck'
    )";

my $answer = eval "$r2";

use Data::Dumper;
print "Evaled =\n" . Dumper($answer);

这不是一个让人困惑的数字,因为他们认为这有点重要:

Evaled =
$VAR1 = 'duck';

将其更改为在列表上下文中分配(该哈希分配是列表分配),您将得到正确的答案:

my $r2 = "(
    'w' => {
               'k2' => 5,
             },
      'q' => 'duck'
    )";

my @answer = eval "$r2";

use Data::Dumper;
print "Evaled =\n" . Dumper(\@answer);

现在它是您认为应该是的数据结构:

Evaled =
$VAR1 = [
          'w',
          {
            'k2' => 5
          },
          'q',
          'duck'
        ];