代码之家  ›  专栏  ›  技术社区  ›  Carl Smotricz

皮条客我的Perl代码

  •  4
  • Carl Smotricz  · 技术社区  · 16 年前

    01 my $config_var = 999;
    
    03 my $result_var = 0;
    
    05 foreach my $file (@files) {
    06   open(my $fh, $file);
    07   while (<$fh>) {
    08     &analyzeLine($_);
    09   }
    10 }
    
    12 print "$result_var\n";
    
    14 sub analyzeLine ($) {
    15   my $line = shift(@_);
    16   $result_var = $result_var + calculatedStuff;
    17 }
    

    在现实生活中,有多达六种不同的方法 config_var s和 result_var

    这些脚本在分配给 配置变量 analyzeLine() 大致相同,但可能有一些小的变化。

    我可以通过复制N份代码来实现我的目的,只需在这里和那里做一些小的更改;但这严重违反了良好设计的各种规则。理想情况下,我希望编写一系列脚本,其中只包含一组配置变量初始化,然后是

    do theCommonStuff;
    

    注意 配置变量 结果变量 还有它的长相 analyzeLine() 做一些计算。

    我应该将“通用”代码打包到模块中吗?创建一个类?使用全局变量?

    期待您的建议,谢谢!


    更新

    真实的 analyzeLine :

    # Update stats with time and call data in one line.
    sub processLine ($) {
      my $line = shift(@_);
      return unless $line =~ m/$log_match/;
      # print "$1 $2\n";
      my ($minute, $function) = ($1, $2);
      $startMinute = $minute if not $startMinute;
      $endMinute = $minute;
      if ($minute eq $currentMinute) {
        $minuteCount = $minuteCount + 1;
      } else {
        if ($minuteCount > $topMinuteCount) {
          $topMinute = $currentMinute;
          $topMinuteCount = $minuteCount;
          printf ("%40s %s : %d\n", '', $topMinute, $topMinuteCount);
        }
        $totalMinutes = $totalMinutes + 1;
        $totalCount = $totalCount + $minuteCount;
        $currentMinute = $minute;
        $minuteCount = 1;
      }
    }
    

    由于这些变量在很大程度上是相互依赖的,我认为一个单独计算的函数解决方案是不实际的。我为误导人们而道歉。

    5 回复  |  直到 16 年前
        1
  •  6
  •   catwalk    16 年前

    继续创建一个类层次结构。您的任务是OOP风格编程的理想场所。 下面是一个例子:

    package Common;
    sub new{
      my $class=shift;
      my $this=bless{},$class;
      $this->init();
      return $this;
    }
    sub init{}
    sub theCommonStuff(){ 
      my $this=shift;
      for(1..10){ $this->analyzeLine($_); }
    }
    sub analyzeLine(){
      my($this,$line)=@_;
      $this->{'result'}.=$line;
    }
    
    package Special1;
    our @ISA=qw/Common/;
    sub init{
      my $this=shift;
      $this->{'sep'}=',';   # special param: separator
    }
    sub analyzeLine(){      # modified logic
      my($this,$line)=@_;
      $this->{'result'}.=$line.$this->{'sep'};
    }
    
    package main;
    my $c = new Common;
    my $s = new Special1;
    $c->theCommonStuff;
    $s->theCommonStuff;
    print $c->{'result'}."\n";
    print $s->{'result'}."\n";
    
        2
  •  10
  •   Sinan Ünür    16 年前

    两条评论:第一,不要发布行号,因为行号会使复制、粘贴和编辑变得非常困难。第二,不要使用 &func() 调用sub。请参见 perldoc perlsub :

    & 前缀这个 & 在现代Perl中是可选的。。。不仅如此 &

    简而言之,使用 & 除非你知道自己在做什么以及为什么要做,否则可能会令人惊讶。

    也, don't use prototypes 非常

    不要忘记检查系统调用的返回值,例如 open autodie 现代的 perl

    analyzeLine .

    #!/usr/bin/perl
    
    use warnings; use strict;
    use autodie;
    
    my %config = (
        frobnicate => 'yes',
        machinate  => 'no',
    );
    
    my $result;
    $result += analyze_file(\%config, $_) for @ARGV;
    
    print "Result = $result\n";
    
    sub analyze_file {
        my ($config, $file) = @_;
    
        my $result;
    
        open my $fh, '<', $file;
        while ( my $line = <$fh> ) {
            $result += analyze_line($config, $line);
        }
    
        close $fh;
    
        return $result;
    }
    
    sub analyze_line {
        my ($line) = @_;
        return length $line;
    }
    

    当然,你会注意到 $config 正在到处传递,这意味着您可能希望将其转化为OO解决方案:

    #!/usr/bin/perl
    
    package My::Analyzer;
    
    use strict; use warnings;
    
    use base 'Class::Accessor::Faster';
    
    __PACKAGE__->follow_best_practice;
    __PACKAGE__->mk_accessors( qw( analyzer frobnicate machinate ) );
    
    sub analyze_file {
        my $self = shift;
        my ($file) = @_;
    
        my $result;
    
        open my $fh, '<', $file;
        while ( my $line = <$fh> ) {
            $result += $self->analyze_line($line);
        }
    
        close $fh;
    
        return $result;
    }
    
    sub analyze_line {
        my $self = shift;
        my ($line) = @_;
        return $self->get_analyzer->($line);
    }
    
    package main;
    
    use warnings; use strict;
    use autodie;
    
    my $x = My::Analyzer->new;
    
    $x->set_analyzer(sub {
            my $length; $length += length $_ for @_; return $length;
    });
    $x->set_frobnicate('yes');
    $x->set_machinate('no');
    
    
    my $result;
    $result += $x->analyze_file($_) for @ARGV;
    
    print "Result = $result\n";
    
        3
  •  2
  •   C. K. Young    16 年前

    如果所有公共代码都在一个函数中,则函数将配置变量作为参数,并返回结果变量(作为返回值或作为in/out参数)即可。否则,创建一个类(“包”)也是一个好主意。

    sub common_func {
        my ($config, $result) = @_;
        # ...
        $result->{foo} += do_stuff($config->{bar});
        # ...
    }
    

        4
  •  2
  •   jcdyer Anand S Kumar    16 年前

    一些想法:

    • 如果有几个 $result_var s、 我建议创建一个单独的子例程来计算每个子例程。
    • $result\u var 作为类的属性。

    实际上,有几种方法可以实现这一点:

    (1) 有你的 &analyzeLine 函数返回 calculatedStuff ,并将其添加到 &result_var

      $result_var = 0;
      foreach my $file (@files) {
          open(my $fh, $file);
              while (<$fh>) {
                  $result_var += analyzeLine($_);
              }
          }
      }
    
      sub analyzeLine ($) {
          my $line = shift(@_);
          return calculatedStuff;
      }
    

    (2) 通过 $result\u var analyzeLine 显式地,并返回更改的 $result\u var .

      $result_var = 0;
      foreach my $file (@files) {
          open(my $fh, $file);
              while (<$fh>) {
                  $result_var = addLineToResult($result_var, $_);
              }
          }
      }
    
      sub addLineToResult ($$) {
          my $running_total = shift(@_);
          my $line = shift(@_);
          return $running_total + calculatedStuff;
      }
    

    重要的一点是,如果您为几个$result_变量中的每一个分离函数,您将更容易编写干净的代码。不要担心优化问题。这可能会在以后,当您的代码被证明自己很慢时出现。改进后的设计将使优化变得更容易。

        5
  •  0
  •   Dyno Fu    16 年前