关于符号
区别Perl和其他语言的一点是它使用符号;放在变量名前面的那些古怪符号。作为经验丰富的Perl程序员,我们认为符号是Perl的必要部分,但当我梦想着我理想的Perl版本时,我在符号如何工作以及是否真的需要它们之间犹豫不决。
背景
首先,一些背景信息。在Perl中,有5种符号类型
符号 | 含义 | 示例 |
---|---|---|
$ |
标量 | $foo |
@ |
数组 | @foo |
% |
哈希 | %foo |
& |
子程序 | &foo |
* |
类型全局变量 | *foo |
子程序中的&符号通常只在创建对其的引用时需要。类型全局变量很少使用,所以在这篇文章的其余部分我将忽略它。
符号有许多好处,其中最显著的是变量可以无额外语法地插入到字符串中。对于已经费心学习Perl的人来说,Perl脚本也易于阅读,因为名词与动词的区别很明显。而且,可以轻松地向语言添加新的动词,而不会破坏旧脚本。
《Perl编程》第1章,第4版
这句话很好地阐述了支持符号的主要论点,我将逐一讨论这些论点。
更简单的字符串插值
不可否认的是,与使用sprintf、连接或join相比,使用符号进行字符串插值更简单。
"$greeting, $name";
sprintf '%s, %s', greeting, name;
greeting . ', ' . name;
join ', ', greeting, name;
不仅语法更简单,而且更容易阅读,因为声明看起来就像最终结果。这意味着在双引号字符串中需要转义美元符号,但这似乎是一个很少用到的用例,并不重要。
可读性
《Perl编程》声称使用符号可以使“名词与动词区分开来”,这可能是对的:符号确实清楚地区分了变量和内置函数以及子程序。然而,当我用C语言等其他语言编程时,我似乎没有在识别变量时遇到困难。文本编辑器通常将变量与其他单词以不同的颜色显示,这有助于。
这个论点具有主观性;我知道其他Perl程序员认为由于符号,它更容易阅读。我认为问题的一部分是Perl的语法非常庞大;有超过220个内置函数。即使使用纯文本编辑器,如果你的语言只有20个关键字,识别变量和函数也会容易得多。
符号将变量分为不同的命名空间。声明不同类型的同名变量是可能的——尽管很令人困惑
《现代Perl》第3章,第4版
Perl 5使用变体符号:符号根据访问的类型而变化。例如
my @num = (1, 2, 3);
my $num = 25;
say $num[1];
这里所有三个变量都是不同的;Perl为每个全局和词法上下文维护了标量、数组、哈希和子程序(等等)的子命名空间。这允许同名不同类型的多个变量的困惑行为。符号根据其使用上下文而变化的事实也是令人困惑的:Perl 6放弃了这种行为,我认为这解决了关于变体符号是否影响可读性的争论。
可扩展性
这是这样一个观点,通过使用符号,可以轻松地向语言添加新关键字,而不会破坏旧代码,因为它们不会包含与关键字冲突的变量名。虽然这无疑是正确的,但我对此有一些问题。
首先,如果我们相信《Perl编程》所说的变量是名词,关键字是动词,那么它们应该很少发生冲突。其次,Perl 允许子程序使用时不带符号。这些符号很可能会与关键字发生冲突,因为它们都是“动词”的一种。第三,Perl 允许“常量”在没有任何符号的情况下声明。因此,如果符号可以减少新关键字破坏旧代码的风险,那么它们并不能处理最常见的情况。
减少冲突风险的另一种方法是使用更少的内置关键字,并将它们作为类方法。例如,而不是提供 open
函数,可以提供一个 IO
类,并带有 open
方法。
类型声明简洁性
对于数组和哈希,在 Perl 中,我们不需要提供类名并调用构造方法,我们只需要简单地使用 @
或 %
。这减少了所需的文本量,考虑
my @numbers = (1, 2, 3);
my numbers = Array->new(1, 2, 3);
第一种方法显然更短。那么其他类型呢?假设我们想要创建一个新的有序哈希类型。尽管它是一个有序的键值对集合,就像数组一样,但我们不能使用 @
或 %
符号。我们必须创建一个对象并使用 $
符号。这是不一致的。对于栈、队列或其他语言未提供的数据类型也是如此。我们还能做什么,为所有类型提供新的符号?我们会用完所有符号的!
Perl 6
Perl 6 采用了不同的方法:符号表示由底层类型支持的接口。例如,@
表示位置,%
表示关联,&
表示可调用。您还可以定义 自定义类型。这种方法保留了 Perl 5 的外观和感觉,同时将语法置于更合理的依据上。但这并不是没有其独特之处。例如,标量符号 $
表示“无类型约束”。因此,您可以这样做
my %h = Hash.new( 'a', 1 );
my $h = Hash.new( 'b', 2 );
此代码声明了两个哈希,一个带有关联符号 %
,另一个带有“无类型约束”符号 $
。这两个有什么区别?您可能会认为只有使用关联符号声明的那个可以使用后缀访问器,但实际上它们都有效
say %h<a>;
say $h<b>;
所以,在 Perl 6 中,一个 @
或 %
符号表示您可以使用的一个接口,但 $
并不表示您不能使用关联或位置接口。此外,这两个变量有相同的名称和类型。然而,它们在同一个作用域中愉快地共存。因此,符号确实表示底层差异,即使只是在命名空间中存储变量的方式上。
这种二分法可以扩展到荒谬的程度:带有可调用符号 &
;在块、箭头和 sub
语法之间,以及可以使用 $
以及 &
,我总共可以找到 10 种不同的方式来分配一个 可调用类型。
这比 Perl 5 的变体符号好吗?考虑我之前提到的有序哈希类型。在 Perl 6 中,它将同时扮演关联和位置的角色。但是,我们在声明变量时只能使用一个符号。我应该选择:$
(无类型)、%
(关联)还是 @
(位置)?
现在想象一下,如果符号在 Perl 6 中确实只是一个接口,我们就可以根据所需的上下文将任何符号应用于同一个变量
my $ordered = OrderedHash.new();
...
if (%ordered<foo>) { ... }
for (@ordered) { ... }
这里的一个改进是,同一作用域中不同变量不能有相同的名称。但这些是变体符号,这降低了可读性。
结论
显然,是否在编程语言中使用符号是一个主观问题,不是一个可以“证明”的问题。但我确实认为可以证明 Perl 语言中符号的不同实现存在缺点。特别是使用不同的符号来表示底层类型或接口似乎是最麻烦的,而且收益甚微。
在我的理想中的幻想Perl中,一切都将面向对象。这将是一个更简单的Perl,其语法比今天的Perl要少得多。我认为它将具有符号,但只有$
。所有变量都将以美元符号开始,类似于PHP。这种更简单的方法将带来符号所声称的主要好处(可读性,字符串插值),而不会因为变量类型的不同而引起混淆,以及使用的符号类型会告知要访问的底层类型。这将防止在同一作用域中存在同名但类型不同的多个变量。它还提高了新来者更快地理解Perl的可能性,尤其是如果他们之前在PHP或shell中编程过。
参考文献
- 符号的问题 是关于符号的赞成和反对的论据集合
- Programming Perl 第四版
- Modern Perl,第四版
- Perl 6 变量 文档
- Perl 6 自定义类型
- Perl 6 可调用角色
这篇文章最初发布在 PerlTricks.com。
标签
反馈
这篇文章有什么问题吗?通过在GitHub上打开问题或拉取请求来帮助我们。