Learning Perl 4ed Reading Notes – Chapter4 Subroutines

來源:互聯網
上載者:User
1. 有關function和subroutine。本書中的function指的是Perl built-in的函數,subroutine指的是user-defined 函數,本質上來說,function和subroutine是一回事。和Pascal不一樣,Pascal中的function和subroutine是 不一樣的,function有傳回值,而subroutine是沒有傳回值的。

2. Defining a Subroutine. 很簡單:

Code: Select all
sub marine {
  $n += 1;  # Global variable $n
  print "Hello, sailor number $n!\n";
}

用 關鍵字sub就定義了一個名為marine的subroutine,注意subroutine中的n變數是一個global variable,後面會介紹如何定義一個局部變數。Perl中的subroutine的代碼可以放置在代碼的任何地方,一般我們都會把 subroutine的代碼放在開頭部分(和C的習慣一樣)。如果我們在代碼中定義了兩個同名的subroutine,那麼後定義的subroutine 會覆蓋前面那個subroutine。

3. Invoking a Subroutine. 很簡單,直接用&就表示調用一個subroutine:

&marine; # says Hello, sailor number 1!
&marine; # says Hello, sailor number 2!
&marine; # says Hello, sailor number 3!
&marine; # says Hello, sailor number 4!

4. Return Values. 這一點Perl和其他的語言很不一樣。Perl預設會把subroutine中最後一句被執行的代碼的傳回值/執行結果作為整個subroutine的return value,除非我們顯式的用return語句。

Code: Select all
sub sum_of_fred_and_barney {
  print "Hey, you called the sum_of_fred_and_barney subroutine!\n";
  $fred + $barney;  # That's the return value
}

上例中,$fred + $barney的結果就是整個subroutine的傳回值。所以,千萬注意最後一句代碼,免得傳回值出錯哦,比如:

Code: Select all
sub sum_of_fred_and_barney {
  print "Hey, you called the sum_of_fred_and_barney subroutine!\n";
  $fred + $barney;  # That's not really the return value!
  print "Hey, I'm returning a value now!\n";      # Oops!
}

最後多了一句print,所以,整個subroutine的return value就發生變化了,就變成print的傳回值了,print在成功的時候返回1(true),列印失敗返回0。

再看這個例子:

Code: Select all
sub larger_of_fred_or_barney {
  if ($fred > $barney) {
    $fred;
  } else {
    $barney;
  }
}

subroutine的傳回值是最後一句被執行的代碼,不是最後一句代碼哦,所以上例中,subroutine會返回兩個變數中較大的那個。

5. Arguments. 本節講述如何定義和使用subroutine arguments。Perl中給subroutine傳遞參數是通過List的方式做的:

$n = &max(10, 15); # This sub call has two parameters

這 樣就把List (10, 15)傳遞給了max subroutine,此時Perl會把這個List存在Perl的預設Array @_中,然後我們用$_[0], $_[1]...這樣的方式就可以引用這些arguments。注意這裡其實變數是_,加上了@符號就表示引用整個List,用$符號就表示引用List 中的一個元素,這在第三章已經詳細討論過了。第三章中講foreach結構的時候我們還講述了$_這個default variable,意思和這裡的是一樣的。

Code: Select all
sub max {
  # Compare this to &larger_of_fred_or_barney
  if ($_[0] > $_[1]) {
    $_[0];
  } else {
    $_[1];
  }
}

於 是代碼就變成了上面的樣子。但是上面的代碼無疑是可讀性較差的,下一節會講述如何改變這種狀況。而且上面的代碼還有一個問題,就是調用max的時候給了三 個參數怎麼辦?很顯然,第三個參數會被ignore;如果調用max的時候給了一個參數的話,第二個參數就是undef。

OK, 本節最後講一個非常重要的東西:每個subroutine都有一個自己的@_,比如我們一個subroutine中調用另外一個subroutine(帶 參數的),那麼這兩個subroutine都有自己的@_,我們不用擔心調用了其他的subroutine會影響到自己的@_ array,Perl會為我們自動處理這些事情,所以不用擔心。

6. Subroutine中的局部變數(Private Variable)。如下, 使用my這個關鍵字:

Code: Select all
sub max {
  my($m, $n);       # new, private variables for this block
  ($m, $n) = @_;    # give names to the parameters
  if ($m > $n) { $m } else { $n }
}

上 例中,我們用my關鍵字定義了一個List,然後將參數array @_賦給了這個list,所以,後面我們可以用$m, $n來表示兩個參數了。而且$m和$n是max subroutine的局部變數,和別人沒關係。沒有使用my定義的變數,Perl都把他們認為是global variable。

上面的代碼中還有一個注意點,請注意最後一句代碼中,$m和$n後面都沒有分號結尾,這是Perl的一個規定,在if從句的最後一句代碼處,可以不寫分號,但是規範一點我們還是寫上比較好,上面的例子只是代碼非常簡單,而且可以寫在一行,所以就省略了分號。

將上面的代碼再精簡一些,就成了非常常用的代碼模板了:

Code: Select all
sub max {
  my($m, $n) = @_;  # Name the subroutine parameters
  if ($m > $n) { $m } else { $n }
}

7. Variable-Length Parameter List. 本節講述如何處理可變長度的參數列表,也就是說,本節中實現的max不限參數個數的多少,一律給出這些參數中最大值的那個。首先來看如何沒有這種可變長度 的結構,我們規定max只能接受兩個參數的話,那麼max subroutine可能會這樣寫來增強容錯性:

Code: Select all
sub max {
  if (@_ != 2) {
    print "WARNING! &max should get exactly two arguments!\n";
  }
  # continue as before...
  .
  .
  .
}

OK?把@_用在了Scalar Context中,@_就返回參數的個數。

然後看如何不限參數個數:

Code: Select all
$maximum = &max(3, 5, 10, 4, 6);

sub max {
  my($max_so_far) = shift @_;  # the first one is the largest yet seen
  foreach (@_) {               # look at the remaining arguments
    if ($_ > $max_so_far) {    # could this one be bigger yet?
      $max_so_far = $_;
    }
  }
  $max_so_far;
}

上述的代碼比較好理解,首先我們用shift取出第一個元素,同時List少掉了一個元素,然後用foreach迴圈遍曆Array,一個個的相 比,然後給出最大值的那個max_so_far。這裡看foreach中我們沒有明確定義control variable,所以,就可以用$_來表示control variable,這是第三章學的內容。用這樣的代碼就可以處理變長的參數列表了。

最後需要考慮的問題是,上述的代碼能應付empty parameter list嗎?來看一下,如果是empty list,那麼shift返回undef,foreach結構中的代碼一次都不會被執行,最後返回的result就是undef,OK,看來這也是期望的 結果。不過這隻是一個例子,我們在書寫任何subroutine的時候,都要考慮參數列表是空列表的情況哦。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.