在内联数据结构定义中嵌入代码

时间:2014-12-09 23:43:48

标签: perl reference

问题:
我有一个数据结构,类似于以下内容:

$foo = [
    {
        bar => "baz",
    },
];

我想在此数据结构中嵌入代码,将另一个hashref添加到foo列表中,以便最终结果如下:

$foo = [
    {
        bar => "baz",
    },
    {
        new => "new",
    },
];

可能的解决方案:

1:我最初的直觉是使用eval

$foo = [
    {
        bar => "baz",
    },
    eval { return {
        new => "new",
    }},
];

2: @Sputnik向我指出perlref。 "制作参考 - > 4"部分帮我提出了另一种可能的解决方案

$foo = [
    {
        bar => "baz",
    },
    &{ sub{ return {
        new => "new",
    }}},
];

问题:
    1.这两种解决方案是否相同?     2.如果它们不相同,每个的利弊是什么?     3.还有其他解决方案吗?     4.如果还有其他解决方案,与上述解决方案相比,它们的优点和缺点是什么?

2 个答案:

答案 0 :(得分:1)

Eval是邪恶的,好方法是:

push @{ $array_ref }, { new => "new" };

我认为您应该阅读有关参考的文档:

http://perldoc.perl.org/perlreftut.html
http://perldoc.perl.org/perlref.html

<强>样本

use strict; use warnings;

my $foo = [
    {
        bar => "baz",
    },
];

push @{ $foo }, { new => "new" };

use Data::Dumper;
print Dumper $foo;

<强>输出

$VAR1 = [
          {
            'bar' => 'baz'
          },
          {
            'new' => 'new'
          }
        ];

答案 1 :(得分:1)

这是do BLOCK的用途:

$foo = [
    {
        bar => "baz",
    },
    do {
        +{
            new => "new",
         },
    },
];

为了记录,解决方案之间的区别是:

  • do BLOCK只占用一个块并将其转换为表达式。它是最快/最便宜的解决方案,副作用最少。
  • eval BLOCK捕获块抛出的任何异常并抛弃它们。除非您之后要检查例外情况,否则通常不安全使用。
  • sub { CODE }->()是真正的代码参考;因此,它更昂贵(一个完整的函数调用与一个块),当然还有更多的代码。
  • &{sub { CODE }}()与上一项相同;它更昂贵,更难阅读。通常,像这样的堆叠嵌套分隔符往往需要花费更多精力才能解码。
  • &{sub { CODE }}是一个函数调用,但与前两个不同,它不会设置新的参数。相反,@_内的CODE仍设置为来电者的参数。如果你没有命名它们,你可以在表达式中访问你的参数,但最好避免它,因为&foo通常是一种非常危险的函数调用方式。

关于最后一点的详细说明:&foo看起来像是在没有参数的情况下调用foo。它不是。相反,它会调用foo,同时将@_别名留给来电者的参数。这意味着如果foo使用标准模式来解包其函数参数:

sub foo {
    my $arg1 = shift;
    my $arg2 = shift;
    ...
}

并且调用者通过@_访问其参数:

sub bar {
    print $_[0], "\n";
    &foo;
    print $_[0], "\n";
}

foo的调用会修改bar的参数,因此此函数会打印bar的第一个和第三个参数(假设{{ 1}}只有两个参数)。

所以永远不要使用foo来调用函数;它总是值得明确:

&foo

foo();

如果您希望 foo(\@_); 修改您的参数。