第章 数据引用与匿名存储

主要有两方面的不同将用语创建真正复杂系统的编程语言,与普通的教学语言区分开来。

那些更加健壮的编程语言具有以下特点:

1. 不必使用变量名就能动态地位数据分配存储空间,我们称之为匿名数据结构

2.可以指向任何数据结构,无论它是静态分配还是动态分配的

指针,简言之,就是保存其他数据地址的变量。这个地址可以是机器地址,在C语言中就是这样,

也可以是一种更高抽象层次的实体,比如名字或数组偏移量。

Perl 对这两种概念都支持的相当好,它允许你创建匿名数据结构,而且还提供了一种称做"引用(reference)"的类似

于C语言指针的基本数据类型。


正像C语言指针可以指向数据甚至函数地址一样,Perl的引用同样可以指向常规数据类型

(如标量变量,数组和散列表)和其他类型的实体



因为和C语言不同,Perl 为你省去了许多不必要的工作。比如下面这行代码:

$line[19] = "hello";


它创建了一个20个元素的数组,然后将最后一个元素赋值为一个字符串。


对已有变量的引用:

如果你有C语言编程背景的话,就会知道有两种方法可以用来初始化C语言中的指针。

int a,*p

p = &a;  /* p 中现在包含a的地址*/

你可以通过在已有变量名前添加"" 来创建对它的引用,例如:


引用本身就是一种标量变量:


在我们讨论这个专题中,有一点很重要,那就是使用引用作为散列表的键值

间接访问:

间接访问(dereference) 的意思就是取得引用所指的变量的值


在C语言中,如果p是一个指针,那么*p 就表示p所指向的值。


对数组的引用:

你可以用三种方式使用普通数组:

1.将数组作为一个整体进行存取,使用记号@array.例如,你可以打印整个数组或向其中添加元素

2.使用记号$array[$i] 来存取数组中的单个元素

3.使用记号@array[index,index2,...] 来分段(slice)存取数组中的元素。



对散列表的引用:

对散列表的引用同样直接了当:

zjzc01:/root/hei# cat a2.pl 
%hash=(key1=>1,b=>2);
$rhash = \%hash;
print $hash{"key1"};  ##普通的散列表元素存取

print $$rhash{"key1"};
zjzc01:/root/hei# perl a2.pl 
11zjzc01:/root/hei# 


优先级:

zjzc01:/root/hei# cat a3.pl 
$rarray=[a,b,c];
print $rarray;
print "
";
print @$rarray;
print "
";
print $$rarray[1];
print "
";

zjzc01:/root/hei# perl a3.pl 
ARRAY(0xc40d48)
abc
b

简明的箭头记号:

Perl 提供了另一种简单易读的用以存取数组和散列表元素的语法结构:"->[]"记号。

例如, 如果给出了数组的引用,你可以这样来获取数组中的第2个元素:

zjzc01:/root/hei# cat a4.pl 
@array=qw/a b c d/;
$rarray = @array;
print $$rarray[1];  ##杂乱,还的考虑优先级
print "
";

print $rarray->[1]; ##易读,简明的方式
print "
";


zjzc01:/root/hei# perl a4.pl 
b
b

我更倾向于使用箭头记号,因为它视觉上更干净些。


zjzc01:/root/hei# cat a5.pl 
%hash=(k1=>1,k2=>2);
$rhash = \%hash;
print $rhash->{"k1"};
print "
";

##也可以使用
print $$rhash{"k1"};
print "
";
zjzc01:/root/hei# perl a5.pl 
1
1

不存在自动间接访问:


Perl 不会进行自动间接访问,你必须使用刚才讲到的结构来执行显示的间接访问操作。

这和C语言一样,在C语言中也必须使用*p 来表示p所指的对象。

zjzc01:/root/hei# cat a6.pl 
$rarray = @array;

push ($array,1,2,3);
zjzc01:/root/hei# perl a6.pl 
Type of arg 1 to push must be array (not scalar dereference) at a6.pl line 3, near "3)"
Execution of a6.pl aborted due to compilation errors.

错误,$rarray 是一个标量变量,而不是数组


push 操作符要求第一个参数为数组而不是指向数组的引用(而引用则是一个标量变量)


使用引用:

向子例程传递数组和散列表:


当你要向子例程中传递一个以上的数组或散列表时,Perl将会把它们合并到@_数组中供子例程使用。


唯一避免合并的方法就是传递输入数组或散列表的引用。下面是一个将一个数组中的元素与另一个数组中对应元素想加的例子:

zjzc01:/root/hei# cat a7.pl 
@array1 = (1,2,3);

@array2 = (4,5,6,7);

AddArrays (@array1,@array2); ###以引用方式传递数组


sub AddArrays {
              my ($rarray1,$rarray2) = @_;
              print $$rarray1[0]."
";
              print $$rarray2[0]."
";
};
zjzc01:/root/hei# perl a7.pl 
1
4

运行效率:

通过使用引用,我们可以高效的向子例程中传入或传出大量数据:

匿名存储的引用:

到目前为止,我们学习创建了对已存在变量的引用,现在我们要学习对"匿名" 数据结构的引用,

也就是那些没有同变量名关联的值。

创建匿名数组,需要使用方括号而不是圆括号,如:


zjzc01:/root/hei# cat a8.pl 
$ra=[ ];  #创建一个空的匿名数组,并返回对它的引用
$ra = [1,"hello"]; #创建一个经过初始化的匿名数组,并返回对它的引用
print $ra;
print "
";
print @$ra;
print "
";
print $$ra[0];
print "
";
zjzc01:/root/hei# perl a8.pl 
ARRAY(0x20fff40)
1hello
1

要创建匿名散列表,就用大括号代替方括号即可:

zjzc01:/root/hei# cat a9.pl 
$rh = {}; ##创建一个空的散列表并返回对它的引用
$rh = {"k1","v1","k2","2"};  ##一个经过初始化的匿名散列表;

print $rh;
print "
";
print %$rh;
print "
";
print $$rh{k1};
print "
";
zjzc01:/root/hei# perl a9.pl 
HASH(0x20a0f40)
k22k1v1
v1

所有这两种记号都很容易记忆,因为它们与其他相应的数据类型使用相同的种类的括号。

数组用数组类型的括号,散列表用散列表类型的括号


zjzc01:/root/hei# cat a10.pl 
%hash=("flock" => "birds","pride" =>"lions"); ##这是一个普通使用%前缀的散列表,它有圆括号所包围的列表初始化;
print %hash;
print "
";
##匿名散列表是一组大括号括起来的列表

$rhash = {"flock" =>"birds","pride"=>"lions"};
print $rhash;
print "
";
print %$rhash;
print "
";
zjzc01:/root/hei# perl a10.pl 
flockbirdspridelions
HASH(0x19b1b98)
flockbirdspridelions


zjzc01:/root/hei# cat a11.pl 
{ my $a="hello world";
     };
print "$a is $a
";

zjzc01:/root/hei# perl a11.pl 
$a is 

zjzc01:/root/hei# cat a12.pl 
{  $a="hello world";
     };
print "$a is $a
";

zjzc01:/root/hei# perl a12.pl 
$a is hello world


多重引用的间接访问:

我们已经看到了引用时如何指向包括其他引用在内的其他实体了(这些引用本身就是普通标量变量).

也就是说我们可以像下面这样创建多重引用:

一种更加通用的规则:

前面早些时候,在讨论优先级时,我们讲过$$rarray[1] 实际上和${$rarray}[1] 是等价的.


花括号表明了一个代码块,并且并不关心你在里面都放些什么,只要其最终返回指向所要求数据类型的引用即可。


对照一下下面的例子,它在括号中调用了一个返回引用的子例程:

zjzc01:/root/hei# cat a14.pl 
sub test {
    return $a;  ##返回一个指向标量的引用
};
$a = 10;
$b=&test;  ##返回引用
print "$b is $$b
"; ##解引用
zjzc01:/root/hei# perl a14.pl 
$b is 10


嵌套数据结构:

大家知道数组和散列表只能包含标量变量类型的元素:

它们不能直接包含别的数组或散列。


但是引用可以指向数组和散列表,而且引用本身就是标量

隐含的创建复杂的数据结构:

假设一下语句是你程序的第一行:

zjzc01:/root/hei# cat a15.pl 
%sue=("children"=>[a,{"age"=>10,"name"=>'xx'}]);
print %sue;
print "
";
print $sue{children}->[1]->{age};
print "
";
zjzc01:/root/hei# perl a15.pl 
childrenARRAY(0xf362c0)
10

Perl 将自动的创建散列表%sue,使其用一个以children为键值的散列元素,


并让它指向一个新建的数组,而它的第2个元素被设置为指向一个新建的散列表,该表则拥有一个以字符串age为键值的元素。


最后的缩写:省去两个下标间的箭头


zjzc01:/root/hei# cat a15.pl 
%sue=("children"=>[a,{"age"=>10,"name"=>'xx'}]);
print %sue;
print "
";
print $sue{children}->[1]->{age};
print "
";
print $sue{children}[1]{age};
print "
";
zjzc01:/root/hei# perl a15.pl 
childrenARRAY(0xf612c0)
10
1

引用的查询:

ref 函数被用来查询标量变量是否包含一个引用,是的话,在判定所指向的是什么数据类型。


符号引用:











原文地址:https://www.cnblogs.com/hzcya1995/p/13351110.html