和口语类似,Perl语言由几个互相关联的小部分组成。
但是也有不同,口语能在概念模糊甚至轻微误解的情况下进行交流,但Perl做不到,计算机语言要求必须准确。得益于Perl的设计特点,你无需掌握Perl语言的所有细节就能写出有用的代码,但你必须明白Perl各个部分之间是如何协同工作的。
名字
名字在Perl程序里随处可见,你可以为变量、函数、包、类甚至文件句柄取个名字,这样就能更好的识别它。Perl里规定有效的名字都是以字母或下划线开头,可以包含字母、数字、和下划线。当启用utf8后,还可以使用UTF-8字符作为名字。
这些名字都是有效的:
my $name;
my @_private_names;
my %Names_to_Addresses;
sub anAwkwardName3;
# with use utf8; enabled
package Ingy::Döt::Net;
而这些是无效的命名:
my $invalid name;
my @3;
my %~flags;
package a-lisp-style-name;
名字的存在主要是为了方便程序员。起个好名字能帮助程序员区分和理解程序(提高可读性)。Perl也允许你以动态生成和外部输入的内容作为名字,这个特性得益于Perl的“符号查找”机制。“符号查找”机制提供了高度灵活性,但是却也带来了安全风险,而且还会让降低代码可读性,所以不建议使用。
名字和记号
变量的名字总会带着一个记号,这个记号标识了变量值的类型。
标量类型用美元符号标识;数组类型用@符号标识;哈希类型用%标识:
my $scalar;
my @array;
my %hash;
不同记号有不同的命名空间,所以可以用不同的记号声明相同名字的变量,但是代表的东西可不一样啊。例如:
my ($bad_name, @bad_name, %bad_name);
这表示了3个完全不同的变量:一个标量,一个数组,一个哈希。Perl不会搞错,但是读代码的人却可能会搞错,所以不建议这样使用。
使用什么记号,取决于你期望什么。如果你要访问数组或哈希中的单个值就使用美元记号($):
my $hash_element = $hash{ $key };
my $array_element = $array[ $index ]
$hash{ $key } = 'value';
$array[ $index ] = 'item';
如果你要访问数组或哈希中的多个值,就必须使用@记号,这个操作也叫做切片:
my @hash_elements = @hash{ @keys };
my @array_elements = @array[ @indexes ];
名字空间
名字多了就容易重复,为了管理名字,Perl提供了一个叫命名空间的机制。命名空间就是一个全局唯一的名称集合。命名空间分层组织,不同层次使用双冒号(::)连接。如:
DessertShop::IceCream 表示甜点商店(DessertShop)里冰激凌(IceCream)的命名空间
在对应命名空间内,我们可以直接使用层级中成员的名字进行访问;但在对应的命名空间外,则必须使用完整的名字(完全限定名)来访问。
比如若处于DessertShop::IceCream
的名字空间中,(假设里面有个名叫add_sprinkles()函数),我们可以直接使用add_sprinkles()
调用该函数。如果不在这个命名空间内则需要使用完全限定名DessertShop::IceCream::add_sprinkles()
来调用该函数。
一个包就代表一层命名空间。Perl约定所有包的名字都是以大写字母开头。
Perl中所有的命名空间都是全局可见的。通过使用完整名字可以访问任何命名空间。
变量
在Perl里,一个变量就是一个值容器。我们当然可以不使用变量,去直接操作值,但是绝大多数程序都会使用变量来抽象逻辑。用变量来代表值会让程序更有效,更抽象。
比如我们会用a,b,c来代表三角形的三边长来表述勾股定理,而不是使用具体数值。
变量作用域
所谓变量的作用域就是指在这个范围内你可以访问该变量。你遇到的作用域通常就是指词法作用域,词法作用域是代码块(花括号{ }之间),或者是整个文件:
package Store::Toy;
my $discount = 0.10;
package Store::Music;
# 仍然可以访问$discount,package声明并不影响词法作用域
say "Our current discount is $discount!";
我们可以使用代码块来限定词法作用域:
package Store::Toy
{
my $discount = 0.10;
}
package Store::Music
{
# $discount 这里不可见
}
package Store::BoardGame;
# $discount 仍然不可见
变量记号
我们已经知道不同的记号代表不同类型的变量值。对不同记号的变量赋值也就指定了不同的语境:
#对列表类型(切片)赋值就给定了列表语境,这样就会在列表语境下调用 some_function()
@values[ @indexes ] = some_function()
#对标量赋值就给定了标量语境,这样就是在标量的语境下对右边的表达式求值
my $element = @values[ @indices ]
匿名变量
Perl的变量并不一定要有名字。正如前面所说,名字的存在是为了帮助程序员理解程序,提高可读性。在创建变量时不给予名字那么这个变量就叫匿名变量。匿名变量只能通过引用访问。
变量,类型,和语境
了解变量类型,记号和语境之间的联系对深入理解Perl是必需的。
变量就是一个存储值的容器。在perl的设计中,容器的类型是不可变的。比如我们无法让一个标量类型的变量转换成数组类型。但对变量施加一个特定值类型的操作时将导致一些行为的转变以适应期望类型。
比如在标量语境中数组将返回元素的数量:
my $count = @items;
这个例子中 $count 仍然是标量类型,它不会变成数组。@items是数组,在标量语境会返回元素的数量(标量类型)以适应$count。