【问题标题】:Perl eval scopePerl 评估范围
【发布时间】:2021-10-13 17:29:54
【问题描述】:

根据 perldoc,String Eval 应该在当前范围内执行。但是下面这个简单的测试似乎与此相矛盾。

我们需要以下两个简单的文件来设置测试。请将它们放在同一个文件夹下。

test_eval_scope.pm

package test_eval_scope;

use strict;
use warnings;

my %h = (a=>'b');

sub f1 {
   eval 'print %h, "\n"';

   # print %h, "\n";   # this would work
   # my $dummy = \%h;  # adding this would also work
}

1

test_eval_scope.pl

#!/usr/bin/perl

use File::Basename;
use lib dirname (__FILE__);
use test_eval_scope;

test_eval_scope::f1();

当我运行程序时,我得到了以下错误

$ test_eval_scope.pl
Variable "%h" is not available at (eval 1) line 1.

我的问题是为什么变量 %h 超出范围。

我做了一些修改,发现如下:

  1. 如果我在没有 eval() 的情况下运行,如上面的注释所示,它将起作用。 意味着 %h 应该在范围内。
  2. 如果我只是在代码中添加一个看似无用的提及,如上 注释,eval() 也可以。
  3. 如果我将 pl 和 pm 文件合并到一个文件中,eval() 也可以工作。
  4. 如果我用 'our' 而不是 'my' 声明 %h,eval() 也会起作用。

我在编写一个在运行时解析用户提供的代码的大程序时遇到了这个问题。我不需要解决方案,因为上面有很多解决方法。但我无法解释为什么上面的代码不起作用。这影响了我对 perl 的自豪感。

我的 perl 版本是 linux 上的 v5.26.1。

感谢您的帮助!

【问题讨论】:

    标签: perl scope eval


    【解决方案1】:

    Subs 只捕获他们使用的变量。由于f1 不使用%h,因此它不会捕获它,并且当模块完成执行时,%h 超出范围后,f1 将无法访问。

    对 var 的任何引用,包括优化后的引用,都会导致 sub 捕获该变量。因此,以下方法确实有效:

    sub f1 {
       %h if 0;
       eval 'print %h, "\n"';
    }
    

    演示:

    $ perl -M5.010 -we'
       {
          my $x = "x";
          sub f {          eval q{$x} }
          sub g { $x if 0; eval q{$x} }
       }
    
       say "f: ", f();
       say "g: ", g();
    '
    Variable "$x" is not available at (eval 1) line 1.
    Use of uninitialized value in say at -e line 8.
    f:
    g: x
    

    【讨论】:

    • 优化似乎是关键。
    • 这不仅仅是优化;它允许及时销毁变量。
    猜你喜欢
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    • 2011-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多