7C00.ME/houmu 2013-05-05

初学perl的感受之数据类型

Perl中四种基本数据类型(就我目前所知):标量、数组、列表、哈希。

标量应该是Perl中的原子数据结构,对程序员来说不能再分解了,类似C语言中的int、double。对于标量,我有以下看法:

“标量”这个名字很奇怪,有一种很“物理”、很“数学”的感觉,而且让初学者以为一定还有个叫“矢量”的数据类型。而实际上,标量就是一种普通的数据类型(有数学概念,跟物理没有什么关系),Perl中没有叫做“矢量”或者“向量”的基本数据类型。真不知道,当初Larry是怎么想的,会起这个名字。

标量包括数值量和字符串,两者会在需要的时候相互转换。如$v1 + $v2时,两个标量自动转换为数值量。转换过程自动进行,不用显示说明,暂时不知道有没有显示转换的语法。转换过程有一定的规则,比如$v1是“world”,那个$v1转化为0,当然不止这一条规则。如果是$v1.$v2,则是字符串拼接了,这里面的转换很好理解。很多时候不许要考虑是数值量还是字符串,因为大多数时候是在处理字符串,需要处理数值量的时候,Perl会自动做很多事情。

对于数值量的标量。Perl不区分是整型还是浮点数,Perl都按照浮点数做内部存储和数值计算,需要的时候(比如做数组索引$array[$index]),Perl内部会做一定的转换,但对程序员不可见和不可控,实际上也不需要。Perl在数值量上的这样的设计,也决定了Perl不适合用于大量数值计算的程序(通过模块等外部手段加速计算,不属于我谈论的范围),Perl本身就是为了处理文本而诞生的,在这种使用场景下,把数值量抽象和弱化,集中精力到字符串上,我喜欢这种专注!

数组和列表,我目前还没想通二者同时存在的必要,或者说二者的区别。我看的书是《Perl语言入门第四版》,网上一个不到2M、200多页的PDF文档。这本书在讲了列表以后,基本上就只有列表了,不见$xxx[$i]的代码了。我暂时就把数组给忘了,记住列表吧。

哈希和其他语言中的“字典”(Python)或“map”(Golang)是一个概念。Larry把这种数据结构叫做哈希,是因为其内部实现使用了哈希表。想到“标量”,又是一个奇怪的命名!有时候通用的东西叫个常用的名字,和人家交流起来也方便啊。在其他时候,我们说哈希,是指和安全、加密相关的一种技术、一种算法、一种函数、一种特殊的字符串!叫哈希表也好啊。这些大师的想法有时候就是与众不同,作为Perl用户,你必须接受哈希。

这四种数据类型,位于不同的名字空间,在变量命名上使用不同的前缀(标量$、列表@、哈希%),所以可以使用相同的名字,而互不影响。举下面这个例子:

#!/usr/bin/perl

$v="hello world";
$v[0]="hello";
$v[1]="hello world";
@v = qw/hello world/;
%v = qw/hello world hi planet/;

print "\$v=$v\n";
print "\$v[0]=$v[0] \$v[1]=$v[1]\n";
print "\@[email protected]\n";
print "\@v[0][email protected][0] \@v[1][email protected][1]\n";
print "$_ in \@v\n" for @v;
print "$_ => $v{$_} in %v\n" for keys %v;

输出结果是:

$v=hello world $v[0]=hello $v[1]=world @v=hello world @v[0]=hello @v[1]=world hello in @v world in @v hi => planet in %v hello => world in %v

Perl有一条设计原则是不给程序员多余的限制。从上面的程序可以看出,变量命名确实够自由的,《Perl语言入门》的作者推荐程序员不要采取上面代码中的做法,这样会给程序的维护带来不便。其实我认为,因为四种数据类型内部实现是位于不同的名字空间,所以不会出现重名的问题,如果不允许不同类型的变量有相同变量名,则需要专门的检查,在某种可能的实现方式下,这反倒会增加额外的编码工作,所以不做重名检查或许是种偷懒。在其他语言中,至今未见过有类似的语法规则的。Perl中的这一条“自由”应该考虑废止。

总体看来Perl中数据类型和Shell有很多共同之处,特别是标量,毕竟Perl一开始是在Unix上工作的。Perl这套数据类型体系对于PHP的影响比较大,PHP中进一步简化,变量类型进一步弱化,变量前缀都是$,数组、列表和哈希也都合并为PHP中的array。这个$符号我感觉也是多余的,像Ruby(Perl对其也有一定的影响)中变量前就不存在这种符号了。