编程学习biancheng.45soft.com 本站提供了各种在线教程和资料,供大家学习与参考.
编程学习
当前位置: 主页 > Perl > 语句和声明 > Perl 语句和声明 全局声明

Perl 语句和声明 全局声明

子过程和格式声明是全局声明.不管你把它们放在哪里,它们声明的东西都是全局的(对包而言是局部的,但是包对程序而言是全局的,所以包里面的任何东西在任何地方都可见)。全局声明可以放在任何可以出现语句的地方,不过它们对语句的主要执行顺序没有影响--声明只在编译时起作用。


这意味着你不能做条件的子过程和/或格式声明。你可能会想用一个运行时的 if 来屏蔽你的声明,使之不为编译器所见,但这是不可能的,因为只有解释器关心那些条件。不管出现在什么地方,子过程和格式声明(还有 use 和 no 声明)都只有编译器能够看到。


全局声明通常出现在你的程序的开头或者结尾,或者是放在其它的文件里。不过,如果你声明的是词法范围的变量(见下节),而且你还希望你的格式或者子过程能够访问某些私有变量,那你就得保证你的声明落在这些变量声明的范围之内。


请注意我们偷偷地从讲声明转移到了讲定义。有时候,把子过程的声明和定义分开能帮我们忙。这两个概念语义上的唯一的区别是定义包含一个要执行的代码块BLOCK,而声明没有。(如果一个子过程没有声明部分,那么它的定义就是它的声明。)把定义从声明里面剥离,就允许你把子过程的声明放在开头而把其定义放在后面(而你的词法范围的变量声明放在中间):

sub count (@);      # 现在编译器知道如何调用 count()。
my $x;         # 现在编译器知道词法变量
$x = count(3,2,1);   # 编译器可以核实函数调用
sub count (@) { @_ }   # 现在编译器知道 count() 是什么意思了

正如上面例子显示的那样,子过程在调用它们之前不用定义也能编译,(实际上,如果你使用自动装载技术,定义甚至可以推迟到首次调用),但是声明子过程可以以各种方式协助编译器,并且给你更多调用它们的选择。


声明一个子过程后允许你不带圆括弧使用它,好象它是一个内建的操作符一样。(我们在上面的例子里用了圆括弧,实际上我们可以不用。)你可以只声明而不定义子过程,只需:

sub myname;
$me = myname $0      or die "can't get myname";

这样的空定义把函数定义成一个列表操作符,但不是一元操作符,所以上面用了 or 而不是  。操作符  
和列表操作符之间的联系太紧密了,以至于基本上只能用于列表操作符后面,当然,你还是可以在列表操作符参数周围放上圆括弧,让列表操作符表现得更象函数调用来解决这个问题。另外,你可以用原型 ($) 把子过程转化成一元操作符:

sub myname ($);   
$me = myname $0      || die "can't get myname";

这样就会按照你想象的那样分析了,不过你还是应该养成在这种情况下用 or 的习惯。有关原型的更多内容,参阅第六章,子过程。


有时候你的确需要定义子过程,否则你在运行时会收到一个错误,说你调用了一个没有定义的子过程。除了自己定义子过程外,还有几个方法从其它地方引入定义。


你可以用简单的 require 语句从其它文件装载定义,在 Perl 4 里,这是装载文件的最好方法,但是这种方法有两个问题。首先,其他文件通常会向一个它们自己选定的包(一个符号表)里插入子过程名,而不是向你的包里插。其次,require 在运行时起作用,这对调用它起声明作用的文件来说有点太晚了。不过,有时候你要的就是推迟的装载。


引入声明和定义的更好的办法是使用 use 声明,它可以在编译时就 require 各模块(因为 use 算做 BEGIN 块),然后你就可以把一些模块的声明引入到你的程序里面来了。所以可以把 use 看成某种类型的全局声明,因为它在编译时把名字输入到你自己的(全局)包里面,就好象你是自己声明的一样。参阅第十章,包,的"符号表"一节,看看包之间的传输运做的低层机制;第十一章,模块,看看如何设置一个模块的输入和输出;以及第十八章,看看 BEGIN 和它的表兄弟 CHECK,INIT,和 END 的解释。它们在某种程度上也是全局声明,因为它们在编译是做处理,而且具有全局影响。



编程学习 Perl 语句和声明 全局声明 转载请保留此行.谢谢.

Perl