############################################################
Chapter 13. Does This Job Require a Reference?
############################################################
################13.1. What Is a Reference? What Is a Pointer?
A reference is a variable that refers to another one. In short, it contains the address of another variable.
A hard reference is a scalar variable that holds the address of another type of data.
硬引用(hard reference)是一种标量型变量,其中含有其他类型数据的地址。
A symbolic reference names another variable rather than just pointing to a value.
Typeglobs, variable names preceded by *, are a kind of symbolic reference. They are aliases.
一个符号引用(symbolic reference)能为另一个变量命名,而不是指向其变量值 。typeglobs 就是一种符号引用,
其变量名前缀是一个 * 字符。它们不过是变量的一种别名而已。
Given:*town = *city
Then:$town refers to the scalar $city
@town refers to the array @city
$town{"mayor"} refers to an element of a hash $city{"mayor"}
############The strict Pragma
To protect yourself from inadvertently using symbolic references in a program, use the strict pragma with the refs argument. This causes Perl to check that symbolic references are not used in the program
使用 strict,参数 refs 可以防止误用符号链接。
The strict pragma ensures that the program uses only hard references and, if it doesn't,
will abort during compilation and print an error message as shown in the output of this script.
strict 编译指示保证程序只使用硬引用,否则就在编译时退出程序,并打印如此脚本输出内 容所示的出错信息。
#!/bin/perl
# Program using symbolic references
1 use strict "refs"; #### 这一行,只有注释掉,才能执行下去。
2 $animal="dog";
3 $dog="Lady";
4 print "Your dog is called ${$animal}\n";
5 eval "\$$animal='Lassie';";
6 print "Why don't you call her ${$animal}?\n";
(Output)
Can't use string ("dog") as a SCALAR ref while "strict refs" in use at
symbolic.plx line 4.
#########The Backslash Operator 反斜杠用于创建硬链接
The backslash unary operator is used to create a hard reference
In the following example, $p is the reference. It is assigned the address of the scalar $x.
$p=\$x;
#######Dereferencing the Pointer. 按地址访问指针
If you print the value of a reference (or pointer), you will see an address.
If you want to go to that address and get the value stored there,that is, dereference the pointer,
the pointer must be prefaced by two "funny" symbols:
1: the dollar sign, because the pointer itself is a scalar
2: the symbol representing the type of data to which it points.
如果打印出引用的内容,会得到一个地址。如果想得到这个地址里存的数据,需要两个符号前缀。
1:$ 符号,因为引用(或叫指针)本身也是一个普通标量,需要$符号得到其值。
2: 获得实际指向的数据需要的符号,可能是$,可能是->就看其存的数据是什么类型了。
一个栗子:
$num=5;
$p = \$num;
print 'The address asigned $p is ', $p,"\n";
print " The Value stored at this address is $$p \n";
-------output:
The address asigned $p is SCALAR(0x7ff1c700be70)
The Value stored at this address is 5
又一个栗子,这次数据不只是标量了:
print "--------13.4 Dereferencing--------\n\n";
@toys=qw(Barbie Elmo ZThomas Barney );
$num=@toys;
%games=("Nintendo" => "Wii",
"SOny" => "PlayStation 3",
"microsoft" => "Xbox 360",
);
$ref1=\$num;
$ref2=\@toys;
$ref3=\%games;
print "There are $$ref1 toys.\n";
print "THey are : ",join(",",@$ref2),"\n";
print "Jessica's favourite toy is $ref2->[0].\n";
while (($key,$value)=each(%$ref3))
{
print "$key => $value\n";
}
print "They waited in line for a $ref3->{'Nintendo'}\n";
-- output:
--------13.4 Dereferencing--------
There are 4 toys.
THey are : Barbie,Elmo,ZThomas,Barney
Jessica's favourite toy is Barbie.
SOny => PlayStation 3
microsoft => Xbox 360
Nintendo => Wii
They waited in line for a Wii
#############13.1.3. References and Anonymous Variables
It is not necessary to name a variable to create a reference (pointer) to it. If a variable or
subroutine has no name, it is called anonymous. If an anonymous variable (or subroutine) is
assigned to a scalar, then the scalar is a reference to that variable (subroutine).
The arrow operator (>), also called the infix operator, is used to dereference the
reference to anonymous arrays and hashes. Although not really necessary, the arrow operator
makes the program easier to read.
一个变量想拥有一个引用(或者叫指针),并不一定它本身也必须有一个名字。换言之,它完全可以是匿名的(anonymous).
假如一个匿名的变量被赋予一个标量,那这个标量就作为它的引用了。可以用箭头符号来获得引用指向的变量内容(dereference).
不用也行,不过用了它会更易读。
######Anonymous Arrays 匿名数组
Anonymous array elements are enclosed in square brackets ([]). These square brackets are not to be confused with the square brackets used to subscript an array. Here they are used as an expression to be assigned to a scalar. The brackets will not be interpolated if enclosed within quotes. The arrow (infix) operator is used to get the individual elements of the array.
匿名数组的元素被放在方括号里。换言之,把一些数据放在方括号里,再指给某个标量,就完成了标量作为数据的引用。
这个方括号,可和引用数组元素的方括号不同。方在方括号里,就被当作匿名数组的元素,不会去解释了。用箭头,可以获取数组里的元素
->[]
举起一个栗子:
$arrayref = [ Hello, World, I, love, Figure, Skating ];
print "The value of the reference is \$arrayref \n $arrayref.\n";
print "$arrayref->[1]\n";
print "$$arrayref[1]\n";
print "${$arrayref}[1]\n";
print "@{$arrayref}\n";
-----output:
The value of the reference is $arrayref
ARRAY(0x7fa5f400b710).
World
World
World
Hello World I love Figure Skating
###############Anonymous Hashes 匿名哈希
An anonymous hash is created by using curly braces ({}). You can mix array and hash composers to produce complex data types. These braces are not the same braces that are used when subscripting a hash. The anonymous hash is assigned to a scalar reference.
用波浪括号来创建匿名哈希。也可以把哈希与数组混合起来创建复杂的数据类型。同样赋予标量就构成了标量对匿名哈希的引用。
一个栗子
my $hashref = { "Name"=>"Woody",
"Type"=>"Cowboy"};
print $hashref->{"Name"}, "\n";
print keys %$hashref, "\n";
print values %$hashref, "\n";
-----output:
Woody
NameType
WoodyCowboy
##########Nested Data Structures
The ability to create references (pointers) to anonymous data structures lends
itself to more complex types. For example, you can have hashes nested in hashes
or arrays of hashes or arrays of arrays, etc.
这种为匿名数据类型建立引用的方式,可以产生复杂的类型。哈希数组的,无穷无尽。
Just as with simpler references, the anonymous data structures are dereferenced
by prepending the reference with the correct funny symbol that represents its
data type. For example, if $p is a pointer to a scalar, you can write $$p to
dereference the scalar, and if $p is a pointer to an array, you can write @$p
to dereference the array or $$p[0] to get the first element of the array.
根据不同的数据类型,调用的前置符号可以区别开来使用。比如,$p是个标量的引用,那就可以把$$p写入
一个标量里。$p一个数组的引用,@$p可以写入数组,等等。
##### Lists of lists
A list may contain another list or set of lists, most commonly used to create
a multidimensional array.
一个列表可以包含另一个列表或列表集,一般用来创建多维数组。
一个栗子:
my $arrays_13=['1','2','3',['red','yellow','blue',]];
# three scalar elements, one refernence element.
# to print the three scalar elements:
for ($i=0;$i<3;$i++)
{
print $$arrays_13[$i],"\n";
#print $arrays_13->[$i],"\n"; # The same result
}
#to print the elements of the reference element.
print "\n";
print $$arrays_13[3];
print "\n";
for ($i=0;$i<3;$i++)
{
print $$arrays_13[3]->[$i];
print " --- ";
print $arrays_13->[3]->[$i],"\n";
}
# to print with type funny symbol.
print "\n";
print "@{$arrays_13}\n";
print "@{$arrays_13->[3]}\n";
-- OUTPUT:
1
2
3
ARRAY(0x7fb3350138e8)
red --- red
yellow --- yellow
blue --- blue
1 2 3 ARRAY(0x7fb3350138e8)
red yellow blue
#############13.1.5:reference and subroutines
### anonymous subroutines
An anonymous subroutine is created by using the keyword sub without a subroutine
name. The expression is terminated with a semicolon.
一个栗子:
my $subref= sub {print @_ ;};
&$subref('a','b','c');
print "\n";
---OUTPUT:
abc
Note:The scalar $subref is assigned an anonymous subroutine by reference.
The only function of the subroutine is to print its arguments stored in
the @_ array.
The subroutine is called via its reference and passed three arguments.
########Subroutines and Passing by Reference
When passing arguments to subroutines, they are sent to the subroutine and
stored in the @_ array. If you have a number of arguments, say an array,
a scalar, and another array, the arguments are all flattened out onto the
@_ array. It would be hard to tell where one argument ended and the other
began unless you also passed along the size of each of the arrays, and
then the size would be pushed onto the @_ array and you would have to get
that to determine where the first array ended, and so on. The @_ could
also be quite large if you are passing a 1,000-element array. So, the
easiest and most efficient way to pass arguments is by address
当子程序的参数多,而且类型很杂的时候,传递参数很容易混淆。比如参数里有标量还是数组,传着传着
就会搞不清标量和数组里面各个元素的开始结束位置等。
因此,最简单高效的传参数方式,是采用地址。
一个栗子:
@toys = qw(Buzzlightyear Woody Bo);
$num = @toys;
sub gifts
{
my ($n,$t)=@_;
print "There are $$n gifts\n";
print "They are: @$t\n";
}
gifts(\$num,\@toys);
---OUTPUT:
There are 3 gifts
They are: Buzzlightyear Woody Bo
另一个栗子:
#########exmaple 13.14reference to pass arrays.
my @list1=(1 .. 100);
my @list2=(5,10,15,20);
sub addemup
{
my($arr1,$arr2)=@_;
my ($total);
print $arr1,"\n";
print $arr2,"\n";
foreach $num(@$arr1,@$arr2)
{
$total+=$num;
}
return $total;
}
print "The total is:", &addemup(\@list1,\@list2);
output:
ARRAY(0x7fa5350452a0)
ARRAY(0x7fa535046618)
The total is:5100
注意!!! 上面当我写作:foreach $num($arr1,$arr2),输出是:
ARRAY(0x7fe58f8090a0)
ARRAY(0x7fe58f80b018)
The total is:281247863619768
可见!!!!! @$arr1带入的是数组地址对应的数组,而 $arr存的是地址,而非数组内容!!!切记!!!
###########
13.1.6. Filehandle References
One of the only ways to pass a filehandle to a subroutine is by reference.
You can use a typeglob to create an alias for the filehandle and then use the backslash
to create a reference to the typeglob. Wow...
把文件句柄传递函数参数,可能最好的方法就是通过引用了。
可以先给文件句柄建个别名,然后用反斜号建立引用。嘿嘿嘿...
一个栗子:
open (README,"/etc/passwd") || die;
&readit(\*README);
sub readit{
my ($passwd)=@_;
print "passwd is $passwd.\n";
while (<$passwd>)
{
# print; #打印出所有,所以我屏了。
}
}
SEEK(README,0,0);
OUTPUT:
passwd is GLOB(0x7fd33481d8b8).
Undefined subroutine &main::SEEK called at ./13_reference.pl line 158, line 108.
#############13.1.7 the ref Function
The ref function is used to test for the existence of a reference. If the argument for ref
is a pointer variable, ref returns the type of data the reference points to; e.g.,
SCALAR is returned if the reference points to a scalar, and ARRAY is returned if it
points to an array. If the argument is not a reference, the null string is turned.
Ref用来测试一个引用是否存在。如果测试的参数是个指向某种类型的指针引用,会返回具体类型。就是说,返回标量,数组等等
What Is ReturnedMeaning
REFPointer to pointer
SCALARPointer to scalar
ARRAYPointer to array
HASHPointer to hash
CODEPointer to subroutine
GLOBPointer to typeglob
一个栗子:
sub gifts; # Forward declaration
$num = 5;
$junk = "xxx";
@toys = qw/Budlightyear Woody Thomas/ ;
gifts( \$num, \@toys, $junk );
sub gifts {
my( $n, $t, $j) = @_;
print "\$n is a reference.\n" if ref($n);
print "\$t is a reference.\n" if ref($t);
print "\$j is a not a reference.\n" if ref($j);
printf "\$n is a reference to a %s.\n", ref($n);
printf "\$t is a reference to an %s.\n", ref($t);
}
OUTPUT:
$n is a reference.
$t is a reference.
$n is a reference to a SCALAR.
$t is a reference to an ARRAY.
###### 13.2 What you should know
1: what is the difference between a symbolic and a hard reference.
A hard reference is a scalar variable that holds the address of another
Type of data.
A symbolic reference names another variable rather than just pointing
to a value.
2: what is a typeglob?
Typeglobs, names preceded by *,are a kind of symbolic reference.
They are alias.
3: How do you create a pointer to a hash?
By using a curly braces ({}):
my $refhash={"Name"=>"Christine
"Type"=>"Idiot"};
4:How can you tell a anonymous array from a named array?
$arrayref=[A, B ,C,D]; : anonymous array $arrayref->[1],$$arrayref[1],${$arrayref}[1]
@array="E ,F ,G ,H"; : named array.
5:Show two ways to dereference this pointer
$ptr={'Name'=>"John"};
$$ptr{"Name"}: John
$ptr->{"Name"}
测试代码如下:
my $ptr={'Name'=>"John"};
print $$ptr{"Name"},"\n";
print " The second:",$ptr->{"Name"},"\n";
6:How do you dereference this pinter? $p=\$x;
$$p
测试代码如下:
my $x="Christine is a fool.";
$p=\$x;
print "the content of \$x is:",$$p,"\n";
7:what is meant by a nested hash?
Create more complex types.
8:How do you create a two-dimensional array?
my $matrix = [
[ 0, 2, 4 ],
[ 4, 1, 32 ],
[ 12, 15, 17 ]
] ;
print "Row 3 column 2 is $matrix->[2]->[1].\n";
9:What is the advantage of passing by reference?
When passing arguments to subroutines, they are sent to the subroutine and stored in the @_ array. If you have a number of arguments, say an array, a scalar, and another array, the arguments are all flattened out onto the @_ array. It would be hard to tell where one argument ended and the other began unless you also passed along the size of each of the arrays, and then the size would be pushed onto the @_ array and you would have to get that to determine where the first array ended, and so on. The @_ could also be quite large if you are passing a 1,000-element array. So, the easiest and most efficient way to pass arguments is by address.
10:What is the purpose of the ref function?
The ref function is used to test for the existence of a reference.
######13.3练习 Exercise 13: It's Not Polite to Point!
1: Rewrite tripper (from Chapter 11) to take two pointers as arguments and copy the arguments from the @_ in the subroutine into two my pointer variables.
Write a program called tripper that will ask the user the number of miles he has driven and the amount of gas he used. In the tripper script, write a subroutine called mileage that will calculate and return the user's mileage (miles per gallon). The number of miles driven and the amount of gas used will be passed as arguments. All variables should be my variables. Print the results. Prototype tripper
print "Please input the miles you have travled:\n";
chomp(my $mil=);
$mil_p=\$mil;
print "Please input the gas you have used:\n";
chomp(my $gas=);
$gas_p=\$gas;
print "You have traveled $$mil_p km and used $$gas_p gallons.\n";
sub trigger
{
my ($x,$y)=@_;
$$x / $$y;
#print $x / $y, "\n";
}
my $fin = &trigger($mil_p,$gas_p);
print " Your mileage is : $fin (miles per gallon). \n";
2: Create a hash named employees with the following three keys:
Name
Ssn
Salary
The values will be assigned as undefined (undef is a built-in Perl function). For example: Name => undef,
- Create a reference to the hash.
- Assign values to each of the keys using the reference.
- Print the keys and values of the hash using the built-in each function and the reference.
- Print the value of the reference; in other words, what the reference variable contains, not what it points to.
The code:
#a
my %employees=("Name"=>"undef",
"Ssn"=>undef,
"Salary"=>undef
);
=pod
foreach $key ( keys(%employees) )
{
print "$key+++++++,$employees{$key}\n";
}
=cut
my $ref_array=\%employees;
#b
$$ref_array{Name}="Christine";
$$ref_array{Ssn}="Idiot";
$$ref_array{Salary}=0;
#no required: to list the hash with the reference by me.
foreach $key (keys(%$ref_array))
{
print "$key--- $$ref_array{$key} \n";
}
print "\n";
#c
while (($key_p,$value_p)=each(%$ref_array))
{
print "$key_p,$value_p";
print "\n";
}
print "\n";
#d
print " The reference is : $ref_array\n”;
3:Rewrite the above exercise so the hash is anonymous, and assign the anonymous hash to a reference (pointer). Delete one of the keys from the hash using the reference (use the delete function).
my $ref_array_e3=("Name"=>undef,
"Ssn"=>undef,
"Salary"=>undef,
"Non"=>undef,
);
#assign values:
$$ref_array_e3{Name}="DaLi";
$$ref_array_e3{Ssn}="Fool";
$$ref_array_e3{Salary}=10;
$$ref_array_e3{Non}="Whatever";
# Not needed. to display the content of the hash by me.
while (($key_p_e3,$value_p_e3)=each(%$ref_array_e3))
{
print "$key_p_e3\t....\t$value_p_e3";
print "\n";
}
# to delete
$fordelete_e3=delete $$ref_array_e3{"Non"};
print "The pool deleted one is : $fordelete_e3\n";
# to display
print "Now the rest hash is:\n";
while (($key_p_e3,$value_p_e3)=each(%$ref_array_e3))
{
print "$key_p_e3\t....\t$value_p_e3";
print "\n";
}
4:Write a program that will contain the following structure:
$student = { Name => undef,
SSN => undef,
Friends => [],
Grades => { Science => [],
Math => [],
English => [],
}
};
Use the pointer to assign and display output resembling the following:
Name is John Smith.
Social Security Number is 510-23-1232.
Friends are Tom, Bert, Nick.
Grades are:
Science--100, 83, 77
Math--90, 89, 85
English--76, 77, 65
Codes:
$student = { Name => undef,
SSN => undef,
Friends => [],
Grades => { Science => [],
Math => [],
English => [],
}
};
# To define the values:
$$student{Name}="John Smith";
$$student{SSN}="510-23-1232";
push (@{$student->{Friends}},"Tom","Bert","Nick");
#push ($student->{Friends},"Tom","Bert","Nick"); ### works also!
push ( $student->{Grades}->{Science},100,83,77);
push ( $student->{Grades}->{Math},90,89,85);
push ( $student->{Grades}->{English},76,77,65);
print "------The output is:--------\n";
print "Name is $$student{Name}\n";
print "Social Security Number is $$student{SSN}\n";
print "Friends are : @{$student->{Friends}}\n";
print "Grades are:\nScience-- @{$student->{Grades}->{Science}}\nMath-- @{$student->{Grades}->{Math}}\nEnglish-- @{$student->{Grades}->{English}}\n ";