2011-11-16 2 views
1

perl에서 참조를 이해하는 데 어려움을 겪고 있습니다. 여기에 내 문제를 설명하는 짧은 펄 스크립트는 [I 펄-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

@Brian Roach, 사실이 아닙니다. Perl은 항상 참조로 전달됩니다. 참조는 참조로 전달되며,이 참조는'$ h1'과'$ h2'에 복사됩니다. '$ h1'과'$ h2'를 렉시 컬 변수이므로 아무 효과가없는 것으로 변경합니다. '$ _ [0]'과'$ _ [1]'을 변경하면 서브 변수에 전달 된 변수에 영향을줍니다. – ikegami

+0

@ikegami, 나는'foo'에서'$ h2 = $ h1'을'$ _ [1] = $ _ [0]'으로 대체했습니다. 출력은 변경되지 않습니다. 나는 여전히 가치에 의한 복사로 남아 있기 때문에 서브 루틴 내부의 변화는 참조 된 변수에 영향을 미치지 않는다. 내 이해가 맞습니까? 아니면 아직도 뭔가 빠졌나요? – 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 
} 

기본적으로 첫 번째 예에서는 값을 다루고 있으며 일반적인 값 의미 체계가 적용됩니다. 두 번째 경우에는 값을 참조 해제하여 고급 유형 (이 경우 해시)으로 되돌립니다.

2

$h2은 참조를 보유하는 어휘입니다. $h2을 변경하면 그 안에있는 참조가 바뀝니다.

%{$h2}

는 (일명 %b) $h2 (일명 %b)에 의해 참조 된 해시를 변경하므로 %{$h2} 변경 $h2 (일명 %b)에 의해 참조되는 해시이다.

하나의 변수 ($h2)를 변경하면 다른 변수 (%b)가 바뀔 것이라고 예상되는 것 같습니다. 그러나 왜 그러한 기대치가 있는지 모르겠습니다. 그들은 심지어 같은 변수 유형이 아닙니다! 스칼라가 엘리먼트를 가지지 않을 때 스칼라를 변경함으로써 어떻게 해시의 엘리먼트를 변경하려고 시도 할 수 있습니까? 적어도 해시와 같은 의미는 아닙니다.

1

에릭 스트롬은 정확하지만 우리가 다른 방법으로 설명 할 수 있는지 알아 보자

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

}

하는의 쉽게 가지 만들어 보자 : 메모리 위치 # 1 $h1 점, 메모리 위치에 $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이 전혀 변경되지 않습니다. 그들은 같은 내용을 공유 할 수도 있지만 같은 변수가 아닙니다.

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); 
관련 문제