📄 ch04_08.htm
字号:
<p>However, any scope within a file (or even the file itself) is fairgame. It's often useful to have scopes larger than subroutinedefinitions, because this lets you share private variables among alimited set of subroutines. This is how you create variables that a Cprogrammer would think of as "static":<blockquote><pre class="programlisting">{ my $state = 0; sub on { $state = 1 } sub off { $state = 0 } sub toggle { $state = !$state }}</pre></blockquote><a name="INDEX-1226"></a></p><p>The <tt class="literal">eval</tt><em class="replaceable">STRING</em> operatoralso works as a nested scope, since the code in the<tt class="literal">eval</tt> can see its caller's lexicals (as long as thenames aren't hidden by identical declarations within the<tt class="literal">eval</tt>'s own scope). Anonymous subroutines canlikewise access any lexical variables from their enclosing scopes; ifthey do so, they're what are known as<em class="emphasis">closures</em>.<a href="#FOOTNOTE-7">[7]</a>Combining those two notions, if a block <tt class="literal">eval</tt>s astring that creates an anonymous subroutine, the subroutine becomes aclosure with full access to the lexicals of both the<tt class="literal">eval</tt> and the block, even after the<tt class="literal">eval</tt> and the block have exited. See the section<a href="ch08_03.htm#ch08-sect-closure">Section 4.3.7, "Closures"</a> in <a href="ch08_01.htm">Chapter 8, "References"</a>.</p><blockquote class="footnote"><a name="FOOTNOTE-7"></a><p>[7]As a mnemonic, note thecommon element between "en<em class="emphasis">clos</em>ing scope"and "<em class="emphasis">clos</em>ure". (The actual definition ofclosure comes from a mathematical notion concerning the completenessof sets of values and operations on those values.)</p></blockquote><p>The newly declared variable (or value, in the case of<tt class="literal">local</tt>) does not show up until the statement<em class="emphasis">after</em> the statement containing the declaration.Thus you could mirror a variable this way:<blockquote><pre class="programlisting">my $x = $x;</pre></blockquote>That initializes the new inner <tt class="literal">$x</tt> with the currentvalue <tt class="literal">$x</tt>, whether the current meaning of<tt class="literal">$x</tt> is global or lexical. (If you don't initializethe new variable, it starts out with an undefined or empty value.)</p><p>Declaring a lexical variable of a particular name hides any previouslydeclared lexical of the same name. It also hides any unqualifiedglobal variable of the same name, but you can always get to theglobal variable by explicitly qualifying it with the name of thepackage the global is in, for example, <tt class="literal">$PackageName::varname</tt>.</p><h3 class="sect2">4.8.3. Lexically Scoped Global Declarations: our</h3><a name="INDEX-1227"></a><a name="INDEX-1228"></a><a name="INDEX-1229"></a><p><a name="INDEX-1230"></a>A better way to access globals, especially for programs and modulesrunning under the <tt class="literal">use strict</tt> declaration, is the<tt class="literal">our</tt> declaration. This declaration is lexicallyscoped in that it applies only through the end of the current scope.But unlike the lexically scoped <tt class="literal">my</tt> or thedynamically scoped <tt class="literal">local</tt>, <tt class="literal">our</tt>does not isolate anything to the current lexical or dynamic scope.Instead, it provides access to a global variable in the currentpackage, hiding any lexicals of the same name that would haveotherwise hidden that global from you. In this respect,<tt class="literal">our</tt> variables act just like <tt class="literal">my</tt>variables.</p><p>If you place an <tt class="literal">our</tt> declaration outside anybrace-delimited block, it lasts through the end of the currentcompilation unit. Often, though, people put it just inside the top ofa subroutine definition to indicate that they're accessing a globalvariable:<blockquote><pre class="programlisting">sub check_warehouse { our @Current_Inventory; my $widget; foreach $widget (@Current_Inventory) { print "I have a $widget in stock today.\n"; }}</pre></blockquote>Since global variables are longer in life and broader in visibilitythan private variables, we like to use longer and flashier names forthem than for temporary variable. This practice alone, if studiouslyfollowed, can do as much as <tt class="literal">use strict</tt> can towarddiscouraging the use of global variables, especially in lessprestidigitatorial typists.</p><p>Repeated <tt class="literal">our</tt> declarations do not meaningfully nest.Every nested <tt class="literal">my</tt> produces a new variable, and everynested <tt class="literal">local</tt> a new value. But every time you use<tt class="literal">our</tt>, you're talking about <em class="emphasis">thesame</em> global variable, irrespective of nesting. When youassign to an <tt class="literal">our</tt> variable, the effects of thatassignment persist after the scope of the declaration. That's because<tt class="literal">our</tt> never creates values; it just exposes a limitedform of access to the global, which lives forever:</p><blockquote><pre class="programlisting">our $PROGRAM_NAME = "waiter";{ our $PROGRAM_NAME = "server"; # Code called here sees "server". ...}# Code executed here still sees "server".</pre></blockquote><p>Contrast this with what happens under <tt class="literal">my</tt> or <tt class="literal">local</tt>, where afterthe block, the outer variable or value becomes visible again:<blockquote><pre class="programlisting">my $i = 10;{ my $i = 99; ...}# Code compiled here sees outer variable.local $PROGRAM_NAME = "waiter";{ local $PROGRAM_NAME = "server"; # Code called here sees "server". ...}# Code executed here sees "waiter" again.</pre></blockquote>It usually only makes sense to assign to an <tt class="literal">our</tt> declarationonce, probably at the very top of the program or module, or, more rarely,when you preface the <tt class="literal">our</tt> with a <tt class="literal">local</tt> of its own:<blockquote><pre class="programlisting">{ local our @Current_Inventory = qw(bananas); check_warehouse(); # no, we haven't no bananas :-)}</pre></blockquote></p><h3 class="sect2">4.8.4. Dynamically Scoped Variables: local</h3><a name="INDEX-1231"></a><a name="INDEX-1232"></a><a name="INDEX-1233"></a><a name="INDEX-1234"></a><p>Using a <tt class="literal">local</tt> operator on a global variable givesit a temporary value each time <tt class="literal">local</tt> is executed,but it does not affect that variable's global visibility. When theprogram reaches the end of that dynamic scope, this temporary value isdiscarded and the original value restored. But it's always still aglobal variable that just happens to hold a temporary value while thatblock is executing. If you call some other function while your globalcontains the temporary value and that function accesses that globalvariable, it sees the temporary value, not the original one. In otherwords, that other function is in your dynamic scope, even though it'spresumably not in your lexical scope.<a href="#FOOTNOTE-8">[8]</a></p><blockquote class="footnote"><a name="FOOTNOTE-8"></a><p>[8] That's whylexical scopes are sometimes called <em class="emphasis">staticscopes</em>: to contrast them with dynamic scopes and emphasizetheir compile-time determinability. Don't confuse this use of theterm with how <tt class="literal">static</tt> is used in C or C++. The termis heavily overloaded, which is why we avoid it.</p></blockquote><p>If you have a <tt class="literal">local</tt> that looks like this:<blockquote><pre class="programlisting">{ local $var = $newvalue; some_func(); ...}</pre></blockquote>you can think of it purely in terms of run-time assignments:<blockquote><pre class="programlisting">{ $oldvalue = $var; $var = $newvalue; some_func(); ...}continue { $var = $oldvalue;}</pre></blockquote>The difference is that with <tt class="literal">local</tt> the value isrestored no matter how you exit the block, even if you prematurely<tt class="literal">return</tt> from that scope. The variable is still thesame global variable, but the value found there depends on which scopethe function was called from. That's why it's called<em class="emphasis">dynamic scoping</em>--because it changes during runtime.</p><p>As with <tt class="literal">my</tt>, you can initialize a<tt class="literal">local</tt> with a copy of the same global variable. Anychanges to that variable during the execution of a subroutine (and anyothers called from within it, which of course can still see thedynamically scoped global) will be thrown away when the subroutinereturns. You'd certainly better comment what you are doing, though:<blockquote><pre class="programlisting"># WARNING: Changes are temporary to this dynamic scope.local $Some_Global = $Some_Global;</pre></blockquote>A global variable then is still completely visible throughout yourwhole program, no matter whether it was explicitly declared with<tt class="literal">our</tt> or just allowed to spring into existence, orwhether it's holding a <tt class="literal">local</tt> value destined to bediscarded when the scope exits. In tiny programs, this isn't so bad,but for large ones, you'll quickly lose track of where in the code allthese global variables are being used. You can forbid accidental useof globals, if you want, through the <tt class="literal">use strict'vars'</tt> pragma, described in the next section.</p><p><a name="INDEX-1235"></a><a name="INDEX-1236"></a>Although both <tt class="literal">my</tt> and <tt class="literal">local</tt>confer some degree of protection, by and large you should prefer<tt class="literal">my</tt> over <tt class="literal">local</tt>. Sometimes,though, you have to use <tt class="literal">local</tt> so you cantemporarily change the value of an existing global variable, likethose listed in <a href="ch28_01.htm">Chapter 28, "Special Names"</a>. Onlyalphanumeric identifiers may be lexically scoped, and many of thosespecial variables aren't strictly alphanumeric. You also need to use<tt class="literal">local</tt> to make temporary changes to a package'ssymbol table as shown in the section <a href="ch10_01.htm#ch10-sect-st">Section 4.1, "Symbol Tables"</a> in <a href="ch10_01.htm">Chapter 10, "Packages"</a>. Finally, you can use<tt class="literal">local</tt> on a single element or a whole slice of anarray or a hash. This even works if the array or hash happens to be alexical variable, layering <tt class="literal">local</tt>'s dynamic scopingbehavior on top of those lexicals. We won't talk much more about thesemantics of <tt class="literal">local</tt> here. See<tt class="literal">local</tt> in <a href="ch29_01.htm">Chapter 29, "Functions"</a> formore information.</p><!-- BOTTOM NAV BAR --><hr width="515" align="left"><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch04_07.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="index.htm"><img src="../gifs/txthome.gif" alt="Home" border="0"></a></td><td align="right" valign="top" width="172"><a href="ch04_09.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr><tr><td align="left" valign="top" width="172">4.7. Global Declarations</td><td align="center" valign="top" width="171"><a href="index/index.htm"><img src="../gifs/index.gif" alt="Book Index" border="0"></a></td><td align="right" valign="top" width="172">4.9. Pragmas</td></tr></table></div><hr width="515" align="left"><!-- LIBRARY NAV BAR --><img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p><font size="-1"><a href="copyrght.htm">Copyright © 2001</a> O'Reilly & Associates. All rights reserved.</font></p><map name="library-map"> <area shape="rect" coords="2,-1,79,99" href="../index.htm"><area shape="rect" coords="84,1,157,108" href="../perlnut/index.htm"><area shape="rect" coords="162,2,248,125" href="../prog/index.htm"><area shape="rect" coords="253,2,326,130" href="../advprog/index.htm"><area shape="rect" coords="332,1,407,112" href="../cookbook/index.htm"><area shape="rect" coords="414,2,523,103" href="../sysadmin/index.htm"></map><!-- END OF BODY --></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -