将多个哈希作为参数传递给 Perl 子程序 (Perl 5.16 / Perl 5.30)

Ad8*_*891 1 perl hash subroutine perl-hash

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

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

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

sub mySub{
   my (%hash0, %hash1, $var0, $var1, $var2) = (@_);
}
Run Code Online (Sandbox Code Playgroud)

或者

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

sub mySub{
   my %hash0 = %{$_[0]};
   my %hash1 = %{$_[1]};
   my $var0  = $[2]; my $var1 = $[3]; my $var3 = $[4];
}
Run Code Online (Sandbox Code Playgroud)

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.
}
Run Code Online (Sandbox Code Playgroud)

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.
}
Run Code Online (Sandbox Code Playgroud)
  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;
Run Code Online (Sandbox Code Playgroud)

我也尝试过这 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
};
Run Code Online (Sandbox Code Playgroud)

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

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

供参考。

zdi*_*dim 7

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

所以随着电话

mySub(\%hash0, \%hash1, $var0, $var1, $var2);
Run Code Online (Sandbox Code Playgroud)

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

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

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

使%hash0填充了一切@_,如

%hash = (\%hash0 => \%hash1, $var0 => $var1, $var2 => undef);
Run Code Online (Sandbox Code Playgroud)

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

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

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

sub mySub{
   my ($ref_to_hash0, $ref_to_hash1, $var0, $var1, $var2) = @_;       
}
Run Code Online (Sandbox Code Playgroud)

现在你有两个选择如何使用它

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

    foreach my $key (keys %$ref_to_hash0) {
        $ref_to_hash0->{$key} ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

    简而言之,这是

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

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

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

      $ref_to_hash0->{some_key} = 'value';  # changes data IN THE CALLER
      
      Run Code Online (Sandbox Code Playgroud)

      这可能很方便,也可能很危险(因为它可能被错误地完成)

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

    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
    }
    
    Run Code Online (Sandbox Code Playgroud)

通常不需要&在问题中的名称前面使用,此处省略,除非您打算在调用中隐藏其原型。