📄 ch08_03.htm
字号:
<html><head><title>Using Hard References (Programming Perl)</title><!-- STYLESHEET --><link rel="stylesheet" type="text/css" href="../style/style1.css"><!-- METADATA --><!--Dublin Core Metadata--><meta name="DC.Creator" content=""><meta name="DC.Date" content=""><meta name="DC.Format" content="text/xml" scheme="MIME"><meta name="DC.Generator" content="XSLT stylesheet, xt by James Clark"><meta name="DC.Identifier" content=""><meta name="DC.Language" content="en-US"><meta name="DC.Publisher" content="O'Reilly & Associates, Inc."><meta name="DC.Source" content="" scheme="ISBN"><meta name="DC.Subject.Keyword" content=""><meta name="DC.Title" content="Using Hard References"><meta name="DC.Type" content="Text.Monograph"></head><body><!-- START OF BODY --><!-- TOP BANNER --><img src="gifs/smbanner.gif" usemap="#banner-map" border="0" alt="Book Home"><map name="banner-map"><AREA SHAPE="RECT" COORDS="0,0,466,71" HREF="index.htm" ALT="Programming Perl"><AREA SHAPE="RECT" COORDS="467,0,514,18" HREF="jobjects/fsearch.htm" ALT="Search this book"></map><!-- TOP NAV BAR --><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch08_02.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="ch08_01.htm">Chapter 8: References</a></td><td align="right" valign="top" width="172"><a href="ch08_04.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr></table></div><hr width="515" align="left"><!-- SECTION BODY --><h2 class="sect1">8.3. Using Hard References</h2><p><a name="INDEX-2006"></a><a name="INDEX-2007"></a>Just as there are numerous ways to create references, there are alsoseveral ways to use, or <em class="emphasis">dereference</em>, a reference. There is just oneoverriding principle: Perl does no implicit referencing ordereferencing.<a href="#FOOTNOTE-4">[4]</a> When a scalar isholding a reference, it always behaves like a simple scalar. It doesn'tmagically start being an array or hash or subroutine; you have to tellit explicitly to do so, by dereferencing it.</p><blockquote class="footnote"><a name="FOOTNOTE-4"></a><p>[4] We already confessed that this was a smallfib. We're not about to do so again.</p></blockquote><h3 class="sect2">8.3.1. Using a Variable as a Variable Name</h3><p><a name="INDEX-2008"></a>When you encounter a scalar like <tt class="literal">$foo</tt>, you should be thinking "thescalar value of <tt class="literal">foo</tt>." That is, there's a <tt class="literal">foo</tt> entry in the symboltable, and the <tt class="literal">$</tt> funny character is a way of looking at whateverscalar value might be inside. If what's inside is a reference, you canlook inside <em class="emphasis">that</em> (dereferencing <tt class="literal">$foo</tt>) by prepending another funnycharacter. Or looking at it the other way around, you can replace theliteral <tt class="literal">foo</tt> in <tt class="literal">$foo</tt> with a scalar variable that points to theactual referent. This is true of any variable type, so not only is<tt class="literal">$$foo</tt> the scalar value of whatever <tt class="literal">$foo</tt> refers to, but <tt class="literal">@$bar</tt>is the array value of whatever <tt class="literal">$bar</tt> refers to, <tt class="literal">%$glarch</tt> is the hashvalue of whatever <tt class="literal">$glarch</tt> refers to, and so on. The upshotis that you can put an extra funny character on the front of anysimple scalar variable to dereference it:<blockquote><pre class="programlisting">$foo = "three humps";$scalarref = \$foo; # $scalarref is now a reference to $foo$camel_model = $$scalarref; # $camel_model is now "three humps"</pre></blockquote>Here are some other dereferences:<blockquote><pre class="programlisting">$bar = $$scalarref;push(@$arrayref, $filename);$$arrayref[0] = "January"; # Set the first element of @$arrayref@$arrayref[4..6] = qw/May June July/; # Set several elements of @$arrayref%$hashref = (KEY => "RING", BIRD => "SING"); # Initialize whole hash$$hashref{KEY} = "VALUE"; # Set one key/value pair@$hashref{"KEY1","KEY2"} = ("VAL1","VAL2"); # Set two more pairs&$coderef(1,2,3);print $handleref "output\n";</pre></blockquote><a name="INDEX-2009"></a></p><p>This form of dereferencing can only make use of a simple scalarvariable (one without a subscript). That is, dereferencing happens<em class="emphasis">before</em> (or binds tighter than) any array or hashlookups. Let's use some braces to clarify what we mean: an expressionlike <tt class="literal">$$arrayref[0]</tt> is equivalent to<tt class="literal">${$arrayref}[0]</tt> and means the first element of thearray referred to by <tt class="literal">$arrayref</tt>. That is not at allthe same as <tt class="literal">${$arrayref[0]}</tt>, which is dereferencingthe first element of the (probably nonexistent) array named<tt class="literal">@arrayref</tt>. Likewise,<tt class="literal">$$hashref{KEY}</tt> is the same as<tt class="literal">${$hashref}{KEY}</tt>, and has nothing to do with<tt class="literal">${$hashref{KEY}}</tt>, which would be dereferencing anentry in the (probably nonexistent) hash named<tt class="literal">%hashref</tt>. You will be miserable until youunderstand this.</p><p>You can achieve multiple levels of referencing and dereferencing byconcatenating the appropriate funny characters. The following prints"<tt class="literal">howdy</tt>":<blockquote><pre class="programlisting">$refrefref = \\\"howdy";print $$$$refrefref;</pre></blockquote>You can think of the dollar signs as operating right to left. But thebeginning of the chain must still be a simple, unsubscripted scalarvariable. There is, however, a way to get fancier, which we already sneakilyused earlier, and which we'll explain in the next section.</p><h3 class="sect2">8.3.2. Using a BLOCK as a Variable Name</h3><a name="INDEX-2010"></a><p>Not only can you dereference a simple variable name, you can alsodereference the contents of a <em class="replaceable">BLOCK</em>. Anywhere you'd put analphanumeric identifier as part of a variable or subroutine name, youcan replace the identifier with a <em class="replaceable">BLOCK</em> returning a reference of thecorrect type. In other words, the earlier examples could all bedisambiguated like this:<blockquote><pre class="programlisting">$bar = ${$scalarref};push(@{$arrayref}, $filename);${$arrayref}[0] = "January";@{$arrayref}[4..6] = qw/May June July/;${$hashref}{"KEY"} = "VALUE";@{$hashref}{"KEY1","KEY2"} = ("VAL1","VAL2");&{$coderef}(1,2,3);</pre></blockquote>not to mention:<blockquote><pre class="programlisting">$refrefref = \\\"howdy";print ${${${$refrefref}}};</pre></blockquote>Admittedly, it's silly to use the braces in these simple cases, butthe <em class="replaceable">BLOCK</em> can contain any arbitrary expression. In particular, itcan contain subscripted expressions. In the following example,<tt class="literal">$dispatch{$index}</tt> is assumed to contain a reference to a subroutine(sometimes called a "coderef"). The example invokes the subroutine withthree arguments.<blockquote><pre class="programlisting">&{ $dispatch{$index} }(1, 2, 3);</pre></blockquote>Here, the <em class="replaceable">BLOCK</em> is necessary. Without that outer pair of braces,Perl would have treated <tt class="literal">$dispatch</tt> as the coderef instead of<tt class="literal">$dispatch{$index}</tt>.</p><h3 class="sect2">8.3.3. Using the Arrow Operator</h3><p><a name="INDEX-2011"></a><a name="INDEX-2012"></a><a name="INDEX-2013"></a><a name="INDEX-2014"></a><a name="INDEX-2015"></a></p><p>For references to arrays, hashes, or subroutines, a third method ofdereferencing involves the use of the <tt class="literal">-></tt> infixoperator. This form of syntactic sugar that makes it easier toget at individual array or hash elements, or to call a subroutineindirectly.</p><p>The type of the dereference is determined by the right operand, thatis, by what follows directly after the arrow. If the next thing afterthe arrow is a bracket or brace, the left operand is treated as areference to an array or a hash, respectively, to be subscripted by theexpression on the right. If the next thing is a left parenthesis, theleft operand is treated as a reference to a subroutine, to be calledwith whatever parameters you supply in the parentheses on the right.</p><p>Each of these next trios is equivalent, corresponding to the threenotations we've introduced. (We've inserted some spaces to line upequivalent elements.)<blockquote><pre class="programlisting">$ $arrayref [2] = "Dorian"; #1${ $arrayref }[2] = "Dorian"; #2 $arrayref->[2] = "Dorian"; #3$ $hashref {KEY} = "F#major"; #1${ $hashref }{KEY} = "F#major"; #2 $hashref->{KEY} = "F#major"; #3& $coderef (Presto => 192); #1&{ $coderef }(Presto => 192); #2 $coderef->(Presto => 192); #3</pre></blockquote>You can see that the initial funny character is missing from the thirdnotation in each trio. The funny character is guessed at by Perl,which is why it can't be used to dereference complete arrays, complete hashes,or slices of either. As long as you stick with scalar values, though,you can use any expression to the left of the <tt class="literal">-></tt>, includinganother dereference, because multiple arrow operators associate left toright:<blockquote><pre class="programlisting">print $array[3]->{"English"}->[0];</pre></blockquote>You can deduce from this expression that the fourth element of<tt class="literal">@array</tt> is intended to be a hash reference, and the value of the"<tt class="literal">English</tt>" entry in that hash is intended to be an array reference.</p><p>Note that <tt class="literal">$array[3]</tt> and <tt class="literal">$array->[3]</tt> are not the same. Thefirst is talking about the fourth element of <tt class="literal">@array</tt>, while thesecond one is talking about the fourth element of the (possiblyanonymous) array whose reference is contained in <tt class="literal">$array</tt>.</p><p>Suppose now that <tt class="literal">$array[3]</tt> is undefined. The following statementis still legal:<blockquote><pre class="programlisting">$array[3]->{"English"}->[0] = "January";</pre></blockquote>This is one of those cases mentioned earlier in which references springinto existence (or "autovivify") when used as an lvalue (that is, whena value is being assigned to it). If <tt class="literal">$array[3]</tt> wasundefined, it's automatically defined as a hash reference so that wecan set a value for <tt class="literal">$array[3]->{"English"}</tt> in it. Once that'sdone, <tt class="literal">$array[3]->{"English"}</tt> is automatically defined as anarray reference so that we can assign something to the first element inthat array. Note that rvalues are a little different: <tt class="literal">print $array[3]->{"English"}->[0]</tt> only defines <tt class="literal">$array[3]</tt> and <tt class="literal">$array[3]->{"English"}</tt>, not <tt class="literal">$array[3]->{"English"}->[0]</tt>,since the final element is not an lvalue. (The fact that it definesthe first two at all in an rvalue context could be considered a bug.We may fix that someday.)</p><p>The arrow is optional between brackets or braces, or between a closingbracket or brace and a parenthesis for an indirect function call. Soyou can shrink the previous code down to:<blockquote><pre class="programlisting">$dispatch{$index}(1, 2, 3);$array[3]{"English"}[0] = "January";</pre></blockquote>In the case of ordinary arrays, this gives you multidimensional arraysthat are just like C's array:<blockquote><pre class="programlisting">$answer[$x][$y][$z] += 42;</pre></blockquote>Well, okay, not <em class="emphasis">entirely</em> like C's arrays. For one thing, C doesn'tknow how to grow its arrays on demand, while Perl does. Also, some constructs that are similar in the two languages parse differently. In Perl,the following two statements do the same thing:<blockquote><pre class="programlisting">$listref->[2][2] = "hello"; # Pretty clear$$listref[2][2] = "hello"; # A bit confusing</pre></blockquote>This second of these statements may disconcert the C programmer, whois accustomed to using <tt class="literal">*a[i]</tt> to mean "what'spointed to by the <em class="emphasis">i</em>th element of<tt class="literal">a</tt>". But in Perl, the five characters (<tt class="literal">$ @
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -