Your skill will accomplish what the force of many cannot |
|
PerlMonks |
(ASCII Graphics in style of PEGS (PErl Graphical Structures) by Joseph Hall)
What is a reference?
There are two kinds of references 'hard references' and 'soft references'. The 'soft' ones are sometimes called 'symbolic' and are not part of this tutorial.
A reference is something like a pointer to a value (I know there are no pointers in Perl like there are in C):
+-----------+ +-----------+ | O-----+----->| 12345 | +-----------+ +-----------+
+----------\ +----------\ | a > | b > +----------/ +----------/ | | +-----------+ +-----------+ | O-----+----->| 12345 | +-----------+ +-----------+
+----------\ | b > +----------\ +----------/ | a > | +----------/ +-----------+ | | O-----+----->+###########+ +-----------+ +"""""""""""+ | Foo | +----------\ +-----------+ | c > | Bar | +----------/ +-----------+ | | Baz | +-----------+ +-----------+ | O-----+----->| Qux | +-----------+ +-----------+
A reference to a list containing references to several lists.+----------\ | a > +-->+###########+ +----------/ | +"""""""""""+ | | | Foo | +-----------+ | +-----------+ | O-----+----->+###########+ | | Bar | +-----------+ +"""""""""""+ | +-----------+ | O-----+---+ +-----------+ | O-----+------>+###########+ +-----------+ +"""""""""""+ | O-----+---+ | Baz | +-----------+ | +-----------+ | | Qux | | +-----------+ | | +-->+###########+ +"""""""""""+ | Baz | +-----------+
A hash containing references to lists.+----------\ | a > +-->+###########+ +----------/ | +"""""""""""+ | | | Foo | +#########################+ | +-----------+ +"""""""""""""""""""""""""+ | | Bar | +-----------\ +-----------+ | +-----------+ | aaa >| O-----+---+ +-----------< +-----------+ | bbb >| O-----+------>+###########+ +-----------< +-----------+ +"""""""""""+ | ccc >| O-----+---+ | Baz | +-----------/ +-----------+ | +-----------+ | | Qux | | +-----------+ | | +-->+###########+ +"""""""""""+ | Baz | +-----------+
$cref = \12345 | Reference to a constant |
$sref = \$s | Reference to the value of $s |
$aref = \@a | Reference to the array @a |
$href = \%h | Reference to the hash %h |
$fref = \&f | Reference to the subroutine &f |
A reference to an anonymous hash:$aref = [123, 456, 789];
A reference to an anonymous subroutine:$href = {NAME => 'Bernd', EMAIL => 'bdulfer@sybase.com'};
$fref = sub { print "AnonSub\n" };
(useless :-) example:
The meaning of @$ is explained later.use Data::Dumper; sub make_hash_from_arrays { my ($aref1, $aref2) = @_; my %hash; $hash{$_} = shift @$aref2 foreach (@$aref1); print Dumper(\%hash); } my @a = ('a', 'b', 'c', 'd'); my @b = (1, 2, 3, 4); make_hash_from_arrays(\@a, \@b);
Case 2. complex datastructures:
A datastructure containing an addressbook.
Without references there are the following possibilities:
1. The addresses are put into a hash, the values of each address are separated by a delimiter. To get distinct values, split is used:
2. The address is distributed over several hashes. To display an address elements are fetched from those hashes:$address{Bernd} = 'Bernd Dulfer|Kapellenstr. 1|bdulfer@sybase.com' +; $email = (split(/\|/, $address{bernd}))[2];
$name{Bernd} = 'Bernd Dulfer'; $str{Bernd} = 'Kapellenstr. 1'; $email{Bernd} = 'bdulfer@sybase.com'; print_address($name{Bernd}, $str{Bernd});
You want to store in addition to the addresse, for instance, a list of lended books. It is almost impossible to do this without references, with references it's like this:+----------\ | address > +----------/ | +#######################+ +"""""""""""""""""""""""+ +-----------\ +---------+ | Bernd >| O----+----->+##################################+ +-----------/ +---------+ +""""""""""""""""""""""""""""""""""+ +-----------\ +--------------------+ | Name >| Bernd Dulfer | +-----------< +--------------------+ | Str >| Kapellenstr. 1 | +-----------< +--------------------+ | EMail >| bdulfer@sybase.com| +-----------/ +--------------------+ $address{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com' }; $email = $address{Bernd}->{EMail}; print_address($address{Bernd});
+----------\ | address > +----------/ | +##########+ +""""""""""+ +----\ +---+ |Bernd>| O-+->+###########################+ +----/ +---+ +"""""""""""""""""""""""""""+ +------\ +------------------+ |Name >|Bernd Dulfer | +------< +------------------+ |Str >|Kapellenstr. 1 | +------< +------------------+ |EMail >|bdulfer@sybase.com| +------< +------------------+ |Books >| O---------+->+#####################+ +------/ +------------------+ +"""""""""""""""""""""+ |Lord of the Rings | +---------------------+ |Hitchhikers Guide ...| +---------------------+ |The Color of Magic | +---------------------+ $address{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com', Books => [ 'Lord of the Rings', 'Hitchhikers Guide to the Galaxy', 'The Color of Magic' ] };
Prints:$s = 'qwertz'; $sref = \$s; print ${$sref}, "\n"; print $$sref, "\n";
qwertz qwertz
Prints:$, = ':'; @a = (123, 456, 789); $aref = \@a; print @{$aref}, "\n"; print @$aref, "\n";
123:456:789 123:456:789
${$aref}[1] or $$aref[1]
Prints:$address{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com', Books => [ 'Lord of the Rings', 'Hitchhikers Guide to the Galaxy', 'The Color of Magic' ] }; print 'Name: ', $address{Bernd}->{Name}, "\n";
Name: Bernd Dulfer
The reference in $address{Bernd} is dereferenced and gives a hash. From this hash the value with the key 'Books', which is a reference, is used. This reference is again dereferenced and gives a list, of which the fourth element gets a new value.$address{Bernd}->{Books}->[3] = 'Goedel, Escher, Bach - An Eternal + Golden Braid';
If something dereferenced shall be used not as a scalar but as an array, it has to be dereferenced with the sigil and { }:
$address{Bernd} contains a reference to an anonymous hash, which can be accessed by using ->.push @{$address{Bernd}->{Books}}, 'Icerigger';
A list of authors and books will be added to the address.
The authors are stored in a hash. The keys are the names of the authors, the values are references to lists of booktitles.
To create the hash of authors separately, use:
A reference to this hash can be added to the address:%authors = ( Tolkien => [ 'The Silmarillion', 'Unfinished Tales' ], Pratchett => [; 'Guards! Guards!', 'Feet of Clay' ] )
A new book by Tolkien is added using:$address{Bernd}->{Authors} = \%authors;
push @{$authors{Tolkien}}, 'The Hobbit';
How can I look into complex datastructures?
The module Data::Dumper has a function Dumper. Pass a reference to this function and Dumper creates Perlcode, representing the whole structure:
Take a close look at the line containing ['Silmarillion', 'Unfinished Tales'].#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my %address; $address{Bernd} = { Name => 'Bernd Dulfer', Str => 'Kapellenstr. 1', EMail => 'bdulfer@sybase.com', Books => [ 'Lord of the Rings', 'Hitchhikers Guide to the Galaxy', 'The Color of Magic' ] }; $address{Bernd}->{Books}->[3] = 'Goedel, Escher, Bach - An Eternal + Golden Braid'; push @{$address{Bernd}->{Books}}, 'Icerigger'; $address{Bernd}->{Authors}->{Tolkien} = ['Silmarillion', 'Unfinish +ed Tales']; print Dumper(\%address);
You get a similar display when you use the Tk-debugger (Devel::ptkdb).$VAR1 = { 'Bernd' => { 'Authors' => { 'Tolkien' => [ 'Silmarillion', 'Unfinished Tales +' ] }, 'Books' => [ 'Lord of the Rings', 'Hitchhikers Guide to the Galaxy', 'The Color of Magic' 'Gödel, Escher, Bach - An Ete +rnal Golden Braid', 'Icerigger' ], 'EMail' => 'bdulfer@sybase.com', 'Str' => 'Kapellenstr. 1', 'Name' => 'Bernd Dulfer' } };
How can I load data from a file into a complex datastructure?
Consider the following file:
The following code creates the well known hash:#Short Name Str EMail Books Bernd |Bernd Dulfer |Kapellenstr. 1 |bdulfer@sybase.com |(Lord of + the Rings|Hitchhikers Guide ...|The Color of Magic) Bilbo |Bilbo Baggins |Bagend | |(The Red + Book)
Line 1: declare the hash %addresses.1: my %addresses; 2: 3: open ADDRESSES, 'addresses.dat' or die "Cannot open addresses.d +at: $!\n"; 4: while (<ADDRESSES>) { 5: next if /^#/; 6: my ($short, $name, $str, $email, $books) = split(/\s*\|/, $_, + 5); 7: $addresses{$short} = { 8: Name => $name, 9: Str => $str, 10: EMail => $email 11: }; 12: $books =~ tr/()//d; 13: push @{$addresses{$short}->{Books}}, split /\|/, $books; 14: } 15: close ADDRESSES;
This is only an example, several things remain unconsidered. For instances a booktitle may contain parens.
How can I iterate through arrays and hashes in datastructures?
All books of a given address:
All authors with their books:foreach (@{$address{Bernd}->{Books}}) { print $_, "\n"; }
foreach (keys %{$address{Bernd}->{Authors}}) { print $_, "\n"; foreach (@{$address{Bernd}->{Authors}->{$_}}) { print "\t", $_, "\n"; } }
What are references to subroutines good for?
References to subroutines are used for several things:
Callbacks:
In a module a subroutine of the main program shall be executed without the module knowing the name of that subroutine.
A reference to the subroutine is passed to the module.:
Tk programmer often use callbacks, events (mouse click, button, ...) are passed to and processed by callbacks.Package Mod; my $callback; sub set_callback { $callback = shift; } sub do_something { do_this(); do_that(); &$callback; do_something_else(); } . . . 1; __END__ #!/usr/bin/perl use strict; use warnings; use Mod; Mod::set_callback(\&print_rubbish); Mod::do_something(); sub print_rubbish ( print "Rubbish!\n"; }
Dispatch Lists:
To avoid large if/elsif/else constructs, pieces of code are put into subroutines.
References to these subroutines are stored in a hash.The keys represent the conditions.
%dispatch = ( insert => \&insert, update => \&update, delete => \&delete ) $dispatch{$token}->($query);
Update: wrong brackets in two places, caught by petral
Update: replaced (PEGS) link
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: references
by Juerd (Abbot) on Jan 08, 2002 at 20:25 UTC | |
Re: references
by planetscape (Chancellor) on Jul 01, 2005 at 04:36 UTC | |
Re: references
by nathanvit (Beadle) on Mar 22, 2003 at 18:06 UTC | |
Re: references
by Anonymous Monk on Jan 17, 2002 at 22:02 UTC | |
Re: references
by serah99 (Initiate) on Jun 10, 2005 at 18:17 UTC | |
Re: intro to references
by lowphive (Monk) on Feb 08, 2007 at 03:22 UTC | |
Re: intro to references
by perl.j (Pilgrim) on Aug 03, 2011 at 03:14 UTC | |
A reply falls below the community's threshold of quality. You may see it by logging in. |