子例程应始终显式返回



如果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中的这种编码风格吗?我是不是在做OOP?

简而言之,是的,你基本上是在做OO,但在某种程度上会让每个人都感到困惑。

做这种潜艇的危险在于你在远处行动。这是一种糟糕的编码风格,必须从其他地方寻找可能破坏代码的东西。

这就是为什么要尽可能避免使用"全局"。

对于一个简短的脚本来说,也不重要

关于返回值,Perl默认返回最后一个表达式的结果。(参见:return

(在没有显式返回的情况下,子程序、eval或do FILE会自动返回最后一个求值表达式的值。)

Perl评论家标记它的原因是:

要求所有子例程使用以下其中一个显式终止:return、鲤鱼、沙鱼、die、exec、exit、goto或throw。

结尾没有显式返回语句的子例程可能会令人困惑。推断回报值可能很有挑战性

此外,如果程序员不希望有一个重要的返回值,并且省略了一个返回语句,那么子程序的一些内部数据可能会泄漏到外部。

不过,批评并不总是正确的——如果有充分的理由去做你正在做的事情,那就关掉它。只要你想过,并意识到风险和后果。

就我个人而言,我认为显式返回某些内容是更好的风格,即使它只是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

不,您不使用OO的任何方面(封装、多态性等)。你正在做的叫做过程编程。这没什么错。我在核电站的所有工作都是用那种风格写的。

问题是使用@main::array,我并不是说你可以把它缩写为@::array。完全限定的名称逃脱了严格的检查,因此它们更容易出错。键入错误的var名称不会那么容易被捕获,而且使用相同的变量名称很容易使两段代码发生冲突。

如果你只使用一个文件,你可以使用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);

我改进了你的界面。(排序不应该打印。如果能推送不同的东西并弹出三个元素以外的元素,那就太好了。)

相关内容

  • 没有找到相关文章

最新更新