Документация
HTML CSS PHP PERL другое

Section 5.5.  Creating an Anonymous Array Directly

 
Previous
Table of Contents
Next

5.5. Creating an Anonymous Array Directly

In the get_provisions_list routine earlier, we created a half dozen array names that we used only so that we could take a reference to them immediately afterward. When the subroutine exited, the array names all went away, but the references remained.

While creating temporarily named arrays would work in the simplest cases, creating such names becomes more complicated as the data structures become more detailed. We'd have to keep thinking of names of arrays just so we could forget them shortly thereafter.

We can reduce the namespace clutter by narrowing down the scope of the various array names. Rather than declaring them within the scope of the subroutine, we can create a temporary block:

my @skipper_with_name;
{
  my @skipper = qw(blue_shirt hat jacket preserver sunscreen);
  @skipper_with_name = ('The Skipper', \@skipper);
}

At this point, the second element of @skipper_with_name is a reference to the array formerly known as @skipper. However, that name is no longer relevant.

This is a lot of typing to simply say "the second element should be a reference to an array containing these elements." We can create such a value directly using the anonymous array constructor, which is yet another use for square brackets:

my $ref_to_skipper_provisions =
  [ qw(blue_shirt hat jacket preserver sunscreen) ];

The square brackets take the value within (evaluated in a list context); establish a new, anonymous array initialized to those values; and (here's the important part) return a reference to that array. It's as if we had said:

my $ref_to_skipper_provisions;
{
  my @temporary_name =
  ( qw(blue_shirt hat jacket preserver sunscreen) );
  $ref_to_skipper_provisions = \@temporary_name;
}

Here we don't need to come up with a temporary name, and we don't need the extra noise of the temporary block. The result of a square-bracketed anonymous array constructor is an array reference, which fits wherever a scalar variable fits.

Now we can use it to construct the larger list:

my $ref_to_skipper_provisions =
  [ qw(blue_shirt hat jacket preserver sunscreen) ];
my @skipper_with_name = ('The Skipper', $ref_to_skipper_provisions);

Of course, we didn't actually need that scalar temporary, either. We can put a scalar reference to an array as part of a larger list:

my @skipper_with_name = (
  'The Skipper',
  [ qw(blue_shirt hat jacket preserver sunscreen) ]
);

Now let's walk through this. We've declared @skipper_with_name, the first element of which is the Skipper's name string, and the second element is an array reference, obtained by placing the five provisions into an array and taking a reference to it. So @skipper_with_name is only two elements long, just as before.

Don't confuse the square brackets with the parentheses here. They each have their distinct purpose. If we replace the square brackets with parentheses, we end up with a six-element list. If we replace the outer parentheses (on the first and last lines) with square brackets, we construct an anonymous array that's two elements long and then take the reference to that array as the only element of the ultimate @skipper_with_name array.[*] So, in summary, if we have this syntax:

[*] In classrooms, we've seen that too much indirection (or not enough indirection) tends to contribute to the most common mistakes made when working with references.

my $fruits;
{
  my @secret_variable = ('pineapple', 'papaya', 'mango');
  $fruits = \@secret_variable;
}

we can replace it with:

my $fruits = ['pineapple', 'papaya', 'mango'];

Does this work for more complicated structures? Yes! Anytime we need an element of a list to be a reference to an array, we can create that reference with an anonymous array constructor. In fact, we can also nest them in our provisions list:

sub get_provisions_list {
  return (
    ['The Skipper',   [qw(blue_shirt hat jacket preserver sunscreen)] ],
    ['The Professor', [qw(sunscreen water_bottle slide_rule radio)  ] ],
    ['Gilligan',      [qw(red_shirt hat lucky_socks water_bottle)   ] ],
  );
}

my @all_with_names = get_provisions_list(  );

Walking through this from the outside in, we have a return value of three elements. Each element is an array reference, pointing to an anonymous two-element array. The first element of each array is a name string, while the second element is a reference to an anonymous array of varying lengths naming the provisionsall without having to come up with temporary names for any of the intermediate layers.

To the caller of this subroutine, the return value is identical to the previous version. However, from a maintenance point of view, the reduced clutter of not having all the intermediate names saves screen and brain space.

We can show a reference to an empty anonymous array using an empty anonymous array constructor. For example, if we add one "Mrs. Howell" to that travel list, as someone who has packed rather light, we'd simply insert:

['Mrs. Howell',
  [  ]
],

This is a single element of the larger list. This item is a reference to an array with two elements, the first of which is the name string, and the second of which is itself a reference to an empty anonymous array. The array is empty because Mrs. Howell hasn't packed anything for this trip.


Previous
Table of Contents
Next
© 2000- NIV