How do references in Perl work

前端 未结 3 1194
无人及你
无人及你 2020-12-20 19:39

Can anyone explain the push statement in the following Perl code to me? I know how push in perl works but I can\'t understand what the first argument in followi

相关标签:
3条回答
  • 2020-12-20 20:16

    Let's start with the following two assertions:

    • @a starts out as an empty array with no elements.
    • $b is assigned the value of 10.

    Now look at this construct:

    @{$a[$b]}

    To understand we can start in the middle: $a[$b] indexes element 10 of the array @a.

    Now we can work outward from there: @{...} treats its contents as a reference to an array. So @{$a[$b]} treats the content of element 10 of the array @a as a reference to an anonymous array. That is to say, the scalar value contained in $a[10] is an array reference.

    Now layer in the push:

    push @{$a[$b]}, $c;

    Into the anonymous array referenced in element 10 of @a you are pushing the value of $c, which is the character "a". You could access that element like this:

    my $value = $a[10]->[0]; # character 'a'

    Or shorthand,

    my $value = $a[10][0];

    If you pushed another value into @{$a[10]} then you would access it at:

    my $other_value = $a[10][1];

    But what about $a[0] through $a[9]? You're only pushing a value into $a[$b], which is $a[10]. Perl automatically extends the array to accommodate that 11th element ($a[10]), but leaves the value in $a[0] through $a[9] as undef. You mentioned that you tried this:

    print "@a\n";

    Interpolating an array into a string causes its elements to be printed with a space between each one. So you didn't see this:

    ARRAY(0xa6f328)

    You saw this:

    ARRAY(0xa6f328)

    ...because there were ten spaces before the 11th element which contains an array reference.

    If you were running your script with use warnings at the top, you would have seen this instead:

    Use of uninitialized value in join or string at scripts/mytest.pl line 12.
    Use of uninitialized value in join or string at scripts/mytest.pl line 12.
    Use of uninitialized value in join or string at scripts/mytest.pl line 12.
    Use of uninitialized value in join or string at scripts/mytest.pl line 12.
    Use of uninitialized value in join or string at scripts/mytest.pl line 12.
    Use of uninitialized value in join or string at scripts/mytest.pl line 12.
    Use of uninitialized value in join or string at scripts/mytest.pl line 12.
    Use of uninitialized value in join or string at scripts/mytest.pl line 12.
    Use of uninitialized value in join or string at scripts/mytest.pl line 12.
    Use of uninitialized value in join or string at scripts/mytest.pl line 12.
              ARRAY(0xa6f328)
    

    ...or something quite similar.

    Your structure currently looks like this:

    @a = (undef,undef,undef,undef,undef,undef,undef,undef,undef,undef,['a'])

    If you ever want to really get a look at what a data structure looks like, rather than using a simple print, do something like this:

    use Data::Dumper;
    print Dumper \@a;
    
    0 讨论(0)
  • 2020-12-20 20:17

    Let's break it down.

    The @{...} is understood from "Using References" in perlref

    Anywhere you'd put an identifier (or chain of identifiers) as part of a variable or subroutine name, you can replace the identifier with a BLOCK returning a reference of the correct type.

    So what is inside { ... } block had better work out to an array reference. You have $a[$b] there, an element of @a at index $b, so that element must be an arrayref.

    Then @{...} dereferences it and pushes a new element $c to it. Altogether, $c is copied into a (sole) element of an anonymous array whose reference is at index $b of the array @a.

    And a crucial part: as there is in fact no arrayref there, the autovivification kicks in and it is created. Since there are no elements at indices preceding $b they are created as well, with value undef.

    Now please work through

    • tutorial perlreftut and

    • data-structures cookbook perldsc

    while using perlref linked in the beginning for a full reference.


    With complex data structures it is useful to be able to see them, and there are tools for that. A most often used one is the core Data::Dumper, and here is an example with Data::Dump

    perl -MData::Dump=dd -wE'@ary = (1); push @{$ary[3]}, "ah"; dd \@ary'
    

    with output

    [1, undef, undef, ["ah"]]
    

    where [] inside indicate an arrayref, with its sole element being the string ah.


    More precisely, an undef scalar is dereferenced and since this happens in an lvalue context the autovivification goes. Thanks to ikegami for a comment. See for instance this post with its links.

    0 讨论(0)
  • 2020-12-20 20:23

    I've had a discussion over this yesterday here

    what it means is that
    @a is an array

    $a[$b]
    

    is a cell in the array the @{} syntax helps perl understand that the cell in question is an array so you can preform push/pop operations on it.
    if you do

    use Data::Dumper;
    print Dumper \@a;
    

    you should see something like:

    $VAR1 = [
              undef,
              undef,
              undef,
              undef,
              undef,
              undef,
              undef,
              undef,
              undef,
              undef,
              [
                'a'
              ]
            ];
    

    as you can see, the 11th cell is an array containing the letter 'a' as its only value
    the push operation on an empty cell could have also been written as:

    $a[$b] = [$c]
    
    0 讨论(0)
提交回复
热议问题