包括Perl中哈希的哈希

时间:2011-01-24 04:29:37

标签: perl perl-data-structures hash

G'Day,

我正在努力从很多小哈希创造大哈希。假设这些较小的哈希值在每个文件中定义,然后可以包含在较大的哈希值中。

例如,让我们看一些小哈希

档案personcontact.pl

   return {
            \'firstname\' => {
                \'__type\' => \'String\'
            },
        \'lastname\' =>  {
            \'__type\' => \'String\'
            },
        %{include("/tmp/address.pl")}
    }

档案address.pl

return {
        \'address\' => {
        \'street\' => {
            \'__type\' => \'String\'
            },
        \'unit\' => {
            \'__type\' => \'String\',
            \'__validation_function\' => {
                \'is_a_number\' => \'\'
            },
            \'__schema_constraints\' => {
                \'is_not_null\' => \'\'
            }
        },
        \'suburb\' => {
            \'__type\' => \'String\'
        },
        \'__type\' => \'ARRAY\'
        }
    } 

我有相当多的这些......

我尝试重新创建哈希的方法是使用include子例程,如下所示:

 sub include {
my ($filename) = @_;
my $file; 
open(my $fh, "<", $filename) or die ("FILEOPEN: $!");
while(my $line = <$fh>) { $file .= $line; }
my $result = eval $file;
die("EVAL: $@") if $@;
close($fh) or die("FILECLOSE: $!");
return $result;
 }

我知道我一定做错了什么,但我不确定是什么。我一直收到Useless use of a variable in void context at (eval 11) line 4, <SCHEMAFILE> line 6Odd number of elements in anonymous hash at (eval 11) line 5, <SCHEMAFILE> line 6等错误。我不知道怎么去寻找(eval 11)第4-3行,第6行。任何有关使用Perl调试器的建议或任何关于我可能出错的指示都将非常感激。

谢谢!

1 个答案:

答案 0 :(得分:11)

欢迎来到Perl。我希望你有一个愉快的学习和使用它。

开始营业,从哪里开始?我在这里有很多话要说。

首先,通过评估文件加载数据会带来不必要的风险。如果您只想序列化数据,请尝试JSON::XSYAML,甚至是Storable。如果您需要配置文件,CPAN上有许多模块可以帮助完成此任务。查看Config::Any

如果要创建要通过eval加载的数据结构(这不是一个好主意),Data::Dumper会生成创建任何数据结构所需的perl代码。我提到它的主要原因是它作为调试辅助工具比串行器更有用。

现在 被处理了,如果你想加载一个文件并对其进行评估(再次,几乎不是每个案例中最好的想法),你应该看{{3} }或do

my $stuff = do 'address.pl';

但不要这样做。字符串require是一种通常最好不使用的工具。 99%的情况下,如果您计划使用字符串评估,请停止并考虑另一种方法来解决问题。 Do是一个隐含的eval,所以它也很重要。

Perl为您提供了许多工具来进行冒险和强大的魔法。成为熟练的Perl编程的很大一部分在于理解什么是有风险的东西,为什么以及何时使用它们是有意义的。不要指望Perl用栅栏和大门来保护你,以保证你的安全。认真考虑选择evalEffective Perl Programming的副本。作为一个新手,当你第一次阅读时,很多东西会超过你的头脑,但是随着你的成长和学习,这两本书都可以成为一个很好的参考。

接下来的主题,您想要通过所有那些转义报价实现什么?看着那些东西让我头疼! Perl有Perl Best Practices,您可以使用它来避免在文字字符串中转义引号。

=>或胖逗号自动引用其左侧(LHS),就像它只是字母数字一样。但是把所有的引用和逃脱都让事情变得非常狡猾。

当您说\'address\' => {}时,Perl将此视为\,将“get reference”运算符应用于字符串文字。在这种情况下,一个未终止的字符串文字,因为你从未在第一个之后提供未转义的'

如果你的目标是使用'address',引号和all作为哈希键,你可以这样做:

my %foo = ( "'address'" => 'blah' );

如果您不想要引号,这似乎是一个更常见的用例,只需执行:

my %foo = ( address => 'blah' );

关于您收到的错误消息!一旦你了解了它们的意思,Perl就会有一些非常好的错误消息。在那之前,理解它们的重要性可能有点困难。幸运的是,Perl附带了一个名为splain的脚本:一个方便的花花公子工具,可以更详细地解释错误消息。您还可以使用some very, very nice quoting operators模块自动获取相同的扩展错误消息。

现在,如果我写这篇文章,我会按照以下方式做点什么:

gen_schema_files.pl - 用于编写JSON模式文件的文件。如果您愿意,可以手动编辑您的模式。如果要提高可读性,可能还需要将输出配置为更漂亮。

#!/usr/bin/perl

use JSON::XS;
use File::Spec;

use constant BASEDIR => '.';

# Key is the file name, value is the data to put into the file.
my %schemata = (
    'address.json' => {
        address => {
            street => { __type => 'String' },
            unit => {
                __type => 'String',
                __validation_function => { is_a_number => '' },
                __schema_constraints  => { is_not_null => ''  }
            },
            suburb => { __type => 'String' },
            __type => 'ARRAY'
        },
    },

    'person_contact.json' => {
         firstname => { __type => 'String' },
         lastname =>  { __type => 'String' },

         # Use a special key to indicate that additional files should be 
         # loaded into this hash.
         INCLUDE  => [qw( address.json )], 
     },

     # And so forth
);

for my $schema ( keys %schemata ) {
    my $path = File::Spec->catfile( BASEDIR, $schema );

    open my $fh, '>', $path
        or die "Error opening '$path' for writing - $!\n";

    print $fh encode_json $schemata{$schema};
}

load_schemas.pl - 这是加载模式并执行操作的代码。我只会装满。我不知道你在做什么数据...

#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;

use JSON::XS;
use File::Spec;

use constant BASEDIR => '.';


my $schema = load_schema( 'person_contact.json' );

print Dumper $schema;


sub load_schema {
    my $file = shift;

    my $path = File::Spec->catfile( BASEDIR, $file );

    open my $fh, '<', $path
        or die "Error opening file '$path' - $!\n";

    my $json = join '', <$fh>; # reads a list of lines and cats them into one string.
                               # One way to slurp out of many.

    my $schema = decode_json( $json );

    # Handle the inclusion stuff:

    if( exists $schema->{INCLUDE} ) {
        # Copy the files to load into an array.
        my @loadme = @{$schema->{INCLUDE}};
        # delete the magic special include key.
        delete $schema->{INCLUDE};

        # Load each file and copy it into the schema hash.
        for my $load ( @loadme ) {
            my $loaded = load_schema( $load );

            # This is a bit of weird syntax.
            # We are using a hash slice assignment to copy the loaded data into the existing hash.
            # keys and values are guaranteed to come out in the same (random) order as each other.
            # the @{$foo}{blahbhal} is how you dereference a hash reference as a slice.
            @{$schema}{keys %$loaded} = values %$loaded;
        }
    }

    return $schema;
}

我已经掩盖了一些事情,但我试图用足够的术语(词汇或甚至行话,如果你愿意)留下评论,以允许你进行有利可图的搜索。

上面的代码有几个缺陷。它不会检查圆形内含物(它会运行很长时间并最终填满内存并崩溃 - 不太好)。魔术键的选择可能不太好。而且我可能还有更多想法。

Perldoc是一个令人惊叹的资源,但有很多东西需要一段时间来学习找东西。请查看diagnosticsPerl Data Structures Cookbook。作为初学者,我发现Arrays of Arrays tutorial非常有帮助。

我想我会停下来,因为我已经写了足够的文字来瞎了普通人。我希望你发现这篇论文很有帮助。欢迎,再次,晚上好(请根据当地时间调整,当你找到这个回复时)。