Тернный оператор Perl - PullRequest
       64

Тернный оператор Perl

4 голосов
/ 31 января 2012

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

#!/usr/bin/perl

use strict;
use warnings;

my @array = ('Serial = "123"', 'Serial = "456"', 'Serial = "789"');
my ($test1,$test2);
foreach my $a (@array){
        !$test1 ? $test1 = $a  : $test1 .= " AND " . $a;
}
foreach my $b (@array){
        if (!$test2) {
                $test2 = $b
        } else {
                $test2 .= " AND " . $b;
        }
}
print "Test1: $test1\n";
print "Test2: $test2\n";

Вывод:

~/bin/test.pl
Test1: Serial = "123" AND Serial = "123" AND Serial = "456" AND Serial = "789"
Test2: Serial = "123" AND Serial = "456" AND Serial = "789"

Вывод Test1 имеет дополнительный "Serial =«123», что я делаю не так?

Ответы [ 5 ]

10 голосов
/ 31 января 2012

Во-первых, у вас есть проблема с приоритетом.

!$test1 ? $test1 = $a : $test1 .= " AND " . $a;

означает

( !$test1 ? $test1 = $a : $test1 ) .= " AND " . $a;

Это можно решить с помощью паренов.

my $test1;
for (@array) {
   !$test1 ? ($test1 = $a) : ($test1 .= " AND " . $a);
}

Но это не читается. Вы явно идете в неправильном направлении! Выполняются две задачи, и вы пытаетесь объединить их в одну. Простое их разделение делает код более читабельным.

my $test1;
for (@array) {
   $test1 .= ' AND ' if $test1;
   $test1 .= $_;
}

Но мы еще не там. Позвольте представить вам join.

my $test1 = join(' AND ', @array);

Так намного лучше!

Наконец, похоже, что вы строите оператор SQL. Если это так, то ваш вопрос спорный, так как вы должны ИСПОЛЬЗОВАТЬ МЕСТА ДЛЯ ПЕРЕДАЧИ ДАННЫХ В БАЗУ ДАННЫХ. Найдите в этом документе документацию DBI .

7 голосов
/ 31 января 2012

Назначение имеет более низкий приоритет, чем ?.Это

!$test1 ? $test1 = $a  : $test1 .= " AND " . $a;

эквивалентно этому:

(!$test1 ? $test1 = $a  : $test1) .= " AND " . $a;

Таким образом, сначала $test1 станет Serial = "123", а затем AND Serial = "123" будет добавлено сразу после.

Попробуйте это:

!$test1 ? ($test1 = $a)  : ($test1 .= " AND " . $a);

Лучшее решение было бы так:

$test1 = !$test1 ? $a  : $test1 . " AND " . $a;

Использование троичного оператора для побочных эффектов может быть довольно грязным, и я бы рекомендовал избегать этого.

Редактировать

Как отмечает MuIsTooShort join(' AND ', array) было бы наиболее кратким и читаемым решением в вашем случае.

3 голосов
/ 31 января 2012

У вас проблема с приоритетом. Вы можете увидеть, как Perl интерпретировал (то есть понял) выражение, используя Deparse

perl -MO=Deparse,-p -e "!$test1 ? $test1 = $a  : $test1 .= q{ AND } . $a;"

-p говорит Deparse поставить много скобок, чтобы вы могли видеть, что случилось:

(((!$test1) ? ($test1 = $a) : $test1) .= (' AND ' . $a));

поэтому здесь вы можете видеть, что строка кода не означает, что вы намеревались.

Это довольно плохой стиль для использования ?:, подобный этому, и он не сделает вещи быстрее.

2 голосов
/ 31 января 2012

Тернарный оператор отлично подходит для ситуаций, когда Z = X OR Y.

Вы на самом деле здесь этого не делаете.Происходит то, что вы строите строку из массива.Вот что такое функция join.

my $test = join ' AND ', @array;

Теперь, когда - это более эффективное кодирование.

0 голосов
/ 31 января 2012

В вашем цикле

my ($test1,$test2);
foreach my $a (@array){
        !$test1 ? $test1 = $a  : $test1 .= " AND " . $a;
}

1-й раз $test1 будет: Serial = "123" AND Serial = "123"

2-й раз: Serial ="123" AND Serial = "123" AND Serial = "456"

третий: Serial "123" AND Serial = "123" AND Serial = "456" AND Serial = "789"

4ht: Тест1: Serial = "123" AND Serial = "123" AND Serial = "456" AND Serial = "789"

...