【问题标题】:Are all references not dereferenced the same?所有引用的取消引用都相同吗?
【发布时间】:2019-03-15 21:20:54
【问题描述】:

我正在构建一个程序,其中包含多个我希望能够反复使用的例程。哦,我也是 perl 的绝对初学者,所以就是这样。所以,我有数组,我用从文件中提取的文本行填充,以便我可以解析、修改、比较等,使用用户输入或从(一个)其他文件中提取的其他数据位,具体取决于在部署子程序的程序上。

所以,我有一个子例程,我将三个数组引用传递给:

@sorted = &sort_arrays(\@order, \@ktms, \@sorted);

我在传入 sub 后取消引用数组以进行如下所示的健全性检查:

sub sort_arrays {
my ($ref_array, $list_array, $sorted_r) = @_;
print "@{$ref_array} \n"; print "@{$list_array} \n"; print "@{$sorted_r} \n";

然后我将每个数组的每个单元格的值打印在一行上,每个单元格之间有一个空格。伟大的!实际上,我将此作为一个单独的程序工作,以根据随机值出现在主控中的顺序对来自主控的随机生成文件进行排序。现在,我正在尝试使其他子例程通用且可通过引用重用,但在取消引用它们时我没有同样的运气。例如:

@that = &get_ktms_from_program(\@this, \@that);

但是,当我尝试取消引用它们时,我得到了坏消息!

    print "\nEntered get_lines_from_program sub\n"; 
    my ($lines_r, $parsed_r) = @_;
    print "@{$lines_r}\n";

输出:

Entered get_lines_from_program sub
ARRAY(0x81c20dc)

因此,出于某种原因,我无法使用之前使用的相同方法取消对 THIS 数组的引用。是什么赋予了? TIA 的帮助!

【问题讨论】:

  • 无需使用&调用子程序;事实上,它可能会产生您可能不想要的其他效果,如 perlsub 中所述。
  • 哇!使当前@_ 对被调用的子程序可见?!?棒极了!但是,我从主程序调用每个子程序。我确实利用@ARGV 来提取文件名;不过,我认为这里不会发生这种情况。也许,但不确定。我会在引用之前检查我的数据,以确保在引用它们之前我的数组中没有数组引用。这些多维数组和散列很密集!
  • 如果你得到Entered get_lines_from_program sub ARRAY(0x81c20dc),那是因为@this 包含一个引用数组的元素。换句话说,您没有向我们展示的代码中似乎存在错误

标签: perl reference dereference


【解决方案1】:

这取决于您如何处理您的潜艇中的这些引用。这里有一些说明

如果您传递参考并使用参考

func(\@ary);
...
sub func {
    my ($ra) = @_;
    ...
    push @$ra, @some_values;  # changes @ary in the caller
}

那么你刚刚更改了调用者中的@ary

但是,如果您在子目录中创建本地副本

sub func {
    my ($ra) = @_;
    my @local_ary = @$ra;
    ...
    return \@local_ary;    # return reference to brand new @local_ary
}

然后更改为@local_ary 不会影响调用者中的@ary(除非它与返回当然有关——被它覆盖,或者返回被pushed 覆盖)。

另一点:传递给数组的参数在 @_ 中具有别名,因此如果在子程序中使用 $_[0](等),那么您将直接更改调用者中的数据。

从图中可以清楚地看出@lines_r 有一个元素,它本身就是一个数组引用。如果没有看到它的代码,很难说它是如何到达那里的。一种可能性是您从某个函数 return \@local_ary 返回了一个数组引用,您没有在调用者中取消引用它,而只是将其添加到 @this@that(由 $list_r 引用)。


问题中代码的几个cmet

sub 前面的& 具有微妙的效果,您几乎肯定不需要。很久很久以前就需要它,但现在不需要也不应该将其用于“正常”呼叫。

数组通过引用传递给子,这很好,因为它避免了可能的大量数据复制。但是,您清楚地返回了一个列表,因为它直接分配给数组。如果这些数组可能有很多数据,最好返回引用,并在调用者中取消引用它

my $ra = func(...);   # func() returns an array reference
my @ary = @$ra;

my @ary = @{ func(...) };

我会考虑总是返回一个包含数据的数组的引用(而不是在列表中返回一小部分标量变量,其中的选择仅取决于调用者的偏好)。

但最重要的是,还要考虑通常没有理由取消引用返回的 arrayref 以创建另一个数组;它是更多的数据副本,这很昂贵,而无论如何您都可以使用数组引用做任何和所有您需要的事情(例如,请参阅this post 的结尾)。

最后,如果你通过引用传递一个数组并将返回值分配给同一个数组,那么你在做什么时要非常非常小心。

【讨论】:

  • 我倒过来了。正如您可能注意到的那样,我试图伪装我的代码的性质,但失败了。排序例程返回引用数组的值@sorted:@sorted = sub(\@reference_ar, \@arraytosort_ar, \@sorted); 当我写完时,我突然想到传递一个数组的引用是愚蠢的,我设置为等于子的返回值...嘘!谢谢!
【解决方案2】:

您可能将此数组引用存储在某个数组中。这意味着您现在拥有一个包含一个元素的数组:数组引用。 (参考资料是在 Perl 中嵌套数据结构的方式;请参阅 perllol)。当您将此数组插入一个字符串时,将打印一个元素(数组引用),并且数组引用的字符串化形式看起来就像您看到的字符串。取而代之的是,将数组引用存储在一个标量变量中,无论您在哪里检索它,它都可以按原样传递给您的其他子例程。

use strict;
use warnings;

my $aref = sub_returning_aref();
other_sub($aref);

sub sub_returning_aref {
  my @stuff;
  return \@stuff;
}

sub other_sub {
  my ($aref) = @_;
  print "@$aref\n";
}

要记住的关键是\@array 返回一个标量值的引用,然后可以用作任何其他标量,但必须取消引用才能产生数组内容。

Data::Dumper 是一个很好的核心工具,用于在调试时确定变量中的确切内容。

use Data::Dumper;
print Dumper \@array;

【讨论】:

  • 感谢您的回答!我说我是 Perl 的新手,但我只是在掩饰我在学习编程语言方面的无能......其中任何一个......通过我的正常工作职能潜入我对工具的实际使用。所以,我去几天,有时甚至一个多星期都没有接触到它。我知道数组的多维功能,最终需要使用该语言与 SQL 表交互,以维护我们成千上万种产品的当前信息。耶!
猜你喜欢
  • 2013-09-13
  • 1970-01-01
  • 1970-01-01
  • 2014-01-13
  • 1970-01-01
  • 2021-08-19
  • 2023-03-20
  • 1970-01-01
相关资源
最近更新 更多