Должна ли подпрограмма всегда возвращаться явно?
Если perlcritic
говорит: "нет возврата в подпункте - это неправильно", какова альтернатива, если они действительно не нужны?
Я разработал две явно вредные привычки:
- Я явно присваиваю переменные пространству имен $main::.
- Затем я играю с этими переменными в подпрограммах.
Например, я мог бы сделать..
#!/usr/bin/perl
use strict;
use warnings;
@main::array = (1,4,2,6,1,8,5,5,2);
&sort_array;
&push_array;
&pop_array;
sub sort_array{
@main::array = sort @main::array;
for (@main::array){
print "$_\n";
}
}
sub push_array{
for ( 1 .. 9 ){
push @main::array, $_;
}
}
sub pop_array {
for ( 1 .. 3 ){
pop @main::array;
}
}
Я не делаю это все время. Но в вышесказанном это имеет смысл, потому что я могу разделять операции, не нужно беспокоиться о передаче значений туда и обратно, и это, как правило, выглядит аккуратно для меня.
Но, как я уже сказал, критик Perl говорит, что это неправильно - потому что нет возврата..
Итак, кто-нибудь может интерпретировать то, что я пытаюсь сделать, и предложить лучший способ приблизиться к этому стилю кодирования в Perl? например. я вроде как делаю ООП?
2 ответа
Короче говоря - да, вы в основном делаете ОО, но таким образом, что это смущает всех.
Опасность таких подводных лодок заключается в том, что вы действуете на расстоянии. Это плохой стиль кодирования, когда приходится искать в другом месте что-то, что может нарушить ваш код.
Именно поэтому, по возможности, следует избегать "глобалов".
Для короткого сценария это не имеет большого значения.
Относительно возвращаемых значений - Perl возвращает результат последнего выражения по умолчанию. (Увидеть: return
)
(При отсутствии явного возврата подпрограмма, eval или do FILE автоматически возвращает значение последнего вычисленного выражения.)
Причина, по которой критик Perl отмечает это:
Требовать, чтобы все подпрограммы явно заканчивались одним из следующих действий: return, carp, croak, die, exec, exit, goto или throw.
Подпрограммы без явных операторов возврата на их концах могут сбивать с толку. Может быть сложно определить, какое возвращаемое значение будет.
Кроме того, если программист не имел в виду существенное возвращаемое значение и пропускает оператор возврата, некоторые из внутренних данных подпрограммы могут просочиться наружу.
Perlcritic не всегда прав, хотя - если есть веская причина делать то, что вы делаете, выключите его. Так же, как вы думаете об этом и знаете о рисках и последствиях.
Лично я считаю, что лучше возвращать что-то явно, даже если это просто return;
,
Во всяком случае, переработать ваш код в (сырой) OO моды:
#!/usr/bin/perl
use strict;
use warnings;
package MyArray;
my $default_array = [ 1,4,2,6,1,8,5,5,2 ];
sub new {
my ( $class ) = @_;
my $self = {};
$self -> {myarray} = $default_array;
bless ( $self, $class );
return $self;
}
sub get_array {
my ( $self ) = @_;
return ( $self -> {myarray} );
}
sub sort_array{
my ( $self ) = @_;
@{ $self -> {myarray} } = sort ( @{ $self -> {myarray} } );
for ( @{ $self -> {myarray} } ) {
print $_,"\n";
}
return 1;
}
sub push_array{
my ( $self ) = @_;
for ( 1 .. 9 ){
push @{$self -> {myarray}}, $_;
}
return 1;
}
sub pop_array {
my ( $self ) = @_;
for ( 1 .. 3 ){
pop @{$self -> {myarray}};
}
return 1;
}
1;
А затем позвоните с помощью:
#!/usr/bin/perl
use strict;
use warnings;
use MyArray;
my $array = MyArray -> new();
print "Started:\n";
print join (",", @{ $array -> get_array()} ),"\n";
print "Reshuffling:\n";
$array -> sort_array();
$array -> push_array();
$array -> pop_array();
print "Finished:\n";
print join (",", @{ $array -> get_array()} ),"\n";
Вероятно, это можно немного привести в порядок, но, надеюсь, это иллюстрирует - внутри вашего объекта у вас есть внутренний "массив", который вы затем "выполняете", выполняя свои вызовы.
Результат во многом тот же (я думаю, что я повторил логику, но не доверяю этому полностью!), Но у вас происходит нечто автономное.
Если функция не предназначена для возврата чего-либо, нет необходимости использовать return
!
Нет, вы не используете какие-либо аспекты ОО (инкапсуляция, полиморфизм и т. Д.). То, что вы делаете, называется процедурным программированием. Ничего плохого в этом нет. Вся моя работа для атомных электростанций была написана в этом стиле.
Проблема заключается в использовании @main::array
и я не говорю о том, что вы можете сократить это до @::array
, Полностью определенные имена избегают строгих проверок, поэтому они гораздо более подвержены ошибкам. Неверное имя переменной будет поймано не так легко, и легко иметь две части кода, сталкивающиеся с использованием одного и того же имени переменной.
Если вы используете только один файл, вы можете использовать my @array
, но я предполагаю, что вы используете @main::array
потому что вы обращаетесь к нему из нескольких файлов / модулей. Я предлагаю размещение our @array
в модуле, и экспортировать его.
package MyData;
use Exporter qw( import );
our @EXPORT = qw( @array );
our @array;
1;
Было бы неплохо иметь некоторую подсказку в имени переменной (например, префикс или суффикс), указывающий, что эта переменная используется во многих модулях.
Кстати, если бы вы хотели создать объект, он бы выглядел как
package MyArray;
sub new {
my $class = shift;
my $self = bless({}, $class);
$self->{array} = [ @_ ];
return $self;
}
sub get_elements {
my ($self) = @_;
return @{ $self->{array} };
}
sub sort {
my ($self) = @_;
@{ $self->{array} } = sort @{ $self->{array} };
}
sub push {
my $self = shift;
push @{ $self->{array} }, @_;
}
sub pop {
my ($self, $n) = @_;
return splice(@{ $self->{array} }, 0, $n//1);
}
my $array = MyArray->new(1,4,2,6,1,8,5,5,2);
$array->sort;
print("$_\n") for $array->get_elements();
$array->push_array(1..9);
$array->pop_array(3);
Я немного улучшил ваш интерфейс. (Сортировка не должна печатать. Было бы неплохо выдвигать разные вещи и вставлять другие, чем три элемента.)