Должна ли подпрограмма всегда возвращаться явно?

Если 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);

Я немного улучшил ваш интерфейс. (Сортировка не должна печатать. Было бы неплохо выдвигать разные вещи и вставлять другие, чем три элемента.)

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