Назначение с использованием троичного оператора? - PullRequest
25 голосов
/ 20 января 2012

Я на Perl 5.8 и мне нужно назначить значение по умолчанию. Я закончил тем, что сделал это:

if ($model->test) {
    $review = "1"
} else {
    $review = ''
}

Значение $model->test будет либо "1", либо неопределенным. Если что-то есть в $model->test, установите $review на "1", в противном случае установите значение ''.

Поскольку это не Perl 5.10, я не могу использовать новый шикарный определенный оператор. Моей первой реакцией было использование троичного оператора, подобного этому ...

defined($model->test) ? $review = "1" : $review = '';

но это тоже не сработало.

У кого-нибудь есть идеи, как назначить это более эффективно? Джени

Ответы [ 7 ]

37 голосов
/ 20 января 2012

Я бы обычно писал это как:

$review = ( defined($model->test) ? 1 : '' );

где скобки для ясности для других людей, читающих код.

20 голосов
/ 20 января 2012

У вас проблема с приоритетом.То, что у вас есть, такое же, как

( defined($model->test) ? $review="1" : $review ) = '';

. Вы можете заставить его работать с паренами.

my $review; $model->test ? ( $review='1' ) : ( $review='' );

Но гораздо проще убрать задание.

my $review = $model->test ? '1' : '';

Конечно, вы можете просто использовать

my $review = $model->test || '';

Но зачем менять undef на пустую строку?

my $review = $model->test;
10 голосов
/ 20 января 2012

$model->test будет либо "1", либо неопределенным.Если что-то есть в $model->test, установите $review на "1", в противном случае установите ''

Затем просто используйте это:

$review = $model->test || "";
7 голосов
/ 22 августа 2013

Помимо условного оператора, мне часто нравится использовать do, который возвращает значение из последнего вычисленного выражения:

my $review = do {
     if( ... ) { 'foo' }
  elsif( ... ) { 'bar' }
  elsif( ... ) { 'baz' }
  else         { 'defaut' }
  };
2 голосов
/ 20 августа 2013

Я предполагаю, что $model->test должен возвращать истинное или ложное значение.

Если специально не указано, что ложное значение равно undef, метод можно переписать, чтобы вместо него начать возвращать какое-то другое ложное значение. Который сломал бы все, что только проверяет, определено ли значение.
(Я думаю, это ошибка, что метод возвращает undef вместо канонического ложного значения.)

Таким образом, лучший способ установить $review - проверить достоверность возвращаемого значения; не определенность.

my $review = $model->test ? 1 : '';

Я хотел бы отметить, что в этом все еще есть ошибка. Если вы хотите использовать значение как число, оно выдаст предупреждение, если оно было ложным.

Чтобы исправить это, вы должны вернуть !1 (каноническое ложное значение), которое будет возвращать значение, которое является строкой '', но также имеет числовое значение 0.

my $review = $model->test ? 1 : !1;

Обратите внимание, что это можно упростить до:

my $review = !! $model->test; # invert it twice

Если вы хотите изменить значение только тогда, когда оно ложно, вы можете использовать оператор или ||.

my $review = $model->test || !1;

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

my $review = defined $model->test;

Если вы хотите изменить значение только тогда, когда оно не определено, и у вас есть Perl 5.10 или новее, вы можете использовать оператор определенный-или (//) .

my $review = $model->test // !1;

На более старом Perl для этого потребуется более одного оператора .

my $review = $model->test;
$review = !1 unless defined $review;
2 голосов
/ 20 января 2012

Прежде всего, «Это тоже не сработало» - не самая полезная вещь, которую вы можете нам сказать.Важно точно знать , как это не сработало: что оно делало, что вы ожидали и чем они отличаются?

Но проблема с

defined($model->test) ? $review="1" : $review='';

- приоритет оператора.Условный оператор ? : связывается более тесно, чем оператор присваивания =, поэтому приведенное выше эквивалентно:

(defined($model->test) ? $review="1" : $review) = '';

Так что, если определено $model->test, оно эквивалентно

$review = "1" = '';

Вы можете исправить эту проблему с помощью скобок:

defined($model->test) ? ($review="1") : ($review='');

Но на самом деле, зачем вам это?Условный (троичный) оператор полезен, когда вы хотите использовать результат.Если результат будет отброшен, как здесь, то будет понятнее (и, как вы видели, менее подвержены ошибкам) ​​использовать оператор if / else:

if (defined($model->test) {
    $review = "1";
}
else {
    $review = "";
}

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

if (defined($model->test) { $review = "1"; } else { $review = ""; }

Если вы действительно хотите использовать условное выражение, вы можете сделать это:

$review = defined($model->test) ? "1" : "";

, что, вероятно, является разумным способом сделатьit.

НО:

Сам оператор defined возвращает либо "1" (true), либо "" (false).так что все это может быть уменьшено до:

$review = defined($model->test);
1 голос
/ 22 января 2012
my $result = defined $model->test ? '1' : '';
...