perlref.html

来自「perl教程」· HTML 代码 · 共 733 行 · 第 1/5 页

HTML
733
字号
<pre>
    <span class="variable">$struct</span> <span class="operator">=</span> <span class="operator">[{</span><span class="string">foo</span> <span class="operator">=&gt;</span> <span class="number">1</span><span class="operator">,</span> <span class="string">bar</span> <span class="operator">=&gt;</span> <span class="number">2</span><span class="operator">}</span><span class="operator">,</span> <span class="string">"FOO"</span><span class="operator">,</span> <span class="string">"BAR"</span><span class="operator">]</span><span class="operator">;</span>
</pre>
<pre>
    <span class="variable">$struct</span><span class="operator">-&gt;</span><span class="operator">{</span><span class="string">foo</span><span class="operator">}</span><span class="operator">;</span>  <span class="comment"># same as $struct-&gt;[1], i.e. "FOO"</span>
    <span class="variable">$struct</span><span class="operator">-&gt;</span><span class="operator">{</span><span class="string">bar</span><span class="operator">}</span><span class="operator">;</span>  <span class="comment"># same as $struct-&gt;[2], i.e. "BAR"</span>
</pre>
<pre>
    <span class="keyword">keys</span> <span class="variable">%$struct</span><span class="operator">;</span>   <span class="comment"># will return ("foo", "bar") in some order</span>
    <span class="keyword">values</span> <span class="variable">%$struct</span><span class="operator">;</span> <span class="comment"># will return ("FOO", "BAR") in same some order</span>
</pre>
<pre>
    <span class="keyword">while</span> <span class="operator">(</span><span class="keyword">my</span><span class="operator">(</span><span class="variable">$k</span><span class="operator">,</span><span class="variable">$v</span><span class="operator">)</span> <span class="operator">=</span> <span class="keyword">each</span> <span class="variable">%$struct</span><span class="operator">)</span> <span class="operator">{</span>
       <span class="keyword">print</span> <span class="string">"$k =&gt; $v\n"</span><span class="operator">;</span>
    <span class="operator">}</span>
</pre>
<p>Perl will raise an exception if you try to access nonexistent fields.
To avoid inconsistencies, always use the fields::phash() function
provided by the <code>fields</code> pragma.</p>
<pre>
    <span class="keyword">use</span> <span class="variable">fields</span><span class="operator">;</span>
    <span class="variable">$pseudohash</span> <span class="operator">=</span> <span class="variable">fields::phash</span><span class="operator">(</span><span class="string">foo</span> <span class="operator">=&gt;</span> <span class="string">"FOO"</span><span class="operator">,</span> <span class="string">bar</span> <span class="operator">=&gt;</span> <span class="string">"BAR"</span><span class="operator">);</span>
</pre>
<p>For better performance, Perl can also do the translation from field
names to array indices at compile time for typed object references.
See <a href="../../lib/fields.html">the fields manpage</a>.</p>
<p>There are two ways to check for the existence of a key in a
pseudo-hash.  The first is to use exists().  This checks to see if the
given field has ever been set.  It acts this way to match the behavior
of a regular hash.  For instance:</p>
<pre>
    <span class="keyword">use</span> <span class="variable">fields</span><span class="operator">;</span>
    <span class="variable">$phash</span> <span class="operator">=</span> <span class="variable">fields::phash</span><span class="operator">(</span><span class="operator">[</span><span class="string">qw(foo bar pants)</span><span class="operator">]</span><span class="operator">,</span> <span class="operator">[</span><span class="string">'FOO'</span><span class="operator">]</span><span class="operator">);</span>
    <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">{</span><span class="string">pants</span><span class="operator">}</span> <span class="operator">=</span> <span class="keyword">undef</span><span class="operator">;</span>
</pre>
<pre>
    <span class="keyword">print</span> <span class="keyword">exists</span> <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">{</span><span class="string">foo</span><span class="operator">}</span><span class="operator">;</span>    <span class="comment"># true, 'foo' was set in the declaration</span>
    <span class="keyword">print</span> <span class="keyword">exists</span> <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">{</span><span class="string">bar</span><span class="operator">}</span><span class="operator">;</span>    <span class="comment"># false, 'bar' has not been used.</span>
    <span class="keyword">print</span> <span class="keyword">exists</span> <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">{</span><span class="string">pants</span><span class="operator">}</span><span class="operator">;</span>  <span class="comment"># true, your 'pants' have been touched</span>
</pre>
<p>The second is to use <a href="../../lib/Pod/perlfunc.html#item_exists"><code>exists()</code></a> on the hash reference sitting in the
first array element.  This checks to see if the given key is a valid
field in the pseudo-hash.</p>
<pre>
    <span class="keyword">print</span> <span class="keyword">exists</span> <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">[</span><span class="number">0</span><span class="operator">]</span><span class="operator">{</span><span class="variable">bar</span><span class="operator">};</span>      <span class="comment"># true, 'bar' is a valid field</span>
    <span class="keyword">print</span> <span class="keyword">exists</span> <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">[</span><span class="number">0</span><span class="operator">]</span><span class="operator">{</span><span class="variable">shoes</span><span class="operator">};</span><span class="comment"># false, 'shoes' can't be used</span>
</pre>
<p><a href="../../lib/Pod/perlfunc.html#item_delete"><code>delete()</code></a> on a pseudo-hash element only deletes the value corresponding
to the key, not the key itself.  To delete the key, you'll have to
explicitly delete it from the first hash element.</p>
<pre>
    <span class="keyword">print</span> <span class="keyword">delete</span> <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">{</span><span class="string">foo</span><span class="operator">}</span><span class="operator">;</span>     <span class="comment"># prints $phash-&gt;[1], "FOO"</span>
    <span class="keyword">print</span> <span class="keyword">exists</span> <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">{</span><span class="string">foo</span><span class="operator">}</span><span class="operator">;</span>     <span class="comment"># false</span>
    <span class="keyword">print</span> <span class="keyword">exists</span> <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">[</span><span class="number">0</span><span class="operator">]</span><span class="operator">{</span><span class="variable">foo</span><span class="operator">};</span>  <span class="comment"># true, key still exists</span>
    <span class="keyword">print</span> <span class="keyword">delete</span> <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">[</span><span class="number">0</span><span class="operator">]</span><span class="operator">{</span><span class="variable">foo</span><span class="operator">};</span>  <span class="comment"># now key is gone</span>
    <span class="keyword">print</span> <span class="variable">$phash</span><span class="operator">-&gt;</span><span class="operator">{</span><span class="string">foo</span><span class="operator">}</span><span class="operator">;</span>            <span class="comment"># runtime exception</span>
</pre>
<p>
</p>
<h2><a name="function_templates">Function Templates</a></h2>
<p>As explained above, an anonymous function with access to the lexical
variables visible when that function was compiled, creates a closure.  It
retains access to those variables even though it doesn't get run until
later, such as in a signal handler or a Tk callback.</p>
<p>Using a closure as a function template allows us to generate many functions
that act similarly.  Suppose you wanted functions named after the colors
that generated HTML font changes for the various colors:</p>
<pre>
    <span class="keyword">print</span> <span class="string">"Be "</span><span class="operator">,</span> <span class="variable">red</span><span class="operator">(</span><span class="string">"careful"</span><span class="operator">),</span> <span class="string">"with that "</span><span class="operator">,</span> <span class="variable">green</span><span class="operator">(</span><span class="string">"light"</span><span class="operator">);</span>
</pre>
<p>The <code>red()</code> and <code>green()</code> functions would be similar.  To create these,
we'll assign a closure to a typeglob of the name of the function we're
trying to build.</p>
<pre>
    <span class="variable">@colors</span> <span class="operator">=</span> <span class="string">qw(red blue green yellow orange purple violet)</span><span class="operator">;</span>
    <span class="keyword">for</span> <span class="keyword">my</span> <span class="variable">$name</span> <span class="operator">(</span><span class="variable">@colors</span><span class="operator">)</span> <span class="operator">{</span>
        <span class="keyword">no</span> <span class="variable">strict</span> <span class="string">'refs'</span><span class="operator">;</span>       <span class="comment"># allow symbol table manipulation</span>
        <span class="operator">*</span><span class="variable">$name</span> <span class="operator">=</span> <span class="variable">*</span><span class="operator">{</span><span class="keyword">uc</span> <span class="variable">$name</span><span class="operator">}</span> <span class="operator">=</span> <span class="keyword">sub</span><span class="variable"> </span><span class="operator">{</span> <span class="string">"&lt;FONT COLOR='$name'&gt;@_&lt;/FONT&gt;"</span> <span class="operator">};</span>
    <span class="operator">}</span>
</pre>
<p>Now all those different functions appear to exist independently.  You can
call red(), RED(), blue(), BLUE(), green(), etc.  This technique saves on
both compile time and memory use, and is less error-prone as well, since
syntax checks happen at compile time.  It's critical that any variables in
the anonymous subroutine be lexicals in order to create a proper closure.
That's the reasons for the <a href="../../lib/Pod/perlfunc.html#item_my"><code>my</code></a> on the loop iteration variable.</p>
<p>This is one of the only places where giving a prototype to a closure makes
much sense.  If you wanted to impose scalar context on the arguments of
these functions (probably not a wise idea for this particular example),
you could have written it this way instead:</p>
<pre>
    <span class="operator">*</span><span class="variable">$name</span> <span class="operator">=</span> <span class="keyword">sub</span><span class="variable"> </span><span class="operator">(</span>$<span class="operator">)</span> <span class="operator">{</span> <span class="string">"&lt;FONT COLOR='$name'&gt;$_[0]&lt;/FONT&gt;"</span> <span class="operator">};</span>
</pre>
<p>However, since prototype checking happens at compile time, the assignment
above happens too late to be of much use.  You could address this by
putting the whole loop of assignments within a BEGIN block, forcing it
to occur during compilation.</p>
<p>Access to lexicals that change over type--like those in the <code>for</code> loop
above--only works with closures, not general subroutines.  In the general
case, then, named subroutines do not nest properly, although anonymous
ones do. Thus is because named subroutines are created (and capture any
outer lexicals) only once at compile time, whereas anonymous subroutines
get to capture each time you execute the 'sub' operator.  If you are
accustomed to using nested subroutines in other programming languages with
their own private variables, you'll have to work at it a bit in Perl.  The
intuitive coding of this type of thing incurs mysterious warnings about
&quot;will not stay shared&quot;.  For example, this won't work:</p>
<pre>
    <span class="keyword">sub</span><span class="variable"> outer </span><span class="operator">{</span>
        <span class="keyword">my</span> <span class="variable">$x</span> <span class="operator">=</span> <span class="variable">$_</span><span class="operator">[</span><span class="number">0</span><span class="operator">]</span> <span class="operator">+</span> <span class="number">35</span><span class="operator">;</span>
        <span class="keyword">sub</span><span class="variable"> inner </span><span class="operator">{</span> <span class="keyword">return</span> <span class="variable">$x</span> <span class="operator">*</span> <span class="number">19</span> <span class="operator">}</span>   <span class="comment"># WRONG</span>
        <span class="keyword">return</span> <span class="variable">$x</span> <span class="operator">+</span> <span class="variable">inner</span><span class="operator">();</span>
    <span class="operator">}</span>
</pre>
<p>A work-around is the following:</p>
<pre>
    <span class="keyword">sub</span><span class="variable"> outer </span><span class="operator">{</span>
        <span class="keyword">my</span> <span class="variable">$x</span> <span class="operator">=</span> <span class="variable">$_</span><span class="operator">[</span><span class="number">0</span><span class="operator">]</span> <span class="operator">+</span> <span class="number">35</span><span class="operator">;</span>
        <span class="keyword">local</span> <span class="variable">*inner</span> <span class="operator">=</span> <span class="keyword">sub</span><span class="variable"> </span><span class="operator">{</span> <span class="keyword">return</span> <span class="variable">$x</span> <span class="operator">*</span> <span class="number">19</span> <span class="operator">};</span>
        <span class="keyword">return</span> <span class="variable">$x</span> <span class="operator">+</span> <span class="variable">inner</span><span class="operator">();</span>
    <span class="operator">}</span>
</pre>
<p>Now <code>inner()</code> can only be called from within outer(), because of the
temporary assignments of the closure (anonymous subroutine).  But when
it does, it has normal access to the lexical variable $x from the scope
of outer().</p>
<p>This has the interesting effect of creating a function local to another
function, something not normally supported in Perl.</p>
<p>
</p>
<hr />
<h1><a name="warning">WARNING</a></h1>
<p>You may not (usefully) use a reference as the key to a hash.  It will be
converted into a string:</p>
<pre>
    <span class="variable">$x</span><span class="operator">{</span> <span class="operator">\</span><span class="variable">$a</span> <span class="operator">}</span> <span class="operator">=</span> <span class="variable">$a</span><span class="operator">;</span>
</pre>
<p>If you try to dereference the key, it won't do a hard dereference, and
you won't accomplish what you're attempting.  You might want to do something
more like</p>
<pre>
    <span class="variable">$r</span> <span class="operator">=</span> <span class="operator">\</span><span class="variable">@a</span><span class="operator">;</span>
    <span class="variable">$x</span><span class="operator">{</span> <span class="variable">$r</span> <span class="operator">}</span> <span class="operator">=</span> <span class="variable">$r</span><span class="operator">;</span>
</pre>
<p>And then at least you 

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?