Когда можно использовать переменную undefined в perl с включенными предупреждениями?

При включенном предупреждении perl обычно печатает Use of uninitialized value $foo, если <$foo используется в выражении и ему не присвоено значение, но в некоторых случаях оно ОК, а переменная рассматривается как false, 0, или '' без предупреждения.

В каких случаях можно использовать неинициализированную переменную / undefined без предупреждения?

Ответы

Ответ 1

Резюме

  • Логические тесты
  • Увеличение или уменьшение значения undefined
  • Добавление к значению undefined
  • Autovivification
  • Другие мутаторы

Логические тесты

В соответствии с документацией perlsyn,

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

Поскольку значение undefined равно false, следующая программа

#! /usr/bin/perl

use warnings;

my $var;
print "A\n" if $var;
$var && print "B\n";
$var and print "C\n";
print "D\n" if !$var;
print "E\n" if not $var;
$var or print "F\n";
$var || print "G\n";

выводит D через G без предупреждений.

Увеличение или уменьшение значения undefined

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

#! /usr/bin/perl

use warnings;

my $i;
++$i while "aaba" =~ /a/g;
print $i, "\n";

Приведенный выше код выводит 3 без предупреждений.

Добавление к значению undefined

Подобно неявному нулю, нет необходимости явно инициализировать скаляры в пустой строке, если вы добавите ее хотя бы один раз:

#! /usr/bin/perl

use warnings;
use strict;

my $str;
for (<*>) {
  $str .= substr $_, 0, 1;
}
print $str, "\n";

Autovivification

Одним из примеров является "автовивитация". Из Статья в Википедии:

Автовивификация является отличительной чертой языка программирования Perl, включающего динамическое создание структур данных. Автовивитация - это автоматическое создание ссылки на переменные, когда значение undefined разыменовывается. Другими словами, автовивитация Perl позволяет программисту ссылаться на структурированную переменную и произвольные подэлементы этой структурированной переменной, не объявляя заранее о существовании переменной и ее полной структуры.

Например:

#! /usr/bin/perl

use warnings;

my %foo;
++$foo{bar}{baz}{quux};

use Data::Dumper;
$Data::Dumper::Indent = 1;
print Dumper \%foo;

Даже если мы явно не инициализируем промежуточные ключи, Perl заботится о строительных лесах:

$VAR1 = {
  'bar' => {
    'baz' => {
      'quux' => '1'
    }
  }
};

Без автообвинения код потребует больше шаблонов:

my %foo;
$foo{bar} = {};
$foo{bar}{baz} = {};
++$foo{bar}{baz}{quux};  # finally!

Не путайте автовивитацию со значениями undefined, которые она может произвести. Например,

#! /usr/bin/perl

use warnings;

my %foo;
print $foo{bar}{baz}{quux}, "\n";
use Data::Dumper;
$Data::Dumper::Indent = 1;
print Dumper \%foo;

получаем

Use of uninitialized value in print at ./prog.pl line 6.

$VAR1 = {
  'bar' => {
    'baz' => {}
  }
};

Обратите внимание, что промежуточные ключи автогенерируются.

Другие примеры автовивитации:

  • ссылка на массив

    my $a;
    push @$a => "foo";
    
  • ссылка на скалярный

    my $s;
    ++$$s;
    
  • ссылка на хэш

    my $h;
    $h->{foo} = "bar";
    

К сожалению, Perl не (пока!) автогенерирует следующее:

my $code;
$code->("Do what I need please!");

Другие мутаторы

В ответе на аналогичный вопрос, ysth сообщает

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

Это: ++ и -- (до или после), +=, -=, .=, |=, ^=, &&=, ||=.

Будучи "определенным" или "//=, с радостью изменяет значение undefined без предупреждения.

Ответ 2

До сих пор я обнаружил следующие случаи:

  • autovivification (ответ gbacon)
  • boolean context, например if $foo или $foo || $bar
  • с ++ или --
  • слева от +=, -= или .=

Есть ли другие?

Ответ 3

Всегда исправлять предупреждения даже досадные досадные.

Undefined предупреждения могут быть отключены. Это можно сделать, создав новую область действия. Подробнее см. perldoc perllexwarn. Этот метод работает во всех версиях perl.

{
  no warnings 'uninitialized';
  my $foo = "foo" + undef = "bar";
}

Для многих бинарных операторов вы можете использовать новый материал Perl 5.10, ~~ и //; См. perldoc perlop для получения дополнительной информации.

use warnings;
my $foo = undef;
my $bar = $foo // ''; ## same as $bar = defined $foo ? $foo : ''

также является вариантом //=, который устанавливает переменную, если она undefined:

$foo //= '';

Оператор Smart Matching (~~) - это классный пример и позволяет осуществлять интеллектуальные сравнения, это отчасти отличная проверка в perldoc perlsyn:

use warnings;
my $foo = "string";
say $foo eq undef;  # triggers warnings
say $foo ~~ undef;  # no undef warnings

Ответ 4

Реальный ответ: почему вы хотите включить это предупреждение? undef - отличное значение для переменной (как может сказать кто-либо, кто когда-либо работал с базой данных), и часто имеет смысл различать истину (что-то случилось), false (ничего не произошло) и undef (произошла ошибка).

Вместо того, чтобы говорить

use strict;
use warnings;

говорят

use common::sense;

и вы получите все преимущества предупреждений, но с раздражающими, например, переменными undefined.

common:: sense доступен из CPAN.