John White
John White

Reputation: 161

Perl - why does my assignment from an array ref give an error

Fragment A below works, copying an array by dereferencing an array ref.

Fragment B, deeper in some real code, does not. The commented-out line is not part of the real code, which works fine (%ips is a hash in which each key is an IP address and each value is a reference to an array).

But why does the commented-out line fail with the message

Global symbol "$ips" requires explicit package name at ...

Fragment A:

my $a1 = [1,2,3];
say $$a1[1];
my @a2 = @$a1;
say "@a2";

Fragment B:

    else {
            # Initialise count to 1, 
            # set both dates:
        $ips{$1} = [1, $2, $2];
        # my @arr = @$ips{$1};  # error...
    }

Upvotes: 1

Views: 148

Answers (3)

ikegami
ikegami

Reputation: 386676

@$ips{$1}

is short for

@{ $ips }{$1}     # Hash slice, like @hash{"a", "b", "c"}

but you want

@{ $ips{$1} }     # Array, like @array

Scalar         Direct           $NAME         $scalar
Scalar         By ref (simple)  $$NAME        $$scalar_ref
Scalar         By ref           $BLOCK        ${ $scalar_ref }

Array          Direct           @NAME         @array
Array          By ref (simple)  @$NAME        @$array_ref
Array          By ref           @BLOCK        @{ $array_ref }

Hash           Direct           %NAME         %hash
Hash           By ref (simple)  %$NAME        %$hash_ref
Hash           By ref           %BLOCK        %{ $hash_ref }

Hash element   Direct           $NAME{EXPR}   $hash{key}
Hash element   By ref (simple)  $$NAME{EXPR}  $$hash_ref{key}
Hash element   By ref           $BLOCK{EXPR}  ${ $hash_ref }{key}

Hash slice     Direct           @NAME{LIST}   @hash{qw( a b c )}
Hash slice     By ref (simple)  @$NAME{LIST}  @$hash_ref{qw( a b c )}
Hash slice     By ref           @BLOCK{LIST}  @{ $hash_ref }{qw( a b c )}

Array element  Direct           $NAME[EXPR]   $array[3]
Array element  By ref (simple)  $$NAME[EXPR]  $$array_ref[3]
Array element  By ref           $BLOCK[EXPR]  ${ $array_ref }[3]

Array slice    Direct           @NAME[LIST]   @array[3..5]
Array slice    By ref (simple)  @$NAME[LIST]  @$array_ref[3..5]
Array slice    By ref           @BLOCK[LIST]  @{ $array_ref }[3..5]

Upvotes: 2

J-L
J-L

Reputation: 1901

The problem with using code like:

@$ips{$1}

is that you think that "@" is dereferencing "$ips{$1}" (so it can be assigned to an array), but in reality that line is using "{$1}" to get an element from "@$ips".

The "@" and "$" sigils bind more tightly than "{$1}" does, so the above is closer to:

(@$ips) {$1}

than what you want, which is:

@ ($ips{$1})

To overcome this, you can tell Perl to have the "@" sigil work on "$ips{$1}" by putting "$ips{$1}" in curly brackets, like this:

@{$ips{$1}}

This way, there's no ambiguity over which happens first.

Upvotes: 2

mpapec
mpapec

Reputation: 50677

Perl is looking for $ips variable as you've made mistake when dereferencing %ips hash. You can

my @arr = @{ $ips{$1} };

or

my $ref = $ips{$1};
my @arr = @$ref; # or @{ $ref }

Upvotes: 3

Related Questions