Effective Perl-chapter6

从perl5开始引入的引用是perl的学习中的一个重点,它为复杂数据结构和面向对象的编程的方式打开了一扇门。要想良好组织数据并对其进行整体传递,引用是关键,要想更好的解决复杂的问题,熟练的掌握引用是必须要攻克的。

理解引用和引用的语法

引用实际上是一个标量值,我们可以像数字和字符串一样,把引用直接存储于标量变量中或者作为元素存储到数组和哈希中。
我们可以把引用当成是指向其他perl对象的“指针”,引用可以指向任何类型的对象
在perl中只能对已经存在的对象创建引用

创建引用
最常用的是反斜杠操作符(或者说是“取引用”操作符)作用于一个变量

my $a = 3.1416;
my $scalar_ref = \$a;

反斜杠可以运用于任何变量名

my $array_ref = \@array;
my $hash_ref = \%hash;
my $sub = \⊂

对于数组和哈希元素也可以取引用

my $array_elem_ref = \$a[0];
my $hash_elem_ref = \$a{"hello"};

而对某个列表取引用的话,返回的是列表中每个元素的引用组成的新列表,而非列表本身引用,究竟返回何种数据的引用,得看取引用的方式

sub val {return 1 .. 3};

# 如果创建引用时用的是&符号,那么得到的是指向子程序val的代码引用
my $a = \(&val);

#如果创建引用前先调用val,那么返回的是标量引用
my $a = \(val() );        #得到的是val返回的列表中的最后一个值3的引用

#在列表上下文赋值
my ($a) = \(val() );      #得到的是val返回的列表中的第一个值1的引用

#上面是对从子程序返回的列表中创建引用的方式,对包含直接量的列表同样适用
my $a = \(1 .. 3);

我们经常用到匿名数组,匿名数组的构造语法和普通列表很像,唯一不同的是匿名数组用的是方括号

匿名数组会在内存中创建一个没有名字的数组,并返回该数组的引用,这是创建一列数据的引用最自然最常用的方法

my $a = [1 .. 3];
#现在$a就是一个数组引用,一个包含数字1,2,3的匿名数组

匿名哈希的构造是用花括号而不是方括号

my $h_ref = {'F' => 9, 'cl' => 17, 'br' => 35};

定义子程序时如果没有给出名字,则返回匿名子程序引用(代码引用)

my $greeting = sub {print "hello world\n"};
$greeting -> ();        #执行代码引用

在传递大字符串时,用标量引用就非常高效

my $string = 'a' x 100000;
some_sub {$string};    #将整个字符串复制了一遍
some_sub {\$string};   #传递字符串的引用

使用引用
解引用指的是取引用指向的那个值。最规范安全的语法是将引用放在代码块(花括号括起来的区块)中返回,然后把它当作某个变量或子程序的标识符使用

#标量解引用
my $a = 1;
my $s_ref = \$a;
print ${$s_ref};
${$s_ref} += 1;

#数组解引用
my @a = 1 ..5;
my $a_ref = \@a;
print "@{$a_ref}";
push @{$a_ref}, 6 .. 10;

如果引用值存在标量变量中,我们可以省略花括号,直接使用标量变量的名字,前面再加上$符号开头

my $string = "hello world";
my $ref = \$string;
print $$ref;

上面解引用的方式看起来不是很直观,可以使用箭头操作符,通过下标的方式取数组或哈希的值

${$h_ref}{'F'}        #常规方式
$$h_ref{'F'}            #简化方式
$h_ref -> {'F'}        #箭头方式

箭头可以连打,如果箭头左右两边都是元素下标的话,那就可以省略箭头

$a ->[1] = {'first' => 'joe',};
print $a -> [1] -> {'first'};
print $a -> [1]{'first'};      #可以省略箭头

自动代入
如果我们把某个含有未定义值的标量当作指向其他数据类型的引用,perl就会自动创建相应类型的数据,并把这个标量指向该数据类型的引用。这种方式称为Autovivification

my $ref;
$ref -> [3] = 'four';
#上述代码自动创建一个包含四个元素的数组,并将$ref作为指向该数组的引用

利用这个特性,我们可以免去逐层定义,非常方便地创建深层次的数据结构

my $ds;
$ds -> {top}[0]{cats}[1]{name} = 'Buster';

软引用
如果对一个字符串值解引用,perl会返回以字符串为名字的变量的值。如果变量不存在,就会自动创建,这个称为软引用

不要把普通标量当作引用使用,实际上创建了一个软引用

my $str = 'pi';
${$str} = 3.14;
print "$pi\n";        #通过软引用自动创建变量$pi

#我们可以直接用字符串创建软引用
${'e' . 'e'} = 2;
print $ee;

类似这样的变量名可以不是合法的标识符,我们可以创建以空白字符命名的变量(可能没什么用)

${} = 'space';

引用创建复杂数据结构

使用某个变量之前,确认它是常规数组还是数组引用

#一个数组,包含其他数组的引用
my @a = ( [1,2] , [3,4] );
print $a[0][1];        # 2

#指向一个数组的引用,该数组包含指向其他数组的引用
my $a = [ [1,2] , [3,4] ];
print $a -> [0][1];      # 2

#快速访问文本中的第几行
my @lines;
while (<>) {
        chomp;
        push @lines, [split];
}
my $thirld_on_seventh = $lines[6][2];        #第七行第三个单词

#统计某一行的单词数量
my $count = @{$lines[6]}        #统计第7行的单词数量

#统计最长单词数量的行数
my ($most_words) = 
map { $_ -> [0] } 
sort { $b -> [1] <=> $a -> [1] }
map { [ $_ , scalar @{ $lines[$_] } ] } 0 .. $#lines;

print "Line $most_words is the longest with" , "scalar @{ $lines[$most_words] }", "words\n"         

匿名数组操作符和列表操作符

匿名数组操作符[]和列表操作符()很像,表面上来看,它们都是为同一个目的服务的,那就是创建列表。但其实还有显著的不同之处

匿名数组返回的是一个引用,而不是列表,因此可以直接创建指向数组对象的引用,无需事先创建一个具名数组

my $aref = [ 0 .. 9 ];        # 列表上下文环境

通过匿名哈希创建C风格的struct结构

perl没有提供像C那样的stuct结构体类型的数据,一句话,perl其实是无结构的。但是,另一个角度看,哈希提供了极为相似的效果

$student{'last'} = 'smith';
$student{'first'} = 'John';
$student{'bday'} = '01/08/72';

当用到一个散列元素时,只要键名是合法的perl标识符,我们就可以省略它两边的引号

$student{last} = 'smith';

实际应用中,我们可以事先创建一个空结构,然后一点一点往里面填充

$student = {};
$student -> {last} = 'smith';

用map和grep操作复杂数据结构

用map切片
读入一个含有三维坐标的文件

# point data
1  2  3
4  5  6
7  8  9

open my ($points), '<' , 'points' or die "$!";

while (<$ponits>) {
        next if /^\s*#.*$/;
        push @xyz, [split];
}

foreach my $pt (@xyz) {
        print "point " ,"x = $pt -> [0] , y = $pt -> [1] , z = $pt -> [2]\n"
}

# 取出每个点的x轴值
for (my $i = 0 ; $i < @xyz ; $i ++) {
        push @x, $xyz[$i][0];
}
#用map最自然
my @x = map { $_ -> [0] } @xyz;  

用map嵌套数据

2019-06-25 10-10-37 的屏幕截图.png

把这些数据组合成三维数据结构

for (mt $i = 0 ; $i < @x ; $i ++) {
        $xyz[$i][0] = $x[$i];
        $xyz[$i][1] = $y[$i];
        $xyz[$i][2] = $z[$i];
}

#然而使用map,则更加简洁,直接在map里面用[]构造内层数据结构
my @xyz = map { [ $x[$_] , $y[$i] ,$z[$i] ] } 0 .. $#x;

#还可以交换x和y坐标的位置
my @yxz = map { [$_ -> [1] , $_ -> [0] , $_ -> [2] ] } @xyz;

#还可以利用切片对数组元素进行重新排列
my @yxz = map { @$_[1 , 0 , 2] } @xyz;

用grep进行选择

#收集y大于x坐标点的x坐标值
my @x = map { $_ -> [0] } grep { $_ -> [0] > $_ -> [1] } @xyz;

以上就是关于引用学习的记录

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容