?? ch5.htm
字號:
refereNCe. When parameters are called by refereNCe, changing their
value in the fuNCtion also changes their value in the main program.
Listing 5.2 shows how this happens.
<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>Create an array with 6 elements.<BR>
Print the elements of the array.<BR>
Call the </I><TT><I>firstSub()</I></TT><I>
fuNCtion.<BR>
Print the elements of the array.<BR>
Define the </I><TT><I>firstSub()</I></TT><I>
fuNCtion.<BR>
Change the values of the first two elements of </I><TT><I>@_</I></TT><I>.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 5.2 05LST02.PL-Using the @Array to Show
Call by RefereNCe<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
@array = (0..5);
print("Before fuNCtion call, array = @array\n");
firstSub(@array);
print("After fuNCtion call, array = @array\n");
sub firstSub{
$_[0] = "A";
$_[1] = "B";
}
</PRE>
</BLOCKQUOTE>
<HR>
<P>
This program prints:
<BLOCKQUOTE>
<PRE>
Before fuNCtion call, array = 0 1 2 3 4 5
After fuNCtion call, array = A B 2 3 4 5
</PRE>
</BLOCKQUOTE>
<P>
You can see that the fuNCtion was able to affect the <TT>@array</TT>
variable in the main program. Generally, this is considered bad
programming practice because it does not isolate what the fuNCtion
does from the rest of the program. If you change the fuNCtion
so that scalars are used inside the fuNCtion, this problem goes
away. List-ing 5.3 shows how to redo the program in Listing 5.2
so scalars are used inside the fuNCtion.
<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>Create an array with 6 elements.<BR>
Print the elements of the array.<BR>
Call the </I><TT><I>firstSub()</I></TT><I>
fuNCtion.<BR>
Print the elements of the array.<BR>
Define the </I><TT><I>firstSub()</I></TT><I>
fuNCtion.<BR>
Assign the first two elements of </I><TT><I>@_</I></TT><I>
to </I><TT><I>$firstVar</I></TT><I>
and </I><TT><I>$secondVar</I></TT><I>.
<BR>
Change the values of the scalar variables.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 5.3 05LST03.PL-Using Scalars Instead of
the @_ Array Inside FuNCtions<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
@array = (0..5);
print("Before fuNCtion call, array = @array\n");
firstSub(@array);
print("After fuNCtion call, array = @array\n");
sub firstSub{
($firstVar, $secondVar) = @_ ;
$firstVar = "A";
$secondVar = "B";
}
</PRE>
</BLOCKQUOTE>
<HR>
<P>
This program prints:
<BLOCKQUOTE>
<PRE>
Before fuNCtion call, array = 0 1 2 3 4 5
After fuNCtion call, array = 0 1 2 3 4 5
</PRE>
</BLOCKQUOTE>
<P>
This example shows that the original <TT>@array</TT>
variable is left untouched. However, another problem has quietly
arisen. Let's change the program a little so the values of <TT>$firstVar</TT>
are printed before and after the fuNCtion call. Listing 5.4 shows
how changing a variable in the fuNCtion affects the main 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>Assign a value to </I><TT><I>$firstVar</I></TT><I>.
<BR>
Create an array with 6 elements.<BR>
Print the elements of the array.<BR>
Call the </I><TT><I>firstSub()</I></TT><I>
fuNCtion.<BR>
Print the elements of the array.<BR>
Define the </I><TT><I>firstSub()</I></TT><I>
fuNCtion.<BR>
Assign the first two elements of </I><TT><I>@_</I></TT><I>
to </I><TT><I>$firstVar</I></TT><I>
and </I><TT><I>$secondVar</I></TT><I>.
<BR>
Change the values of the scalar variables.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 5.4 05LST04.PL-Using Variables in FuNCtions
Can Cause Unexpected Results<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
$firstVar = 10;
@array = (0..5);
print("Before fuNCtion call\n");
print("\tfirstVar = $firstVar\n");
print("\tarray = @array\n");
firstSub(@array);
print("After fuNCtion call\n");
print("\tfirstVar = $firstVar\n");
print("\tarray = @array\n");
sub firstSub{
($firstVar, $secondVar) = @_ ;
$firstVar = "A";
$secondVar = "B";
}
</PRE>
</BLOCKQUOTE>
<HR>
<P>
This program prints:
<BLOCKQUOTE>
<PRE>
Before fuNCtion call
firstVar = 10
array = 0 1 2 3 4 5
After fuNCtion call
firstVar = A
array = 0 1 2 3 4 5
</PRE>
</BLOCKQUOTE>
<P>
By using the <TT>$firstVar</TT> variable
in the fuNCtion you also change its value in the main program.
By default, all Perl variables are accessible everywhere inside
a program. This ability to globally access variables can be a
good thing at times. It does help when trying to isolate a fuNCtion
from the rest of your program. The next section shows you how
to create variables that can only be used inside fuNCtions.
<H3><A NAME="ExampleScopeofVariables">
Example: Scope of Variables</A></H3>
<P>
<I>Scope</I> refers to the visibility of variables. In other words,
which parts of your program can see or use it. Normally, every
variable has a global scope. ONCe defined, every part of your
program can access a variable.
<P>
It is very useful to be able to limit a variable's scope to a
single fuNCtion. In other words, the variable wil have a limited
scope. This way, changes inside the fuNCtion can't affect the
main program in unexpected ways. Listing 5.5 introduces two of
Perl's built-in fuNCtions that create variables of limited scope.
The <TT>my()</TT> fuNCtion creates
a variable that only the current fuNCtion can see. The <TT>local()</TT>
fuNCtion creates a variable that fuNCtions the current fuNCtion
calls can see. If that sounds confusing, don't worry. It is confusing;
but, Listing 5.5 should clear things up. In this case, it's a
listing that is worth a thousand words, not a picture!
<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 </I><TT><I>firstSub()</I></TT><I>
with a two parameters.<BR>
Define the </I><TT><I>firstSub()</I></TT><I>
fuNCtion.<BR>
Assign the first parameter to local variable </I><TT><I>$firstVar</I></TT><I>.
<BR>
Assign the second parameter to my variable </I><TT><I>$secondVar</I></TT><I>.
<BR>
Print the variables.<BR>
Call the second fuNCtion without any parameters.<BR>
Print the variables to see what changed.<BR>
Define the </I><TT><I>secondSub()</I></TT><I>
fuNCtion.<BR>
Print the variables.<BR>
Assign new values to the variables.<BR>
Print the variables to see that the new values were assigned correctly.</I>
</BLOCKQUOTE>
<HR>
<BLOCKQUOTE>
<B>Listing 5.5 05LST05.PL-Using the Local and My FuNCtions
to Create Local Variables<BR>
</B>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
firstSub("AAAAA", "BBBBB");
sub firstSub{
local ($firstVar) = $_[0];
my($secondVar) = $_[1];
print("firstSub: firstVar = $firstVar\n");
print("firstSub: secondVar = $secondVar\n\n");
secondSub();
print("firstSub: firstVar = $firstVar\n");
print("firstSub: secondVar = $secondVar\n\n");
}
sub secondSub{
print("secondSub: firstVar = $firstVar\n");
print("secondSub: secondVar = $secondVar\n\n");
$firstVar = "ccccC";
$secondVar = "DDDDD";
print("secondSub: firstVar = $firstVar\n");
print("secondSub: secondVar = $secondVar\n\n");
}
</PRE>
</BLOCKQUOTE>
<HR>
<P>
This program prints:
<BLOCKQUOTE>
<PRE>
firstSub: firstVar = AAAAA
firstSub: secondVar = BBBBB
secondSub: firstVar = AAAAA
Use of uninitialized value at test.pl line 19.
secondSub: secondVar =
secondSub: firstVar = ccccC
secondSub: secondVar = DDDDD
firstSub: firstVar = ccccC
firstSub: secondVar = BBBBB
</PRE>
</BLOCKQUOTE>
<P>
The output from this example shows that <TT>secondSub()</TT>
could not access the <TT>$secondVar</TT>
variable that was created with <TT>my()</TT>
inside <TT>firstSub()</TT>. Perl even
prints out an error message that warns about the uninitialized
value. The <TT>$firstVar</TT> variable,
however, can be accessed and valued by <TT>secondSub()</TT>.
<BR>
<p>
<CENTER>
<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Tip</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
It's generally a better idea to use <TT>my()</TT> instead of <TT>local()</TT> so that you can tightly control the scope of local variables. Think about it this way-it's 4:00 in the morning and the project is due. Is that the time to be checking variable
scope? No. Using <TT>my()</TT>enforces good programming practices and reduces headaches.
</BLOCKQUOTE>
</TD></TR>
</TABLE>
</CENTER>
<P>
<P>
Actually, the <TT>my()</TT> fuNCtion
is even more complex than I've said. The easy definition is that
it creates variables that only the current fuNCtion can see. The
true definition is that it creates variables with lexical scope.
This distiNCtion is only important when creating modules or objects,
so let's ignore the complicated definition for now. You'll hear
more about it in <A HREF="ch15.htm" tppabs="http://cheminf.nankai.edu.cn/~eb~/Perl%205%20By%20Example/ch15.htm" >Chapter 15</A>, "Perl Modules."
<P>
If you remember, I mentioned calling parameters by refereNCe.
Passing parameters by refereNCe means that fuNCtions can change
the variable's value, and the main program sees the change. When
<TT>local()</TT> is used in conjuNCtion
with assigning the <TT>@_ </TT>array
elements to scalars, then the parameters are essentially being
called by value. The fuNCtion can change the value of the variable,
but only the fuNCtion is affected. The rest of the program sees
the old value.
<H3><A NAME="ExampleUsingaListasaFuNCtionParameter">
Example: Using a List as a FuNCtion Parameter</A></H3>
<P>
Now that you understand about the scope of variables, let's take
another look at parameters. Because all parameters are passed
to a fuNCtion in one array, what if you need to pass both a scalar
and an array to the same fuNCtion? This next example shows you
what happens.
<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>firstSub()</I></TT><I>
fuNCtion with two parameters: a list and a scalar.<BR>
Define the </I><TT><I>firstSub()</I></TT><I>
fuNCtion.<BR>
Assign the elements of the </I><TT><I>@_</I></TT><I>
array to </I><TT><I>@</I></TT><I>array
and </I><TT><I>$firstVar</I></TT><I>.
<BR>
Print </I><TT><I>@array</I></TT><I>
and </I><TT><I>$firstVar</I></TT><I>.</I>
</BLOCKQUOTE>
<BLOCKQUOTE>
<PRE>
firstSub((0..10), "AAAA");
sub firstSub{
local(@array, $firstVar) = @_ ;
print("firstSub: array = @array\n");
print("firstSub: firstVar = $firstVar\n");
}
</PRE>
</BLOCKQUOTE>
<P>
This program prints:
<BLOCKQUOTE>
<PRE>
firstSub: array = 0 1 2 3 4 5 6 7 8 9 10 AAAA
Use of uninitialized value at test.pl line 8.
firstSub: firstVar =
</PRE>
</BLOCKQUOTE>
<P>
When the local variables are initialized, the <TT>@array</TT>
variables grab all of the elements in the <TT>@</TT>
array, leaving none for the scalar variable. This results in the
uninitialized value message displayed in the output. You can fix
this by merely reversing the order of parameters. If the scalar
value comes first, then the fuNCtion processes the parameters
without a problem.
<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>firstSub()</I></TT><I>
fuNCtion with two parameters: a scalar and a list.<BR>
Define the </I><TT><I>firstSub()</I></TT><I>
fuNCtion.<BR>
Assign the elements of the </I><TT><I>@_</I></TT><I>
array to </I><TT><I>$firstVar</I></TT><I>
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -