my, our, local 以及 typeglob(转)

写在前面our local 是声明包符号表的变量, my 的变量不在符号表中。

这也产生了很多例子来说明他们说。

1.查看符号表

our $var;
my $va;
local $ss;
foreach (keys %main::)
{
    print $_, "\n";
}

2. local 保存以前的值,出了一个block之后会恢复

  our  $va = 2;
  *foo = \$va;
{
    local  $va = 1;
   print $foo;  # 输出2

 }

这里 如果 *foo = \$va; 改为*foo =*bar 输出1 ,因为是别名。

 local另两个用法是   local $\ = "" ; my $all = <fh> ; 改变特殊符号变量;

                          传文件句柄引用    sub newopen{

                    my $path = shift; 

                      local *fh ;

                     open fh ,"$path";

                     return \*fh; 

                }

以下转自http://hi.baidu.com/nily_zhong/item/eeacb1d06d47da2a39f6f7d9

Perl中有两种名字空间(namespace):符号表(symbol table)和词法作用域(lexical scopes).在Perl中, 每个包(Package)有一个

符号表, 可以通过Packeagename::获取包中的变量.
比如:
package A;
$test = 1;
可以通过$A::test访问包A的变量test.
符号表是一个Hash表, 该Hash表的名字就是符号表所在包的名字.
比如你可以用下面的语句打印出在main包中的所有符号:
foreach (keys %main::)
{
    print $_, "\n";
}

又比如, 如果在程序中声明了:
$test = 1;
可以通过$main::test来访问该变量(假设变量是在main包中).

在同一个符号表中, 可以存在同样名字的标量变量, 数组变量, Hash变量, 函数变量等.Perl中采用*符号来表示一个typeglobs,意思
就是"所有名字为XX的变量",比如:
$type = *test;
此时变量type中存放的就是当前包中所有名字为test的变量, 
如果我们调用语句:
print $$type;
则将$type所指向的变量解释为标量, 类似的可以解释为数组, Hash, 函数等等.

但是, 如果你仅仅想让这个typeglobs作用于一个类型的变量, 也可以明确的指出来, 如:
*dick = \$richard;
这样dick变量就只能访问名为richard的标量了.

可以把typeglobs想象为另一个typeglobs的别名, 当写下代码
$type = *test;
的时候, type就是test这个typeglobs的别名了.

Perl中还支持符号引用, 它可以根据一个标量存放的字符串去查找名为该字符串的typeglobs,如:
$test = 1;
$name = "test";
print $$name;
Perl解释器首先去解释变量$name, 发现是一个字符串, 再根据该字符串去解释这个解引用, 也就是说:
$$name -> $test -> 1


在Perl中, 变量的名字是可以和Perl的关键字同名的, 只要在使用的时候有"足够的办法"让Perl解释器去明确辨别出来到底是哪种变量.
比如我写了一个名为for的函数, 一般而言, 在Perl中, 函数调用是可以省略掉前面的&符号的, 但是在这里对这个名为for的函数则不行, 
Perl会把它解释为for循环.因此, 要明确的表示是在调用一个叫for的函数, 需要在前面加上&符号.对其它类型的变量, 这个例子同样适用.
在<<Perl语言编程>>(大骆驼)中, 将$&%@这几种分别作用在不同类型变量前面的特殊符号称之为"funny character".

在Perl中, 有三种修饰符是修饰变量的作用域的:our, my, local,它们与前面提到的Perl中的作用域息息相关.
our声明的变量是包全局的, 也就是说, our声明的变量会出现在这个包的符号表中;my声明的变量仅作用于一个块(block), 在Perl中, 
一对{}包起来的部分称之为一个块, 比如一个函数是一个块, 一个循环是一个块,等等,my修饰的变量普遍作用于这些地方, 如果没有在哪一个
块中, 那么就仅作用于当前文件, 但是,无论如何, my修饰的变量都不会进入一个包的符号表中, 这也就意味着my声明的变量不能使用typeglobs
进行访问, 如:
my $test = 1;

$type = *test;
print $$type;
这段代码是没有任何效果的, 因为在当前包中找不到名字是test的变量.把上面代码中修饰变量test的my去掉, 再试试就知道区别了.

local是作用于那些在符号表中出现的变量的, 它让对这些变量的修改局限在一个块(block)中, 比如:
our $var;
$var = 1;
{
    local $var;
    $var = 2;
    print $var, "\n";
}
print $var, "\n";
打印的结果是
2
1
local的出现让块中对变量var的修改仅仅局限在这个块中了.

总结:
1. Perl中有两个作用域:符号表和词法作用域, 每个包都有自己的符号表, 这样可以避免名字污染问题的出现, 类似于C++中的
namespace, 全局变量, 以及用our修饰的变量都属于这个作用域, 可以通过:包名称::变量名称来访问一个包中的全局变量.而词法作用域
是指的一个块, 或者一个文件, 凡是由my修饰的变量都是词法作用域中的变量, 它们不会出现在包中的符号表中, 在包之外不可见, 
更甚者, 如果一个由my修饰的变量在一个块中, 它就仅仅在这个块中可见了.

2. 如果想让对某个全局变量的修改局部化, 那么就使用local修饰符, 在出了这个块之后, 自动恢复为全局变量原来的数据.
posted @ 2012-12-03 22:15  程序员杰诺斯  阅读(153)  评论(0编辑  收藏  举报