Что происходит, когда у вас есть условный оператор и постфиксное условие в одном и том же операторе Perl?

Кто-нибудь может объяснить, как работает эта линия?

return $y < 0 ? - pip2 : pip2 if $x == 0;

если $y <0, он возвращает -pip2, но что он возвращает, когда $y >= 0 и $x != 0?

Эта строка из этой функции:

sub _atan {
    my( $y, $x ) = @_;

    return $y < 0 ? - pip2 : pip2 if $x == 0;
    return atan( $y / $x );
}

person astropanic    schedule 14.09.2009    source источник


Ответы (4)


Постфикс «если» означает, что оператор возврата выполняется только в том случае, если условие истинно, поэтому

return $y < 0 ? - pip2 : pip2 if $x == 0;

такой же как

if ($x == 0)
{
    return $y < 0 ? - pip2 : pip2 ;
}

Если вас смущает тернарный оператор ?:, его также можно переписать как обычный оператор if, чтобы получить следующее

if ($x == 0)
{
    if ($y<0)
    {
        return -pip2;
    }
    else
    {
        return pip2;
    }
}
person Paul Dixon    schedule 14.09.2009
comment
Я бы, наверное, написал это, используя unless($x){ ... - person Brad Gilbert; 14.09.2009
comment
Это условный оператор, а не тернарный оператор. :) - person Ether; 14.09.2009
comment
Я просто подразумевал, что это был тернарный оператор a, а не тернарный оператор :) - person Paul Dixon; 14.09.2009
comment
@Брэд Гилберт, будь осторожен, unless($x) и if ($x == 0) имеют разные значения. unless($x) будет выполняться, когда $x равно undef, 0, 0.0, "" и "0". if ($x == 0) будет выполняться, когда $x равно 0, 0.0 и любой строке, которая не проходит look_like_number или оценивается как 0 (например, "0e0"). - person Chas. Owens; 15.09.2009

это то же самое, что

if($x == 0){
  if($y<0){
    return -pip2;
  }else{
    return pip2;
  }
}

Тогда вся функция становится:

sub _atan {
  my( $y, $x ) = @_;
  if($x == 0){
    if($y<0){
      return -pip2;
    }else{
      return pip2;
    }
  }else{
    return atan( $y / $x );
  }
}
person Marius    schedule 14.09.2009

Это хороший пример трудночитаемого кода.

Давайте сравним несколько разных способов переписать пример кода и посмотрим, как мы сохраним краткость и улучшим читаемость.

Эта троичная версия выигрывает за краткость, но ее все еще трудно читать:

sub _atan {
    my( $y, $x ) = @_;

    return $x == 0 ? ($y < 0  ? -pip2 : pip2)
                   : atan( $y / $x );  
}

Я считаю, что связанные условные операторы (?:) доступны для чтения только тогда, когда последующие операторы попадают в позицию else:

sub _atan {
    my( $y, $x ) = @_;

    return $x != 0 ? atan( $y / $x ) : 
           $y < 0  ? -pip2           : pip2;  
}

По-прежнему кратко, но читабельность улучшена.

А как насчет использования if и unless? Можем ли мы получить краткий, читаемый код с их использованием?

По своей природе прямой подход if/else будет более подробным:

sub _atan {
    my( $y, $x ) = @_;

    my $atan;
    if( x == 0 ) {
        if( $y < 0 ) {
            $atan = -pip2;
        }
        else {
            $atan = pip2;
        }
    }
    else {
        $atan = atan( $y / $x )
    }            

    return $atan;  
}

Легко проследить все вышеперечисленное и посмотреть, каким будет результат. Так что читабельность выигрывает, но краткость страдает.

Я считаю, что использование форм модификатора оператора unless и if обеспечивает чистый способ добавить логику короткого замыкания в фрагмент кода:

sub _atan {
    my( $y, $x ) = @_;

    return atan( $y / $x )
        unless $x == 0;

    return -pip2 if $y < 0;

    return pip2;  
}

Это лаконично и читабельно, но мне кажется, что мы получили больше результатов, чем нам нужно.

Итак, если мы введем в смесь условный оператор, мы получим

sub _atan {
    my( $y, $x ) = @_;

    return atan( $y / $x )
        unless $x == 0;       

    return $y < 0  ? -pip2 : pip2;  
}

Эта форма столь же кратка, как и любая из вышеперечисленных форм, но гораздо проще для понимания:

sub _atan {
    my( $y, $x ) = @_;

    return atan( $y / $x )
        unless $x == 0;

    return $y < 0  ? -pip2 : pip2;  
}

Вложенные операторы if/else могут быть трудны для понимания. Небольшая осторожность при структурировании кода решения может значительно улучшить читабельность и, следовательно, удобство сопровождения, сохраняя при этом краткое выражение лежащей в основе логики.

Запах кода, который нужно было исправить здесь, был причудливой комбинацией условного оператора (?:) с формой модификатора оператора if. Изменив порядок тестов и тщательно выбрав способ представления условной логики, мы смогли сохранить краткость и ясность кода.

person daotoad    schedule 14.09.2009

Слишком много строк, используемых для решения проблемы, затрудняет поддержку кода (всегда приходится прокручивать). Решение с вложенным if в 4 раза длиннее. Представьте, что вы работаете с экраном в 4 раза меньше. Мой любимый синтаксис:

sub _atan {
    my ($y, $x) = @_;
    return atan ($y / $x) if $x != 0;
    return $y < 0  ? -pip2 : pip2;
}

Преимущество использования постфиксного оператора уменьшается, если вы помещаете его на следующую строку. Этот порядок строк (предложенный @daotoad) позволяет поместить постфиксное условие в более простую строку.

Исходный синтаксис тоже хорош, но я не хотел бы работать над кодом, содержащим предлагаемые вложенные условия if из предыдущих постов.

person webreac    schedule 23.04.2012
comment
Преимущество постфиксного оператора одинаково, где бы вы его ни разместили. Если на вашем экране не видно 24 строк кода, у вас другие проблемы. :) - person brian d foy; 04.05.2012