소스 정보
- 저장소
- aaione/everything-claude-code-zh
- 최근 소스 활동
- 2026년 5월 31일 04:33
- 감지된 SKILL.md 언어
- 중국어
- 스타
- 27
- 포크
- 13
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/aaione/everything-claude-code-zh --skill perl-patterns명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | perl-patterns |
| description | 现代 Perl 5.36+ 惯用写法、最佳实践和约定,用于构建健壮、可维护的 Perl 应用程序。 |
| origin | ECC |
惯用的 Perl 5.36+ 模式和最佳实践,用于构建健壮、可维护的应用程序。
将这些模式作为对现代 Perl 5.36+ 默认设置的偏好来应用:签名、显式模块、聚焦错误处理和可测试边界。下面的示例旨在作为起点复制,然后针对你面前的实际应用、依赖栈和部署模型进行细化。
v5.36 编译指示单个 use v5.36 替代了旧的样板代码,并启用 strict、warnings 和子程序签名。
# 好的做法:现代前导声明
use v5.36;
sub greet($name) {
say "Hello, $name!";
}
# 不好的做法:遗留样板代码
use strict;
use warnings;
use feature 'say', 'signatures';
no warnings 'experimental::signatures';
sub greet {
my ($name) = @_;
say "Hello, $name!";
}
使用签名以获得清晰度和自动参数数量检查。
use v5.36;
# 好的做法:带默认值的签名
sub connect_db($host, $port = 5432, $timeout = 30) {
# $host 是必需的,其他有默认值
return DBI->connect("dbi:Pg:host=$host;port=$port", undef, undef, {
RaiseError => 1,
PrintError => 0,
});
}
# 好的做法:可变参数的 slurpy 参数
sub log_message($level, @details) {
say "[$level] " . join(' ', @details);
}
# 不好的做法:手动参数解包
sub connect_db {
my ($host, $port, $timeout) = @_;
$port //= 5432;
$timeout //= 30;
# ...
}
理解标量与列表上下文 —— Perl 的核心概念。
use v5.36;
my @items = (1, 2, 3, 4, 5);
my @copy = @items; # 列表上下文:所有元素
my $count = @items; # 标量上下文:计数(5)
say "Items: " . scalar @items; # 强制标量上下文
对嵌套结构使用后缀解引用语法以提高可读性。
use v5.36;
my $data = {
users => [
{ name => 'Alice', roles => ['admin', 'user'] },
{ name => 'Bob', roles => ['user'] },
],
};
# 好的做法:后缀解引用
my @users = $data->{users}->@*;
my @roles = $data->{users}[0]{roles}->@*;
my %first = $data->{users}[0]->%*;
# 不好的做法:环绕式解引用(在链式中难以阅读)
my @users = @{ $data->{users} };
my @roles = @{ $data->{users}[0]{roles} };
isa 运算符(5.32+)中缀类型检查 —— 替代 blessed($o) && $o->isa('X')。
use v5.36;
if ($obj isa 'My::Class') { $obj->do_something }
use v5.36;
sub parse_config($path) {
my $content = eval { path($path)->slurp_utf8 };
die "Config error: $@" if $@;
return decode_json($content);
}
use v5.36;
use Try::Tiny;
sub fetch_user($id) {
my $user = try {
$db->resultset('User')->find($id)
// die "User $id not found\n";
}
catch {
warn "Failed to fetch user $id: $_";
undef;
};
return $user;
}
use v5.40;
sub divide($x, $y) {
try {
die "Division by zero" if $y == 0;
return $x / $y;
}
catch ($e) {
warn "Error: $e";
return;
}
}
优先使用 Moo 进行轻量级现代面向对象编程。仅当需要 Moose 的元协议时才使用 Moose。
# 好的做法:Moo 类
package User;
use Moo;
use Types::Standard qw(Str Int ArrayRef);
use namespace::autoclean;
has name => (is => 'ro', isa => Str, required => 1);
has email => (is => 'ro', isa => Str, required => 1);
has age => (is => 'ro', isa => Int, default => sub { 0 });
has roles => (is => 'ro', isa => ArrayRef[Str], default => sub { [] });
sub is_admin($self) {
return grep { $_ eq 'admin' } $self->roles->@*;
}
sub greet($self) {
return "Hello, I'm " . $self->name;
}
1;
# 用法
my $user = User->new(
name => 'Alice',
,
[, ],
);
User;
{
(, ) = ;
\, ;
}
{ []->{name} }
;
package Role::Serializable;
use Moo::Role;
use JSON::MaybeXS qw(encode_json);
requires 'TO_HASH';
sub to_json($self) { encode_json($self->TO_HASH) }
1;
package User;
use Moo;
with 'Role::Serializable';
has name => (is => 'ro', required => 1);
has email => (is => 'ro', required => 1);
sub TO_HASH($self) { { name => $self->name, email => $self->email } }
1;
class 关键字(5.38+,Corinna)use v5.38;
use feature 'class';
no warnings 'experimental::class';
class Point {
field $x :param;
field $y :param;
method magnitude() { sqrt($x**2 + $y**2) }
}
my $p = Point->new(x => 3, y => 4);
say $p->magnitude; # 5
/x 标志use v5.36;
# 好的做法:使用 /x 的命名捕获以提高可读性
my $log_re = qr{
^ (?<timestamp> \d{4}-\d{2}-\d{2} \s \d{2}:\d{2}:\d{2} )
\s+ \[ (?<level> \w+ ) \]
\s+ (?<message> .+ ) $
}x;
if ($line =~ $log_re) {
say "Time: $+{timestamp}, Level: $+{level}";
say "Message: $+{message}";
}
# 不好的做法:位置捕获(难以维护)
if ($line =~ /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\[(\w+)\]\s+(.+)$/) {
say "Time: $1, Level: $2";
}
use v5.36;
# 好的做法:编译一次,多次使用
my $email_re = qr/^[A-Za-z0-9._%+-]+\@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;
sub validate_emails(@emails) {
return grep { $_ =~ $email_re } @emails;
}
use v5.36;
# 哈希和数组引用
my $config = {
database => {
host => 'localhost',
port => 5432,
options => ['utf8', 'sslmode=require'],
},
};
# 安全深层访问(如果任何层级缺失则返回 undef)
my $port = $config->{database}{port}; # 5432
my $missing = $config->{cache}{host}; # undef,无错误
# 哈希切片
my %subset;
@subset{qw(host port)} = @{$config->{database}}{qw(host port)};
# 数组切片
my @first_two = $config->{database}{options}->@[0, 1];
# 多变量 for 循环(5.36 中为实验性,5.40 中稳定)
use feature 'for_list';
no warnings 'experimental::for_list';
for my ($key, $val) (%$config) {
say "$key => $val";
}
use v5.36;
# 好的做法:带 autodie 的三参数 open(核心模块,消除 'or die')
use autodie;
sub read_file($path) {
open my $fh, '<:encoding(UTF-8)', $path;
local $/;
my $content = <$fh>;
close $fh;
return $content;
}
# 不好的做法:两参数 open(shell 注入风险,参见 perl-security)
open FH, $path; # 永远不要这样做
open FH, "< $path"; # 仍然不好 —— 用户数据在模式字符串中
use v5.36;
use Path::Tiny;
my $file = path('config', 'app.json');
my $content = $file->slurp_utf8;
$file->spew_utf8($new_content);
# 遍历目录
for my $child (path('src')->children(qr/\.pl$/)) {
say $child->basename;
}
MyApp/
├── lib/
│ └── MyApp/
│ ├── App.pm # 主模块
│ ├── Config.pm # 配置
│ ├── DB.pm # 数据库层
│ └── Util.pm # 工具类
├── bin/
│ └── myapp # 入口脚本
├── t/
│ ├── 00-load.t # 编译测试
│ ├── unit/ # 单元测试
│ └── integration/ # 集成测试
├── cpanfile # 依赖
├── Makefile.PL # 构建系统
└── .perlcriticrc # Lint 配置
package MyApp::Util;
use v5.36;
use Exporter 'import';
our @EXPORT_OK = qw(trim);
our %EXPORT_TAGS = (all => \@EXPORT_OK);
sub trim($str) { $str =~ s/^\s+|\s+$//gr }
1;
-i=4 # 4 空格缩进
-l=100 # 100 字符行长度
-ci=4 # 续行缩进
-ce # 贴合 else
-bar # 开括号在同一行
-nolq # 不突出长引用字符串
severity = 3
theme = core + pbp + security
[InputOutput::RequireCheckedSyscalls]
functions = :builtins
exclude_functions = say print
[Subroutines::ProhibitExplicitReturnUndef]
severity = 4
[ValuesAndExpressions::ProhibitMagicNumbers]
allowed_values = 0 1 2 -1
cpanm App::cpanminus Carton # 安装工具
carton install # 从 cpanfile 安装依赖
carton exec -- perl bin/myapp # 使用本地依赖运行
# cpanfile
requires 'Moo', '>= 2.005';
requires 'Path::Tiny';
requires 'JSON::MaybeXS';
requires 'Try::Tiny';
on test => sub {
requires 'Test2::V0';
requires 'Test::MockModule';
};
| 遗留模式 | 现代替代 |
|---|---|
use strict; use warnings; | use v5.36; |
my ($x, $y) = @_; | sub foo($x, $y) { ... } |
@{ $ref } | $ref->@* |
%{ $ref } | $ref->%* |
open FH, "< $file" | open my $fh, '<:encoding(UTF-8)', $file |
blessed hashref | 带类型的 Moo 类 |
$1, $2, $3 | $+{name}(命名捕获) |
eval { }; if ($@) | Try::Tiny 或原生 try/catch(5.40+) |
BEGIN { require Exporter; } | use Exporter 'import'; |
| 手动文件操作 | Path::Tiny |
blessed($o) && $o->isa('X') | $o isa 'X'(5.32+) |
builtin::true / false | use builtin 'true', 'false';(5.36+,实验性) |
# 1. 两参数 open(安全风险)
open FH, $filename; # 永远不要这样做
# 2. 间接对象语法(歧义解析)
my $obj = new Foo(bar => 1); # 不好的做法
my $obj = Foo->new(bar => 1); # 好的做法
# 3. 过度依赖 $_
map { process($_) } grep { validate($_) } @items; # 难以跟踪
my @valid = grep { validate($_) } @items; # 更好:拆分
my @results = map { process($_) } @valid;
# 4. 禁用 strict refs
no strict 'refs'; # 几乎总是错误的
${"My::Package::$var"} = $value; # 改用哈希
# 5. 全局变量作为配置
our $TIMEOUT = 30; # 不好的做法:可变全局变量
use constant TIMEOUT => 30; # 更好:常量
# 最好的做法:带默认值的 Moo 属性
# 6. 字符串 eval 加载模块
eval ;
;
Module::Runtime ;
require_module();
记住:现代 Perl 是干净、可读和安全的。让 use v5.36 处理样板代码,使用 Moo 进行面向对象编程,优先使用 CPAN 经过实战检验的模块而非手工编写的解决方案。