Perl - 传递对子例程的引用

发布于 2024-12-16 12:06:08 字数 611 浏览 1 评论 0原文

我在理解 Perl 中的引用时遇到困难。这是一个简短的 perl 脚本来解释我的问题 [我使用 perl-5.8.3 运行此代码]:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my %a = ("a" => 1, "b" => 2);
my %b = ();
print Dumper(\%a, \%b);
foo(\%a, \%b);
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
print "+-----------------------+\n";
bar(\%a, \%b);
print "+==After fn call==+\n";
print Dumper(\%a, \%b);

sub foo {
    my($h1, $h2) = @_;
    $h2 = $h1;
    print Dumper($h2);
}

sub bar {
    my($h1, $h2) = @_;
    %{$h2} = %{$h1};
}

我猜在两个子例程中, $h1 和 $h2 都是本地变量。尽管如此, bar() 实际上改变了原始 %b 的值,而 foo() 则没有。这是为什么?

I am facing difficulty understanding references in perl. Here is a short perl script to explain my problem [I ran this code using perl-5.8.3]:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my %a = ("a" => 1, "b" => 2);
my %b = ();
print Dumper(\%a, \%b);
foo(\%a, \%b);
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
print "+-----------------------+\n";
bar(\%a, \%b);
print "+==After fn call==+\n";
print Dumper(\%a, \%b);

sub foo {
    my($h1, $h2) = @_;
    $h2 = $h1;
    print Dumper($h2);
}

sub bar {
    my($h1, $h2) = @_;
    %{$h2} = %{$h1};
}

I guess in both subroutines, $h1 and $h2 are local vars. Still, bar() actually changes value of original %b, while foo() does not. Why is that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

心碎的声音 2024-12-23 12:06:08
sub foo {
    my($h1, $h2) = @_;  # copy two hash references into lexicals
    $h2 = $h1;          # copy the value in lexical $h1 into $h2
                        # $h2 looses its binding to the hash ref
    print Dumper($h2);
}

如果值包含字符串或任何其他简单值,这与您将得到的行为完全相同。

sub bar {
    my($h1, $h2) = @_;  # copy two hash references into lexicals
    %{$h2} = %{$h1};    # the hash referred to by $h1 is unpacked into a list
                        # the hash referred to by $h2 is exposed as an lvalue
                        # the assignment operator installs the rhs list into 
                        # the lvalue, replacing any previous content
}

所以基本上,在第一个示例中,您只是处理值,并且应用正常的值语义。在第二种情况下,您取消引用这些值,这会将它们恢复为高级类型(在本例中为 HASH)。

sub foo {
    my($h1, $h2) = @_;  # copy two hash references into lexicals
    $h2 = $h1;          # copy the value in lexical $h1 into $h2
                        # $h2 looses its binding to the hash ref
    print Dumper($h2);
}

this is the same exact behavior you would get if the values contained strings or any other simple value.

sub bar {
    my($h1, $h2) = @_;  # copy two hash references into lexicals
    %{$h2} = %{$h1};    # the hash referred to by $h1 is unpacked into a list
                        # the hash referred to by $h2 is exposed as an lvalue
                        # the assignment operator installs the rhs list into 
                        # the lvalue, replacing any previous content
}

So basically, in the first example, you are just dealing with values, and normal value semantics apply. In the second case, you are dereferencing the values, which turns them back into their advanced types (in this case a HASH).

半城柳色半声笛 2024-12-23 12:06:08

$h2 是一个保存引用的词法变量。更改 $h2 只是替换其中的引用。

%{$h2}$h2 (又名 %b)引用的哈希,因此更改 %{$h2}< /code>(又名 %b)更改 $h2(又名 %b)引用的哈希值。

您似乎期望更改一个变量($h2)会更改另一个变量(%b),但我不知道您为什么有这样的期望。它们甚至不是相同的变量类型!当标量没有元素时(至少与哈希不同),如何尝试通过更改标量来更改哈希的元素。

$h2 is a lexical var that holds a reference. Changing $h2 just replaces the reference therein.

%{$h2} is the hash referenced by $h2 (aka %b), so changing %{$h2} (aka %b) changes the hash referenced by $h2 (aka %b).

You seem to be expecting that changing one variable ($h2) will change another (%b), but I have no idea why you have any such expectation. They're not even the same variable type! How can one even try to change the elements of a hash by changing a scalar when a scalar doesn't have elements (at least not in the same sense as a hash does).

许久 2024-12-23 12:06:08

Eric Strom 是正确的,但让我们看看是否可以用另一种方式解释这一点:

sub foo {
    my($h1, $h2) = @_;
    $h2 = $h1;

}

让我们让事情变得更简单:$h1 指向内存位置 #1,$h2 指向内存位置#2。您的语句 $h2 = $h1 现在也使 $h2 指向内存位置 #1。

内存位置 #1 的内容是否已更改?否。内存位置 #2 的内容是否已更改?不会。

一旦离开子例程,$h1$h2 就不再存在。

sub bar {
    my($h1, $h2) = @_;
    %{$h2} = %{$h1};
}

当您说 %{$h1} 时,您现在正在谈论内存位置 #1 的内容。您在作业中所做的是将内存位置 #1 的内容复制到内存位置 #2。请注意,$h1 仍然指向内存位置#1,而$h2 仍然指向内存位置#2。因此,$h1$h2 的值不会改变,但它们指向的内容会改变。

现在,让我们看看 %a%b%a 的内容位于内存位置#1,%b 的内容位于内存位置#2。在sub foo中,我们没有改变内存位置#2中的信息,因此%b的值没有改变。

sub bar中,我们弄乱了内存位置#2的内容,因此%b的值(将其内容存储在内存位置#2中)发生了变化。

顺便说一下,请注意,在子例程调用之后更改 %a 根本不会更改 %b。它们可能共享相同的内容,但它们不是相同的变量。

Eric Strom is correct, but let's see if we can explain this another way:

sub foo {
    my($h1, $h2) = @_;
    $h2 = $h1;

}

Let's make things easier: $h1 points to memory location #1 and $h2 points to memory location #2. Your statement $h2 = $h1 now makes $h2 point to memory location #1 too.

Has the contents of memory location #1 changed? No. Has the contents of memory location #2 changed? No.

Once you leave the subroutine, $h1 and $h2 no longer exist.

sub bar {
    my($h1, $h2) = @_;
    %{$h2} = %{$h1};
}

When you say %{$h1}, you're now talking about the contents of memory location #1. What you're doing in your assignment is copying the contents of memory location #1 to memory location #2. Notice that $h1 still points to memory location #1 and $h2 still points to memory location #2. Thus, the values of $h1 and $h2 don't change, but what they point to does change.

Now, let's look at %a and %b. The contents of %a were in memory location #1 and the contents of %b were in memory location #2. In sub foo, we didn't change the information in memory location #2, so the value of %b didn't change.

In sub bar, we messed with the contents of memory location #2, so the value of %b (which stores its contents in memory location #2) has changed.

By the way, note that changing %a after the subroutine call doesn't change %b at all. They might share the same contents, but they aren't the same variable.

云柯 2024-12-23 12:06:08

这与传递或子例程无关。这只会让问题变得混乱。如果您考虑相同的代码而不调用子例程,您会更好地理解它:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my %a = ("a" => 1, "b" => 2);
my %b = ();
print Dumper(\%a, \%b);
my $h1 = \%a;
my $h2 = \%b;
$h2 = $h1;
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
print "+-----------------------+\n";
$h1 = \%a;
$h2 = \%b;
%{$h2} = %{$h1};
print "+==After fn call==+\n";
print Dumper(\%a, \%b);

This has nothing to do with passing or subroutines. That just confuses the issue. You'll understand it better if you consider the same code without calling subroutines:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;

my %a = ("a" => 1, "b" => 2);
my %b = ();
print Dumper(\%a, \%b);
my $h1 = \%a;
my $h2 = \%b;
$h2 = $h1;
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
print "+-----------------------+\n";
$h1 = \%a;
$h2 = \%b;
%{$h2} = %{$h1};
print "+==After fn call==+\n";
print Dumper(\%a, \%b);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文