子例程

最后更新于:2022-04-01 21:07:18

## 使用 `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}; ... } ~~~
';