第八章 引用:
在C里,间接的最常见的形式就是指针,它可以让一个变量保存另外一个变量的内存地址。
在Perl里,间接的最常见的形式是引用
@vitals = ('john', 'mary', 'bill');
一个引用可以指向任何数据结构。因为引用是标量,所以你可以把它们保存在数组的散列里,
因此我们就可以做出数组的数组,散列的数组,数组的散列
8.2.1 反斜杠操作符:
你可以用一个反斜杠创建一个指向任何命名变量或者子过程的引用。(你还可以把它用于一个匿名标量值,
比如7或"camel",尽管你通常并不需要这些东西。) 乍一看,这个操作符的作用类似C里的&(取址)操作符
8.2.2.1 匿名数组组合器:
你可以用方括弧创建一个指向匿名数组的引用:
zjzc01:/root/big2# cat a6.pl
$arrayref = [1, 2, ['a', 'b', 'c', 'd']];
print $arrayref."
";
print @$arrayref."
";
print $$arrayref[0]."
";
print $$arrayref[1]."
";
print $$arrayref[2]."
";
print $$arrayref[2][0]."
";
print $$arrayref[2]->[0]."
";
zjzc01:/root/big2# perl a6.pl
ARRAY(0x20e5608)
3
1
2
ARRAY(0x20c8d48)
a
a
现在我们有一个方法来表示我们本章开头的表:
zjzc01:/root/big2# cat a7.pl
$table = [ [ "john", 47, "brown", 186], [ "mary", 23, "hazel", 128], [ "bill", 35, "blue", 157] ];
print "$table is $table
";
print "@$table is @$table
";
print $$table[0][0]."
";
print $$table[0][1]."
";
print $$table[1][0]."
";
zjzc01:/root/big2# perl a7.pl
$table is ARRAY(0x1bf56d8)
@$table is ARRAY(0x1bcdd48) ARRAY(0x1bea4a0) ARRAY(0x1bf5648)
john
47
mary
8.2.2.2 匿名散列组合器:
你可以用花括弧创建一个指向匿名散列的引用:
zjzc01:/root/big2# cat a8.pl
$hashref = {
'Adam' => 'Eve',
'Clyde' => $bonnie,
'Antony' => 'Cleo' . 'patra',
};
print %$hashref."
";
print $$hashref{Adam}."
";
zjzc01:/root/big2# perl a8.pl
2/8
Eve
现在我们有了表示本章开头的另外一种方法:
zjzc01:/root/big2# cat a9.pl
$table = {
"john" => [47, "brown", 186],
"mary" => [23, "hazel", 128],
"bill" => [35, "blue", 157],
};
print $table."
";
print %$table;
print "
";
print $$table{john}[0];
print "
";
zjzc01:/root/big2# perl a9.pl
HASH(0xb975f0)
johnARRAY(0xb7ad48)billARRAY(0xb97578)maryARRAY(0xb97500)
47
这是一个数组散列,选择最好的数据结构是难度很高的工种,下一章专门讲这个。
但是为了恶作剧,我们甚至可以将散列的散列用于我们的表:
zjzc01:/root/big2# cat a10.pl
$table = {
"john" => { age => 47,
eyes => "brown",
weight => 186,
},
"mary" => { age => 23,
eyes => "hazel",
weight => 128,
},
"bill" => { age => 35,
eyes => "blue",
weight => 157,
},
};
print $table;
print "
";
print %$table;
print "
";
print $$table{john}{age};
print "
";
zjzc01:/root/big2# perl a10.pl
HASH(0x164c368)
johnHASH(0x1628d48)billHASH(0x1645638)maryHASH(0x16455c0)
47
8.2.2.3 匿名子过程组合器:
你可以通过不带子过程名字的sub创建一个匿名子过程:
你可以通过用不带子过程名字的sub 创建一个匿名子过程:
zjzc01:/root/big2# cat a11.pl
$coderef = sub {print "Boink!
"};
print &$coderef."
";
zjzc01:/root/big2# perl a11.pl
Boink!
1
8.2.3
构造器可以用下列任何方法调用:
$objref = Doggie::->new(Tail => 'short', Ears => 'long'); #1
$objref = new Doggie:: Tail => 'short', Ears => 'long'; #2
$objref = Doggie->new(Tail => 'short', Ears => 'long'); #3
$objref = new Doggie Tail => 'short', Ears => 'long'; #4
第一个和第2个调用方法是一样的,它们都调用了Doggie模块提供的一个叫new的函数。
8.2.5 符号表引用:
$scalarref = *foo{SCALAR}; # 和 $foo 一样
$arrayref = *ARGV{ARRAY}; # 和 @ARGV 一样
$hashref = *ENV{HASH}; # 和 \%ENV 一样
$coderef = *handler{CODE}; # 和 &handler 一样
$globref = *foo{GLOB}; # 和 *foo 一样
$ioref = *STDIN{IO}; # ?...
8.3.1 把一个变量当作变量名使用:
bless 以一个普通的指向数据结构的引用参数。它将会把那个数据结构(注意,不是引用本身)
标记为属于某个特定的包,于是这样就赋予了它更强大的功能。
bless有两个参数:对象的引用、类的名称。
类的名称是一个字符串,代表了类的类型信息,这是理解bless的关键。
所谓bless就是把 类型信息 赋予 实例变量。
一个象 $$arrayref[0] 这样的表达式等于
${$arrayref}[0] 并且意思是数组的第一个元素由 $arrayref 指向。
8.3.2 把一个BLOCK块当作变量名用:
8.3.3 使用箭头操作符:
对于指向数组,散列,或者子过程的引用,第三种解引用的方法涉及到使用-> 中缀操作符。
这样做就形成了一种语法糖,这样就让我们可以更容易访问独立的数组或者散列元素,或者间接地调用一个子过程。
zjzc01:/root/big2# cat a12.pl
$arrayref=[a,b,c,d];
print @$arrayref;
print "
";
print $$arrayref[2]."
";
print ${ $arrayref }[2]."
";
print $arrayref->[2]."
";
zjzc01:/root/big2# perl a12.pl
abcd
c
c
c
zjzc01:/root/big2# cat a13.pl
$hashref={"a"=>1,"b"=>2,"c"=>3};
print %$hashref;
print "
";
print $$hashref{a}."
";
print ${ $hashref }{a}."
";
print $hashref->{a}."
";
zjzc01:/root/big2# perl a13.pl
c3a1b2
1
1
1
zjzc01:/root/big2# cat a14.pl
$array=[1,2,3,{"English"=>[a,b,c]}];
print @$array;
print "
";
print $$array[3]->{"English"}->[0];
print "
";
zjzc01:/root/big2# perl a14.pl
123HASH(0xd6b488)
a
请注意 $array[3] 和 $array->[3] 是不一样的。第一个东西讲的是 @array 里的第四
个元素,而第二个东西讲的是一个保存在 $array 里的数组(可能是匿名的数组)引用的
第四个元素。
8.3.4 使用对象方法:
8.3.5 伪散列:
zjzc01:/root/big2# cat a15.pl
$john = [ {age => 1, eyes => 2, weight => 3}, 47, "brown", 186 ];
print @$john;
print "
";
print $$john[0]{age}."
";
zjzc01:/root/big2# perl a15.pl
HASH(0x11c6d48)47brown186
1
8.3.6 硬引用可以用的其他技巧:
8.3.7 闭包(闭包)
我们早些时候谈到过用一个没有名字的sub{} 创建匿名子过程。
你可以把那些子过程看作是在运行时定义,这就意味着它们有一个生成的时间和一个定义的地点。
zjzc01:/root/big2# cat a16.pl
{
my $critter = "camel";
$critterref = $critter;
};
print "$critter is $critter
";
print "$critterref is $$critterref
";
zjzc01:/root/big2# perl a16.pl
$critter is
$critterref is camel
$$critterref 的数值仍将是“camel”,即使在离开闭合的花括弧之后 $critter 消失了也如
此。但是 $critterref 也可以指向一个指向了 $critter 的子过程:
(请注意这些与闭合相关的事情只适用于 my 变量。全局量还是和往
常一样运转,因为它们不是按照词法变量的方式创建和删除的。)