如何确定是否使用调用者在eval内调用子例程?

时间:2014-03-04 21:04:42

标签: perl

我还在学习Perl,我的任务是使用caller来确定是否从任何更高级别的eval调用子程序。我应该提出一些代码来测试这个并打印Yes,如果它来自evalNo,如果不是。{我找不到关于如何在网络上使用caller的任何好例子,并且想知道是否有人对如何做到这一点有任何想法或建议。

2 个答案:

答案 0 :(得分:5)

你不应该使用来电。请参阅perlvar

$EXCEPTIONS_BEING_CAUGHT
$^S
Current state of the interpreter.

    $^S         State
    ---------   -------------------------------------
    undef       Parsing module, eval, or main program
    true (1)    Executing an eval
    false (0)   Otherwise

The first state may happen in $SIG{__DIE__} and $SIG{__WARN__} handlers.
The English name $EXCEPTIONS_BEING_CAUGHT is slightly misleading, because the
undef value does not indicate whether exceptions are being caught, since 
compilation of the main program does not catch exceptions.

This variable was added in Perl 5.004.

至于原因:

C:\Users\user>perl -MBenchmark -E "timethese(20000000, {'caller' => sub {caller()}, '$^S' => sub {$^S}})"
Benchmark: timing 20000000 iterations of $^S, caller...
       $^S:  0 wallclock secs ( 0.11 usr +  0.00 sys =  0.11 CPU) @ 183486238.53/s (n=20000000)
            (warning: too few iterations for a reliable count)
    caller:  1 wallclock secs ( 0.87 usr +  0.00 sys =  0.87 CPU) @ 22909507.45/s (n=20000000)

这是在我们甚至通过调用堆栈上的多次迭代以及针对堆栈级别运行字符串函数来调低调用者代码之前,假设我们将为所有边缘情况编写无错代码等。

编写代码以使用调用者来确定这是核心功能的完整重新实现。这就像问“我如何使用标量实现链表?”答案应该是“使用数组”,而不是“这就是如何!”

答案 1 :(得分:2)

使用代码:

#!/usr/bin/perl -w

eval "test_eval();";

test_eval();

sub test_eval {
  my ($e,$v,$a,$l,) = caller(0);

  print "[$e], [$v], [$a], [$l]\n";
}

我得到输出

[main], [(eval 1)], [1], [main::test_eval]
[main], [test.pl], [21], [main::test_eval]

但如果我将其更改为使用caller(1),那么我会得到

[main], [test.pl], [19], [(eval)]
[], [], [], []

以及关于未初始化值的几个警告。

这应该为您提供一个起点。请注意,在此程序中忽略了索引3之后的数组中的值,因为它们似乎与手头的问题无关,而是返回the caller documentation以查明这些值是否有用。

编辑:

鉴于对另一个答案的讨论和内容,你可以提供这样一个厚颜无耻的解决方案:

sub func_under_eval {
  if (0) { # change this to 1 when the time is right
    return (defined($^S) and $^S>0)?"Yes":"No";
  }
  else {
    my @calls = caller(0);
    my $back = 1;
    while (defined($caller[0])) {
      if (index("(eval", $caller[1] . $caller[3])>-1)
        return "Yes";
      @calls = caller($back++);
    }
    return "No";
  }
}
相关问题