作用域与闭包 #
一、变量作用域 #
1.1 词法作用域 my #
my 声明词法变量,作用域限于当前块:
perl
my $global = "global";
{
my $local = "local";
print $global;
print $local;
}
print $global;
1.2 块作用域 #
perl
my $x = 10;
{
my $x = 20;
print "Inside: $x\n";
}
print "Outside: $x\n";
1.3 循环作用域 #
perl
for my $i (1..5) {
print $i . "\n";
}
1.4 子程序作用域 #
perl
sub outer {
my $x = 10;
sub inner {
print $x;
}
inner();
}
outer();
二、my、local、our #
2.1 my - 词法变量 #
perl
my $var = "lexical";
- 创建新的词法变量
- 作用域限于当前块
- 最常用的声明方式
2.2 local - 动态作用域 #
perl
our $global = "original";
sub show {
print $global . "\n";
}
show();
{
local $global = "temporary";
show();
}
show();
2.3 our - 包变量 #
perl
our $PACKAGE_VAR = "package";
sub show_var {
our $PACKAGE_VAR;
print $PACKAGE_VAR . "\n";
}
2.4 三者对比 #
| 关键字 | 作用域 | 说明 |
|---|---|---|
| my | 词法 | 创建新变量,块内有效 |
| local | 动态 | 临时修改全局变量 |
| our | 包 | 声明包变量 |
三、特殊变量作用域 #
3.1 临时修改特殊变量 #
perl
{
local $/ = undef;
my $content = <DATA>;
print $content;
}
__DATA__
Line 1
Line 2
Line 3
3.2 临时修改分隔符 #
perl
my @arr = (1, 2, 3);
{
local $" = " | ";
print "@arr\n";
}
print "@arr\n";
3.3 临时修改警告 #
perl
{
no warnings 'uninitialized';
my $result = $undefined_var;
}
四、闭包 #
4.1 什么是闭包 #
闭包是捕获外部变量的子程序:
perl
sub make_counter {
my $count = 0;
return sub {
return ++$count;
};
}
my $counter = make_counter();
print $counter->() . "\n";
print $counter->() . "\n";
print $counter->() . "\n";
4.2 闭包捕获变量 #
perl
sub make_multiplier {
my $factor = shift;
return sub {
my $num = shift;
return $num * $factor;
};
}
my $double = make_multiplier(2);
my $triple = make_multiplier(3);
print $double->(5) . "\n";
print $triple->(5) . "\n";
4.3 多个闭包共享变量 #
perl
sub make_account {
my $balance = shift // 0;
return {
deposit => sub {
my $amount = shift;
$balance += $amount;
return $balance;
},
withdraw => sub {
my $amount = shift;
$balance -= $amount if $balance >= $amount;
return $balance;
},
balance => sub {
return $balance;
},
};
}
my $account = make_account(100);
print $account->{balance}() . "\n";
print $account->{deposit}(50) . "\n";
print $account->{withdraw}(30) . "\n";
4.4 循环中的闭包 #
perl
my @funcs;
for my $i (1..5) {
push @funcs, sub {
return $i * 2;
};
}
foreach my $func (@funcs) {
print $func->() . "\n";
}
五、state变量 #
5.1 基本用法 #
state 声明持久化变量(Perl 5.10+):
perl
use v5.10;
sub counter {
state $count = 0;
return ++$count;
}
say counter();
say counter();
say counter();
5.2 state vs my #
perl
use v5.10;
sub with_my {
my $count = 0;
$count++;
return $count;
}
sub with_state {
state $count = 0;
$count++;
return $count;
}
say "my: " . with_my();
say "my: " . with_my();
say "state: " . with_state();
say "state: " . with_state();
5.3 state数组/哈希 #
perl
use v5.10;
sub get_cache {
state %cache;
return \%cache;
}
my $cache = get_cache();
$cache->{a} = 1;
$cache->{b} = 2;
my $cache2 = get_cache();
say $cache2->{a};
六、实用模式 #
6.1 单例模式 #
perl
{
my $instance;
sub get_instance {
return $instance //= bless {}, __PACKAGE__;
}
}
6.2 配置缓存 #
perl
use v5.10;
sub get_config {
state $config;
return $config if $config;
$config = {
host => "localhost",
port => 3306,
};
return $config;
}
6.3 工厂函数 #
perl
sub create_validator {
my %rules = @_;
return sub {
my $data = shift;
my @errors;
foreach my $field (keys %rules) {
my $rule = $rules{$field};
unless ($data->{$field} =~ $rule) {
push @errors, "Invalid $field";
}
}
return @errors;
};
}
my $validate = create_validator(
email => qr/^[\w.]+@[\w.]+$/,
phone => qr/^\d{3}-\d{3}-\d{4}$/,
);
my @errors = $validate->({
email => "test@example.com",
phone => "123-456-7890",
});
七、实践练习 #
练习1:计数器 #
perl
#!/usr/bin/perl
use strict;
use warnings;
use v5.10;
sub make_counter {
my $start = shift // 0;
my $count = $start;
return {
next => sub { return $count++; },
reset => sub { $count = $start; return $count; },
current => sub { return $count; },
};
}
my $counter = make_counter(10);
say $counter->{next}();
say $counter->{next}();
say $counter->{current}();
$counter->{reset}();
say $counter->{next}();
练习2:配置管理 #
perl
#!/usr/bin/perl
use strict;
use warnings;
use v5.10;
{
my %config;
sub set_config {
my %args = @_;
%config = (%config, %args);
}
sub get_config {
my $key = shift;
return $key ? $config{$key} : %config;
}
}
set_config(host => "localhost", port => 3306);
set_config(debug => 1);
say "Host: " . get_config("host");
say "Port: " . get_config("port");
say "Debug: " . get_config("debug");
练习3:事件系统 #
perl
#!/usr/bin/perl
use strict;
use warnings;
use v5.10;
sub create_emitter {
my %events;
return {
on => sub {
my ($event, $callback) = @_;
push @{$events{$event}}, $callback;
},
emit => sub {
my ($event, @args) = @_;
$_->(@args) foreach @{$events{$event} // []};
},
};
}
my $emitter = create_emitter();
$emitter->{on}("greet", sub {
my $name = shift;
say "Hello, $name!";
});
$emitter->{on}("greet", sub {
my $name = shift;
say "Welcome, $name!";
});
$emitter->{emit}("greet", "Tom");
八、总结 #
本章学习了:
- 词法作用域(my)
- 动态作用域(local)
- 包变量(our)
- 闭包的概念和应用
- state变量
下一章将学习文件操作。
最后更新:2026-03-27