Perl 作用域

Perl eval scope

根据 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。

感谢您的帮助!

潜艇只捕获他们使用的变量。由于 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