2013-06-18 4 views
2

Это следующий вопрос для this one.В Perl - может быть отключена оценка короткого замыкания, если необходимо?

Например, предположим, что у меня есть три процедуры, которые мне нужно работать независимо от того, что и выход, если все они вернутся 1.

while (&proc1 && &proc2 && &proc3); 

Поскольку Perl использует оценку короткого замыкания, код может или не могут выполнять подпрограммы & proc2 и & proc3 в зависимости от предыдущих операндов (если операнд является ложным, следующие операнды не будут выполнены; больше информации here и on wiki). Если необходимо, есть ли способ отключить эту функцию?

+2

Опишите здесь свой полный вопрос, чтобы это было полезно для других. – woz

+2

никогда не вызывают подпрограммы с '&', но без '()', если вы не знаете и не хотите, чтобы срабатывало специальное поведение. – ysth

+0

@ysth Пожалуйста, объясните «особое поведение» или укажите ссылку для будущего чтения. –

ответ

3

Вы можете использовать оператор умножения

while (&proc1 * &proc2 * &proc3) { ... } 

Это будет оценивать все три операнда и оценивать ложь, если какой-либо один из них является ложным (ноль).

Если вы беспокоитесь о предупреждения о неинициализированных значений, вы можете использовать побитовое и с псевдо-оператора !! монолитно-к-логическое значение:

while (!!&proc1 & !!&proc2 & !!&proc3) { ... } 

, который будет делать почти то же самое. Приведение от буфера к буле необходимо, потому что результат поразрядного и двух произвольных истинных значений может по-прежнему быть ложным (например, 1 & 2 оценивает 0).

+4

Это зависит от значений true/false, возвращаемых подпрограммами '1' /' 0'. Они также могли бы легко быть '{}'/'undef'. – Borodin

+0

решение '!!' возвращает правильное значение. другим решением будет 'до (proc1() | proc2() | proc3())'. И да, я тестировал: 'perl -E 'say for! ({} | {}),! ({} | Undef),! (Undef | undef)'' ничего не говорит, ничего и 1. – Massa

+3

Ответ совершенно правильно, но я боюсь, что это один из тех случаев, когда ваш программист по обслуживанию вас будет ненавидеть. – innaM

8

Вы можете просто оценить каждое предложение во временных переменных, а затем оценить все выражение. Например, чтобы избежать оценки короткого замыкания в:

if ($x < 10 and $y < 100) { do_something(); } 

пишут:

$first_requirement = ($x < 10); 
$second_requirement = ($y < 100); 
if ($first_requirement and $second_requirement) { do_something(); } 

будет оцениваться Оба условными. Предположительно, вам нужны более сложные условия с побочными эффектами, иначе нет смысла оценивать второе условие, если первое ложно.

+0

Спасибо, что нашли время ответить. Я выбрал ответ толпы как принятый ответ, потому что imho это немного больше «perl-centric». –

+2

Я не вижу ничего, кроме этого. Если что-нибудь, то это понятно. – doubleDown

5

Вы могли бы написать

until (grep !$_, proc1(), proc2(), proc3()) { 
    ... 
} 

Что бы вы ни делали, вы не должны вызывать подпрограммы, используя синтаксис амперсанд, как &proc1. Это было неправильно в течение многих лет, заменено на proc1()

+0

+1 для предупреждения амперсанда. – Massa

+0

Если все функции возвращают true, grep возвращает пустой массив, который вычисляется как false. если какая-либо функция возвращает false, grep возвращает непустой массив, который оценивается как true ... nice. – doubleDown

+1

@doubleDown: более простой способ подумать о том, что 'grep' в скалярном контексте (который' до' налагает) возвращает количество элементов списка, которые удовлетворяют условию. В этом случае он подсчитывает количество возвращаемых значений, которые не являются истинными, и мы хотим, чтобы цикл был равен нулю (false). – Borodin

1

Я не знаю, каким образом можно отключить оценку короткого замыкания, но вы можете оценить каждый компонент в начале тела цикла и разорвать его условий ложно.

while (1) { 
    my $result1 = &proc1; 
    my $result2 = &proc2; 
    my $result3 = &proc3; 
    last unless ($result1 && $result2 && $result3); 
    ... 
} 
Смежные вопросы