2015-07-15 2 views
2

Я пытаюсь анализировать фрагмент кода Perl, который содержит следующее:Пытаясь понять сложный синтаксис Perl: массив и пустой квадрат брекет

unless(@{$avl->Rates() || []}) { 
    if(!$nobar) { push @rptmp, 'BAR' unless @rptmp; } 
} 

Внутреннее действие я думаю, я понимаю. Это означает «если $ nobar false (0 в этом случае), то добавьте строку« BAR »в массив @rptmp, если @rptmp уже существует».

У меня есть проблема с первым условием «если»: unless (@{$avl->Rates() || []}). $avl->Rates() - функция, которая возвращает список (или, может быть, указатель на список?). Но действительно запутанная часть для меня - это || []. Это «или» что-то, поэтому он не выбран, если только $avl->Rates() ничего не возвращает. Но я не уверен, что он делает, особенно пустые квадратные скобки. И если он возвращает что-то пустое, не всегда ли оно ложно? Кроме того, есть ли лучший, или, по крайней мере, более ясный способ написать это?

+0

Это ужасно Perl – Borodin

ответ

2

Хм. Давайте посмотрим на это. Я думаю, что это ужасный Perl, но другие явно не согласны. Есть много людей, которые имеют проблемы с unless (что означает просто if not) и в подобных ситуациях я сочувствую: есть просто слишком много происходит

Вот все это

unless (@{ $avl->Rates() || [] }) { 
    if (!$nobar) { push @rptmp, 'BAR' unless @rptmp; } 
} 

Прежде всего я хотел бы извлечь звоните в Rates как этот

my $rates = $avl->Rates(); 
unless (@{ $rates || [] }) { 
    if (!$nobar) { push @rptmp, 'BAR' unless @rptmp; } 
} 

Я не знаю, что $avl может быть, но это выглядит как его метод Rates будет возвращать либо повторно массива или false Значение - возможно undef. Таким образом, выражение $rates || [] присваивает значение false к ссылке на массив энтути. Теперь ограждающие @{ ... } баллончика разыменовать него безопасно в любом случае

Тест пуст ли массив, и я хотел бы написать

unless ($rates and @$rates) 

т.е. если метод Rates не дал истинное значения а, и это было ссылка на непустой массив

Теперь у нас есть внутренний оператор с другим unless, за исключением того, что на этот раз он написан как if not, а внутри него есть является реальным unless

if (!$nobar) { 
    push @rptmp, 'BAR' unless @rptmp; 
} 

Внутреннее утверждение прост. Он проверяет @rptmp, что верно, если массив не пуст, и толкает BAR на него только если он пуст

вмещающих условных проверок, что, по-видимому вариант $nobar, и если это верно то BAR никогда не помещается в массив, независимо от каких-либо других условий

Я бы реорганизовать все это таким образом, извлекая вызов метода в отдельности и с помощью unless по всей

my $rates = $avl->Rates; 

unless ($rates and @$rates) { 
    unless ($nobar) { 
     push @rptmp, 'BAR' unless @rptmp; 
    } 
} 

Если вы unless -phobic, то вот версия, которая использует только if повсюду, но я считаю его менее читаемым

my $rates = $avl->Rates; 

if (not $rates or @$rates == 0) { 
    if (not $nobar) { 
     push @rptmp, 'BAR' if @rptmp == 0; 
    } 
} 

Я надеюсь, что помогает

+0

У меня все еще есть ментальный блок относительно || []. Я понимаю (пожалуйста, поправьте меня, если я ошибаюсь), что если выражение $ avl-> Rates() возвращает undef, тогда [] создает пустой анонимный массив и возвращает ссылку на него. Но какова цель этого? Является ли пустой массив полезным для чего-либо самого, или он только там, чтобы исключить условное выражение из ошибки, если первое выражение является undef? –

+0

В значительной степени. Это так, что '@ {...}' не требует разыменования 'undef', что не имеет смысла и приведет к фатальной ошибке, если' use strict' действует, как и должно быть – Borodin

5

поэтому не будет выбран, если $avl->Rates() возвращает ничего

Это невозможно не вернуть ничего в скалярном контексте. Предположительно, он возвращает ссылку на массив или undef. unless (@{ $avl->Rates }) потерпел неудачу в последнем случае, поэтому кодер решил использовать ссылку на пустой массив в этом случае.

[] 

примерно эквивалентно

# Create an array, and return a reference to it. 
do { my @anon; \@anon } 

Это немного расточительно, но

if ([email protected]{ $avl->Rates() || [] }) { 
    ... 
} 

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

my $rates = $avl->Rates(); 
if (!$rates || [email protected]$rates) { 
    ... 
} 

Следующая понятнее, и избегает вызова Rates, когда он не нужен:

if (!$nobar && [email protected]) { 
    my $rates = $avl->Rates; 
    push @rptmp, 'BAR' 
     if !$rates || [email protected]$rates; 
} 
+0

* "Это невозможно для него ничего не вернуть в скалярном контексте »* Это немного напоминает мета. Невозможно, чтобы какая-либо подпрограмма возвращалась без определения возвращаемого стека.Если по * ничего * вы имеете в виду 'undef', пустой список или любое значение * false *, то да, это возможно, но контекст не имеет значения, если вы не определяете свой * ничего *, так что это – Borodin

+0

@Borodin, subs возвращают ноль или больше скаляров. В скалярном контексте они всегда должны возвращать скаляр. – ikegami

+0

Или, в контексте списка, список – Borodin

0

unless @rptmp долота сделать это, если @rptmp не является пустым.

Пустые квадратные скобки являются ссылкой на пустой массив.

@{...} является разыменование того, что находится в фигурных скобках, и оценивает его как массив.

Таким образом, $avl->Rates() предположительно возвращает ссылку на массив или 0. Если он возвращает 0, первый unless выше будет оценивать []. Выделение домена $avl->Rates() || [] либо получит массив, на который указывает ссылка массива, возвращаемая $avl->Rates(), или пустой массив.

-1

Чтобы ответить

Кроме того, есть лучше, или, по крайней мере, понятнее, способ написать это?

Номер является понятным способом. Это очень идиоматично в Perl; вы найдете его много.

+0

Вы разочаровали меня – Borodin

Смежные вопросы