1

我们试图将多个散列与一堆标量一起作为参数传递给子例程。问题在于这个子程序的多次调用,(如果我们在函数内部检索到两个哈希后打印它们),只有一个(第一个)得到正确的值。第二个是空的。我们尝试了很多东西-

1 ) 来自 Stackoverflow/PerlMonks 等具有不同语法的两个独立哈希,并作为参考传递。

&mySub(\%hash0, \%hash1, $var0, $var1, $var2);

sub mySub{
   my (%hash0, %hash1, $var0, $var1, $var2) = (@_);
}

或者

&mySub(\%hash0, \%hash1, $var0, $var1, $var2);

sub mySub{
   my %hash0 = %{$_[0]};
   my %hash1 = %{$_[1]};
   my $var0  = $[2]; my $var1 = $[3]; my $var3 = $[4];
}

2)创建两个哈希数组并传递

my @joined_arr = (\%hash0, \%hash1);
&mySub (\@joined_arr, $var0, $var1, $var2);

sub mySub{
   my (@joined_arr, $var0, $var1, $var2) = (@_);
   my %hash0 = %{joined_arr[0]};
   my %hash1 = %{joined_arr[1]};
   # rest of the variables.
}

4 ) 创建哈希值并通过

my %joined_hash;
%joined_hash{"first_one"} = %hash0;
%joined_hash{"second_one"} = %hash1;
&mySub (\%joined_hash, $var0, $var1, $var2);

sub mySub{
   my %joined_hash, %hash0, %hash1;
   %joined_hash = %{$_[0]};
   %hash0 = %joined_hash{"first_one"};
   %hash1 = %joined_arr{"second_one"};
   # rest of the variables.
}
  1. 在 Perl 5.16(CentOS 7 的默认发行版)和 Perl 5.30 中尝试它们。

到目前为止,这还没有成功。如果有人有想法并愿意分享,那将是很大的帮助。


编辑

在@zdim 和@Polar Bear 的建议下,我尝试了这些东西->

将 @_ 卸载到函数内部的标量的语法 ->

一个) my ($ref_to_hash0, $ref_to_hash1, $var0, $var1, $var2) = @_;

b)

$ref_to_hash0 = shift;
$ref_to_hash1 = shift;
$var0 = shift;
$var1 = shift;    
$var2 = shift;

我也尝试过这 3 种散列引用风格的散列赋值。

一个) my %local_hash_shallow_copy = %$ref_to_hash0;

b) my $local_hashref_deep_copy = dclone $ref_to_hash0;

C) my %local_hash_shallow_copy = %{$ref_to_hash0};

似乎在这个 sub 调用的 9 次迭代中,我在 sub 2 内得到了正确的哈希值。在其他时候,我只是简单地丢了一个指针-

$VAR1 = {
   'HASH(0x1e32cc8)' => undef
};

我正在使用 Dumper 将散列转储在外部 - 就在子调用之前,并且就在内部 - 就在我将值从 ref 转移到实际散列之后。这应该避免任何愚蠢的错误。

要么我在这里犯了一个非常基本的错误,要么遇到了一个不可思议的问题。正在调试它。

供参考。

4

2 回答 2

8

Perl 中的函数调用将标量列表作为参数传递,这是您正确执行的操作。该函数接收 中的标量列表,@_这些标量是这些参数的别名。

所以打电话†</sup>

mySub(\%hash0, \%hash1, $var0, $var1, $var2);

该函数有@_五个标量,前两个是感兴趣的哈希引用。

但是现在您将它们分配给哈希!

sub mySub{
   my (%hash0, %hash1, $var0, $var1, $var2) = (@_);   # WRONG
}

这样%hash0子例程中的变量就会填充 中的所有内容@_例如

# MySub variable      # variables from the caller, (their aliases) passed in
my %hash0         =   (\%hash0 => \%hash1, $var0 => $var1, $var2 => undef);

因为连续的标量被分配为键值对。列表中以 开头的其余变量%hash1也在该子例程中作为词汇符号引入,并且是undef

如果参数的数量确实是奇数,您应该会收到警告。use warnings;(程序顶部有一行,对吗?)

相反,需要将元素分配@_给合适的标量,例如

sub mySub{
   my ($ref_to_hash0, $ref_to_hash1, $var0, $var1, $var2) = @_;       
}

现在您有两种选择如何使用它

  • 直接使用参考文献,$ref_to_hash0. 喜欢

    foreach my $key (keys %$ref_to_hash0) {
        $ref_to_hash0->{$key} ...
    }
    

    简而言之,这是

    • 高效,因为您不复制数据

    • 它可能效率低下,因为每次访问都需要取消引用

    • 它允许您通过写入来更改调用方中的数据$ref_to_hash0

      $ref_to_hash0->{some_key} = 'value';  # changes data IN THE CALLER
      

      这可能很方便,也可能很危险(因为它可能是错误的)

  • 制作调用者数据的本地副本并使用它。请注意,这可能会有一些问题,因为您可能需要一个深层副本

    use Storable qw(dclone);  # may be needed
    
    sub mySub{
        my ($ref_to_hash0, $refhash1, $var0, $var1, $var2) = @_;       
    
        # If the caller's %hash0 has no references for values just dereference
        # Tricky though -- what when the calling hash changes in the future?
        my %local_hash_shallow_copy = %$ref_to_hash0;
    
        # If the caller's %hash0 is a complex data structure, need a deep copy
        my $local_hashref_deep_copy = dclone $ref_to_hash0;
    
        # Changes to local hash/hashref do not affect data in the caller
    }
    

†</sup> 通常不需要&在问题名称前面的那个前导,这里省略,除非你的意思是在调用中抑制它的原型。

于 2021-08-23T19:17:09.800 回答
2

您不能将哈希数组传递给子程序,而是传递哈希引用数组引用\%hash\@array)。

在子程序中,您应该将收到的参数视为参考。$hashref->{key}您可以通过引用或直接访问数据$arrayref->[index],或创建副本(CPU 周期和内存成本更高)my %hash = %{$hashref}my @array = @{$arrayref}

请参阅下面的演示示例代码。

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my %hash_0 = ( data => [ 'it is snowing', 'this month', 'almost every day'] );
my %hash_1 = ( data => [ 1, 2, 5, 7, 11 ] );
my $var0 = 'The summer at it\'s end';
my $var1 = 3356;
my $var2 = 'Adorable child';

my $agregate = { hash_0 => \%hash_0, 
                 hash_1 => \%hash_1, 
                 var0   => $var0, 
                 var1   => $var1,
                 var2   => $var2 
            };
            
subHashes_1(\%hash_0, \%hash_1, $var0, $var1, $var2);
say "\n";
subHashes_2(\%hash_0, \%hash_1, $var0, $var1, $var2);
say "\n";
subHashes_3($agregate);
say "\n";
subHashes_4(\%hash_0, \%hash_1, $var0, $var1, $var2);

sub subHashes_1 {
    my($href_0, $href_1, $var0, $var1, $var2) = @_;
    
    say '--- subHashes_1 --------------';
    say 'Hash 0';
    say Dumper($href_0->{data});
    say 'Hash 1';
    say '-' x 45;
    say Dumper($href_1->{data});
    say 'Var0: ' . $var0;
    say 'Var1: ' . $var1;
    say 'Var2: ' . $var2;
}

sub subHashes_2 {
    my $href_0 = shift;
    my $href_1 = shift;
    my $var0   = shift;
    my $var1   = shift;
    my $var2   = shift;

    say '--- subHashes_2 --------------';
    say 'Hash 0';
    say Dumper($href_0->{data});
    say 'Hash 1';
    say '-' x 45;
    say Dumper($href_1->{data});
    say 'Var0: ' . $var0;
    say 'Var1: ' . $var1;
    say 'Var2: ' . $var2;
}

sub subHashes_3 {
    my $args = shift;
    
    my $href_0 = $args->{hash_0};
    my $href_1 = $args->{hash_1};
    my $var0   = $args->{var0};
    my $var1   = $args->{var1};
    my $var2   = $args->{var2};
    
    say '--- subHashes_3 --------------';
    say 'Hash 0';
    say Dumper($href_0->{data});
    say 'Hash 1';
    say '-' x 45;
    say Dumper($href_1->{data});
    say 'Var0: ' . $var0;
    say 'Var1: ' . $var1;
    say 'Var2: ' . $var2;
}

sub subHashes_4 {
    my $href_0 = shift;
    my $href_1 = shift;
    my $var0   = shift;
    my $var1   = shift;
    my $var2   = shift;

    say '--- subHashes_4 --------------';
    say 'Hash 0';
    say "\t$_ => " . join("\n\t",@{$href_0->{$_}}) for (keys %$href_0);
    say 'Hash 1';
    say '-' x 45;
    say "\t$_ => " . join("\n\t",@{$href_1->{$_}}) for (keys %$href_1);
    say 'Var0: ' . $var0;
    say 'Var1: ' . $var1;
    say 'Var2: ' . $var2;
}

输出

--- subHashes_1 --------------
Hash 0
$VAR1 = [
          'it is snowing',
          'this month',
          'almost every day'
        ];

Hash 1
---------------------------------------------
$VAR1 = [
          1,
          2,
          5,
          7,
          11
        ];

Var0: The summer at it's end
Var1: 3356
Var2: Adorable child


--- subHashes_2 --------------
Hash 0
$VAR1 = [
          'it is snowing',
          'this month',
          'almost every day'
        ];

Hash 1
---------------------------------------------
$VAR1 = [
          1,
          2,
          5,
          7,
          11
        ];

Var0: The summer at it's end
Var1: 3356
Var2: Adorable child


--- subHashes_3 --------------
Hash 0
$VAR1 = [
          'it is snowing',
          'this month',
          'almost every day'
        ];

Hash 1
---------------------------------------------
$VAR1 = [
          1,
          2,
          5,
          7,
          11
        ];

Var0: The summer at it's end
Var1: 3356
Var2: Adorable child


--- subHashes_4 --------------
Hash 0
        data => it is snowing
        this month
        almost every day
Hash 1
---------------------------------------------
        data => 1
        2
        5
        7
        11
Var0: The summer at it's end
Var1: 3356
Var2: Adorable child
于 2021-08-23T19:38:25.097 回答