<perl> 符号引用
2013-08-09 08:39
134 查看
for (1..5){ $name="$_"; ${"var".$name}="Hello,this is VAR $_!"; } print $var3; #Hello,this is VAR 3!
可以用这个实现动态定义新变量。
对于一般的符号引用,可以省略{}:
$name="some"; $$name = 3; #${$name}=3; # same above #$some=3; # same above print $some;
注意:一旦用了use strict; 符号引用就会失效!
参考(转载):
==通过子程序的引用调用子程序=============================================
(原链接)
假如我有一个子过程,定义如下:
sub test_sub { print "test"; }
我又有一个变量:
$test = "test_sub";
这个 $test 的值刚好就是上面子过程的名称。既然我通过 $test 知道了这个子过程名称,我可以通过 $test 达到调用这个子过程的目的吗?也就是说,我让用户从命令行里输入一个子过程的名称,然后就可以根据这个名称来调用相对应的子过程。
方法一,直接根据用户输入的子过程名来调用该子过程。
完整的例子代码如下:
use warnings;
no strict 'refs';
sub test_sub { print "test"; }
$test = "test_sub";
$test->();
&{$test}(); #anyway to invoke the subroutine
这里要注意,需要用
no strict 'refs';
这个语句,否则脚本不能运行,Perl 解释器会提示类似于下面的错误:
Global symbol “$test” requires explicit package name at test2.pl line 10.
方法二,更常规的做法是专门用一个起分派作用的散列,根据用户输入的请示而调用相应的子过程。例如下面的 %dispatcher 就起到了绑定识别标记与相应子过程引用的作用,通过这个唯一的标记 (key),我们可以很容易地找到对应的子过程引用。
my %dispatcher = ( sub_test => sub { print "test" }, );
然后可以用和方法一相同的语法来调用这个子过程:
$dispatcher{$sub_name}->();
下面是方法二的一个完整的例子:
use warnings; use strict; sub test_sub { print "test\n"; } sub test_other { print "test other\n"; } my %dispatcher = ( "test_sub" => \&test_sub, "test_other" => \&test_other, ); print "\nPlease enter the test case you want to test:\n"; while( my $cmd = <> ) { chomp($cmd); $dispatcher{$cmd}->() if exists $dispatcher{$cmd}; }
当然,方法二要比方法一优秀得多,它可以避免用户输入错误的子过程名而导致一系列的麻烦。
==符号引用===========================================================
一般来说,类似$$var的结构表示,$var是一个引用变量,而且程序员希望该表达式能够返回$var所指向的值。
假如$var不是引用变量的话会出现什么情况呢?Perl并不是断然打印出错误信息,而是尝试检查$var的值是否为一字符串。如果是,Perl将以该字符串作为正规的变量名与这个变量重新加以组合!考虑下面的例子:
$x = 10; $var = "x"; $$var = 30; #$x的将被改为30,因为$var是一种符号引用
当对$$var进行间接访问时,Perl首先检查$var是否是引用,在这里它不是,而是字符串。于是Perl会再给该表达式一次机会:它将$var的内容当作变量标识符($x)。这样一来,最终$x的值就被修改成30了。
应当注意重要的一点是符号引用只对全局变量有效,而不能应用于那些用my标识为私有的变量。
符号引用对数组和散列表同样适用:
$var = "x"; @$var = (1,2,3); #将@x的值设置为右边的枚举列表
注意$var前面的符号指示变量的存取类型:$$var等价于$x,@$var也等价于@x,这种特性非常有用。
对于那些在Perl的早期版本中就实现过此类功能的人来说,这要比使用eval更为高效。举例说明,你要在自己的脚本程序中,处理诸如“-Ddebug_level=3”的选项,并设置$debug_level变量。下面是其中的一种实现方式:
while($arg = shift @ARGV){ if($arg =~ /-D(\w+)=(\w+)/){ $var_name = $1; $value = $2; $$var_name = $value; #更为简洁的可书写为:$$1 = $2; } }
从另一方面说,Perl竭尽全力使一个表达式正常工作,有时却于事无补。在前面的例子中,如果你所希望程序使用一个真正的引用,而不是字符串的话,那么你就会希望Perl能够指出这种情况而不是做任何的假定。幸运的的是,这种“急于求成”的方式科以被关闭。Perl有许多编译时指令和指示。strict编译指示将告诉Perl做严格的错误检查。你甚至科以指定需要进行严格检查的范围,其中之一就包括“refs”这一项:
use strict 'refs'; #告诉Perl不允许符号引用 $var = "x"; $$var = 30;
无论何时你试图使用符号引用时均会导致运行时错误:
can't use string ("x") as a SCALAR ref while "strict refs" in use at try.pl line 3
strict指令直至程序块结束仍然有效。可以通过输入no strict 或更明确的no strict 'refs'将其关闭。
相关文章推荐
- <转>关于 error LNK2019:无法解析的外部符号 ,该符号在函数**中被引用的思考
- 网页引用外部js脚本文件时必须是<script></script>标记格式
- Spring基础_在JavaConfig中引用xml配置<四>
- java移位运算符:<<(左移)、>>(带符号右移)和>>>(无符号右移)
- 【Android】代码引用资源 [<package_name>.]R.<resource_type>.<resource_name>
- 在AnyTao<参数之惑>基础之上再讨论按值传递与按引用传递
- JAVA这个符号<< >> >>>是什么
- WCF---客户端引用服务时List<T>变为数组T[]的问题
- Google-Guava学习:用Optional<T>表示可能为null的T类型引用
- Android Java四种引用区分 <17>
- 编辑xml文件的时候特殊符号的处理 < >
- 智能指针里弱引用应该如何实现?(WeakReference/WeakPtr<T>)
- 编写一个智能指针类,自动记录SmartPointer<T*>对象的引用计数,一旦T类型对象的引用计数为零,就会释放对象
- 错误 1 error LNK2019: 无法解析的外部符号 "public: __thiscall chain<int>::~chain<int>(void)" (??1?$chain@H@@QAE@
- 【FastJSON】解决FastJson中“$ref 循环引用”的问题<三种方式对应不同需求>
- <climits>头文件定义的符号常量
- wcf服务引用-List<T> to T[]
- 解决常见特殊符号 & ,<, >等在xml文件中显示报错的问题
- error LNK2019: 无法解析的外部符号 ___glutInitWithExit@12,该符号在函数 _glutInit_ATEXIT_HACK@8 中被引用 1>GEARS.obj : er
- Unity中加入Android项目的Build步骤 .<unity引用Android的jar包><Android对unity做二次开发>