我应该避免Perl中的嵌套if语句吗?

我应该避免Perl中的嵌套if语句吗?,perl,coding-style,nested,Perl,Coding Style,Nested,我正在做一些Perl,看到嵌套的“if”语句让我抓狂。我设法在另一个部分用防护块减少了一些,但我被困在这里了 你认为我可以让代码保持原样,还是有一种“适当”的方法来重构以下内容?(我也承认对Perl来说是比较新的) 这实际上是一个子例程,要求用户输入列表(外部文件)的每个参数$[3] 是匹配模式,$[2]是所考虑的参数的默认值(如果没有,则为NULL),$\U1]指定它是否为必需的。“next”语句引用下一个读取的参数(while循环) 在大家的帮助下(谢谢!),这是最新的版本 100

我正在做一些Perl,看到嵌套的“if”语句让我抓狂。我设法在另一个部分用防护块减少了一些,但我被困在这里了

你认为我可以让代码保持原样,还是有一种“适当”的方法来重构以下内容?(我也承认对Perl来说是比较新的)

这实际上是一个子例程,要求用户输入列表(外部文件)的每个参数$[3] 是匹配模式,$[2]是所考虑的参数的默认值(如果没有,则为NULL),$\U1]指定它是否为必需的。“next”语句引用下一个读取的参数(while循环)

在大家的帮助下(谢谢!),这是最新的版本

100         if ( $input ne '' && ( $input !~ $match || $input =~ /'.+'/ ) ) {
101             print "! Format not respected. Match : /$match/ (without \' \')\n";
102             next;
103         }
104         if ( $input eq '' ) {
105             if ( $default eq 'NULL' ) {
106                 if ( $manda eq 'y' ) {
107                     print "! Mandatory parameter not filled in\n";
108                     next;
109                 }
110                 print "+ Ignoring parameter.\n";
111                 $input = '';
112             }
113             else {
114                 print "+ Using default value\n";
115                 $input = $default;
116             }
117         }


若您需要嵌套If语句,那个么我猜它们并没有什么问题

但是,您可以通过以下方式提高代码的可读性

  • 只需要多一点空白和
  • 通过使用您自己的变量,而不是直接对@_
  • 这不是更有可读性吗

     98        if ($input eq '') {
     99             if ($default eq 'NULL'){
    100                 if ($input eq 'y'){
    101                     print "! Mandatory parameter not filled in\n";
    102                     next;
    103                 }
    104                 else {
    105                     print "+ Ignoring parameter.\n";
    106                     $input = '';
    107                 }
    108             }
    109             else {
    110                 print "+ Using default value\n";
    111                 $input = $default;
    112             }
    113         }
    114         elsif ($input !~ $foo || $input =~ /'.+'/) {
    115                 print "! Format not respected. Match : /$foo/ (without \' \')\n"; 
    116                 next;
    117             }
    118         }
    

    通常的做法是为数组索引定义常量,并为它们指定有意义的名称。例如:

    use constant MANDATORY => 1,
                 DEFAULT => 2,
                 PATTERN => 3;
    ...
    if($_[DEFAULT] eq 'NULL') {
       ...
    }
    

    至于嵌套——您应该经常尝试减少缩进(意思是保持嵌套级别较低),但决不能以保持代码可理解为代价。我对嵌套级别没有问题,但这也只是代码的一小部分。如果这确实是一个问题,您可以将条件分解为单独的子例程。

    考虑到您可能会做一个意大利面
    转到
    ,否则,绝对不会


    如果你不喜欢其他的,你可以简化为以下内容

    if($input eq ''){
        $input = $_[2];
        $output = "+ Using default value\n";
        if($_[2] eq 'NULL'){
            $input = '';
            $output = "+ Ignoring parameter.\n";
            if($_[1] eq 'y'){
                $output = "! Mandatory parameter not filled in\n";
            }
        }
    }
    elsif($input !~ $_[3] || $input =~ /'.+'/){
        $output = "! Format not respected. Match : /$_[3]/ (without \' \')\n"; 
    }
    print $output;
    

    主要关注点是保持代码可读性


    如果可以使用嵌套的If语句获得可读代码,请继续。但要始终保持常识的活跃性。

    我想你可以通过逻辑组合来平复它:

    if(($input eq '')&&($_[2] eq 'NULL')&&($_[1] eq 'y')){
      print "! Mandatory parameter not filled in\n";
      next;
    }
    
    elsif(($input eq '')&&($_[2] eq 'NULL')){
      print "+ Ignoring parameter.\n";
      $input = '';
    }
    
    elsif($input eq ''){
      print "+ Using default value\n";
      $input = $_[2];
      next;
    }
    
    
    elsif($input !~ $_[3] || $input =~ /'.+'/){
      print "! Format not respected. Match : /$_[3]/ (without \' \')\n";
    }
    
    print $output;
    

    然后你可以使用一个开关使它变得更好。

    这里有一个更易读的混沌答案:

    # Set sane variable names...
    my ($is_required, $default, $pattern) = @_
    
    # Convert the external string convention for simpler evaluation...
    $default = undef if $default eq 'NULL'
    
    # Refuse problematic input before going any further...
    if ($input ne '' && $input !~ $pattern || $input =~ /'.+'/) {
        print "! Format not respected. Match : /$pattern/ (without \' \')\n"; 
        next;
    }
    
    
    # If there was no input string...
    if($input eq '') {
    
        # Set the default, if one was provided...
        if( $default ) {
            print "+ Using default value\n";
            $input = $default;
        } 
        # otherwise, complain if a default was required...
        else {
            if( $is_required eq 'y' ){
                print "! Mandatory parameter not filled in\n";
                next;
            }
            print "+ Ignoring parameter (no input or default provided).\n";
        }
    }
    
    重点是:

    • 如果要使用“下一步”退出当前循环,则不需要使用else
    • 特殊情况应首先处理
    • 通过使用命名变量,可以极大地提高可读性
    我认为有关嵌套的主要(如果不是唯一)原因是算法复杂性。在其他情况下,您应该担心可读性和可维护性,这可以通过适当的注释和缩进来解决


    我总是发现阅读我的旧代码的可维护性是一个很好的练习,不仅是对可读性的反馈,还有对技术的反馈。

    有时有助于提高可读性的另一种方法是将部分或所有分支放在命名良好的代码引用中。以下是这个想法的开始:

    $format_not_respected = sub {
        return 0 if ...;
        print "! Format not respected....";
        return 1;
    }
    $missing_mandatory_param = sub {
        return 0 if ...;
        print "! Mandatory parameter not filled in\n";
        return 1;
    }
    
    next if $format_not_respected->();
    next if $missing_mandatory_param->();
    etc...
    


    到底是什么让你对那些嵌套的如果感到愤怒?我不知道,我只是觉得有另一种写作方式……关于第1点,我每隔一段时间就会使用Perltidy。我目前正在尝试解决问题并预先调试。2.我(在O'reilly的书和其他地方)读到it$和$@被广泛使用,但没有提到任何缺点?1。使用易于阅读的代码解决问题更容易。2.缺点是可读性。例如,在替换$x[x]的各种用法时,我立即注意到,您对这些变量所包含内容的描述并不完全正确。1。你完全正确。我喜欢代码本身,但它肯定会被其他人(首先是你)维护。2. @_ 是一个数组,其中包含(按值)传递给函数的参数列表。正确的?至于$\,我只在r/w(进入)文件句柄时使用它。关于@\,你是对的。但最好的做法是将@uu中的值转换成具有合适名称的标量变量。正如我所说的,这是一个子程序,我所有的变量都是局部变量。因此,我不能使用“use”语句?谢天谢地,嵌套不是代码其余部分的问题。谢谢你的回答。“使用常量”有一些缺点。使用use constant创建的常量不能插值(例如,在字符串中),因为它们没有符号,并且在运行时没有词汇范围。它们是包范围的,并在编译时生成。如果在运行时设置了一个常量(例如通过函数),则会出现此问题。Damian Conway在《Perl最佳实践》一书中对这一点进行了更好的描述,并给出了很好的例子。我从中吸取了教训:goto就是地狱从没想过。Switch case在这里并不适用,因为我正在测试4个不同的变量。你是说
    给定的
    /
    时吗?它不是只使用“use-feature”或“use-Switch”perl 6.0“”实现吗?我喜欢这样!谢谢(除了拥抱的else:p)如果你必须维护我的代码,你会有困难吗?@Isaac,没有。(但我受过训练,要维护难以阅读的代码,所以我不是一个好的参考)。这实际上是我以前的版本,“&&&”测试不适合我。这甚至不是Perl。Perl没有
    elseif
    只有
    elsif
    @Imagest,在这种情况下,可读性比微小的速度差异更重要,根据问题作者的说法,阿谀奉承对他来说更具可读性,这正是他所要求的@布拉德·吉尔伯特好吧,你抓到我了,我甚至不认识珀尔,但这没关系,很明显其他人是什么,不是吗。我帮你改了答案。谢谢你。我们的回复错了(见我的第一篇文章编辑)。顺便说一句,在我的代码中,$is_required强制用户填写,这不是抱怨:p(虽然没有更改任何内容,而且您还没有阅读整个子例程)很抱歉重复发布,但我喜欢您的评论方式;我说的“你还没读过”是指“我还没发帖”。谢谢,尽管我不能要求任何信用。评论风格是达米安·康威的——我是在读了他的文章后采用的,因为
    # Set sane variable names...
    my ($is_required, $default, $pattern) = @_
    
    # Convert the external string convention for simpler evaluation...
    $default = undef if $default eq 'NULL'
    
    # Refuse problematic input before going any further...
    if ($input ne '' && $input !~ $pattern || $input =~ /'.+'/) {
        print "! Format not respected. Match : /$pattern/ (without \' \')\n"; 
        next;
    }
    
    
    # If there was no input string...
    if($input eq '') {
    
        # Set the default, if one was provided...
        if( $default ) {
            print "+ Using default value\n";
            $input = $default;
        } 
        # otherwise, complain if a default was required...
        else {
            if( $is_required eq 'y' ){
                print "! Mandatory parameter not filled in\n";
                next;
            }
            print "+ Ignoring parameter (no input or default provided).\n";
        }
    }
    
    $format_not_respected = sub {
        return 0 if ...;
        print "! Format not respected....";
        return 1;
    }
    $missing_mandatory_param = sub {
        return 0 if ...;
        print "! Mandatory parameter not filled in\n";
        return 1;
    }
    
    next if $format_not_respected->();
    next if $missing_mandatory_param->();
    etc...