Perl 子程序(函数)
定义子程序
基本 sub 定义
perl
sub greet {
print "Hello, World!\n";
}
# 调用子程序
greet();带参数的子程序
perl
sub greet_person {
my ($name) = @_;
print "Hello, $name!\n";
}
greet_person("Alice");
greet_person("Bob");多个参数
perl
sub add_numbers {
my ($a, $b) = @_;
return $a + $b;
}
my $result = add_numbers(10, 20);
print "Result: $result\n"; # Result: 30参数传递
使用 @_
@_ 是包含所有参数的特殊数组:
perl
sub print_params {
print "Number of parameters: " . scalar(@_) . "\n";
foreach my $param (@_) {
print "Parameter: $param\n";
}
}
print_params("apple", "banana", "orange");直接访问参数
perl
sub add {
my $sum = $_[0] + $_[1];
return $sum;
}
print add(5, 3); # 8使用 my 获取参数副本
perl
sub multiply {
my ($a, $b) = @_; # 将参数赋值给局部变量
return $a * $b;
}
print multiply(4, 5); # 20修改原始参数
perl
sub modify_array {
my ($arr_ref) = @_; # 接收数组引用
foreach my $elem (@$arr_ref) {
$elem *= 2;
}
}
my @numbers = (1, 2, 3);
modify_array(\@numbers);
print "@numbers\n"; # 2 4 6返回值
使用 return
perl
sub divide {
my ($a, $b) = @_;
return $a / $b if $b != 0;
return undef; # 除以零时返回 undef
}
my $result = divide(10, 2);
print "Result: $result\n"; # Result: 5隐式返回
子程序最后执行的值会自动返回:
perl
sub implicit_return {
my $x = 10;
$x * 2; # 返回 20
}
print implicit_return(); # 20返回多个值
perl
sub get_stats {
my @numbers = @_;
my $sum = 0;
my $min = $numbers[0];
my $max = $numbers[0];
foreach my $num (@numbers) {
$sum += $num;
$min = $num if $num < $min;
$max = $num if $num > $max;
}
return ($sum, $min, $max);
}
my ($total, $minimum, $maximum) = get_stats(1, 5, 3, 9, 2);
print "Sum: $total, Min: $minimum, Max: $maximum\n";返回列表和标量
perl
sub get_data {
return (1, 2, 3, 4, 5);
}
# 列表上下文
my @data = get_data();
print "@data\n"; # 1 2 3 4 5
# 标量上下文
my $count = get_data();
print "Count: $count\n"; # Count: 5默认参数
使用 // 定义默认值
perl
sub greet_with_default {
my ($name, $greeting) = @_;
$name //= "World";
$greeting //= "Hello";
print "$greeting, $name!\n";
}
greet_with_default(); # Hello, World!
greet_with_default("Alice"); # Hello, Alice!
greet_with_default("Bob", "Hi"); # Hi, Bob!使用 || 定义默认值(注意陷阱)
perl
sub multiply {
my ($a, $b) = @_;
$a ||= 1;
$b ||= 1;
return $a * $b;
}
print multiply(); # 1
print multiply(5); # 5
print multiply(5, 0); # 5(0 被替换为 1)命名参数
使用哈希实现命名参数
perl
sub create_user {
my %params = @_;
my $name = $params{name} // "Anonymous";
my $age = $params{age} // 0;
my $email = $params{email} // "";
return {
name => $name,
age => $age,
email => $email
};
}
my $user1 = create_user(name => "Alice", age => 25);
my $user2 = create_user(email => "bob@example.com");
print "$user1->{name}, $user1->{age}\n";
print "$user2->{email}\n";使用引用实现命名参数
perl
sub process_data {
my ($data_ref, $options_ref) = @_;
my $verbose = $options_ref->{verbose} // 0;
if ($verbose) {
print "Processing " . scalar(@$data_ref) . " items\n";
}
return [map { $_ * 2 } @$data_ref];
}
my @numbers = (1, 2, 3);
my $result = process_data(\@numbers, {verbose => 1});
print "@$result\n";递归
基本递归示例:阶乘
perl
sub factorial {
my ($n) = @_;
return 1 if $n <= 1;
return $n * factorial($n - 1);
}
print factorial(5); # 120递归示例:斐波那契数列
perl
sub fibonacci {
my ($n) = @_;
return $n if $n <= 1;
return fibonacci($n - 1) + fibonacci($n - 2);
}
for (my $i = 0; $i < 10; $i++) {
print fibonacci($i) . " ";
}
# 0 1 1 2 3 5 8 13 21 34递归示例:汉诺塔
perl
sub hanoi {
my ($n, $from, $to, $aux) = @_;
return if $n == 0;
hanoi($n - 1, $from, $aux, $to);
print "Move disk $n from $from to $to\n";
hanoi($n - 1, $aux, $to, $from);
}
hanoi(3, "A", "C", "B");匿名子程序
基本匿名子程序
perl
my $greet = sub {
my ($name) = @_;
print "Hello, $name!\n";
};
$greet->("World");作为回调函数
perl
sub process_list {
my ($list, $callback) = @_;
foreach my $item (@$list) {
$callback->($item);
}
}
my @fruits = ("apple", "banana", "orange");
process_list(\@fruits, sub {
my ($fruit) = @_;
print "Fruit: $fruit\n";
});闭包(Closure)
perl
sub make_counter {
my $count = 0;
return sub {
return ++$count;
};
}
my $counter1 = make_counter();
my $counter2 = make_counter();
print $counter1->(); # 1
print $counter1->(); # 2
print $counter2->(); # 1
print $counter1->(); # 3原型(Prototype)
基本原型
perl
sub add($$) { # 接受两个标量
my ($a, $b) = @_;
return $a + $b;
}
print add(10, 20); # 30数组原型
perl
sub sum_array(\@) { # 接受一个数组
my ($arr_ref) = @_;
my $total = 0;
$total += $_ for @$arr_ref;
return $total;
}
my @numbers = (1, 2, 3, 4, 5);
print sum_array(@numbers); # 15哈希原型
perl
sub print_hash(\%) {
my ($hash_ref) = @_;
while (my ($k, $v) = each %$hash_ref) {
print "$k: $v\n";
}
}
my %data = (a => 1, b => 2);
print_hash(%data);实践示例
示例 1:简单的计算器
perl
#!/usr/bin/perl
use strict;
use warnings;
sub add {
my ($a, $b) = @_;
return $a + $b;
}
sub subtract {
my ($a, $b) = @_;
return $a - $b;
}
sub multiply {
my ($a, $b) = @_;
return $a * $b;
}
sub divide {
my ($a, $b) = @_;
die "Cannot divide by zero" if $b == 0;
return $a / $b;
}
print "计算器\n";
print "请输入第一个数字: ";
chomp(my $num1 = <STDIN>);
print "请输入第二个数字: ";
chomp(my $num2 = <STDIN>);
printf "加法: %.2f\n", add($num1, $num2);
printf "减法: %.2f\n", subtract($num1, $num2);
printf "乘法: %.2f\n", multiply($num1, $num2);
printf "除法: %.2f\n", divide($num1, $num2);示例 2:数据验证
perl
#!/usr/bin/perl
use strict;
use warnings;
sub is_email {
my ($email) = @_;
return $email =~ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
}
sub is_phone {
my ($phone) = @_;
return $phone =~ /^\d{3}-\d{3}-\d{4}$/;
}
sub validate_user {
my ($name, $email, $phone) = @_;
my @errors = ();
push @errors, "Name is required" unless $name;
push @errors, "Invalid email format" unless is_email($email);
push @errors, "Invalid phone format" unless is_phone($phone);
return @errors;
}
my $name = "Alice";
my $email = "alice@example.com";
my $phone = "123-456-7890";
my @errors = validate_user($name, $email, $phone);
if (@errors) {
print "Validation errors:\n";
print "- $_\n" for @errors;
} else {
print "Validation passed!\n";
}示例 3:文本处理工具
perl
#!/usr/bin/perl
use strict;
use warnings;
sub count_words {
my ($text) = @_;
my @words = split /\s+/, $text;
return scalar @words;
}
sub count_chars {
my ($text) = @_;
return length($text);
}
sub count_lines {
my ($text) = @_;
my @lines = split /\n/, $text;
return scalar @lines;
}
sub find_longest_word {
my ($text) = @_;
my @words = split /\s+/, $text;
my $longest = "";
foreach my $word (@words) {
$longest = $word if length($word) > length($longest);
}
return $longest;
}
my $sample_text = "This is a sample text for demonstration purposes.
It contains multiple lines and words.";
printf "Words: %d\n", count_words($sample_text);
printf "Characters: %d\n", count_chars($sample_text);
printf "Lines: %d\n", count_lines($sample_text);
printf "Longest word: %s\n", find_longest_word($sample_text);小结
本章节学习了 Perl 的子程序:
- ✅ 定义和调用子程序
- ✅ 参数传递
- ✅ 返回值
- ✅ 默认参数
- ✅ 命名参数
- ✅ 递归
- ✅ 匿名子程序
- ✅ 原型
接下来,我们将学习 Perl 引用。