Shan
Shan

Reputation: 81

Can't resolve scalars from Perl arrays

I have a Perl reference to a hash $conf that has an array as one of the values. I can retrieve it by:

$conf->{group}->{names} # returns an array (NOT array ref)

But when I store it in some other variable I get this unusual behaviour.

say ($conf->{group}->{names}); # some array ref
say ($conf->{group}->{names}[1]); # some string
my @list = $conf->{group}->{names};
say ($list[0]); # same array ref

What may be the reason for this behaviour? I want to loop over this array but using foreach but unable to do so because of this.

I wish to iterate over the elements of the array, but I can't figure out how.

Upvotes: 0

Views: 68

Answers (1)

ikegami
ikegami

Reputation: 385897

You claim $conf->{group}->{names} is an array as opposed to a reference to one, but that's impossible. Hashes values are scalars; they can't be arrays. This is why we store references to arrays in hashes.

That $conf->{group}->{names}[1] works (short for $conf->{group}->{names}->[1]) indicates $conf->{group}->{names} it's an a reference to an array.[1]

You assign this reference to the @list, and therefore populate @list with this reference. This is why $list[0] is this reference.


You wish to iterate over the elements of the array. If you had a named array, you would use

for (@array) {
   ...
}

But you have a reference to an array. There are two syntaxes that can be used to accomplish that.

  1. The circumfix syntax features a block that returns the reference

    for (@{ $ref }) {   # Or just @$ref when the block contains a simple scalar.
       ...
    }
    

    In your case,

    my $ref = $conf->{group}{names}[1];
    for (@$ref) {
       ...
    }
    

    or

    for (@{ $conf->{group}{names}[1] }) {
       ...
    }
    
  2. The postfix (aka "arrow") syntax features can be tacked onto an expression.

    for ($ref->@*) {
       ...
    }
    

    In your case,

    my $ref = $conf->{group}{names}[1];
    for ($ref->@*) {
       ...
    }
    

    or

    for ($conf->{group}{names}[1]->@*) {
       ...
    }
    

    ->@* requires Perl 5.24+. It's available in Perl 5.20+ by adding both use feature qw( postderef ); and no warnings qw( experimental::postderef );, or by adding use experimental qw( postderef );. This is safe because the then-experimental feature was accepted into Perl without change.

See Perl Dereferencing Syntax and the documentation linked by it.


  1. I'm assuming you're using use strict; as you always should.

Upvotes: 7

Related Questions