
关于
现代 Perl 5.36+ 惯用写法、最佳实践和编码规范,用于构建健壮、易维护的 Perl 应用。
name: perl-patterns description: 现代 Perl 5.36+ 惯用法、最佳实践和约定,用于构建健壮、可维护的 Perl 应用程序。 origin: ECC
现代 Perl 开发模式
用于构建健壮、可维护应用程序的惯用 Perl 5.36+ 模式和最佳实践。
何时激活
- 编写新的 Perl 代码或模块
- 审查 Perl 代码的惯用法合规性
- 将遗留 Perl 重构为现代标准
- 设计 Perl 模块架构
- 将 5.36 之前的代码迁移到现代 Perl
工作原理
将这些模式作为现代 Perl 5.36+ 默认值的偏好应用:签名、显式模块、专注的错误处理和可测试的边界。以下示例旨在作为起点复制,然后根据实际应用、依赖栈和部署模型进行调整。
核心原则
1. 使用 v5.36 编译指示
单个 use v5.36 替代旧的样板代码,并启用 strict、warnings 和子程序签名。
# Good: Modern preamble
use v5.36;
sub greet($name) {
say "Hello, $name!";
}
# Bad: Legacy boilerplate
use strict;
use warnings;
use feature 'say', 'signatures';
no warnings 'experimental::signatures';
sub greet {
my ($name) = @_;
say "Hello, $name!";
}
2. 子程序签名
使用签名以提高清晰度和自动参数数量检查。
use v5.36;
# Good: Signatures with defaults
sub connect_db($host, $port = 5432, $timeout = 30) {
# $host is required, others have defaults
return DBI->connect("dbi:Pg:host=$host;port=$port", undef, undef, {
RaiseError => 1,
PrintError => 0,
});
}
# Good: Slurpy parameter for variable args
sub log_message($level, @details) {
say "[$level] " . join(' ', @details);
}
# Bad: Manual argument unpacking
sub connect_db {
my ($host, $port, $timeout) = @_;
$port //= 5432;
$timeout //= 30;
# ...
}
3. 上下文敏感性
理解标量与列表上下文——Perl 的核心概念。
use v5.36;
my @items = (1, 2, 3, 4, 5);
my @copy = @items; # List context: all elements
my $count = @items; # Scalar context: count (5)
say "Items: " . scalar @items; # Force scalar context
4. 后缀解引用
使用后缀解引用语法以提高嵌套结构的可读性。
use v5.36;
my $data = {
users => [
{ name => 'Alice', roles => ['admin', 'user'] },
{ name => 'Bob', roles => ['user'] },
],
};
# Good: Postfix dereferencing
my @users = $data->{users}->@*;
my @roles = $data->{users}[0]{roles}->@*;
my %first = $data->{users}[0]->%*;
# Bad: Circumfix dereferencing (harder to read in chains)
my @users = @{ $data->{users} };
my @roles = @{ $data->{users}[0]{roles} };
5. isa 运算符(5.32+)
中缀类型检查——替代 blessed($o) && $o->isa('X')。
use v5.36;
if ($obj isa 'My::Class') { $obj->do_something }
错误处理
eval/die 模式
use v5.36;
sub safe_divide($a, $b) {
die "Division by zero" if $b == 0;
return $a / $b;
}
my $result = eval { safe_divide(10, 0) };
if (my $err = $@) {
warn "Caught: $err";
}
Try::Tiny 替代方案
use v5.36;
use Try::Tiny;
try {
dangerous_operation();
} catch {
log_error("Failed: $_");
} finally {
cleanup();
};
模块设计
面向对象(Moo/Moose)
use v5.36;
package My::Service;
use Moo;
use Types::Standard qw(Str Int);
has name => (is => 'ro', isa => Str, required => 1);
has timeout => (is => 'ro', isa => Int, default => 30);
sub connect($self) {
# implementation
}
函数式导出
use v5.36;
package My::Utils;
use Exporter 'import';
our @EXPORT_OK = qw(slugify trim);
sub slugify($text) {
$text =~ s/[^\w]+/-/gr =~ s/^-|-$//gr;
}
sub trim($text) {
$text =~ s/^\s+|\s+$//gr;
}
测试
use v5.36;
use Test2::V0;
is slugify("Hello World!"), "Hello-World", "basic slugify";
like dies { safe_divide(1, 0) }, qr/Division by zero/, "catches zero division";
done_testing;
最佳实践总结
- 始终使用
use v5.36作为起点 - 优先使用签名而非手动参数解包
- 使用 Moo 进行面向对象设计(除非需要 Moose 的元编程)
- 使用 Test2::V0 进行测试
- 使用后缀解引用以提高可读性
- 使用
isa运算符进行类型检查 - 优先使用 Path::Tiny 而非手动文件操作
兼容工具
Claude CodeCursor
标签
后端开发

