2011-11-16 81 views
1

我在perl中遇到困難。下面是一個簡短的perl腳本解釋我的問題[我跑用perl-5.8.3驗證碼]:Perl - 將子引用傳遞給子例程

#!/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()則沒有。這是爲什麼?

+1

,因爲它不是真的* *參照打電話:如果你考慮相同的代碼,而無需調用子程序你會更好地理解它。參考值按值傳遞給子例程。 –

+4

@布萊恩羅奇,不正確。 Perl *總是*通過引用傳遞。引用被引用傳遞,然後被複制到'$ h1'和'$ h2'中。改變'$ h1'和'$ h2'沒有效果,因爲它們是詞法變量。更改'$ _ [0]'和'$ _ [1]'會影響傳遞給子的變量。 – ikegami

+0

@ikegami,我用'$ _ [1] = $ _ [0]'在'foo'中替換了'$ h2 = $ h1'。輸出不會改變。我猜它仍然是按值複製的,所以子程序內部的變化不會影響被引用的變量。我的理解是否正確?還是我仍然想念一些東西? – Unos

回答

6
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)。

2

$h2是一個詞彙變量,它包含一個引用。更改$h2只是取代其中的參考。

%{$h2}是由$h2(又名%b)引用的散列,所以改變%{$h2}(又名%b)改變由$h2(又名%b)引用的哈希值。

你似乎希望改變一個變量($h2)會改變另一個(%b),但我不知道爲什麼你有這樣的期望。他們甚至不是相同的變量類型!當標量沒有元素(至少與散列沒有相同的意義)時,甚至可以通過改變標量來嘗試更改散列元素。

1

埃裏克·斯特羅姆是正確的,但讓我們看看我們能不能解釋一下這個另一種方式:

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中)的值已更改。

順便說一句,請注意,在子程序調用完全不會改變%b之後更改%a。他們可能會共享相同的內容,但它們不是同一個變量。

0

這與傳遞或子程序無關。這只是混淆了這個問題。

#!/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); 
相關問題