免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 9953 | 回复: 11
打印 上一主题 下一主题

perl local my our 的前世今生 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-05-10 11:04 |只看该作者 |倒序浏览
Perl中的变量作用范围 local, my, our与全局变量

很古老很古老以前......嗯,不用老到白垩纪,那时候的Perl是自由射击的。没有什么定义变量的说法,所有的变量都是全局变量,也不需要任何 定义就可以使用。后来就出现了local, 再后来出现了use strict 'vars'和my, 再后来又有了our......所以今天的Perl大陆就有了崇山巨岭,一些变量就被限制在盆地里,老死于桃花源中也。

因为要使用一个跨模块全局变量,研究了一下Perl的变量作用范围,写一点笔记吧。

1. 首先说our, 这个最晚出现但其实质却最早出现的变量修饰符。众所周知,在Perl不使用use strict 'vars'的时候,你可以任意使用变量而不需要实现定义:

$szStateMachineStatus = undef;

这行代码在使用了use strict 'vars'以后是编译不能通过的。如果这个变量是一个全局变量,那么可以定义

our $szStateMachineStatus = undef;

这个效果和在不使用use strict 'vars'时一样。"一样"意味着什么呢?

our $szStateMachineStatus = 'init';
{
$szStateMachineStatus = 'inited';
print $szStateMachineStatus;
}
print $szStateMachineStatus;

打印的结果是两个'inited'。顺便说,用our定义过的变量,可以在任何地方被再次用our定义,仍然和第一个our定义的变量是同一个。

2. my

慢慢地有人觉得Perl的"自由射击式"变量定义法则不行,最突出的就是一些常会打错字(typo)的人。假如你定义了一个变量叫$ szStateMachineStatus,可是在某个地方写成了$szStatMachineStatus,少了一个e。因为不use strict啊,所以没有任何警告,可以这样用。结果就是出了错你就慢慢debug去吧,很浪费时间,不符合Perl的懒惰文化。

然后就有了use strict 'vars'和my。有了use strict 'vars'以后,所有的变量在使用前必须先被定义。my的法则很简单,只在当前作用域起作用。比如说定义了
my $szStateMachineStatus;
那么如果是在文件头定义的,作用范围就到文件尾,在子函数里也能用。如果是在子函数里定义的,那么作用范围就只到函数结束。试看以下代码
foreach my $szName (@arrName){
print $szName;
}
在这个循环里Perl每次都创建一个新的$szName变量。换句话说,"my"是属于"见到my就新建"的变量。

3. local

其实这个定义都可以取消了。它是在my还没出现之前的一个权宜方案。比如说一个变量$i被定义成了全局变量,可是你又想暂时使用一个也叫$i的临时变量。
no strict 'vars';
$i = 9999;
{
local $i = 7777;
print "$i\n";
}
print "$i\n";
结果是7777, 9999。在出了local的作用域以后$i又回到了原来的值。在出现了my以后,没有任何理由需要使用local了,请忘记掉它吧。

4. 最后一个话题,全局变量

当你只有一个pl文件时,很简单,把你的全局变量在文件头部定义成our就行。可能你会看到有些书上说要使用use vars qw( $szVersion $szToolName); 这样的方式来把 $szVersion和$szToolName定义成全局变量。注意了,use vars的用法是在my出现后,our出现之前的一个历史的盲肠。our的语法更自然,更易于理解,为什么不用our呢? --另外,在文件头把变量定义成my, 也是全局可用的,但是冒了风险,假如在某个函数里用my再定义一次,原来的值可就消失了。用our就不存在多次定义会导致丢值的状况。

当你在写一个有一个pl文件,N个pm文件的系统时该如何呢?事实上Perl里的变量和函数名都有一个系统级的名字。比如说你在某pm文件的头上定义了包名和全局变量
package bagua;
our $east = 'wood';
那么在任何地方,任何pm和pl文件里都可以使用$bagua::east来访问这个变量。$bagua::east就被称为系统级名字。这也能回答一个问题,为什么不同的perl包里面定义的同名全局变量间不会冲突,因为它们都被限制在包的名字空间下面了。

如果你是在pl里定义全局变量,而且该文件没有定义package名字怎么办?Perl会生成一个缺省的package,名字叫"main"。所以如果你的pl文件是这样
our $szVersion = '1.0.1";
那么在其它文件里就可以用$main::szVersion来访问,并不需要你定义package main.
最后,说一个邪门招式。你可以试一下定义任意一个含有::的变量
our $gColor::Blue = '0x0000FF';
这个变量就在任何地方可用,哪怕你从来没有定义过gColor这个package。这个是Perl的灵活性的体现,它看到这个就自动生成了gColor这个名字空间。当然,我不鼓励这种无厘头的用法。

论坛徽章:
0
2 [报告]
发表于 2010-05-10 13:45 |只看该作者
local my 差异
local函数能从参数列表中创建局部变量。任何使用local函数声明的变量都是动态拷贝,也就是说,该变量不但在创建它的块中可见,而且对于任何从该代码块调用的函数或在嵌入定义的代码块中都是可见的。
my函数只在声明之处开始到最内层才是可见的。

论坛徽章:
0
3 [报告]
发表于 2010-05-11 15:34 |只看该作者
好文章,顶起。。。。。

论坛徽章:
0
4 [报告]
发表于 2010-05-12 13:10 |只看该作者
perl 5.12 把local 删除了

论坛徽章:
0
5 [报告]
发表于 2010-05-12 14:24 |只看该作者
删掉了好     不过老程序里还看到好多

论坛徽章:
0
6 [报告]
发表于 2010-05-17 10:00 |只看该作者
对perl的符号有点头大

论坛徽章:
0
7 [报告]
发表于 2010-09-15 17:15 |只看该作者
最近在学习PERL,帖子不错,我这里有个问题请教:
my 和local定义变量冲突的,比如在文件头定义一个my $var, 在下面就不能用local定义一个同名变量了,比如:
my  $var = 'global';
sub visible {
   print "var has value $var\n";
}

sub dynanic {
local $var = 'local';   # new temporary value for the still-global
visible();              #   variable called $var
}

sub lexical {
    my $var = 'private';    # new private variable, $var
    visible();              # (invisible outside of sub scope)
}

visible();                  
dynamic();                  
lexical();                 

为什么会报错,说不能定义local类型的变量呢?
Can't localize lexical variable $var at.... -->(local 定义变量的行)

另外,加入把my $var定义在函数什么之后又可以了呢?比如:
sub visible {
   print "var has value $var\n";
}

sub dynamic {
local $var = 'local';   # new temporary value for the still-global
  visible();              #   variable called $var
}

sub lexical {
     my $var = 'private';    # new private variable, $var
     visible();              # (invisible outside of sub scope)
}

my  $var = 'global';

visible();                  # prints global
dynamic();               # prints global
  lexical();                 # prints global

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
8 [报告]
发表于 2010-09-15 17:19 |只看该作者
local 不是定义,是局部化。

论坛徽章:
0
9 [报告]
发表于 2010-09-15 22:45 |只看该作者
这个帖子,还是很有意义的。

论坛徽章:
1
未羊
日期:2014-09-08 22:47:27
10 [报告]
发表于 2010-09-16 09:17 |只看该作者
  1. {
  2.     local $| = 1;    #我想临时刷新缓冲
  3.     print "Display.\n";
  4.     do_something();
  5. }
  6. #这个时候$|又恢复原来的值啦。local在这种场合很方便。
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP