Perl:do和eval导致不同的答案?

时间:2011-01-24 07:25:08

标签: perl

我的文件中包含以下语句:

    {
        %{do '/tmp/personcontact.pl'},
        %{do '/tmp/address.pl'}
    }

现在,临时文件如下: Personcontact.pl:

            {
        'firstname' => {
            '__type' => 'String'
            },
        'lastname' =>  {
            '__type' => 'String'
            }
    }

Address.pl:

     {
        'address' => {
            'street' => {
                '__type' => 'String'
                },
            'unit' => {
                '__type' => 'String',
            },
            'suburb' => {
                '__type' => 'String'
            },
            '__type' => 'HASH'
        }
    }

现在,当我这样做时:

    open(SCHEMAFILE, "<", $schema) or return undef; 
my $schemafile;     
while(my $line = <SCHEMAFILE>) { $schemafile .= $line;}
my $tempref = eval $schemafile;
print Dumper $tempref;

结果为$VAR1 = '1/8'

当我这样做时:

    print Dumper do "/tmp/schemawithinschema.pl";

结果是

                    $VAR1 = 'firstname';
        $VAR2 = {
            '__type' => 'String'
            };
        $VAR3 = 'address';
        $VAR4 = {
            'suburb' => {
                    '__type' => 'String'
                },
            'unit' => {
                '__type' => 'String'
                },
            'street' => {
                    '__type' => 'String'
                },
            '__type' => 'ARRAY'
            };
        $VAR5 = 'lastname';
        $VAR6 = {
            '__type' => 'String'
            };

这里有什么问题?谢谢!

3 个答案:

答案 0 :(得分:9)

好的,为了防止这种情况永远存在,这里有一个基于模块的解决方案:

Foo.pm:

package Foo;

use strict;
use warnings;

BEGIN {
    require Exporter;
    our @ISA = qw( Exporter );
    our @EXPORT_OK = qw( get_person get_address get_all );
    our $VERSION = '0.01';
}

my %person = (
    firstname => {
        __type => 'String',
    },
    lastname => {
        __type => 'String',
    },
);

my %address = (
    address => {
        street => {
            __type => 'String',
        },
        unit => {
            __type => 'String',
        },
        suburb => {
            __type => 'String',
        },
        __type => 'HASH',
    },
);

sub get_person
{
    return \%person;
}

sub get_address
{
    return \%address;
}

sub get_all
{
    return( { %person, %address } );
}

1;

__END__

bar.pl:

#!/usr/bin/perl

use Data::Dumper;
use strict;
use warnings;
use lib '.';
use Foo qw( get_person get_address get_all );

my $junk = get_all();

print Dumper $junk;

真的,为了您的维护程序员(通常是您自己在6个月内),请使用JSONYAML(或更快YAML::XS) ,以便可以将数据维护为简单的文本文件,而不是一系列嵌套的数据伪装代码引用。

引用Perl Best Practices(不确定最初是否是Damian):

  

总是编码好像最终维护你的代码的人会是一个知道你住在哪里的暴力精神病患者。


编辑:为了完整性,以下是使用YAML(来自CPAN)的等效解决方案:

data.yml:

---
firstname:
  __type: String
lastname:
  __type: String
address:
  __type: HASH
  street:
    __type: String
  suburb:
    __type: String
  unit:
    __type: String

baz.pl:

#!/usr/bin/perl

use YAML qw( Load Dump LoadFile DumpFile );
use Data::Dumper;
use strict;
use warnings;

my $data = LoadFile( 'data.yml' );
print Dumper $data;

答案 1 :(得分:5)

虽然问题的目的让我哭泣,但两个代码段之间的区别与doeval以及与上下文无关。由于这是一个合法的Perl主题,我将简要回答它。

my $tempref = eval $schemafile;

eval发生在标量上下文中(由$tempref赋值)。但是,$schemafile包含由哈希引用解除引用运算符%{}创建的哈希。当该散列被评估为标量时,它会生成1/8,这是散列的正常行为。

print Dumper do "/tmp/schemawithinschema.pl";

do发生在Dumper调用强加的列表上下文中(后者又位于print的列表上下文中)。 do创建了eval所做的相同哈希,但现在它正在列表上下文中进行评估,实际上是Dumper的参数列表。顶级哈希变为扁平化为Label => HashRef对的列表,但这还不足以阻止Dumper向您显示与您尝试创建的哈希很相似的内容。< / p>

为了将来参考,在尝试确定行为的奇怪差异以在两种情况下呈现完全相同的调用时,它是有帮助的。两个测试用例之间的变量越多,你不期望重要的事情就会越多,这会让你感到困惑和迷惑。

所有这些都说明了“这里有什么问题?”的真正答案。仍然是“试着做到这一点。”。

答案 2 :(得分:4)

一个小指针。当你在标量上下文中评估哈希时,你得到的是“1/8”。 8是分配给散列的桶数,1是正在使用的桶数。

它通常是无用的,除了作为你正在做错事的旗帜。