在Perl中,local()可以创建一个变量吗?

时间:2015-07-05 07:34:40

标签: perl scope

我在Stackoverflow和Google中阅读了很多帖子,告诉local不创建变量,而是在现有变量上运行。

我下面有一小段代码,我想知道local在没有创建这样的变量时是如何工作的。

#use strict;
#use warnings;

&func;

sub func{
    local $temp = 20;
    print $temp;        
}

我写这篇文章只是为了理解这个概念而且我对Perl来说相对较新。

5 个答案:

答案 0 :(得分:8)

除非您使用my声明变量,否则没有完整包规范的变量将进入当前包。以下是您第一次看到变量的用法以及它们的用途:

my $temp;       # a scoped, lexical variable that does not live in any package
state $temp;    # a persistent lexical variable
our $temp;      # a package variable in the current package, declared
$temp;          # a package variable in the current package
$main::temp     # a package variable in main
$Foo::Bar::temp # a package variable in Foo::Bar
local $temp     # a package variable in the current package, with a dynamically-scoped (temporary) value

local设置包变量的范围。当您声明这个“动态”范围时,Perl会使用您设置的临时值,直到范围结束。与其他包变量一样,Perl在您第一次使用它们时会创建它们。您可以先在local前面使用它并不会影响它。

许多试图回答你问题的人立刻唠叨了你strict。这是一个编程辅助工具,它可以帮助您通过强制声明要使用的所有变量来错误输入变量名。当您使用未声明的变量名时,它会停止编译程序。您可以使用vars pragma,mystateour执行此操作:

use vars qw($temp);
our $temp;
my $temp;
state $temp;
正如你所见,

local不是其中的一部分。为什么?因为那就是它的样子。如果不同的话,我会更喜欢它。

如果您使用完整的包规范,

strict将不会抱怨,例如$Foo::Bar::temp。你可以在没有注意到的情况下输错所有这些。

我主要保留将local用于Perl的特殊变量,您不必声明这些变量。如果我想在子例程中使用$_,也许默认使用$_的运算符,我可能会从local $_开始:

 sub something {
     local $_ = shift @_;
     s/.../.../;
     tr/.../.../;
     ...;
     }

我可能会更频繁地使用local输入记录分隔符,因此我可以使用不同的行结尾而不影响之前的结果:

 my $data = do { local $/; <FILE> };

这些工作是因为隐含的第一次使用了那些你没见过的变量。

否则,我可能希望将变量设置为其子例程的私有,因此子例程之外的任何内容都无法看到它。在这种情况下,我不希望程序的其余部分可以读取或写入的包变量。这是my变量的工作:

sub something {
    my $temp = ...;

    }

编程的诀窍是限制你想要的东西。如果您的程序的其余部分无法查看或更改变量,那么my就可以了。

我解释这是Learning Perl并在Mastering Perl中写下包变量的详细信息。

答案 1 :(得分:5)

  

local不会创建变量,而是对现有变量起作用。但我在下面有一小段代码,我想知道当没有这样的变量已经创建时本地如何工作

让我们做几步,让perl做一些诊断,

perl -wE 'local $temp =3'
Name "main::temp" used only once: possible typo at -e line 1.

所以local $temp改变$main::temp这是包变量和

perl -wE 'local $main::temp =3'
Name "main::temp" used only once: possible typo at -e line 1.

发出同样的警告。所以我们创建了一个新的包变量本地化

这是什么意思?这意味着,与our $temp不同,它会保留包(&#39;全局&#39;)变量$ temp的值,直到它退出enclosing block,此时它会将值恢复为之前的值。

还有一些测试,

perl -MData::Dumper -E 'say Dumper [exists $main::{t}, ${$main::{t}}]'
$VAR1 = [
      '',     # `$main::t` is NOT created in main package
      undef   # retrieving value of `$main::t` thus returns undef
    ];
perl -MData::Dumper -E '{our $t=7} say Dumper [exists $main::{t}, ${$main::{t}}]'
$VAR1 = [
      1,      # `$main::t` is created in main package
      7       # value of `$main::t`
    ];

最后,

perl -MData::Dumper -E '{local $t=7} say Dumper [exists $main::{t}, ${$main::{t}}]'
$VAR1 = [
      1,      # `$main::t` is *CREATED* in main package
      undef   # value of `$main::t` reverts to undef at exit of enclosing block
    ];

答案 2 :(得分:3)

local不会创建变量。只需提及$temp即可创建变量。它是在第一次遇到时创建的,无论是在编译时还是在运行时。

$ perl -E'
   $foo;
   ${"bar"};
   BEGIN { say $::{foo} && *{ $::{foo} }{SCALAR} ? "exists" : "doesn'\''t exist"; }
   BEGIN { say $::{bar} && *{ $::{bar} }{SCALAR} ? "exists" : "doesn'\''t exist"; }
   BEGIN { say $::{baz} && *{ $::{baz} }{SCALAR} ? "exists" : "doesn'\''t exist"; }
   say $::{foo} && *{ $::{foo} }{SCALAR} ? "exists" : "doesn'\''t exist";
   say $::{bar} && *{ $::{bar} }{SCALAR} ? "exists" : "doesn'\''t exist";
   say $::{baz} && *{ $::{baz} }{SCALAR} ? "exists" : "doesn'\''t exist";
'
exists               # $foo exists at compile-time
doesn't exist        # $bar doesn't exist at compile-time
doesn't exist        # $baz doesn't exist at compile-time
exists               # $foo exists at run-time
exists               # $bar exists at run-time
doesn't exist        # $baz doesn't exist at run-time

只需通过命名变量创建变量就很难发现拼写错误。我们使用use strict;因为it prevents that

local只有运行时效果。 local暂时以一种导致Perl在退出词法范围时恢复它的方式备份$temp的值。

$ perl -E'
   sub f { say $temp; }

   $temp = 123;
   f();

   {
      local $temp = 456;
      f();
   }

   f();
'
123
456
123

答案 3 :(得分:0)

您忘记使用use strict。如果您不use strict,则将使用全局包变量$temp。请参阅http://perlmaven.com/global-symbol-requires-explicit-package-name

包变量总是全局的。它们有名称和包限定符。您可以省略包限定符,在这种情况下,Perl使用默认值,您可以使用包声明设置该默认值。 为避免意外使用全局变量,请将use strict 'vars'添加到您的程序中。 来自documentation

  

使用严格的变量:如果您访问的是变量,则会生成编译时错误   既没有明确声明(使用我的,我们的,州或任何使用vars   )也不完全合格。 (因为这是为了避免变异自杀   问题和微妙的动态范围问题,仅仅是局部变量   不够好。)

答案 4 :(得分:0)

没有use strict - 特别是use strict 'vars',这是一个子集 - 只需提及变量就会在当前包中创建它。甚至不需要local,您的代码可以像这样编写

sub func{
    $temp = 20;
    print $temp;
}

func();

输出

20

这是use strict如此重要的一个原因,省略它是危险的。如果没有它,你就无法防止拼写错误的变量并无声地破坏你的程序