开始学习函数。
函数的返回值是最后一个表达式的值,或者是return语句显式返回的值。
挺有意思的,perl函数的参数不需要声明,用@_,$_[0],$_[1],$_[2],$_[3],...来引用。
做个练习(f71.pl):
1)看看是传值还是传引用
2)顺便掌握内插函数的写法${\&Test($v1,$v2)} 。为什么需要${\}转义没明白。练习的环境是5.8.8,希望更高版本能更省事一些。
3)$v2传进去了,但是没使用。这说明perl在传参数这件事上还是很灵活的。
- #!/usr/bin/perl -w
- sub Test {
- $p1 = $_[0];
- $_[0] .= " be changed.";
- return $p1;
- }
- $v1 = "abc";
- $v2 = "efg";
- print "Test return: ${\&Test($v1,$v2)} \n";
- print qq(now v1=$v1\n);
- #others' code
- print "foo: [${ \&foo() }]\n";
- print "bar: [@{ [&bar()] }]\n";
- sub foo {
- return "single message";
- }
- sub bar {
- return ("hello", "world");
- }
$ perl f71.pl
Test return: abc
now v1=abc be changed.
foo: [single message]
bar: [hello world]
目前我的理解是这种传参数的方式的要点在于函数是用动态长度的列表来接收参数的。这样,想一次传多个列表就要想别的办法。例如,(@a,@b)=@_;这种接收方式的结果是@a把@_全部接收了。($a,$b,@others)=@_;这样可以接收多个变量和1个列表,但是列表要放最后面。传哈希列表类似的,也要放最后面。
吃完饭回来继续写。。。。。
开始学习引用(指针/别名)。
引用的语法:$ref=\$a; 这样$ref和$a就指向同一个数据块了吗?噢,使用$ref和使用$a还是有差别的。$a和$$ref返回的结果是一样的。为什么ref前面有两个$?哈哈,这下大约是捕捉到$的含义了。为了方便阅读,下面另起一段专门说说这个事。
变量在内存中应该是由2部分组成,一部分是“名字”,另一部分是“值的位置”。如果把“值”理解为没有“名字”的变量,那么这个事情就能忽悠圆了。执行完$a="abc"; $ref=\$a;以后,内存中应该有三块了:ref(a的位置)、a("abc"的位置)、("abc"),即,ref-->a-->"abc"。\$这个符号返回的是变量的位置,$要根据位置去找下一个变量,那么$ref就不应该是("abc的位置"),而应该是(复制)ref所指向的变量或常量。因此,想得更多一些,$b=$a; 不应理解为“将a的值拷贝给b”,而应理解为“复制一份a所指向的变量,然后让b指向这个复制品(保存这个复制品的位置)”。
通过以上讨论,不难发现要想彻底控制ref-->a-->"abc",还缺少获取变量名称的操作符。花了不少时间,得到的答案是要用到安装PadWalker模块(下次再学),网址:http://search.cpan.org/~robin/PadWalker-1.9/PadWalker.pm
练习(f73.pl):
- #!/usr/bin/perl -w
- $a="abc";
- print "\$a: address " . \$a . "value $a\n";
- $b=$a;
- print "\$b: address " . \$b . "value $b\n";
- $ra=\$a;
- print "\\\$ra: address " . \$ra . " value $ra\n";
- $rb=$ra;
- print "\\\$rb: address " . \$rb . " value $rb\n";
- $$rb="cde";
- print qq(after reset \$\$rb=cde a=$a b=$b \$\$ra=$$ra \$\$rb=$$rb);
- print "\n";
$ perl f73.pl
$a: address SCALAR(0x8c45600)value abc
$b: address SCALAR(0x8c45684)value abc
\$ra: address REF(0x8c456fc) value SCALAR(0x8c45600)
\$rb: address REF(0x8c45774) value SCALAR(0x8c45600)
after reset $$rb=cde a=cde b=abc $$ra=cde $$rb=cde
数组引用和哈希引用同样的道理。ref-->a-->('a','b','c');
练习(f74.pl):
- #!/usr/bin/perl -w
- @a=qw(a b c);
- $ra=\@a;
- %ha=(a=>"1",b=>"2",c=>"3");
- $rha=\%ha;
- print qq(\$\$ra[0]=$$ra[0] \@\$ra[1,2]=@$ra[1,2] \$\$rha{a}=$$rha{a});
- print("\n");
$ perl f74.pl
$$ra[0]=a @$ra[1,2]=b c $$rha{a}=1
用{}匿名引用哈希列表,用[]匿名引用顺序列表(终于想到一个好名字“顺序列表”)。下面是代码片断:
- $rh1={a=>"11",b=>"22"};
- print $$rh1{b} . "\n";
- $r1=["a","b","c"];
- print $$r1[2] . "\n";
打印(print)结果:
22
c
引用是用变量存储的,函数用列表接收参数,这样我们就能够实现用函数接收多个列表了。而且,通过引用,我们还能模拟二维列表,甚至N维数据结构。
在给函数传递引用时,需要特别注意的是引用是可以修改原值的。一般教程中会提示说“危险”,我想这个危险应该是源自“无知”而不是“引用”本身,既然已经明白了引用,就没什么可畏惧的,带着畏惧之心更容易出错。在实践中可以增加函数的注释,注明其传递的是引用,还应注明是否对原值有修改。
这次就到这,下次学习正则表达式和CPAN。