📄 ch5.htm
字号:
refereNCe. When parameters are called by refereNCe, changing theirvalue in the fuNCtion also changes their value in the main program.Listing 5.2 shows how this happens.<P><IMG SRC="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 ShowCall 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 5After 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 badprogramming practice because it does not isolate what the fuNCtiondoes from the rest of the program. If you change the fuNCtionso that scalars are used inside the fuNCtion, this problem goesaway. List-ing 5.3 shows how to redo the program in Listing 5.2so scalars are used inside the fuNCtion.<P><IMG SRC="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 ofthe @_ 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 5After 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 quietlyarisen. 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 showshow changing a variable in the fuNCtion affects the main program.<P><IMG SRC="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 FuNCtionsCan 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 5After fuNCtion call firstVar = A array = 0 1 2 3 4 5</PRE></BLOCKQUOTE><P>By using the <TT>$firstVar</TT> variablein the fuNCtion you also change its value in the main program.By default, all Perl variables are accessible everywhere insidea program. This ability to globally access variables can be agood thing at times. It does help when trying to isolate a fuNCtionfrom the rest of your program. The next section shows you howto 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, everyvariable has a global scope. ONCe defined, every part of yourprogram can access a variable.<P>It is very useful to be able to limit a variable's scope to asingle fuNCtion. In other words, the variable wil have a limitedscope. This way, changes inside the fuNCtion can't affect themain program in unexpected ways. Listing 5.5 introduces two ofPerl's built-in fuNCtions that create variables of limited scope.The <TT>my()</TT> fuNCtion createsa variable that only the current fuNCtion can see. The <TT>local()</TT>fuNCtion creates a variable that fuNCtions the current fuNCtioncalls 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 alisting that is worth a thousand words, not a picture!<P><IMG SRC="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 FuNCtionsto 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 = AAAAAfirstSub: secondVar = BBBBBsecondSub: firstVar = AAAAAUse of uninitialized value at test.pl line 19.secondSub: secondVar =secondSub: firstVar = ccccCsecondSub: secondVar = DDDDDfirstSub: firstVar = ccccCfirstSub: 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 evenprints out an error message that warns about the uninitializedvalue. 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> fuNCtionis even more complex than I've said. The easy definition is thatit creates variables that only the current fuNCtion can see. Thetrue 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 hearmore about it in <A HREF="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 changethe variable's value, and the main program sees the change. When<TT>local()</TT> is used in conjuNCtionwith assigning the <TT>@_ </TT>arrayelements to scalars, then the parameters are essentially beingcalled by value. The fuNCtion can change the value of the variable,but only the fuNCtion is affected. The rest of the program seesthe 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 takeanother look at parameters. Because all parameters are passedto a fuNCtion in one array, what if you need to pass both a scalarand an array to the same fuNCtion? This next example shows youwhat happens.<P><IMG SRC="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>arrayand </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 AAAAUse 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 theuninitialized value message displayed in the output. You can fixthis by merely reversing the order of parameters. If the scalarvalue comes first, then the fuNCtion processes the parameterswithout a problem.<P><IMG SRC="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>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -