22、Perl编程技巧:提升你的代码能力

Perl编程技巧:提升你的代码能力

1. 生成序列

在Perl中,我们通常可以使用简单的语法 @count_up = 0..100; 来生成递增的整数序列。但如果我们想要更复杂的序列,比如以2为步长计数或者倒序计数,就需要自己创造语法了。

Perl中的尖括号有两种用途:作为 readline 的简写和 glob 的简写。我们可以利用这一点,将非 readline 的尖括号用于列表推导式。

以下是具体操作步骤:
1. 安装新的 glob 函数:

package Glob::Lists;
use Carp;
# Regexes to parse the extended list specifications...
my $NUM    = qr{\s* [+-]? \d+ (?:\.\d*)? \s* }xms;
my $TO     = qr{\s* \.\. \s*}xms;
my $FILTER = qr{ (?: : (.*) )? }xms;
my $ABtoZ  = qr{\A ($NUM) (,) ($NUM) ,? $TO ($NUM) $FILTER \Z}xms;
my $AZxN   = qr{\A ($NUM) $TO ($NUM) (?:x ($NUM))? $FILTER \Z}xms;
# Install a new glob( ) function...
no warnings 'redefine';
*CORE::GLOBAL::glob = sub
{
    my ($listspec) = @_;
    # Does the spec match any of the acceptable forms?
    croak "Bad list specification: <$listspec>"
        if $listspec !~ $ABtoZ && $listspec !~ $AZxN;
    # Extract the range of values and any filter...
    my ($from, $to, $incr, $filter) =  $2 eq ',' ? ($1, $4, $3-$1, $5)
                                    :              ($1, $2, $3,    $4);
    # Work out the implicit increment, if no explicit one...
    $incr = $from > $to ? -1 : 1 unless defined $incr;
    # Check for nonsensical increments (zero or the wrong sign)...
    my $delta = $to - $from;
    croak sprintf "Sequence <%s, %s, %s...> will never reach %s",
        $from, $from+$incr, $from+2*$incr, $to
            if $incr == 0 || $delta * $incr < 0;
    # Generate list of values (and return it, if not filter)...
    my @vals = map { $from + $incr * $_ } 0..($delta/$incr);
    return @vals unless defined $filter;
    # Apply the filter before returning the values...
    $filter =~ s/\b[A-Z]\b/\$_/g;
    return eval "grep {package ".caller."; $filter } \@vals";
};
  1. 使用新的语法生成序列:
use Glob::Lists;
for ( <1..100 x 7> ) {...}           # 1, 8, 15, 22,...85, 92, 99
my @even_countdown  = <10,8..0>;     # 10, 8, 6, 4, 2, 0
my @fract_countdown = <10,9.5,..0>;  # 10, 9.5, 9,...1, 0.5, 0
my @some_primes = <1..100 x 3 : /7/ && is_prime(N)>;
                                     # 7, 37, 67, 73, 79, 97
2. 减少错误检查代码

在与外部世界交互时,程序可能会遇到各种错误,如磁盘空间不足、网络连接丢失等。为了使程序更健壮,我们通常需要检查这些错误,但这会导致大量重复的代码。

Perl的 Fatal 核心模块可以帮助我们在不显式检查错误的情况下处理错误。以下是具体操作步骤:
1. 引入 Fatal 模块并指定要覆盖的函数:

use Fatal qw( open close );
open( my $fh, '>', '/invalid_directory/invalid_file' );
print {$fh} "Hello\n";
close $fh;
  1. 如果需要更优雅地处理错误,可以使用 eval 块:
use Fatal qw( open close );
eval {
    open( my $fh, '>', '/invalid_directory/invalid_file' );
    print {$fh} "Hello\n";
    close $fh;
};
die "File error: $!" if $@;
  1. 在自己的模块中使用 Fatal 模块:
package MyCode;
sub succeed { 1 }
sub fail    { 0 }
use Fatal qw( :void succeed fail );
succeed( );
fail( );
1;
3. 返回更智能的值

在Perl中,返回值的上下文有列表上下文、标量上下文和空上下文。在标量上下文中,我们可以返回多种类型的值,如字符串、计数、布尔值等,但Perl没有提供足够的上下文来帮助我们决定返回什么。

Contextual::Return 模块可以帮助我们解决这个问题。以下是一个示例:

use Time::HiRes 'time';
use Contextual::Return;
my $elapsed       = 0;
my $started_at    = 0;
my $is_running    = 0;
# Convert elapsed seconds to HH::MM::SS string...
sub _HMS
{
    my ($elapsed) = @_;
    my $hours     = int($elapsed / 3600);
    my $mins      = int($elapsed / 60 % 60);
    my $secs      = int($elapsed) % 60;
    return sprintf "%02d:%02d:%02d", $hours, $mins, $secs;
}
sub stopwatch
{
    my ($run)     = @_;
    # Update elapsed time...
    my $now       =  time( );
    $elapsed     +=  $now - $started_at if $is_running;
    $started_at   =  $now;
    # Defined arg turns stopwatch on/off, undef arg resets it...
    $is_running   =  $run if @_;
    $elapsed      =  0 if @_ && !defined $run;
    # Handle different scalar contexts...
    return
         NUM { $elapsed         }
         STR { _HMS( $elapsed ) }
        BOOL { $is_running      }
}
4. 返回动态值

Contextual::Return 模块还有一个强大的功能,即返回的标量值可以是动态的。动态值每次被计算时都会自适应。

以下是一个示例:

use Contextual::Return;
use Time::HiRes qw( sleep time );      # Allow subsecond timing
# Subroutine returns an active timer value...
sub timer
{
    my $start = time;                  # Set initial start time
    return VALUE                       # Return an active value that...
    {
        my $elapsed = time - $start;   #    1. computes elapsed time
        $start      = time;            #    2. resets start time
        return $elapsed;               #    3. returns elapsed time
    }
}
# Create an active value...
my $process_timer = timer( );
# Use active value...
while (1)
{
    do_some_long_process( );
    print "Process took $process_timer seconds\n";
}
5. 添加自定义Perl语法

有时候,Perl的语法可能无法满足我们的需求,我们可以尝试添加自定义语法。

例如,在定义子例程时,我们希望可以直接指定参数列表,但Perl没有提供这样的语法。我们只能自己处理参数:

sub convert_to_base
{
    my ($base, $number) = @_;   # <-- DIY parameter list
    my $converted       = ''
    while ($number > 0)
    {
        $converted      = $NUMERAL_FOR[$number % $base] . $converted;
        $number         = int( $number / $base);
    }
    return $converted;
}

以下是一个流程图,展示了生成序列的大致流程:

graph TD;
    A[输入序列规范] --> B{规范是否匹配};
    B -- 是 --> C[提取范围和过滤器];
    B -- 否 --> D[抛出错误];
    C --> E{是否有显式增量};
    E -- 是 --> F[使用显式增量];
    E -- 否 --> G[计算隐式增量];
    F --> H{增量是否合理};
    G --> H;
    H -- 是 --> I[生成值列表];
    H -- 否 --> D;
    I --> J{是否有过滤器};
    J -- 是 --> K[应用过滤器];
    J -- 否 --> L[返回值列表];
    K --> L;

通过以上这些技巧,我们可以提升Perl代码的效率和可维护性,让我们的编程工作更加轻松。

Perl编程技巧:提升你的代码能力

6. 各技巧总结与对比

为了更清晰地了解上述几种Perl编程技巧,下面通过表格进行总结对比:
| 技巧名称 | 作用 | 示例代码 | 优点 |
| — | — | — | — |
| 生成序列 | 自定义生成复杂整数序列 | perl use Glob::Lists; for ( <1..100 x 7> ) {...} | 可灵活生成不同步长、顺序的序列,支持过滤 |
| 减少错误检查代码 | 减少错误检查的重复代码 | perl use Fatal qw( open close ); open( my $fh, '>', '/invalid_directory/invalid_file' ); | 简化错误处理,使代码更简洁 |
| 返回更智能的值 | 根据不同上下文返回合适的值 | perl sub stopwatch {... return NUM { $elapsed } STR { _HMS( $elapsed ) } BOOL { $is_running } } | 提高返回值的灵活性和适用性 |
| 返回动态值 | 返回值可自动更新 | perl sub timer {... return VALUE { my $elapsed = time - $start; $start = time; return $elapsed; } } | 方便跟踪动态信息,如时间间隔 |
| 添加自定义Perl语法 | 扩展Perl语法以满足特定需求 | perl sub convert_to_base { my ($base, $number) = @_; ... } | 使代码更符合特定业务逻辑,提高可读性 |

7. 技巧的综合应用

在实际编程中,我们可以综合运用这些技巧来解决复杂的问题。例如,我们要编写一个程序来监控一系列任务的执行时间,并将结果记录到文件中。

以下是具体的实现步骤:
1. 使用 timer 函数创建动态计时器:

use Contextual::Return;
use Time::HiRes qw( sleep time );

sub timer
{
    my $start = time;
    return VALUE
    {
        my $elapsed = time - $start;
        $start = time;
        return $elapsed;
    }
}
  1. 使用 Fatal 模块处理文件操作的错误:
use Fatal qw( open close );
  1. 定义任务列表并执行任务:
my $task_timer = timer();
my @tasks = ('task1', 'task2', 'task3');

open(my $log_fh, '>', 'task_log.txt');

for my $task (@tasks)
{
    print "Performing $task...\n";
    print {$log_fh} "Performing $task...\n";
    do_task($task);
    print "Finished $task in $task_timer seconds\n";
    print {$log_fh} "Finished $task in $task_timer seconds\n";
}

close $log_fh;

sub do_task
{
    my ($task) = @_;
    # 模拟任务执行
    sleep(rand(2));
}
8. 注意事项

在使用这些技巧时,也有一些注意事项需要我们关注:
- 生成序列 :在使用自定义序列语法时,要确保序列规范的正确性,否则会抛出错误。例如,序列的增量不能为零或方向错误。
- 减少错误检查代码 :在使用 Fatal 模块时,要注意函数的声明顺序。如果在函数声明之前使用 Fatal 模块,可能会导致模块无法找到函数而抛出错误。
- 返回更智能的值 :在使用 Contextual::Return 模块时,要确保不同上下文的返回值逻辑正确,避免出现意外的结果。
- 返回动态值 :动态值的计算逻辑要清晰,避免出现逻辑错误导致值计算不准确。
- 添加自定义Perl语法 :自定义语法要符合整体代码的风格和逻辑,避免使代码变得过于复杂难以维护。

以下是一个流程图,展示了综合应用技巧的大致流程:

graph TD;
    A[开始] --> B[创建动态计时器];
    B --> C[引入Fatal模块];
    C --> D[定义任务列表];
    D --> E[打开日志文件];
    E --> F{是否有任务};
    F -- 是 --> G[执行任务];
    G --> H[记录任务执行时间];
    H --> F;
    F -- 否 --> I[关闭日志文件];
    I --> J[结束];

通过掌握这些Perl编程技巧,并注意相关的注意事项,我们可以编写出更高效、更健壮、更易维护的代码,提升我们的编程能力。

内容概要:本文设计了一种基于PLC的全自动洗衣机控制系统内容概要:本文设计了一种,采用三菱FX基于PLC的全自动洗衣机控制系统,采用3U-32MT型PLC作为三菱FX3U核心控制器,替代传统继-32MT电器控制方式,提升了型PLC作为系统的稳定性与自动化核心控制器,替代水平。系统具备传统继电器控制方式高/低水,实现洗衣机工作位选择、柔和过程的自动化控制/标准洗衣模式切换。系统具备高、暂停加衣、低水位选择、手动脱水及和柔和、标准两种蜂鸣提示等功能洗衣模式,支持,通过GX Works2软件编写梯形图程序,实现进洗衣过程中暂停添加水、洗涤、排水衣物,并增加了手动脱水功能和、脱水等工序蜂鸣器提示的自动循环控制功能,提升了使用的,并引入MCGS组便捷性与灵活性态软件实现人机交互界面监控。控制系统通过GX。硬件设计包括 Works2软件进行主电路、PLC接梯形图编程线与关键元,完成了启动、进水器件选型,软件、正反转洗涤部分完成I/O分配、排水、脱、逻辑流程规划水等工序的逻辑及各功能模块梯设计,并实现了大形图编程。循环与小循环的嵌; 适合人群:自动化套控制流程。此外、电气工程及相关,还利用MCGS组态软件构建专业本科学生,具备PL了人机交互C基础知识和梯界面,实现对洗衣机形图编程能力的运行状态的监控与操作。整体设计涵盖了初级工程技术人员。硬件选型、; 使用场景及目标:I/O分配、电路接线、程序逻辑设计及组①掌握PLC在态监控等多个方面家电自动化控制中的应用方法;②学习,体现了PLC在工业自动化控制中的高效全自动洗衣机控制系统的性与可靠性。;软硬件设计流程 适合人群:电气;③实践工程、自动化及相关MCGS组态软件与PLC的专业的本科生、初级通信与联调工程技术人员以及从事;④完成PLC控制系统开发毕业设计或工业的学习者;具备控制类项目开发参考一定PLC基础知识。; 阅读和梯形图建议:建议结合三菱编程能力的人员GX Works2仿真更为适宜。; 使用场景及目标:①应用于环境与MCGS组态平台进行程序高校毕业设计或调试与运行验证课程项目,帮助学生掌握PLC控制系统的设计,重点关注I/O分配逻辑、梯形图与实现方法;②为工业自动化领域互锁机制及循环控制结构的设计中类似家电控制系统的开发提供参考方案;③思路,深入理解PL通过实际案例理解C在实际工程项目PLC在电机中的应用全过程。控制、时间循环、互锁保护、手动干预等方面的应用逻辑。; 阅读建议:建议结合三菱GX Works2编程软件和MCGS组态软件同步实践,重点理解梯形图程序中各环节的时序逻辑与互锁机制,关注I/O分配与硬件接线的对应关系,并尝试在仿真环境中调试程序以加深对全自动洗衣机控制流程的理解。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值