從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嵌套數據
把這些數據組合成三維數據結構
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;
以上就是關于引用學習的記錄