0

这是第一个例子:

$g=5;
sub A {
    my  $x=2;    # $x uses static scoping
    local $y=3;  # $y uses dynamic soping
    local $g=7;
    print "In A: g=$g, x=$x, y=$y\n";
    B();
}

sub B {
    print "In B: g=$g, x=$x, y=$y\n";
    C();
}

sub C {
    print "In B: g=$g, x=$x, y=$y\n";
}

A();
print "In main: g=$g, x=$x, y=$y\n";

这是第一个示例的输出:

In A: g=7, x=2, y=3
In B: g=7, x=, y=3
In B: g=7, x=, y=3
In main: g=5, x=, y=

这是第二个例子:

sub big {
    my $var=1;
    sub sub1 () {
    print "  In sub1 var=$var\n";
    }
    sub sub2 () {
        $var = 2;
    print "In sub2, var is $var\n";
        sub1();
    }
    sub1();
    sub2();
    sub1();
}

big();

这是第二个输出:

  In sub1 var=1
In sub2, var is 2
  In sub1 var=2
  In sub1 var=2

问题是:为什么在第二个示例sub Bsub C可以访问,my $x=2;而在第一个示例 sub1()中却sub2()不能访问,my $var=1; 我相信my用于静态范围$x,在示例 2 的静态范围内也没有任何其他内容sub big,我预计在第二个例子,像这样:In sub1 var=。在第二个例子中,can sub1and sub2can access to $xalough it has been declaration with word my,为什么它的行为不像第一个例子?

4

2 回答 2

2

所有词法变量(用 声明的my)仅在其最里面的封闭代码块内可见。代码块是由{...包围的语句列表}或代码文件。

在您的第一个示例中,子例程都在文件的顶层定义。定义子程序的代码块都是完全独立的,并且在这些子程序之一中声明的任何词法变量在其他任何子程序中都不可见。

在第二个示例中,您定义了子例程sub1()和子例程sub2()内部big()。这意味着定义两个内部子例程的代码块在定义外部子例程的代码块内 - 因此,两个内部子例程可以看到在其中声明的任何词法变量big()(因为这些变量在big()'s代码块)。

于 2019-11-15T10:51:27.040 回答
1

词法 ( my) 变量的范围(即从哪里可以看到/访问它们)由它们所在的最内层块(卷曲)或文件定义。

$ perl -e'
   use strict;
   use warnings;

   my $x = 123;
   {
      my $x = 456;
      print "$x\n";
      # The second $x can only be seen up to here.
   }

   # It is as is the second $x never existed here.
   print "$x\n";
'
456
123

内部块是子声明的一部分这一事实并没有什么不同。

也就是说,不要将命名的 subs 放在命名的 subs 内。

首先,它不会将它们设为私有。

$ perl -e'
   use strict;
   use warnings;

   sub outer {
      sub inner { print "inner\n"; }
   }

   inner();
'
inner

更重要的是,它会导致很多奇怪的行为。

$ perl -e'
   use strict;
   use warnings;

   sub outer {
      my ($x) = @_;
      sub inner { print "inner $x\n"; }
      print "outer $x\n";
      inner();
   }

   outer(123);
   outer(456);
'
Variable "$x" will not stay shared at -e line 7.
outer 123
inner 123
outer 456
inner 123

命名子例程在编译时捕获,因此inner捕获在编译时$x退出的子例程。outer退出时,它$x会被替换为新$x的断开outer's$xinner's 之间的连接。

这正是您必须始终使用use strict; use warnings;.

如果您想要一个私有内部子,请改用匿名子;他们在运行时捕获。

$ perl -e'
   use strict;
   use warnings;

   sub outer {
      my ($x) = @_;
      my $inner = sub { print "inner $x\n"; };
      print "outer $x\n";
      $inner->();
   }

   outer(123);
   outer(456);
'
outer 123
inner 123
outer 456
inner 456

您还可以使用一个实验性功能。

$ perl -e'
   use strict;
   use warnings;
   use experimental qw( lexical_subs );

   sub outer {
      my ($x) = @_;
      my sub inner { print "inner $x\n"; }
      print "outer $x\n";
      inner();
   }

   outer(123);
   outer(456);
'
outer 123
inner 123
outer 456
inner 456
于 2019-11-15T11:18:23.170 回答