2017-11-15 2 views
0

내부 배열을 Perl의 함수에 전달하려고합니다. 여기 내 Perl 프로그램입니다.내부 배열을 함수에 전달

#!/usr/bin/perl 
use strict; 
use warnings; 

my %data = (
    'a' => (
     x => 'Hello', 
     y => 'World' 
    ), 
    'b' => (
     x => 'Foo', 
     y => 'Bar' 
    ) 
); 

#prototype 
sub p(\%); 

{ #main 
    p(%data{'a'}); # should print "Hello Wolrd". 
} 

sub p(\%) { 
    print "$_[0]{x} $_[0]{y}\n"; 
} 

대신 다음 오류가 표시됩니다. Type of arg 1 to main::p must be hash (not key/value hash slice).

이 작동 :

#!/usr/bin/perl 
use strict; 
use warnings; 

#prototype 
sub p(\%); 

{ #main 
    my %a = (
     x => 'Hello', 
     y => 'World' 
    ); 
    p(%a); 
} 

sub p(\%) { 
    print "$_[0]{x} $_[0]{y}\n"; 
} 

그래서 메소드 호출에 문제가 있어야합니다. 근데 뭐? 의 내용은 해시, 그래서 p( 후 첫 번째 문자 % (나는 너무 p($data{'a'});을 시도해야하지만 의 내용 때문에, 논리적 인 것 같다 다른 오류 (나를 잎) 스칼라 아니다 . 나는 함수 프로토 타입을 선언하기 때문에 수동으로 해시와 역 참조에 대한 참조를 만들 필요가 없습니다. 나는 무엇을 놓치고?

답변

3

코드에 배열이 없습니다. 그리고 코드에는 메서드 호출이 없습니다.

해시가 잘못 정의되었습니다. 다른 해시 안에 해시를 포함 할 수 없습니다. 해시 참조를 사용해야합니다. 이처럼 :

my %data = (
    'a' => { 
     x => 'Hello', 
     y => 'World' 
    }, 
    'b' => { 
     x => 'Foo', 
     y => 'Bar' 
    } 
); 

주, 나는 당신의 내면의 해시하지 (...)을 정의 할 { ... }을 사용하고 있습니다.

그래도 여전히 오류가 발생합니다. 그 불분명 경우

Type of arg 1 to main::p must be hash (not hash element) at passhash line 20, near "})"

, 우리는 항상 오류의 자세한 정보를 얻을 수 use diagnostics를 추가하는 시도 할 수 있습니다 :

(F) This function requires the argument in that position to be of a certain type. Arrays must be @NAME or @{EXPR}. Hashes must be %NAME or %{EXPR}. No implicit dereferencing is allowed--use the {EXPR} forms as an explicit dereference. See perlref.

매개 변수 유형의 정의는 프로토 타입에서 온다. 귀하의 프로토 타입은 \%입니다. 사람들은 종종 해시 참조를 의미한다고 생각합니다. 그렇지 않습니다. 즉, "이 위치에 실제 해시를 주면 해당 참조를 가져 와서 해당 참조를 서브 루틴으로 전달합니다"를 의미합니다.

는 (사람들이 프로토 타입은 Perl로 사용되어서는 안된다는 말을하는 이유를 참조입니다 -. 그들은 종종 당신이 그들이 생각하지 않는다) 당신은 해시를 통과하지 않을

. 해시 참조를 전달 중입니다. 서브 루틴 호출에서 해시를 역 참조 (dereferencing)하여 수정할 수 있습니다.

p(%{$data{a}}); 

하지만 그건 정말 바보 같은 생각입니다. 해시 참조를 가져 와서 해시로 변환하면 Perl이 참조를 가져 와서 서브 루틴으로 전달할 수 있습니다.

정말로 원하는 것은 프로토 타입을 $으로 변경하여 서브 루틴이 해시 참조를 허용하도록하는 것입니다. ref을 사용하여 해시 참조가 있는지 확인할 수 있습니다.

하지만 여전히 잔인합니다. 사람들은 아주 좋은 이유로 Perl 프로토 타입을 사용하지 말 것을 권고합니다. 그냥 제거하십시오.

4

구조의 당신의 정의가 잘못되었습니다. 내부 해시가 {}하지 ()를 사용해야합니다.

my %data = (
    a => { 
     x => 'Hello', 
     y => 'World' 
    }, 
    b => { 
     x => 'Foo', 
     y => 'Bar' 
    } 
); 

또한 단일 해시 요소 인 %data{'a'}이 아닌 $data{'a'} (또는 심지어 $data{a})을 사용하십시오.

또한 프로토 타입을 사용하지 않는 이유에 대해서는 Why are Perl 5's function prototypes bad?을 참조하십시오. 위와 같이 구문을 수정하면 코드가 프로토 타입 없이도 작동합니다. 프로토 타입이 실제로 필요한 경우 %을 사용하십시오 (\%이 아님). 그러나 프로토 타입이 어떤 용도로 제공되는지 정확히 알지 못하므로 사용하지 마십시오.

+0

내부 배열 정의에서 중괄호를 사용해도 아무 것도 바뀌지 않지만 오류가 유지됩니다. '$ data { 'a'}'를 사용하여 요소에 접근하면 다른 오류 메시지가 나타납니다. 즉, arg 1의 유형이 main :: p는 해시 (해시 요소가 아님) 여야합니다. 프로토 타입 선언을 제거하면 실제로 작동하지만 경고 :'main :: p()가 너무 일찍 호출되어 ex2.pl 17 행에서 프로토 타입을 검사했습니다. '라는 경고 메시지가 출력됩니다.'use warnings; '을 제거하지 않으려합니다. 그들 중 많은 사람들이 나에게 helfpul을 보입니다. 프로토 타입, ** 또는 **을 제거하지 않고이 특정 문제없이 경고를 계속 유지하면서이 문제를 해결할 수 있습니까? – Paramaeleon

+1

프로토 타입의 두 언급을 제거하십시오. – choroba