子程序基础 #
一、子程序概述 #
子程序(Subroutine)是Perl中可重用的代码块,使用 sub 关键字定义。
1.1 定义子程序 #
perl
sub greet {
print "Hello, World!\n";
}
1.2 调用子程序 #
perl
greet();
&greet();
1.3 先调用后定义 #
perl
greet();
sub greet {
print "Hello, World!\n";
}
二、参数传递 #
2.1 传递参数 #
参数存储在 @_ 数组中:
perl
sub greet {
my $name = $_[0];
print "Hello, $name!\n";
}
greet("Tom");
2.2 解包参数 #
推荐使用列表赋值解包:
perl
sub add {
my ($a, $b) = @_;
return $a + $b;
}
print add(3, 5);
2.3 多个参数 #
perl
sub print_info {
my ($name, $age, $city) = @_;
print "Name: $name\n";
print "Age: $age\n";
print "City: $city\n";
}
print_info("Tom", 25, "Beijing");
2.4 可变参数 #
perl
sub sum {
my $total = 0;
$total += $_ foreach @_;
return $total;
}
print sum(1, 2, 3, 4, 5);
三、返回值 #
3.1 return语句 #
perl
sub add {
my ($a, $b) = @_;
return $a + $b;
}
my $result = add(3, 5);
print $result;
3.2 隐式返回 #
子程序返回最后一条语句的值:
perl
sub add {
my ($a, $b) = @_;
$a + $b;
}
my $result = add(3, 5);
print $result;
3.3 返回多个值 #
perl
sub min_max {
my @arr = @_;
my $min = $arr[0];
my $max = $arr[0];
foreach my $val (@arr) {
$min = $val if $val < $min;
$max = $val if $val > $max;
}
return ($min, $max);
}
my ($min, $max) = min_max(3, 1, 4, 1, 5, 9, 2, 6);
print "Min: $min, Max: $max\n";
3.4 返回列表 #
perl
sub get_numbers {
return (1, 2, 3, 4, 5);
}
my @nums = get_numbers();
print "@nums\n";
四、调用约定 #
4.1 省略括号 #
如果子程序已定义,可省略括号:
perl
sub greet {
print "Hello!\n";
}
greet;
greet();
4.2 &前缀 #
使用 & 前缀调用:
perl
&greet();
4.3 作为引用 #
perl
my $func_ref = \&greet;
$func_ref->();
&$func_ref();
五、子程序签名 #
Perl 5.20+ 支持签名(需启用):
perl
use v5.20;
use feature 'signatures';
no warnings 'experimental::signatures';
sub add($a, $b) {
return $a + $b;
}
sub greet($name = "World") {
say "Hello, $name!";
}
add(3, 5);
greet();
greet("Tom");
六、递归 #
6.1 基本递归 #
perl
sub factorial {
my $n = shift;
return 1 if $n <= 1;
return $n * factorial($n - 1);
}
print factorial(5);
6.2 斐波那契数列 #
perl
sub fibonacci {
my $n = shift;
return $n if $n <= 1;
return fibonacci($n - 1) + fibonacci($n - 2);
}
print fibonacci(10);
6.3 尾递归优化 #
perl
sub factorial_tail {
my ($n, $acc) = @_;
$acc //= 1;
return $acc if $n <= 1;
return factorial_tail($n - 1, $n * $acc);
}
print factorial_tail(5);
七、实践练习 #
练习1:数学函数 #
perl
#!/usr/bin/perl
use strict;
use warnings;
use v5.10;
sub max {
my @arr = @_;
my $max = $arr[0];
$max = $_ > $max ? $_ : $max foreach @arr;
return $max;
}
sub min {
my @arr = @_;
my $min = $arr[0];
$min = $_ < $min ? $_ : $min foreach @arr;
return $min;
}
sub average {
my @arr = @_;
my $sum = 0;
$sum += $_ foreach @arr;
return @arr ? $sum / @arr : 0;
}
my @numbers = (3, 1, 4, 1, 5, 9, 2, 6);
say "Max: " . max(@numbers);
say "Min: " . min(@numbers);
say "Average: " . sprintf("%.2f", average(@numbers));
练习2:字符串处理 #
perl
#!/usr/bin/perl
use strict;
use warnings;
use v5.10;
sub reverse_words {
my $str = shift;
my @words = split /\s+/, $str;
return join " ", reverse @words;
}
sub count_words {
my $str = shift;
my @words = split /\s+/, $str;
return scalar @words;
}
my $text = "Hello Perl World";
say "Original: $text";
say "Reversed: " . reverse_words($text);
say "Word count: " . count_words($text);
练习3:验证函数 #
perl
#!/usr/bin/perl
use strict;
use warnings;
use v5.10;
sub is_email {
my $str = shift;
return $str =~ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
}
sub is_phone {
my $str = shift;
return $str =~ /^\d{3}-\d{3}-\d{4}$/;
}
my @tests = (
"test@example.com",
"invalid-email",
"123-456-7890",
"12345",
);
foreach my $test (@tests) {
say "$test:";
say " Email: " . (is_email($test) ? "Yes" : "No");
say " Phone: " . (is_phone($test) ? "Yes" : "No");
}
八、总结 #
本章学习了:
- 子程序的定义和调用
- 参数传递(@_)
- 返回值
- 递归
下一章将学习参数与返回值的更多细节。
最后更新:2026-03-27