【问题标题】:Difference between a BLOCK and a function in terms of scoping in PerlPerl 中 BLOCK 和函数在作用域方面的区别
【发布时间】:2025-11-24 15:50:02
【问题描述】:

伙计们,我有点困惑,当我遇到这个时,我正在使用 Perl 进行范围界定:

#! usr/bin/perl
use warnings;
use strict;

sub nested {
   our $x = "nested!";
}

print $x;     # Error "Variable "$x" is not imported at nested line 10."
print our $x; # Doesn't print "nested!"
print our($x) # Doesn't print "nested!"

但是当我这样做时:

{
   our $x = "nested";
}

print our($x);  # Prints "nested"
print our $x;   # Prints "nested"
print $x;       # Prints "nested"

那么你们能向我解释为什么这些有效而不是无效吗?

【问题讨论】:

    标签: perl variables scope


    【解决方案1】:

    重申 DVK 的答案,our 只是一个方便的别名工具。您在这些示例中使用的每个变量实际上都命名为$main::x。在任何词法范围内,您都可以使用 our 在同一范围内为该变量创建一个别名,并使用缩写名称;该变量不会在外部重置或删除,只有别名。这与 my 关键字不同,后者将新变量绑定到该词法范围。

    【讨论】:

      【解决方案2】:
      1. 为了解释块示例为何如此工作,让我们看一下来自"Modern Perl" book, chapter 5our 解释

        我们的范围

        在给定范围内,使用我们的内置函数声明包变量的别名。
        完全限定名称随处可见,但词法别名仅在其范围内可见。

        这解释了为什么第二个示例的前两个打印有效(我们在打印的范围内重新声明),而第三个无效(因为我们唯一的别名 $x 到块范围内的包变量)。请注意,打印$main::x 正常工作 - 它只是作用域为块的别名,而不是包变量本身。


      2. 就功能而言:

        • print our $x;print our($x) “不工作” - 即,正确声明该值未初始化 - 因为您从未调用过初始化变量的函数。观察差异:

          c:\>perl -e "use strict; use warnings; sub x { our $x = 1;} print our $x"
          Use of uninitialized value $x in print at -e line 1.
          
          c:\>perl -e "use strict; use warnings; sub x { our $x = 1;} x(); print our $x"
          1
          
        • print $x; 不会因为与块相同的原因而工作 - our 仅将别名限定为块(即在这种情况下为子的主体)因此您必须在主中重新命名它块的范围(根据print our $x 示例),或者在子外部使用完全限定的全局包,在这种情况下它将按预期运行:

          c:\>perl -e "use strict; use warnings;  sub x { our $x = 1;}  print  $main::x"
          Use of uninitialized value $x in print at -e line 1.
          
          c:\>perl -e "sub x { our $x = 1;} x(); print  $main::x"
          1
          

      【讨论】:

      • 但是在函数的范围内呢?
      • @BelmarkCaday - 你没有等到第二次编辑:)。顺便说一句,我在最后一个命令中省略了严格/警告,只是因为 SE 的格式由于字符串太长而创建了水平 scoller。
      • @DVK : $ perl -Mstrict -we '...'
      • @Zaid - -w'use warnings' 不同。警告用户:)
      • @GregD'Arcy :你能举个例子说明两者的行为不同吗?