Reference Basics

You create and assign a normal scalar variable by using an assignment operator, as follows:

$a="Stones";   # A normal scalar

After this snippet, a scalar variable called $a is created, and it contains the string "Stones". So far, nothing unusual. Now somewhere in the computer is a place labeled $a that contains that string, as illustrated here:

If you were to assign the scalar $b to $a—like $a=$b;—you would wind up with two copies of the data, with two different names, as shown here:

Having two copies might be okay if you want separate, independent copies of the data. But if you want both $a and $b to refer to the same piece of data—not a copy—you must create a reference. A reference is simply a pointer to a piece of data; it doesn't contain any real data itself. The reference is usually stored in another scalar variable.

To create a reference to any given variable, you put a backslash in front of it. For example, to create a reference to $a called $ref, you simply assign the reference to $ref like this:

$ref=$a;   # Create a reference to $a

This assignment creates a situation like the following:

$ref doesn't contain any data for itself; it simply is a reference to $a. The variable $a isn't changed at all; it can still be assigned to ($a="Foo") or displayed (print $a) as normal.

The variable $ref now contains a reference to $a. You cannot simply manipulate $ref because it doesn't have a normal scalar value in it. In fact, printing $ref would display something similar to SCALAR(0×0000). To get to the value inside $a through $ref, you must dereference $ref. Think of dereferencing as following the arrow in the preceding block diagram. To print the value of $a through the reference $ref, you use an extra $ like this:

print $$ref;

In the preceding snippet, $ref contains, of course, the reference. The extra $ tells Perl that the reference in $ref refers to a scalar value. The scalar value that $ref refers to is fetched and printed.

You can also modify the original value through the reference—something you can't do with a copy. The following code modifies the original value in $a:

$$ref="Sticks";    # De-references $ref

This modification creates something like the following:

If you had used $ref instead of $$ref

$ref="Break";

then the reference stored in $ref would have been destroyed and replaced with a real value, as shown here:

After the preceding snippet, $ref no longer contains a reference; it's just another scalar. You can assign a reference like any other scalar value:

$name="Gandalf";
$nref=$name;        # Has a reference to $name
$oref=$nref;         # Has a copy of the reference to $name

You get this result:

After the preceding snippet, $$oref and $$nref both can be used to get to the value "Gandalf". You can also store a reference to a reference, like this:

$book="Lord of the Rings";
$bref=$book;    # A reference to $book
$bref2=$bref;   # A reference to $bref (not to $book!)

In this case, the chain of references looks like the following:

and to print the book title using $bref2 would be $$$bref2, and using $bref would be $$bref. Notice that $$$bref2 has an extra dollar sign; it requires one more level of dereferencing to get to the original value.

References to Arrays

References can also be created to arrays and hashes. You create them the same way you create a reference to a scalar—by using a backslash:

$aref=@arr;

Now the scalar variable $aref contains a reference to the entire array @arr. Visually, it might resemble the following:

To access portions of @arr using the reference $aref, you would use one of the following examples:

$$aref[0]The first element of @arr
@$aref[2,3]A slice of @arr
@$arefThe whole of array @arr

You can use braces to separate the reference from the portions dealing with the array itself, for clarity, as shown here:

$$aref[0]is the same as${$aref}[0]
@$aref[2,3]is the same as@{$aref}[2,3]
@$arefis the same as@{$aref}

For example, to print all the elements of @arr using the array reference $aref, you can use this code:

foreach $element (@{$aref}) {
    print $element;
}

References to Hashes

To create a reference to a hash, you use the backslash, just as with scalars and arrays:

$href=\%hash;

The preceding snippet creates a reference to the hash %hash and stores it in $href. This snippet creates a reference structure something like this:

To access portions of %hash using the hash reference %href, you can use the following examples:

$$href{key}An individual key in %hash, also ${$href}{key}
%$hrefThe whole hash, also %{$href}

To iterate through the hash printing all the values, you can use this code:

foreach $key (keys %$href) {
    print $$href{$key};   # same as $hash{$key}
}

References as Arguments

Because an entire array or hash can be referenced and the reference stored in a scalar, with references you can now call functions with multiple arrays or hashes.

You'll recall from Hour 8, "Functions," that the following type of snippet does not work:

# Buggy!
sub getarrays {
    my(@a, @b)=@_;
    :
}
@fruit=qw(apples oranges banana);
@veggies=qw(carrot cabbage turnip);
getarrays(@fruit, @veggies);

This code does not work because getarrays(@fruit, @veggies) flattens both arrays into the single array @_. Inside the getarrays() function, assigning @a and @b to @_ causes all the elements of @fruits and @vegetables—now stored in @_—to be assigned to @a.

After all the arrays are squashed into @_, there's no way to tell when one array ends and the next begins; you just have one big, flat list.

This is the place where references come in. Instead of passing the entire array to getarrays, just passing the references to those arrays works splendidly:

# Works OK!
sub getarrays {
    my($fruit_ref, $veg_ref)=@_;
    :
}
@fruit=qw(apples oranges banana);
@veggies=qw(carrot cabbage turnip);
getarrays(@fruit, @veggies);

The function getarrays() always receives two values—references—no matter what the length of the arrays those references point to. Now $fruit_ref and $veg_ref can be used to display or edit the data, as shown here:

sub getarrays {
    my($fruit_ref, $veg_ref)=@_;

    print "Fruits:", join(',', @$fruit_ref);
    print "Veggies:", join(',', @$veg_ref);
}

Here's something to keep in mind when passing references to scalars, arrays, or hashes into functions as arguments. When you pass references, the function can manipulate the original data to which the reference points. Notice these two examples:


# Passing Values

sub changehash {

    my(%local_hash)=@_;


    $local_hash{mammal}='bear';

    return;

}

%hash=(fish => 'shark',

bird=> 'robin'),

changehash(%hash);

# Passing references

sub changehash {

  my($href)=@_;


  $$href{mammal}='bear';

  return;

}

%hash=(fish => 'shark',

bird=> 'robin'),

changehash(\%hash);

In the example on the left, when the hash is passed normally, @_ takes on the values of each key-value pair in the original hash, %hash. Inside the subroutine changehash(), the hash elements—now in @_—are copied to a new hash called %local_hash. The hash %local_hash is modified, and the subroutine returns. After the subroutine returns, %local_hash is destroyed, and %hash in the main portion of the program remains unmodified.

In the example on the right, a reference to %hash is passed into the subroutine changehash() via @_. The reference is copied to the scalar $href; it still refers to the original hash %hash. Inside the subroutine, the hash referred to by $href is changed, and the subroutine returns. After changehash() returns, the original hash %hash contains the new key bear.

Note

The array @_ is an array of references when used to pass subroutine arguments. Modifying the @_ array's elements changes the original values passed into the function. Modifying arguments passed to subroutines is generally considered rude. If you want your subroutines to modify the arguments passed into them, pass references to the subroutine instead; this approach is clearer, and when you pass a reference, it's expected that the original value may be modified.


Building Structures

Creating references to arrays and hashes is useful for passing them back and forth to subroutines and for creating complex structures that you'll learn about momentarily. However, consider that after you've created a reference to a hash or an array, you no longer need the original hash or array. As long as a reference to a hash or array exists, Perl keeps the hash and array elements around, even if the original data no longer exists.

In the following snippet, a hash, %hash, is created inside a block of code, and the hash is private to that block:

my $href;
{
    my %hash=(phone=> 'Bell', light=> 'Edison'),
    $href=\%hash;
}
print $$href{light};   # It will print "Edison"!

Within the block, the scalar $href is assigned to a reference to %hash. When the block exits, the reference in $href is still valid even though %hash has disappeared (because %hash was private to the block). References to a structure can exist after the structure itself has gone out of scope. The hash referred to by $href can be still be modified.

If you look at the preceding block of code, you can see that its only purpose seems to be to create a reference to a hash. Perl provides a mechanism for creating such a reference without using the intermediate hash %hash. It is called anonymous storage. The following example creates a reference to an anonymous hash and stores it in $ahref:

$ahref={ phone => 'Bell', light => 'Edison' };

The braces ({}) enclose a hash and return a reference to it without actually creating a new variable. You can manipulate the anonymous hash using all the techniques described previously in the section "References to Hashes."

You can construct an anonymous array by using brackets ([]):

$aaref=[ qw( Crosby Stills Nash Young ) ];

Again, this array reference can be manipulated as described in "References to Arrays."

The data pointed to by the reference vanishes completely when the reference variable itself goes out of scope if it's a private variable, as shown here:

{
    my $ref;
    {
    $ref=[ qw ( oats peas beans barley ) ];
    }
    print $$ref[0];        # Prints "oats", $ref is still in scope
}
print $$ref[0];            # $ref is no longer in scope--this is an error.

The preceding snippet does not even compile if use strict is in effect; Perl recognizes the last instance to $ref as being a global variable, which is not allowed. Even without use strict, Perl's -w warnings will probably print an undefined value message.

These anonymous hashes and anonymous arrays can be combined into structures, as you'll see in the next section. Each hash and array reference represents one scalar value, and because it's a single scalar value, it can be stored in other arrays and hashes, as shown here:

$a=[ qw( rock pop classical ) ];
$b=[ qw( mystery action drama ) ];
$c=[ qw( biography novel periodical )];

# A hash of references to arrays
%media=( music => $a, film => $b, 'print' =>$c);

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.248.37