我在Stackoverflow和Google中阅读了很多帖子,告诉local
不创建变量,而是在现有变量上运行。
我下面有一小段代码,我想知道local
在没有创建这样的变量时是如何工作的。
#use strict;
#use warnings;
&func;
sub func{
local $temp = 20;
print $temp;
}
我写这篇文章只是为了理解这个概念而且我对Perl来说相对较新。
答案 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,my
,state
或our
执行此操作:
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
如此重要的一个原因,省略它是危险的。如果没有它,你就无法防止拼写错误的变量并无声地破坏你的程序