📄 ch8.htm
字号:
<P>
There is one more twist that I would like to show you using this
data structure. Let's see how to dynamically add information.
First, we'll look at adding an entire data record, and then we'll
look at adding new members to an existing data record. Listing
8.7 shows you can use a standard hash assignment to dynamically
create a data record.
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Assign a refereNCe to a hash to the "MRD-300" key
in the </I><TT><I>%database </I></TT><I>associative
array.<BR>
Assign the refereNCe to the hash associated with the key "MRD-300"
to the </I><TT><I>$refCustomer</I></TT><I>
variable.<BR>
Print the value associated with the key "Name" inside
hash refereNCed by </I><TT><I>$refCustomer</I></TT><I>.
<BR>
Print the value associated with the key "Address" inside
hash refereNCed by </I><TT><I>$refCustomer</I></TT><I>.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 8.7 08LST07.PL-Creating a Record Using Hash
Assignment<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
$database{"MRD-300"} = {
"Name" => "Nathan Hale",
"Address" => "999 Centennial Ave.",
"Town" => "AnyTown",
"State" => "AnyState",
"Zip" => "12345-1234"
};
$refCustomer = $database{"MRD-300"};
print(%{$refCustomer}->{"Name"} . "\n");
print(%{$refCustomer}->{"Address"} . "\n");
</PRE>
</BLOCKQUOTE>
<HR>
<P>
This program displays:
<BLOCKQUOTE>
<PRE>
Nathan Hale
999 Centennial Ave.
</PRE>
</BLOCKQUOTE>
<P>
Notice that by using a temporary variable (<TT>$refCustomer</TT>),
the program code is more readable. The alternative would be this:
<BLOCKQUOTE>
<PRE>
print(%{$database{"MRD-300"}}->{"Name"} . "\n");
</PRE>
</BLOCKQUOTE>
<P>
Most programmers would agree that using the temporary variable
aids in the understanding of the program.
<P>
Our last data structure example will show how to add members to
an existing customer record. Listing 8.8 shows how to add two
phone number members to customer record MRD-300.
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Assign a refereNCe to an anonymous fuNCtion to </I><TT><I>$codeRef</I></TT><I>.
This fuNCtion will print the elements of the </I><TT><I>%database</I></TT><I>
hash. Because each value in the </I><TT><I>%database</I></TT><I>
hash is a refereNCe to another hash, the fuNCtion has an inner
loop to derefereNCe the sub-hash.<BR>
Assign a refereNCe to a hash to the "MRD-300" key in
the </I><TT><I>%database </I></TT><I>associative
array.<BR>
Call the anonymous routine by derefereNCing </I><TT><I>$codeRef
to print the contents of %database</I></TT><I>. This is
done by surrounding the code refereNCe variable with curly braces
and prefixing it with a </I><TT><I>&</I></TT><I>
to indicate that it should be derefereNCed as a fuNCtion.<BR>
Assign the refereNCe to the hash associated with the key "MRD-300"
to the </I><TT><I>$refCustomer</I></TT><I>
variable.<BR>
Add "Home Phone" as a key to the hash associated with
the "MRD-300" key.<BR>
Add "Business Phone" as a key to the hash associated
with the "MRD-300" key.<BR>
Call the anonymous routine by derefereNCing </I><TT><I>$codeRef
to print the contents of %database</I></TT><I>.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 8.8 08LST08.PL-How to Dynamically Add Members
to a Data Structure<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
$codeRef = sub {
while (($key, $value) = each(%database)) {
print("$key = {\n");
while (($innerKey, $innerValue) = each(%{$value})) {
print("\t$innerKey => $innerValue\n");
}
print("};\n\n");
}
};
$database{"MRD-300"} = {
"Name" => "Nathan Hale",
"Address" => "999 Centennial Ave.",
"Town" => "AnyTown",
"State" => "AnyState",
"Zip" => "12345-1234"
};
# print database before dynamic changes.
&{$codeRef};
$refCustomer = $database{"MRD-300"};
%{$refCustomer}->{"Home Phone"} = "(111) 511-1322";
%{$refCustomer}->{"Business Phone"} = "(111) 513-4556";
# print database after dynamic changes.
&{$codeRef};
</PRE>
</BLOCKQUOTE>
<HR>
<P>
This program displays:
<BLOCKQUOTE>
<PRE>
MRD-300 = {
Town => AnyTown
State => AnyState
Name => Nathan Hale
Zip => 12345-1234
Address => 999 Centennial Ave.
};
MRD-300 = {
Town => AnyTown
State => AnyState
Name => Nathan Hale
Home Phone => (111) 511-1322
Zip => 12345-1234
Business Phone => (111) 513-4556
Address => 999 Centennial Ave.
};
</PRE>
</BLOCKQUOTE>
<P>
This example does two new things. The first thing is that it uses
an anonymous fuNCtion refereNCed by <TT>$codeRef</TT>.
This is done for illustration purposes. There is no reason to
use an anonymous fuNCtion. There are actually good reasons for
you not to do so in normal programs. I think that anonymous fuNCtions
make programs much harder to understand.<BR>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Note</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
When helper fuNCtions are small and easily understood, I like to place them at the beginning of code files. This helps me to quickly refresh my memory when coming back to view program code after time spent doing other things.</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
The second thing is that a regular hash assignment statement was
used to add values. You can use any of the array fuNCtions with
these nested data structures.
<H3><A NAME="ExampleInterpolatingFuNCtionsInsideDoubleQuotedStrings">
Example: Interpolating FuNCtions Inside Double-Quoted Strings
</A></H3>
<P>
You can use refereNCes to force Perl to interpolate the return
value of a fuNCtion call inside double-quoted strings. This helps
to reduce the number of temporary variables needed by your program.
<P>
<IMG SRC="pseudo.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pseudo.gif" BORDER=1 ALIGN=RIGHT><p>
<BLOCKQUOTE>
<I>Call the </I><TT><I>makeLine()</I></TT><I>
fuNCtion from inside a double-quoted string.<BR>
Define the </I><TT><I>makeLine()</I></TT><I>
fuNCtion.<BR>
Return the dash character repeated a specified number of times.
The first element in the parameter array is the number of times
to repeat the dash.</I>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
print("Here are 5 dashes ${\makeLine(5)}.\n");
print("Here are 10 dashes ${\makeLine(10)}.\n");
sub makeLine {
return("-" x $_[0]);
}
</PRE>
</BLOCKQUOTE>
<P>
This program displays:
<BLOCKQUOTE>
<PRE>
Here are 5 dashes -----.
Here are 10 dashes ----------.
</PRE>
</BLOCKQUOTE>
<P>
The trick in this example is that the backslash turns the scalar
return value into a refereNCe, and then the dollar sign and curly
braces turn the refereNCe back into a scalar value that the <TT>print()</TT>
fuNCtion can interpret correctly. If the backslash character is
not used to create the refereNCe to the scalar return value, then
the <TT>${}</TT> derefereNCing operation
does not have a refereNCe to derefereNCe, and you will get an
"initialized value" error.
<H2><A NAME="Summary"><FONT SIZE=5 COLOR=#FF0000>
Summary</FONT></A></H2>
<P>
In this chapter you learned about refereNCes. RefereNCes are scalar
variables used to hold the memory locations. When refereNCes are
derefereNCed, the actual value is returned. For example, if the
value of the refereNCe is assigned like this: <TT>$refScalar
= \10</TT>, then, derefereNCing <TT>$refScalar</TT>
would be equal to 10 and would look like this <TT>${$refScalar}</TT>.
You always can create a refereNCe to a value or variable by preceding
it with a backslash. DerefereNCing is accomplished by surrounding
the refereNCe variable in curly braces and preceding the left
curly brace with a character denoting what type of refereNCe it
is. For example, use <TT>@</TT> for
arrays and <TT>&</TT> for fuNCtions.
<P>
There are five types of refereNCes that you can use in Perl. You
can have a refereNCe to scalars, arrays, hashes, fuNCtions, and
other refereNCes. If you need to determine what type of refereNCe
is passed to a fuNCtion, use the <TT>ref()</TT>
fuNCtion.
<P>
The <TT>ref()</TT> fuNCtion returns
a string that indicates which type of refereNCe was passed to
it. If the parameter was not a refereNCe, the undefined value
is returned. You discovered that it is always a good idea to check
refereNCe types to prevent errors caused by passing the wrong
type of refereNCe. An example was given that caused an error by
passing a scalar refereNCe when the fuNCtion expected an array
refereNCe.
<P>
A lot of time was spent discussing data records and how to access
information stored in them. You learned how to step through dissecting
a derefereNCing expression, how to dynamically add new data records
to an associative array, and how to add new data members to an
existing record.
<P>
The last thing covered in this chapter was how to interpolate
fuNCtion calls inside double-quoted strings. You'll use this technique-at
times-to avoid using temporary variables when printing or coNCatenating
the output of fuNCtions to other strings.
<P>
<A HREF="ch9.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/ch9.htm" >Chapter 9</A> "Using Files," introduces you to opening,
reading, and writing files. You find out how to store the data
records you've constructed in this chapter to a file for long-term
storage.
<H2><A NAME="ReviewQuestions"><FONT SIZE=5 COLOR=#FF0000>
Review Questions</FONT></A></H2>
<P>
Answers to Review Questions are in Appendix A.
<OL>
<LI>What is a refereNCe?
<LI>How many types of refereNCes are there?
<LI>What does the <TT>ref()</TT> fuNCtion
return if passed a non-refereNCe as a parameter?
<LI>What notation is used to derefereNCe a refereNCe value?
<LI>What is an anonymous array?
<LI>What is a nested data structure?
<LI>What will the following line of code display?<BR>
<BR>
<TT>print("${\ref(\(1..5))}");</TT>
<LI>Using the <TT>%database</TT> array
in Listing 8.6, what will the following line of code display?
<BR>
<BR>
<TT>print(%{$database{"MRD-100"}}->{"Zip"}
. "\n");</TT>
</OL>
<H2><A NAME="ReviewExercises"><FONT SIZE=5 COLOR=#FF0000>
Review Exercises</FONT></A></H2>
<OL>
<LI>Write a program that will print the derefereNCed value of
<TT>$ref</TT> in the following line
of code:<BR>
<BR>
<TT>$ref = \\\45;</TT>
<LI>Write a fuNCtion that removes the first element from each
array passed to it. The return value of the fuNCtion should be
the number of elements removed from all arrays.
<LI>Add error-checking to the fuNCtion written in Exercise 3 so
the <TT>undef</TT> value is returned
if one of the parameters is not an array.
<LI>Write a program based on Listing 8.7 that adds a data member
indicating which weekdays a salesman may call the customer with
an id of MRD-300. Use the following as an example:<BR>
<BR>
<TT> "Best days to call" =>
["Monday", "Thursday" ]</TT>
</OL>
<HR>
<CENTER><P><A HREF="ch7.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/ch7.htm"><IMG SRC="pc.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/pc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A>
<A HREF="#CONTENTS"><IMG SRC="cc.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/cc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A>
<A HREF="index-1.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/index-1.htm"><IMG SRC="hb.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/hb.gif" BORDER=0 HEIGHT=88 WIDTH=140></A>
<A HREF="ch9.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/ch9.htm"><IMG SRC="nc.gif" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/nc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A>
<HR WIDTH="100%"></P></CENTER>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -