亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

第十二章 Perl5中的引用/指針

by flamephoenix

一、引用簡介
二、使用引用
三、使用反斜線(\)操作符
四、引用和數(shù)組
五、多維數(shù)組
六、子程序的引用
  子程序模板
七、數(shù)組與子程序
八、文件句柄的引用

一、引用簡介
    引用就是指針,可以指向變量、數(shù)組、哈希表(也叫關(guān)聯(lián)數(shù)組)甚至子程序。Pascal或C程序員應(yīng)該對引用(即指針)的概念很熟悉,引用就是某值的地址,對其的使用則取決于程序員和語言的規(guī)定。在Perl中,可以把引用稱為指針,二者是通用的,無差別的。引用在創(chuàng)建復(fù)雜數(shù)據(jù)方面十分有用。
    Perl5中的兩種引用類型為硬引用和符號引用。符號引用含有變量的名字,它對運(yùn)行時(shí)創(chuàng)建變量名并定位很有用,基本上,符號引用就象文件名或UNIX系統(tǒng)中的軟鏈接。而硬引用則象文件系統(tǒng)中的硬鏈接。
    Perl4只允許符號引用,給使用造成一些困難。例如,只允許通過名字對包的符號名哈希表(名為_main{})建立索引。Perl5則允許數(shù)據(jù)的硬引用,方便多了。
    硬引用跟蹤引用的計(jì)數(shù),當(dāng)其數(shù)為零時(shí),Perl自動(dòng)將被引用的項(xiàng)目釋放,如果該項(xiàng)目是對象,則析構(gòu)釋放到內(nèi)存池中。Perl本身就是個(gè)面向?qū)ο蟮恼Z言,因?yàn)镻erl中的任何東西都是對象,包和模塊使得對象更易于使用。
    簡單變量的硬引用很簡單,對于非簡單變量的引用,你必須顯式地解除引用并告訴其應(yīng)如何做,詳見《第 章Perl中的面向?qū)ο缶幊獭贰?br> 二、使用引用
    本章中,簡單變量指像$pointer這樣的變量,$pointer僅含一個(gè)數(shù)據(jù)項(xiàng),其可以為數(shù)字、字符串或地址。
    任何簡單變量均可保存硬引用。因?yàn)閿?shù)組和哈希表含有多個(gè)簡單變量,所以可以建立多種組合而成的復(fù)雜的數(shù)據(jù)結(jié)構(gòu),如數(shù)組的數(shù)組、哈希表的數(shù)組、子程序的哈希表等等。只要你理解其實(shí)只是在用簡單變量在工作,就應(yīng)該可以正確的在最復(fù)雜的結(jié)構(gòu)中正確地解除引用。
    首先來看一些基本要點(diǎn)。
    如果$pointer的值為一個(gè)數(shù)組的指針,則通過形式@$pointer來訪問數(shù)組中的元素。形式@$pointer的意義為“取出$pointer中的地址值當(dāng)作數(shù)組使用”。類似的,%$pointer為指向哈希表中第一個(gè)元素的引用。
    有多種構(gòu)建引用的方法,幾乎可以對任何數(shù)據(jù)建立引用,如數(shù)組、簡單變量、子程序、文件句柄,以及--C程序員會(huì)感興趣的--引用。Perl使你有能力寫出把自己都搞糊涂的極其復(fù)雜的代碼。:)
    下面看看Perl中創(chuàng)建和使用引用的方法。
三、使用反斜線(\)操作符
    反斜線操作符與C語言中傳遞地址的操作符&功能類似。一般是用\創(chuàng)建變量又一個(gè)新的引用。下面為創(chuàng)建簡單變量的引用的例子:
    $variavle = 22;
    $pointer = \$variable;
    $ice = "jello";
    $iceprt = \$ice;
    引用$pointer指向存有$variable值的位置,引用$iceptr指向"jello"。即使最初的引用$variable銷毀了,仍然可以通過$pointer訪問該值,這是一個(gè)硬引用,所以必須同時(shí)銷毀$pointer和$variable以便該空間釋放到內(nèi)存池中。
    在上面的例子中,引用變量$pointer存的是$variable的地址,而不是值本身,要獲得值,形式為兩個(gè)$符號,如下:
#!/usr/bin/perl
$value = 10;
$pointer = \$value;
printf "\n Pointer Address $pointer of $value \n";
printf "\n What Pointer *($pointer) points to $$pointer\n";
    結(jié)果輸出如下:
Pointer Address SCALAR(0x806c520) of 10
What Pointer *(SCALAR(0x806c520)) points to 10
    每次運(yùn)行,輸出結(jié)果中的地址會(huì)有所改變,但可以看到$pointer給出地址,而$$pointer給出$variable的值。
    看一下地址的顯示,SCALAR后面一串十六進(jìn)制,SCALAR說明該地址指向簡單變量(即標(biāo)量),后面的數(shù)字是實(shí)際存貯值的地址。
    注意:指針就是地址,通過指針可以訪問該地址處存貯的數(shù)據(jù)。如果指針指向了無效的地址,就會(huì)得到不正確的數(shù)據(jù)。通常情況下,Perl會(huì)返回NULL值,但不該依賴于此,一定要在程序中把所有的指針正確地初始化,指向有效的數(shù)據(jù)項(xiàng)。
四、引用和數(shù)組
    關(guān)于Perl語言應(yīng)該記住的最重要的一點(diǎn)可能是:Perl中的數(shù)組和哈希表始終是一維的。因此,數(shù)組和哈希表只保存標(biāo)量值,不直接存貯數(shù)組或其它的復(fù)雜數(shù)據(jù)結(jié)構(gòu)。數(shù)組的成員要么是數(shù)(或字符串)要么是引用。
    對數(shù)組和哈希表可以象對簡單變量一樣使用反斜線操作符,數(shù)組的引用如下:
1  #!/usr/bin/perl
2  #
3  # Using Array references
4  #
5  $pointer = \@ARGV;
6  printf "\n Pointer Address of ARGV = $pointer\n";
7  $i = scalar(@$pointer);
8  printf "\n Number of arguments : $i \n";
9  $i = 0;
10 foreach (@$pointer) {
11   printf "$i : $$pointer[$i++]; \n";
12 }
    運(yùn)行結(jié)果如下:
$ test 1 2 3 4
Pointer Address of ARGV = ARRAY(0x806c378)
Number of arguments : 4
0 : 1;
1 : 2;
2 : 3;
3 : 4;     第5行將引用$pointer指向數(shù)組@ARGV,第6行輸出ARGV的地址。$pointer返回?cái)?shù)組第一個(gè)元素的地址,這與C語言中的數(shù)組指針是類似的。第7行調(diào)用函數(shù)scalar()獲得數(shù)組的元素個(gè)數(shù),該參數(shù)亦可為@ARGV,但用指針則必須用@$pointer的形式指定其類型為數(shù)組,$pointer給出地址,@符號說明傳遞的地址為數(shù)組的第一個(gè)元素的地址。第10行與第7行類似,第11行用形式$$pointer[$i]列出所有元素。
    對關(guān)聯(lián)數(shù)組使用反斜線操作符的方法是一樣的--把所有關(guān)聯(lián)數(shù)組名換成引用$poniter。注意數(shù)組和簡單變量(標(biāo)量)的引用顯示時(shí)均帶有類型--ARRAY和SCALAR,哈希表(關(guān)聯(lián)數(shù)組)和函數(shù)也一樣,分別為HASH和CODE。下面是哈希表的引用的例子。
#!/usr/bin/perl
1  #
2  # Using Associative Array references
3  #
4  %month = (
5   '01', 'Jan',
6   '02', 'Feb',
7   '03', 'Mar',
8   '04', 'Apr',
9   '05', 'May',
10  '06', 'Jun',
11  '07', 'Jul',
12  '08', 'Aug',
13  '09', 'Sep',
14  '10', 'Oct',
15  '11', 'Nov',
16  '12', 'Dec',
17  );
18
19 $pointer = \%month;
20
21 printf "\n Address of hash = $pointer\n ";
22
23 #
24 # The following lines would be used to print out the
25 # contents of the associative array if %month was used.
26 #
27 # foreach $i (sort keys %month) {
28 # printf "\n $i $$pointer{$i} ";
29 # }
30
31 #
32 # The reference to the associative array via $pointer
33 #
34 foreach $i (sort keys %$pointer) {
35   printf "$i is $$pointer{$i} \n";
36 }
    結(jié)果輸出如下:
$ mth
Address of hash = HASH(0x806c52c)
01 is Jan
02 is Feb
03 is Mar
04 is Apr
05 is May
06 is Jun
07 is Jul
08 is Aug
09 is Sep
10 is Oct
11 is Nov
12 is Dec
    與數(shù)組類似,通過引用訪問哈希表的元素形式為$$pointer{$index},當(dāng)然,$index是哈希表的鍵值,而不僅是數(shù)字。還有幾種訪問形式,此外,構(gòu)建哈希表還可以用=>操作符,可讀性更好些。下面再看一個(gè)例子:
1  #!/usr/bin/perl
2  #
3  # Using Array references
4  #
5  %weekday = (
6    '01' => 'Mon',
7    '02' => 'Tue',
8    '03' => 'Wed',
9    '04' => 'Thu',
10   '05' => 'Fri',
11   '06' => 'Sat',
12   '07' => 'Sun',
13   );
14 $pointer = \%weekday;
15 $i = '05';
16 printf "\n ================== start test ================= \n";
17 #
18 # These next two lines should show an output
19 #
20   printf '$$pointer{$i} is ';
21   printf "$$pointer{$i} \n";
22   printf '${$pointer}{$i} is ';
23   printf "${$pointer}{$i} \n";
24   printf '$pointer->{$i} is ';
25
26   printf "$pointer->{$i}\n";
27 #
28 # These next two lines should not show anything 29 #
30   printf '${$pointer{$i}} is ';
31   printf "${$pointer{$i}} \n";
32   printf '${$pointer->{$i}} is ';
33   printf "${$pointer->{$i}}";
34 printf "\n ================== end of test ================= \n";
35
    結(jié)果輸出如下:
================== start test =================
$$pointer{$i} is Fri
${$pointer}{$i} is Fri
$pointer->{$i} is Fri
${$pointer{$i}} is
${$pointer->{$i}} is
================== end of test =================
    可以看到,前三種形式的輸出顯示了預(yù)期的結(jié)果,而后兩種則沒有。當(dāng)你不清楚是否正確時(shí),就輸出結(jié)果看看。在Perl中,有不明確的代碼就用print語句輸出來實(shí)驗(yàn)一下,這能使你清楚Perl是怎樣解釋你的代碼的。
五、多維數(shù)組
    語句@array = list;可以創(chuàng)建數(shù)組的引用,中括號可以創(chuàng)建匿名數(shù)組的引用。下面語句為用于畫圖的三維數(shù)組的例子:
    $line = ['solid' , 'black' , ['1','2','3'] , ['4','5','6']];
    此語句建立了一個(gè)含四個(gè)元素的三維數(shù)組,變量$line指向該數(shù)組。前兩個(gè)元素是標(biāo)量,存貯線條的類型和顏色,后兩個(gè)元素是匿名數(shù)組的引用,存貯線條的起點(diǎn)和終點(diǎn)。訪問其元素語法如下:
$arrayReference->[$index]     single-dimensional array
$arrayReference->[$index1][$index2]   two-dimensional array
$arrayReference->[$index1][$index2][$index3] three-dimensional array
    可以創(chuàng)建在你的智力、設(shè)計(jì)經(jīng)驗(yàn)和計(jì)算機(jī)的內(nèi)存允許的情況下極盡復(fù)雜的結(jié)構(gòu),但最好對可能讀到或管理你的代碼的人友好一些--盡量使代碼簡單些。另一方面,如果你想向別人炫耀你的編程能力,Perl給你足夠的機(jī)會(huì)和能力編寫連自己都難免糊涂的代碼。:)
    建議:當(dāng)你想使用多于三維的數(shù)組時(shí),最好考慮使用其它數(shù)據(jù)結(jié)構(gòu)來簡化代碼。
    下面為創(chuàng)建和使用二維數(shù)組的例子:
1  #!/usr/bin/perl
2  #
3  # Using Multi-dimensional Array references
4  #
5  $line = ['solid', 'black', ['1','2','3'] , ['4', '5', '6']];
6  print "\$line->[0] = $line->[0] \n";
7  print "\$line->[1] = $line->[1] \n";
8  print "\$line->[2][0] = $line->[2][0] \n";
9  print "\$line->[2][1] = $line->[2][1] \n";
10 print "\$line->[2][2] = $line->[2][2] \n";
11 print "\$line->[3][0] = $line->[3][0] \n";
12 print "\$line->[3][1] = $line->[3][1] \n";
13 print "\$line->[3][2] = $line->[3][2] \n";
14 print "\n"; # The obligatory output beautifier.
    結(jié)果輸出如下:
$line->[0] = solid
$line->[1] = black
$line->[2][0] = 1
$line->[2][1] = 2
$line->[2][2] = 3
$line->[3][0] = 4
$line->[3][1] = 5
$line->[3][2] = 6
    那么三維數(shù)組又如何呢?下面是上例略為改動(dòng)的版本。
1  #!/usr/bin/perl
2  #
3  # Using Multi-dimensional Array references again
4  #
5  $line = ['solid', 'black', ['1','2','3', ['4', '5', '6']]];
6  print "\$line->[0] = $line->[0] \n";
7  print "\$line->[1] = $line->[1] \n";
8  print "\$line->[2][0] = $line->[2][0] \n";
9  print "\$line->[2][1] = $line->[2][1] \n";
10 print "\$line->[2][2] = $line->[2][2] \n";
11 print "\$line->[2][3][0] = $line->[2][3][0] \n";
12 print "\$line->[2][3][1] = $line->[2][3][1] \n";
13 print "\$line->[2][3][2] = $line->[2][3][2] \n";
14 print "\n";
    結(jié)果輸出如下:
$line->[0] = solid
$line->[1] = black
$line->[2][0] = 1
$line->[2][1] = 2
$line->[2][2] = 3
$line->[2][3][0] = 4
$line->[2][3][1] = 5
$line->[2][3][2] = 6
    訪問第三層元素的方式形如$line->[2][3][0],類似于C語言中的Array_pointer[2][3][0]。本例中,下標(biāo)均為數(shù)字,當(dāng)然亦可用變量代替。用這種方法可以把數(shù)組和哈希表結(jié)合起來構(gòu)成復(fù)雜的結(jié)構(gòu),如下:
1 #!/usr/bin/perl
2 #
3 # Using Multi-dimensional Array and Hash references
4 #
5 %cube = (
6 '0', ['0', '0', '0'],
7 '1', ['0', '0', '1'],
8 '2', ['0', '1', '0'],
9 '3', ['0', '1', '1'],
10 '4', ['1', '0', '0'],
11 '5', ['1', '0', '1'],
12 '6', ['1', '1', '0'],
13 '7', ['1', '1', '1']
14 );
15 $pointer = \%cube;
16 print "\n Da Cube \n";
17 foreach $i (sort keys %$pointer) {
18 $list = $$pointer{$i};
19 $x = $list->[0];
20 $y = $list->[1];
21 $z = $list->[2];
22 printf " Point $i = $x,$y,$z \n";
23 }
    結(jié)果輸出如下:
Da Cube
Point 0 = 0,0,0
Point 1 = 0,0,1
Point 2 = 0,1,0
Point 3 = 0,1,1
Point 4 = 1,0,0
Point 5 = 1,0,1
Point 6 = 1,1,0
Point 7 = 1,1,1
    這是一個(gè)定義立方體的例子。%cube中保存的是點(diǎn)號和坐標(biāo),坐標(biāo)是個(gè)含三個(gè)數(shù)字的數(shù)組。變量$list獲取坐標(biāo)數(shù)組的引用:$list = $$ pointer{$i}; 然后訪問各坐標(biāo)值:$x = $list->[0]; ... 也可用如下方法給$x、$y和$z賦值:($x,$y,$z) = @$list;
    使用哈希表和數(shù)組時(shí),用$和用->是類似的,對數(shù)組而言下面兩個(gè)語句等效:
    $$names[0] = "kamran";
    $names->[0] = "kamran";
    對哈希表而言下面兩個(gè)語句等效:
    $$lastnames{"kamran"} = "Husain";
    $lastnames->{"kamran"} = "Husain";
    Perl中的數(shù)組可以在運(yùn)行中創(chuàng)建和擴(kuò)展。當(dāng)數(shù)組的引用第一次在等式左邊出現(xiàn)時(shí),該數(shù)組自動(dòng)被創(chuàng)建,簡單變量和多維數(shù)組也是一樣。如下句,如果數(shù)組contours不存在,則被創(chuàng)建:
    $contours[$x][$y][$z] = &xlate($mouseX, $mouseY);
六、子程序的引用
    perl中子程序的引用與C中函數(shù)的指針類似,構(gòu)造方法如下:
    $pointer_to_sub = sub {... declaration of sub ...};
    通過所構(gòu)造的引用調(diào)用子程序的方法為:
    &$pointer_to_sub(parameters);
  • 子程序模板

  •     子程序的返回值不僅限于數(shù)據(jù),還可以返回子程序的引用。返回的子程序在調(diào)用處執(zhí)行,但卻是在最初被創(chuàng)建的調(diào)用處被設(shè)置,這是由Perl對Closure處理的方式?jīng)Q定的。Closure意即如果你定義了一個(gè)函數(shù),它就以最初定義的內(nèi)容運(yùn)行。(Closure詳見OOP的參考書)下面的例子中,設(shè)置了多個(gè)錯(cuò)誤信息顯示子程序,這樣的子程序定義方法可用于創(chuàng)建模板。
    #!/usr/bin/perl
    sub errorMsg {
      my $lvl = shift;
      #
      # define the subroutine to run when called.
      #
      return sub {
        my $msg = shift; # Define the error type now.
        print "Err Level $lvl:$msg\n"; }; # print later.
      }
    $severe = errorMsg("Severe");
    $fatal = errorMsg("Fatal");
    $annoy = errorMsg("Annoying");

    &$severe("Divide by zero");
    &$fatal("Did you forget to use a semi-colon?");
    &$annoy("Uninitialized variable in use");
        結(jié)果輸出如下:
    Err Level Severe:Divide by zero
    Err Level Fatal:Did you forget to use a semi-colon?
    Err Level Annoying:Uninitialized variable in use
        上例中,子程序errorMsg使用了局域變量$lvl,用于返回給調(diào)用者。當(dāng)errorMsg被調(diào)用時(shí),$lvl的值設(shè)置到返回的子程序內(nèi)容中,雖然是用的my函數(shù)。三次調(diào)用設(shè)置了三個(gè)不同的$lvl變量值。當(dāng)errorMsg返回時(shí),$lvl的值保存到每次被聲明時(shí)所產(chǎn)生的子程序代碼中。最后三句對產(chǎn)生的子程序引用進(jìn)行調(diào)用時(shí)$msg的值被替換,但$lvl的值仍是相應(yīng)子程序代碼創(chuàng)建時(shí)的值。
        很混淆是嗎?是的,所以這樣的代碼在Perl程序中很少見。
    七、數(shù)組與子程序
        數(shù)組利于管理相關(guān)數(shù)據(jù),本節(jié)討論如何向子程序傳遞多個(gè)數(shù)組。前面我們講過用@_傳遞子程序的參數(shù),但是@_是一個(gè)單維數(shù)組,不管你傳遞的參數(shù)是多少個(gè)數(shù)組,都按序存貯在@_中,故用形如my(@a,@b)=@_; 的語句來獲取參數(shù)值時(shí),全部值都賦給了@a,而@b為空。那么怎么把一個(gè)以上的數(shù)組傳遞給子程序呢?方法是用引用。見下例:
    #!/usr/bin/perl
    @names = (mickey, goofy, daffy );
    @phones = (5551234, 5554321, 666 );
    $i = 0;
    sub listem {
      my ($a,$b) = @_;
      foreach (@$a) {
        print "a[$i] = " . @$a[$i] . " " . "\tb[$i] = " . @$b[$i] ."\n";
        $i++;
      }
    }
    &listem(\@names, \@phones);
        結(jié)果輸出如下:
    a[0] = mickey     b[0] = 5551234
    a[1] = goofy      b[1] = 5554321
    a[2] = daffy      b[2] = 666
    
    注意:
    1、當(dāng)想傳遞給子程序的參數(shù)是多于一個(gè)的數(shù)組時(shí)一定要使用引用。
    2、一定不要在子程序中使用形如 (@variable)=@_; 的語句處理參數(shù),除非你想把所有參數(shù)集中到一個(gè)長的數(shù)組中。
    八、文件句柄的引用
        有時(shí),必須將同一信息輸出到不同的文件,例如,某程序可能在一個(gè)實(shí)例中輸出到屏幕,另一個(gè)輸出到打印機(jī),再一個(gè)輸出到記錄文件,甚至同時(shí)輸出到這三個(gè)文件。相比較于每種處理寫一個(gè)單獨(dú)的語句,可以有更好的實(shí)現(xiàn)方式如下:
        spitOut(\*STDIN);
        spitOut(\*LPHANDLE);
        spitOut(\*LOGHANDLE);
        其中子程序spitOut的代碼如下:
    sub spitOut {
      my $fh = shift;
      print $fh "Gee Wilbur, I like this lettuce\n";
    }
        注意其中文件句柄引用的語法為\*FILEHANDLE。

    上一章 下一章 目錄