在Perl中使用未知方法

时间:2013-06-08 20:32:27

标签: perl prototype

我无法理解,为什么Perl会在像这样的程序中用花括号执行代码:

unknown_method {
    # some code
};

我的节目:

文件Transaction.pm:

package Transaction;
use strict;
use warnings;
use feature qw/ say /;

sub transaction(&) {
    say 'BEGIN TRANSACTION';
    eval {
        shift->()
    };
    if ( $@ ) {
        say 'ROLLBACK TRANSACTION';
        die($@);  # reraise error
    } else {
        say 'COMMIT TRANSACTION';
    }
}
1;

文件run_properly.pl:

use feature qw/ say /;
use Transaction;
eval {
    Transaction::transaction {
        say "insert some data to DB";
        die("KnownException")
    }
};
warn $@;

文件run_wrong.pl:

use feature qw/ say /;
# I forgot to import Transaction
eval {
    Transaction::transaction {
        say "insert some data to DB";
        die("KnownException")
    }
};
warn $@;

执行:

$ perl run_properly.pl 
BEGIN TRANSACTION
insert some data to DB
ROLLBACK TRANSACTION
KnownException at run_properly.pl line 6.

$ perl run_wrong.pl 
insert some data to DB
KnownException at run_wrong.pl line 6.

为什么Perl允许这样的事情?

3 个答案:

答案 0 :(得分:9)

Perl语法灵活,通常有多种语法可以做。例如,调用方法。这是常规和推荐的语法:

  Foo  ->  new       (1, 2, 3);
# ^-object ^- method ^- arguments

这是间接语法:

  new       Foo       1, 2, 3;
# ^- method ^- object ^- arguments, parens are optional

这一切都很好,但是当我们想要将复杂计算的结果用作间接对象表示法的对象时会发生什么?

# set up some constructors for demonstration purposes
*Foo::new = *Bar::new = sub {say "@_"};

# This obviously fails
# new (rand > .5 ? "Foo" : "Bar") 1, 2, 3;

解决方案是 dative块

new {rand > .5 ? "Foo" : "Bar"} 1, 2, 3;

您可能已经知道文件句柄中的dative块:print {$handles[-1]} $_

在方法解析之前执行dative块,因为方法解析通常(但不是在你的情况下)取决于对象的类型。但是,如果阻止die s。

,则不会解决任何方法

间接表示法对构造函数来说仍然很流行,因为它使Perl看起来像C ++。但是,Perl(与C ++不同)没有new 运算符:它只是一种常规方法。这种灵活性可能是一个坏主意,所以如果您对此有强烈的感觉,可以使用no indirect来“修复”它。

答案 1 :(得分:1)

它首先执行块(因为它必须将结果传递给Transaction::transaction)。由于您在该区块内die,因此它永远不会到达Transaction::transaction

答案 2 :(得分:1)

当你有这样的调用时:

 name { ... } etc.

如果name是一个内置函数,它将BLOCK作为其参数或带有&原型的预先声明的子例程,则BLOCK(即{ ... })不会被评估,而是按原样传递到name

  • e.g。 grep { $_ > 9000 } @levels
  • 这适用于run_properly.pl案例

否则(例如,没有原型或不存在的子例程的预先声明的子例程),评估BLOCK,然后Perl查找名为name的子例程/方法,并将评估结果作为参数传递给name (如果未定义name,则引发错误。)

  • 这适用于run_wrong.pl案例
  • 如果您想阻止在这种情况下评估BLOCK,则可以使用sub { ... }而不是{ ... }