📄 ch13_16.htm
字号:
><ACLASS="title"NAME="ch13-chap13_tie_1">Tie Example: Make a Hash That Always Appends</A></H3><PCLASS="para"><ACLASS="indexterm"NAME="ch13-idx-1000004692-0"></A>The class shown below produces a hash whose keys accumulate in an array.</P><PRECLASS="programlisting">#!/usr/bin/perl # <ACLASS="indexterm"NAME="ch13-idx-1000004713-0"></A>appendhash_demo - show magic hash that autoappendsuse Tie::AppendHash;tie %tab, 'Tie::AppendHash';$tab{beer} = "guinness";$tab{food} = "potatoes";$tab{food} = "peas";while (my($k, $v) = each %tab) { print "$k => [@$v]\n";}</PRE><PCLASS="para">Here is the result:</P><PRECLASS="programlisting"><BCLASS="emphasis.bold">food => [potatoes peas]</B><BCLASS="emphasis.bold">beer => [guinness]</B></PRE><PCLASS="para">To make this class easy, we will use the boilerplate hash tying module from the standard distribution, shown in <ACLASS="xref"HREF="ch13_16.htm#ch13-15202"TITLE="Tie::AppendHash">Example 13.5</A>. To do this, we load the Tie::Hash module and then inherit from the Tie::StdHash class. (Yes, those are different names. The file <EMCLASS="emphasis">Tie/Hash.pm</EM> provides both the Tie::Hash and Tie::StdHash classes, which are slightly different.)</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch13-15202">Example 13.5: Tie::AppendHash</A></H4><PRECLASS="programlisting">package Tie::AppendHash;use strict;use Tie::Hash;use Carp;use vars qw(@ISA);@ISA = qw(Tie::StdHash);sub STORE { my ($self, $key, $value) = @_; push @{$self->{$key}}, $value;} 1;</PRE></DIV></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-chap13_tie_2">Tie Example: Case-Insensitive Hash</A></H3><PCLASS="para"><ACLASS="indexterm"NAME="ch13-idx-1000006808-0"></A>Here's a fancier hash tie called Tie::Folded. It provides a hash with case-insensitive keys.</P><PRECLASS="programlisting">#!/usr/bin/perl # <ACLASS="indexterm"NAME="ch13-idx-1000004715-0"></A>folded_demo - demo hash that magically folds caseuse Tie::Folded;tie %tab, 'Tie::Folded';$tab{VILLAIN} = "big "; $tab{herOine} = "red riding hood";$tab{villain} .= "bad wolf"; while ( my($k, $v) = each %tab ) { print "$k is $v\n";}</PRE><PCLASS="para">The following is the output of this demo program:</P><PRECLASS="programlisting"><BCLASS="emphasis.bold">heroine is red riding hood</B><BCLASS="emphasis.bold">villain is big bad wolf</B></PRE><PCLASS="para">Because we have to trap more accesses, the class in <ACLASS="xref"HREF="ch13_16.htm#ch13-20857"TITLE="Tie::Folded">Example 13.6</A> is slightly more complicated than the one in <ACLASS="xref"HREF="ch13_16.htm#ch13-15202"TITLE="Tie::AppendHash">Example 13.5</A>.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch13-20857">Example 13.6: Tie::Folded</A></H4><PRECLASS="programlisting">package Tie::Folded;use strict;use Tie::Hash;use vars qw(@ISA);@ISA = qw(Tie::StdHash);sub STORE { my ($self, $key, $value) = @_; return $self->{lc $key} = $value; } sub FETCH { my ($self, $key) = @_; return $self->{lc $key};} sub EXISTS { my ($self, $key) = @_; return exists $self->{lc $key};} sub DEFINED { my ($self, $key) = @_; return defined $self->{lc $key};} 1;<ACLASS="indexterm"NAME="ch13-idx-1000006068-0"></A></PRE></DIV></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-chap13_tie_3">Tie Example: Hash That Allows Look-Ups by Key or Value</A></H3><PCLASS="para">Here is a hash that lets you look up members by key or by value. It does this by having a store method that not only uses the key to store the value, it also uses the value to store the key.</P><PCLASS="para">Normally there could be a problem if the value being stored were a reference, since you can't normally use a <ACLASS="indexterm"NAME="ch13-idx-1000006817-0"></A>reference as a key. The standard distribution comes with the Tie::RefHash class that avoids this problem. We'll inherit from it so that we can also avoid this difficulty.</P><PRECLASS="programlisting">#!/usr/bin/perl -w# <ACLASS="indexterm"NAME="ch13-idx-1000004717-0"></A>revhash_demo - show hash that permits key *or* value lookupsuse strict;use Tie::RevHash;my %tab;tie %tab, 'Tie::RevHash';%tab = qw{ Red Rojo Blue Azul Green Verde};$tab{EVIL} = [ "No way!", "Way!!" ];while ( my($k, $v) = each %tab ) { print ref($k) ? "[@$k]" : $k, " => ", ref($v) ? "[@$v]" : $v, "\n";} </PRE><PCLASS="para">When run, <ICLASS="filename">revhash_demo</I> produces this:</P><PRECLASS="programlisting"><BCLASS="emphasis.bold">[No way! Way!!] => EVIL</B><BCLASS="emphasis.bold">EVIL => [No way! Way!!]</B><BCLASS="emphasis.bold">Blue => Azul</B><BCLASS="emphasis.bold">Green => Verde</B><BCLASS="emphasis.bold">Rojo => Red</B><BCLASS="emphasis.bold">Red => Rojo</B><BCLASS="emphasis.bold">Azul => Blue</B><BCLASS="emphasis.bold">Verde => Green</B></PRE><PCLASS="para">The module is shown in <ACLASS="xref"HREF="ch13_16.htm#ch13-33223"TITLE="Tie::RevHash">Example 13.7</A>. Notice how small it is!</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch13-33223">Example 13.7: Tie::RevHash</A></H4><PRECLASS="programlisting">package Tie::RevHash;use Tie::RefHash;use vars qw(@ISA);@ISA = qw(Tie::RefHash);sub STORE { my ($self, $key, $value) = @_; $self->SUPER::STORE($key, $value); $self->SUPER::STORE($value, $key);}sub DELETE { my ($self, $key) = @_; my $value = $self->SUPER::FETCH($key); $self->SUPER::DELETE($key); $self->SUPER::DELETE($value);}1;<ACLASS="indexterm"NAME="ch13-idx-1000006111-0"></A></PRE></DIV></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-chap13_tie_4">Tie Example: Handle That Counts Access</A></H3><PCLASS="para"><ACLASS="indexterm"NAME="ch13-idx-1000004700-0"></A>Here's an example of tying a filehandle:</P><PRECLASS="programlisting">use Counter;tie *CH, 'Counter';while (<CH>) { print "Got $_\n";} </PRE><PCLASS="para">When run, that program keeps printing <CODECLASS="literal">Got</CODE> <CODECLASS="literal">1</CODE>, <CODECLASS="literal">Got</CODE> <CODECLASS="literal">2</CODE>, and so on until the universe collapses, you hit an interrupt, or your computer reboots, whichever comes first. Its simple implementation is shown in <ACLASS="xref"HREF="ch13_16.htm#ch13-36823"TITLE="Counter">Example 13.8</A>.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch13-36823">Example 13.8: Counter</A></H4><PRECLASS="programlisting">package Counter;sub TIEHANDLE { my $class = shift; my $start = shift; return bless \$start => $class;} sub READLINE { my $self = shift; return ++$$self;} 1;</PRE></DIV></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-chap13_tie_5">Tie Example: Multiple Sink Filehandles</A></H3><PCLASS="para">Finally, here's an example of a tied handle that implements a <EMCLASS="emphasis">tee</EM>-like functionality by twinning standard out and standard error:</P><PRECLASS="programlisting">use Tie::Tee;tie *TEE, 'Tie::Tee', *STDOUT, *STDERR;print TEE "This line goes both places.\n";</PRE><PCLASS="para">Or, more elaborately:</P><PRECLASS="programlisting">#!/usr/bin/perl# demo_tieteeuse Tie::Tee;use Symbol;@handles = (*STDOUT);for $i ( 1 .. 10 ) { push(@handles, $handle = gensym()); open($handle, ">/tmp/teetest.$i");} tie *TEE, 'Tie::Tee', @handles;print TEE "This lines goes many places.\n";</PRE><PCLASS="para">The <EMCLASS="emphasis">Tie/Tee.pm</EM> file is shown in <ACLASS="xref"HREF="ch13_16.htm#ch13-36731"TITLE="Tie::Tee">Example 13.9</A>.</P><DIVCLASS="example"><H4CLASS="example"><ACLASS="title"NAME="ch13-36731">Example 13.9: Tie::Tee</A></H4><PRECLASS="programlisting">package Tie::Tee;sub TIEHANDLE { my $class = shift; my $handles = [@_]; bless $handles, $class; return $handles;}sub PRINT { my $href = shift; my $handle; my $success = 0; foreach $handle (@$href) { $success += print $handle @_; } return $success == @$href;} 1;<ACLASS="indexterm"NAME="ch13-idx-1000006714-0"></A><ACLASS="indexterm"NAME="ch13-idx-1000006714-1"></A><ACLASS="indexterm"NAME="ch13-idx-1000006714-2"></A><ACLASS="indexterm"NAME="ch13-idx-1000006714-3"></A><ACLASS="indexterm"NAME="ch13-idx-1000006714-4"></A></PRE></DIV></DIV><DIVCLASS="sect2"><H3CLASS="sect2"><ACLASS="title"NAME="ch13-pgfId-1000000533">See Also</A></H3><PCLASS="para">The <CODECLASS="literal">tie</CODE> function in <ICLASS="filename">perlfunc </I>(1); <ICLASS="filename">perltie </I>(1); the section on "Using Tied Variables" in <ACLASS="olink"HREF="../prog/ch05_01.htm">Chapter 5</A> of <ACLASS="citetitle"HREF="../prog/index.htm"TITLE="Programming Perl"><CITECLASS="citetitle">Programming Perl</CITE></A></P></DIV></DIV><DIVCLASS="htmlnav"><P></P><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><TABLEWIDTH="684"BORDER="0"CELLSPACING="0"CELLPADDING="0"><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228"><ACLASS="sect1"HREF="ch13_15.htm"TITLE="13.14. Overloading Operators"><IMGSRC="../gifs/txtpreva.gif"ALT="Previous: 13.14. Overloading Operators"BORDER="0"></A></TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="book"HREF="index.htm"TITLE="Perl Cookbook"><IMGSRC="../gifs/txthome.gif"ALT="Perl Cookbook"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228"><ACLASS="chapter"HREF="ch14_01.htm"TITLE="14. Database Access"><IMGSRC="../gifs/txtnexta.gif"ALT="Next: 14. Database Access"BORDER="0"></A></TD></TR><TR><TDALIGN="LEFT"VALIGN="TOP"WIDTH="228">13.14. Overloading Operators</TD><TDALIGN="CENTER"VALIGN="TOP"WIDTH="228"><ACLASS="index"HREF="index/index.htm"TITLE="Book Index"><IMGSRC="../gifs/index.gif"ALT="Book Index"BORDER="0"></A></TD><TDALIGN="RIGHT"VALIGN="TOP"WIDTH="228">14. Database Access</TD></TR></TABLE><HRALIGN="LEFT"WIDTH="684"TITLE="footer"><FONTSIZE="-1"></DIV<!-- LIBRARY NAV BAR --> <img src="../gifs/smnavbar.gif" usemap="#library-map" border="0" alt="Library Navigation Links"><p> <a href="copyrght.htm">Copyright © 2002</a> O'Reilly & Associates. All rights reserved.</font> </p> <map name="library-map"> <area shape="rect" coords="1,0,85,94" href="../index.htm"><area shape="rect" coords="86,1,178,103" href="../lwp/index.htm"><area shape="rect" coords="180,0,265,103" href="../lperl/index.htm"><area shape="rect" coords="267,0,353,105" href="../perlnut/index.htm"><area shape="rect" coords="354,1,446,115" href="../prog/index.htm"><area shape="rect" coords="448,0,526,132" href="../tk/index.htm"><area shape="rect" coords="528,1,615,119" href="../cookbook/index.htm"><area shape="rect" coords="617,0,690,135" href="../pxml/index.htm"></map> </BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -