лучший способ написать код для компиляции со строгим - PullRequest
2 голосов
/ 23 июля 2010

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

У меня есть большая старая библиотека, я хочу исправить код, чтобы я мог добавить use strict; к этому большинство моих ошибок таковы (при загрузке страницы генерируется 189 ошибок):

Use of uninitialized value in string eq at ../lib/cgilibtest.pl line 1510
Use of uninitialized value in concatenation (.) or string at ../lib/cgilibtest.pl line 1511.

Они генерируются подпрограммами, написанными так:

#!/usr/bin/perl -w
sub example()
{
    my $var1 = shift @_;
    my $var2 = shift @_;
    my $var3 = shift @_;
    if($var2 eq ""){var2 = "something";} # this line generates the first type of error beacause $var2 is not defined
    return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3; # this line generates the second type of error, beacause $var3 is not defined
}
print "Content-type: text/html\n\n";
$someVar = &example("firstVar");
print $someVar;

Мое решение состояло в том, чтобы использовать троичный оператор и записать их как:

#!/usr/bin/perl -w
use strict;

sub example()
{
    my $var1 = ($_[0])?$_[0]:"";
    my $var2 = ($_[1])?$_[1]:"something";
    my $var3 = ($_[2])?$_[2]:"";
    return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3;
}
print "Content-type: text/html\n\n";
my $someVar = &example("firstVar");
print $someVar;

в PHP я использую function example ($var1, $var2 = null, $var3 = null){...}

P.S. Если кто-то знает хороший учебник или руководство по «написанию строгого кода на Perl», пожалуйста, оставьте ссылку на него.

Спасибо.

Ответы [ 3 ]

3 голосов
/ 23 июля 2010
  • Я думаю, что PBP ( Perl Best Practices ) - хорошее чтение в "строгом" стиле. Если следуя тому, что он говорит, вы будете по крайней мере писать код, совместимый с strict и warnings.

То, что я вижу, это неявные предупреждения. И, неявные предупреждения приходят с warnings, а не strict. Хотя обычно это идет рука об руку со строгим.

Для вашей конкретной ошибки важно понимать, что когда вы сдвигаете массив arg (который я склонен называть «deck»), пользователь метода / функции, возможно, ничего не передал в этой позиции. Таким образом, это хорошая идиома;

my $var1 = shift || '';

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

Конечно, есть еще одна проблема. Если вы посмотрите на код выше, что я ожидаю? Я ожидаю, что $var1, возможно, не было передано никаких данных. Если это так, и я все еще хочу привести его в соответствие - и в локальном коде есть достаточно подобных случаев - иногда вы просто делаете это:

# don't bug me about uninitialized stringed values
# just concatenate them
no warnings 'uninitialized'; 
return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3; 

Это эквивалентно коду с кучей переменных:

my $var = shift || '';

Идея не должна застать врасплох 1037 * с неинициализированными данными - с политикой, которая соответствует экземпляру, а не рабским кодированием по стандарту.

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

{   no warnings 'uninitialized';
    $string = ...;
}
$obj_that_should_be_defined->do_something_objecty( $string );

do блоки также полезны для этого.

$obj_that_should_be_defined->do_something_objecty( 
    do { no warnings 'uninitialized'; sprintf( ... ); }
);

Конечно, все, что вы передаете в качестве переменной, вы также можете фильтровать с помощью map. Следующее работает, если вы просто хотите позаботиться о undefs.

$object->method( map { defined() ? $_ : '' } @anon_args );  
  • Я предупреждаю, что все, что еще не было проверено в области видимости - что-либо, поступающее откуда-то еще: параметр, ввод-вывод, захват регулярного выражения, возврат из функций - может быть неинициализировано. Практика хорошего кодирования должна заставить вас проверять все эти вещи ЕСЛИ , в данном случае вам небезразлично, являются ли они undef нет.

Теперь, часто люди проверяют неопределенные переменные, чтобы просто выдохнуть. С тех пор сообщения Perl стали лучше, и, возможно, могли бы они улучшиться в будущем. Возможно, нет необходимости специально крякать.

my $feldman = Feldman->new( qw<here is some data for you> )
    or die 'Could not create Feldman!'
    ;
$feldman->dont_just_sit_there_do_something();

Однако без явного or die приведенный выше код точно умрет, если $feldman не определено. Вы не можете вызывать метод для неопределенного значения, поэтому есть причина для не конкретной проверки. Если $feldman не определено, значит, вы его не создавали, есть еще один уровень вывода, который вы должны сделать: от неопределенного до сообщения об ошибке. Ни один из них не говорит нам , почему объект не был создан, просто это не так. (Конструктор должен был хотя бы придраться к тому, чего у него не было.)

2 голосов
/ 23 июля 2010
sub example {
  my $var1 = shift || '';
  my $var2 = shift || 'something';
  my $var3 = shift || '';

  return "var1 = ".$var1.", var2 = ".$var2.", var3 = ".$var3;
}
1 голос
/ 23 июля 2010

Я бы рекомендовал взглянуть на Perl Best Practices . Дамиан Конвей - отличный учитель. Также имейте в виду, что книга не предназначена для догматического прочтения, и даже предложения, которые вы не принимаете, заслуживают внимания.

Для позиционных аргументов, которые все принимают одно и то же значение по умолчанию, я часто делаю что-то вроде этого:

sub example {
    my ($var1, $var2, $var3) = map { defined() ? $_ : '' } @_;
}

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

sub example {
    my %DEFAULTS = ( foo => 0, bar => '', fubb => 'blah' );

    # When the hashes are merged, user-supplied arguments
    # will trump the defaults.
    my %args = (%DEFAULTS, @_);
}

example(foo => 123);

Если я правильно помню, PBP обсуждает этот прием слияния хэшей, который полезен во многих контекстах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...