⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch3.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
$y = $list-&gt;[1];</FONT></TT>

</BLOCKQUOTE>

<P>

Note that the same result of assigning values to <TT><FONT FACE="Courier">$x</FONT></TT>,

<TT><FONT FACE="Courier">$y</FONT></TT>, and <TT><FONT FACE="Courier">$z</FONT></TT>

could be achieved by these two lines of code:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">($x,$y,$z) = @$list;<BR>

$x = $list-&gt;[0];</FONT></TT>

</BLOCKQUOTE>

<P>

This works because you are dereferencing what <TT><FONT FACE="Courier">$list</FONT></TT>

points to and using it as an array, which in turn is assigned

to the list <TT><FONT FACE="Courier">($x,$y,$z)</FONT></TT>. <TT><FONT FACE="Courier">$x</FONT></TT>

is still assigned with the <TT><FONT FACE="Courier">-&gt;</FONT></TT>

operator.

<P>

When working with hashes or arrays, dereferencing by <TT><FONT FACE="Courier">-&gt;</FONT></TT>

is like a dollar-sign (<TT><FONT FACE="Courier">$</FONT></TT>)

dereference. When accessing individual array elements, you are

often faced with writing statements like these two:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$$names[0] = &quot;Kamran&quot;;<BR>

$names-&gt;[0] = &quot;Kamran&quot;;</FONT></TT>

</BLOCKQUOTE>

<P>

Both lines are equivalent. The substring <TT><FONT FACE="Courier">&quot;$names&quot;</FONT></TT>

in the first line has been replaced with the <BR>

<TT><FONT FACE="Courier">-&gt;</FONT></TT> operator to create

the second line. The same procedure can be applied for hash operations:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$$lastnames{&quot;Kamran&quot;} = &quot;Husain&quot;;

<BR>

$lastnames-&gt;{&quot;Kamran&quot;} = &quot;Husain&quot;;</FONT></TT>

</BLOCKQUOTE>

<P>

Arrays in Perl can be created with a fixed size set to the value

of the highest index that is used. They do not have to remain

at this size, though, and can grow on demand. Referencing them

for the first time creates the array and space for the item that

is being indexed in the array. Referencing the array again at

different indexes creates those elements at the indexed references

if they do not already exist. Array references can be created

automatically when first referenced in the left side of an equation.

Using a reference such as <TT><FONT FACE="Courier">$array[$i]</FONT></TT>

creates an array into which you can index with <TT><FONT FACE="Courier">$i</FONT></TT>.

Such is the case with scalars and even multidimensional arrays.

<H2><A NAME="ReferencestoSubroutines"><FONT SIZE=5 COLOR=#FF0000>References

to Subroutines</FONT></A></H2>

<P>

Just as you can reference individual items such as arrays and

scalar variables, you can also point to subroutines. In C, this

would be akin to pointing to a function. To construct such a reference,

you use a statement like this:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$pointer_to_sub = sub { ... <I>declaration

of sub</I> ... } ;</FONT></TT>

</BLOCKQUOTE>

<P>

Note the use of the semicolon at the end of the <TT><FONT FACE="Courier">sub()</FONT></TT>

declaration. The subroutine pointed to by <TT><FONT FACE="Courier">$pointer_to_sub</FONT></TT>

points to the same function reference even if the statement is

placed in a loop. This feature in Perl lets you declare several

anonymous <TT><FONT FACE="Courier">sub()</FONT></TT> functions

in a loop without worrying about the fact that you are chewing

up memory by declaring the same function over and over as you

go about in a loop. As you come around the loop and reassign a

scalar to the <TT><FONT FACE="Courier">sub</FONT></TT>, Perl simply

assigns to the same subroutine declared with the first use of

the <TT><FONT FACE="Courier">sub()</FONT></TT> statement.

<P>

To call a referenced subroutine, use this syntax:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&amp;$pointer_to_sub( parameters );</FONT></TT>

</BLOCKQUOTE>

<P>

This code works because you are dereferencing the <TT><FONT FACE="Courier">$pointer_to_sub</FONT></TT>

and using it with the ampersand (<TT><FONT FACE="Courier">&amp;</FONT></TT>)

as a pointer to a function. The parameters portion may or may

not be empty, depending on how your function is defined. The code

within a sub is simply a declaration created with this statement.

The code within the sub is not executed immediately; however,

it is compiled and set for each use. Consider the script shown

in Listing 3.8.

<HR>

<BLOCKQUOTE>

<B>Listing 3.8. Using references to subroutines.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 <BR>

&nbsp;3 sub print_coor{<BR>

&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

my ($x,$y,$z) = @_;<BR>

&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

print &quot;$x $y $z \n&quot;;<BR>

&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

return $x;};<BR>

&nbsp;7 <BR>

&nbsp;8 $k = 1;<BR>

&nbsp;9 $j = 2;<BR>

10 $m = 4;<BR>

11 $this&nbsp;&nbsp;= print_coor($k,$j,$m);<BR>

12 <BR>

13 $that&nbsp;&nbsp;= print_coor(4,5,6);</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

When you execute this listing, you get the following output:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$ <B>test<BR>

</B>1 2 4<BR>

4 5 6</FONT></TT>

</BLOCKQUOTE>

<P>

This output tells you that assignments of <TT><FONT FACE="Courier">$x</FONT></TT>,

<TT><FONT FACE="Courier">$y</FONT></TT>, and <TT><FONT FACE="Courier">$z</FONT></TT>

were done when the first declaration of <TT><FONT FACE="Courier">print_coor</FONT></TT>

was encountered as a call. Each reference to <TT><FONT FACE="Courier">$this</FONT></TT>

and <TT><FONT FACE="Courier">$that</FONT></TT> now points to a

completely different subroutine, the arguments to which were passed

at runtime.

<H3><A NAME="UsingSubroutineTemplates">Using Subroutine Templates</A>

</H3>

<P>

Subroutines are not limited to returning only data types. They

can return references to other subroutines, too. The returned

subroutines run in the context of the calling routine but are

set up in the original routine that created them. This type of

behavior is caused by the way closure is handled in Perl. Closure

means that if you define a function in one context, it runs in

that particular context in which it was first defined. (A book

on object-oriented programming would provide more information

on closure.)

<P>

To see how closure works, look at Listing 3.9, which you can use

to set up different types of error messages. Such subroutines

are useful in creating templates of all error messages.

<HR>

<BLOCKQUOTE>

<B>Listing 3.9. Using closure.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 <BR>

&nbsp;3 sub errorMsg {<BR>

&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my

$lvl = shift;<BR>

&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

#<BR>

&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

# define the subroutine to run when called.<BR>

&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

#<BR>

&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return

sub {<BR>

&nbsp;9 <BR>

10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

my $msg = shift;&nbsp;&nbsp;# Define the error type now.<BR>

11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

print &quot;Err Level $lvl:$msg\n&quot;; }; # print later.<BR>

12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

<BR>

13 <BR>

14 $severe&nbsp;&nbsp;= errorMsg(&quot;Severe&quot;);<BR>

15 $fatal = errorMsg(&quot;Fatal&quot;);<BR>

16 $annoy = errorMsg(&quot;Annoying&quot;);<BR>

17 <BR>

18 &amp;$severe(&quot;Divide by zero&quot;);<BR>

19 &amp;$fatal(&quot;Did you forget to use a semi-colon?&quot;);

<BR>

20 &amp;$annoy(&quot;Uninitialized variable in use&quot;);</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

The subroutine <TT><FONT FACE="Courier">errorMsg</FONT></TT> declared

here uses a local variable called <TT><FONT FACE="Courier">lvl</FONT></TT>.

After this declaration, <TT><FONT FACE="Courier">errorMsg</FONT></TT>

uses <TT><FONT FACE="Courier">$lvl</FONT></TT> in the subroutine

it returns back to the caller. Therefore, the value of <TT><FONT FACE="Courier">$lvl</FONT></TT>

is set in the context when the subroutine <TT><FONT FACE="Courier">errorMsg</FONT></TT>

is first called, even though the keyword <TT><FONT FACE="Courier">my</FONT></TT>

is used. Therefore, the following three calls set up three different

<TT><FONT FACE="Courier">$lvl</FONT></TT> variable values, each

in their own context:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$severe&nbsp;&nbsp;= errorMsg(&quot;Severe&quot;);

<BR>

$fatal&nbsp;&nbsp;&nbsp;= errorMsg(&quot;Fatal&quot;);<BR>

$annoy&nbsp;&nbsp;&nbsp;= errorMsg(&quot;Annoying&quot;);</FONT></TT>

</BLOCKQUOTE>

<P>

Now, when the reference to a subroutine is returned by the call

to the <TT><FONT FACE="Courier">errorMsg</FONT></TT> function

in each of the lines above, the value of <TT><FONT FACE="Courier">$lvl</FONT></TT>

within the <TT><FONT FACE="Courier">errorMsg</FONT></TT> function

is retained for each context in which <TT><FONT FACE="Courier">$lvl</FONT></TT>

was declared. Thus, the <TT><FONT FACE="Courier">$msg</FONT></TT>

value from the referenced call is used, but the value of <TT><FONT FACE="Courier">$lvl</FONT></TT>

is the value that was first set in the actual creation of the

function.

<P>

Sound confusing? It is. This is primarily the reason why you do

not see this type of code in most Perl programs.

<H2><A NAME="ImplementingStateMachines"><FONT SIZE=5 COLOR=#FF0000>Implementing

State Machines</FONT></A></H2>

<P>

Using arrays and pointers to subroutines, you can come up with

some nifty applications. Consider using an array of pointers to

subroutines to implement a state machine. Listing 3.10 provides

an example of a simple, asynchronous state machine.

<HR>

<BLOCKQUOTE>

<B>Listing 3.10. A simple, asynchronous state machine.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 # --------------------------------------------------------------

<BR>

&nbsp;3 # Define each state

as subroutine. Then create a<BR>

&nbsp;4 # reference to each subroutine. We have four states here.

<BR>

&nbsp;5 # --------------------------------------------------------------

<BR>

&nbsp;6 $s0 = sub {<BR>

&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local

$a = $_[0];<BR>

&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print

&quot;State 0 processing $a \n&quot;;<BR>

&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '0')&nbsp;&nbsp;{ return(0); }<BR>

10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '1')&nbsp;&nbsp;{ return(1); }<BR>

11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '2')&nbsp;&nbsp;{ return(2); }<BR>

12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '3')&nbsp;&nbsp;{ return(3); }<BR>

13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return

0;<BR>

14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};

<BR>

15 # --------------------------------------------------------------

<BR>

16 $s1 = sub {<BR>

17&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local

$a = shift @_;<BR>

18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print

&quot;State 1 processing $a \n&quot;;<BR>

19&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '0')&nbsp;&nbsp;{ return(0); }<BR>

20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '1')&nbsp;&nbsp;{ return(1); }<BR>

21&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '2')&nbsp;&nbsp;{ return(2); }<BR>

22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '3')&nbsp;&nbsp;{ return(3); }<BR>

23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return

1;<BR>

24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};

<BR>

25 # --------------------------------------------------------------

<BR>

26 $s2 = sub {<BR>

27&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;local

$a = $_[0];<BR>

28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print

&quot;State 2 processing $a \n&quot;;<BR>

29&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '0')&nbsp;&nbsp;{ return(0); }<BR>

30&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '1')&nbsp;&nbsp;{ return(1); }<BR>

⌨️ 快捷键说明

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