Perl5:从sub返回几个数组/哈希值

时间:2014-04-04 18:10:01

标签: arrays perl perl-module

我想从sub返回几个数组和哈希值。当我执行sub时,第一个输出数组将所有输出包装为toguether,其他输出数组保持为空。请看这个例子:

主文件script.pl有:

use mymodule;
my (@o1, $o2)=mymodule::mysub;
print "o1 gives ".$o1[0]."  ".$o1[1]."  ".$o1[2];
print ", and o2 gives ".$o2."  \n";

文件mymodule.pm看起来像:

package mymodule;
sub mysub{
   my @a = ('a', 'b');
   my $b = 4;
   return (@a, $b);
   };
1;

运行script.pl将返回o1给出b 4,o2给出。

如您所见,(@ o1,$ o2)与模块返回的值(@ a,$ b)的对应关系不会被保留。

有人可以帮我吗? 很多!


这是解释的问题。但是我无法通过你的建议获得目标结果。这段代码:

my ($o1_ref, $o2)=mysub;
my @o1 = @{$o1_ref};
print "o1 has ".$#o1." elements, o2 has ".$#o2." elements\n";
print "the first element of o1 is ".$o1->[0]."\n";

sub mysub{
   my @a = ('a', 'b');
   my $b = 4;
   return (\@a, $b);
   };

将返回

o1 has -1 elements, o2 has -1 elements
the first element of o1 is 

因此它对我的perl 5.14不起作用。

4 个答案:

答案 0 :(得分:6)

是时候了解References

在Perl中,您可以从子例程返回单个列表项目,或者使用单个列表项目进行导入。只有一个列表,所以如果我尝试返回两个数组,Perl会将它们放入一个无差别的列表中:

use strict;
use warnings;
use feature qw(say);

my (@a, @b) = foo();
say join ": ", @a;
say join ": ", @b;

sub foo {
    my @first = qw(one two thee);
    my @second = qw(uno dos tres);
    return (@first, @second);
}

如果您运行此操作,则会看到所有数据都返回到@a,而@b中没有任何数据。

引用允许您绕过此限制。引用只是指向内存中实际包含数据的位置的指针。该数据可以是标量($foo),数组(@foo)或散列(%foo)。由于内存中的位置是单个数据位,因此引用允许您拥有一个包含对其他数组的引用的数组,从而为您提供数组数组。或者哈希数组,哈希哈希,或者各种更复杂的数据结构。

让我们看一下你的模块并稍微修改它的代码:

sub mysub{
   my @a = ('a', 'b');
   my $b = 4;
   return (\@a, $b);  # Look I added a backslash!
};
1;

反斜杠说我没有返回数组。相反,我在内存中返回该阵列所在的位置。

现在我的程序可以执行此操作:

my ($o1_ref, $o2) = mymodule::mysub();   # We'll talk about this later..

代码中的另一个细微变化。我正在返回的第一个项目不是数组,而是对数组的引用。现在,我所要做的就是取消引用它(允许我访问数组):

my @o1 = @{ $o1_ref };

通过将数据结构的符号放在引用前面来取消引用。你甚至可以做到这一点:

my @o1 = @$o1_ref;

我不喜欢这样,因为很容易错过@$组合。使用花括号强调您要取消引用数组引用。

现在,你的程序的其余部分应该可以工作。


奖金建议

查看Exporter模块。它是Perl附带的标准模块。

这将允许您从模块中导出您的功能,因此您不必在其前面加上模块的名称:

package Mymodule;              # Custom says to give modules capital names.

use strict;
use warnings;
use Exporter qw(import);

our @EXPORT_OK = qw(mysub);  # A list of all the subroutines you want main to use

sub mysub {        我的@a = qw(a b);        我的$ b = 4;        return(\ @a,$ b);    } 1;

现在,您所要做的就是在主程序中说mysub

use strict;
use warnings;
use Mymodule  qw(mysub);     # Include a list of what you want imported
use feature qw(say);          # Better "print" than "print"

my ($o1_ref, $o2) = mysub();
my @01 = @{ $o1_ref };
say "o1 gives ".$o1[0]."  ".$o1[1]."  ".$o1[2];

响应This

这是你的代码:

my ($o1_ref, $o2)=mysub;
my @o1 = @{$o1_ref};
print "o1 has ".$#o1." elements, o2 has ".$#o2." elements\n";
print "the first element of o1 is ".$o1->[0]."\n";

sub mysub{
   my @a = ('a', 'b');
   my $b = 4;
   return (\@a, $b);
};
  • 没有数组@o2,因此$#o2无效。
  • $#返回LAST索引而不是项目数。使用scalar函数获取数组中的项目数。
  • 您已取消引用@o1。我这样做是为了简化问题。现在,当您执行$o1->[0]时,您将取消引用引用的项目。顺便说一句$o1不作为变量存在。
  • 始终使用strictwarnings个pragma。使用这些错误时会发现很多错误。
  • 使用say代替打印。你又忘了\n了。如果您要这样做,请将sayuse feature qw(say);
  • 一起使用

更正代码

use strict;
use warnings;
use feature qw(say);

my ($o1_ref, $o2) = mysub();
my @o1 = @{$o1_ref};

say "\@o1 has " . scalar @o1 . " elemenets";
say "The first element of \@o1 is '$o1[0]'";
say "The second element of \@o1 is '$o1[1]'";
say "\$o2 is equal to  '$o2'";

sub mysub{
    my @a = ('a', 'b');
    my $b = 4;
    return (\@a, $b);
};

输出:

@o1 has 2 elemenets
The first element of @o1 is 'a'
The second element of @o1 is 'b'
$o2 is equal to  '4'

一切正确。

答案 1 :(得分:2)

或传回数组引用

#!/usr/bin/perl
sub mysub{
   my @a = ('a', 'b');
   my $b = 4;
   return (\@a, $b);
 };

my ($o1, $o2) = mysub();
print "o1 gives ".${$o1}[0]."  ".${$o1}[1]."  ".$o1[2];
print ", and o2 gives ".$o2."  \n";

答案 2 :(得分:1)

你这样做的方式不适用于Perl。 @a已展开,只是包含@a$b的列表的第一部分。

分配列表中的数组“greedy”。这有效:

my ( $o2, @o1 ) = gimme();

但这不是:

my ( @o1, $o2 ) = gimme();

因为所有内容都已分配给@o1。然而,标量优先分配列表从列表中拉出第一个返回并将其分配给标量$o2,其余分配给@o1

答案 3 :(得分:0)

Perl无法从sub返回数组。相反,将@a作为arrayref返回如下:

package mymodule;
sub mysub{
  my @a = ('a', 'b');
  my $b = 4;
  return (\@a, $b);
};

使用arrayref,如下所示:

use mymodule;
my ($o1, $o2)=mymodule::mysub;
print "o1 gives ".$o1->[0]."  ".$o1->[1]."  ".$o1->[2];
print ", and o2 gives ".$o2."  \n";

Bonus:如果你需要arrayref的最后一个元素的索引(也许你想迭代通过arrayref构建一个数组?):

$last_index = $#$o1;

正如其他人推荐的那样,我建议您了解Perl References。