## 使用?`shift`?檢索子例程的參數
子例程的參數來自于特殊的?`@_`?數組。不帶參數的?`shift`?默認使用?`@_`。
~~~
sub volume {
my $height = shift;
my $width = shift;
my $depth = shift;
return $height * $width * $depth;
}
~~~
## 使用列表賦值來賦給子例程參數
你也可以使用列表賦值賦給子例程參數:
~~~
sub volume {
my ($height, $width, $depth) = @_;
return $height * $width * $depth;
}
~~~
## 通過訪問?`@_`?直接處理子例程參數
在某些情況下,但我們希望很少,你能夠通過?`@_`?數組直接訪問參數。
~~~
sub volume {
return $_[0] * $_[1] * $_[2];
}
~~~
## 傳遞的參數能被修改
傳遞給子例程的參數是實際參數的別名。
~~~
my $foo = 3;
print incr1($foo) . "\n"; # prints 4
print "$foo\n"; # prints 3
sub incr1 {
return $_[0]+1;
}
~~~
如果你想要這種效果的話,這樣更好:
~~~
sub incr2 {
return ++$_[0];
}
~~~
## 子例程沒有檢查參數
如果你喜歡,你能夠將任意東東傳遞給子例程。
~~~
sub square {
my $number = shift;
return $number * $number;
}
my $n = square( 'Dog food', 14.5, 'Blah blah blah' );
~~~
該函數只會使用第一個參數。因為這個關系,你可以使用任意數目的參數, 甚至沒有參數來調用函數。
~~~
my $n = square();
~~~
Perl 不會對此抱怨。
_Params::Validate_?模塊解決了許多驗證問題。
## Perl 有原型,忽略它們
在演進的道路上加入了原型,因此你可以像這樣干:
~~~
sub square($) {
...
}
my $n = square( 1, 2, 3 ); # run-time error
~~~
無論如何都不要使用它們。它們不會作用于對象,它們需要在調用子例程 前先予以聲明。它們是好想法,但只是不實用。
## 利用?`BEGIN`?塊在編譯時做事
`BEGIN`?是一種特殊的代碼塊類型。它允許程序員在 Perl 的編譯階段執行 代碼,這樣可以執行初始化及做其他事情。
Perl 使用?`BEGIN`?在任意時導入模塊。下列兩個語句是等效的:
~~~
use WWW::Mechanize;
BEGIN {
require WWW::Mechanize;
import WWW::Mechanize;
}
~~~
## 傳遞數組及哈希引用
記住傳給子例程的參數是作為一個大數組傳遞的。如果你像下面這樣干:
~~~
my @stooges = qw( Moe Larry Curly );
my @sandwiches = qw( tuna ham-n-cheese PBJ );
lunch( @stooges, @sandwiches );
~~~
那么傳給?`lunch`?的是列表:
~~~
( "Moe", "Larry", "Curly", "tuna", "ham-n-cheese", "PBJ" );
~~~
在?`lunch`?中,你如何能告訴 stooges 結束及 sandwiches 開始的位置? 你不能。如果你嘗試這樣:
~~~
sub lunch {
my (@stooges, @sandwiches) = @_;
~~~
那么所有 6 個元素都會跑到?`@stooges`?中,而?`@sandwiches`?什么都不會 得到。
答案是使用引用,正如:
~~~
lunch( \@stooges, \@sandwiches );
sub lunch {
my $stoogeref = shift;
my $sandwichref = shift;
my @stooges = @{$stoogeref};
my @sandwichref = @{$sandwichref};
...
}
~~~