
最近看了看Perl,主要是想看看Ruby都从Perl那拿来了些什么。同时,也是我学习Perl的一篇笔记。
为什么大家都是Perl的代码丑陋,是什么导致了Perl程序晦涩难懂,Ruby中又是如何取舍这些元素的呢?我认为Perl社区追求更少代码的风气助长了大量使用预设变量的风气,从而导致了Perl代码的晦涩。
下面的每个Perl的例子总伴有Ruby的对照。
Perl的理念-条条大道通罗马「There is more than one way to do it」。
都说Perl简单、“万能”、快速、丑陋,Ruby咋就这么慢呢?
Perl的前身语言:C, awk, sed, sh, 以系统管理为目标, 强调使用性而不是美观。
Perl的语句是以分号";"作为分隔,而Ruby是以换行。所以Ruby的代码中鲜见分号。
Ruby的输出(print)似乎就是从Perl那直接拿过来的:
但字符串的内插就有所不同了。
Perl中可以这样实现字符串的变量替换:
而Ruby中是将变量用#{}包裹起来:
Perl的输入使用<STDIN>。不过,大家一般用钻石运算符(diamond operator)"<>":
在Ruby中,一般用STDIN.gets或者gets:
Perl的字符串可以用双引号括起来,也可以用qq//,qq||,qq{},qq后跟任意成对的符号.
Ruby也学来了,用%q或%Q加任意成对的符号.不过,Rubyist喜欢用%q[].(附带说明一下%q和%Q的区别,用%q来括就好象是用单引号,而%Q如同双引号.单双引号是不同的喔!)
在Perl中,数组变量是以@符开头,用小括号把值括起来.
用qw也行:
Ruby中是用中括号,也可用%w。
Perl和Ruby的数组都可以自动扩充。数组中没有指定值的元素会被Perl设为undef,而Ruby中是nil。在Perl中计算数组长度是用$#array+1,其中$#array是数组array的最后一个索引值;而Ruby中就比较简单,可以用size或者length。
两者都有切片。
Ruby中还可以用Array.slice:
Perl用sort对数组排序。
($a和$b是Perl的预设常量,在排序时被用来作为两两取出的两个数字。Ruby中就不必这样,Ruby是用块中的变量来实现array.sort!{|a, b| a <=> b})
或者直接sort
Ruby还学来了join:
还有map:
Ruby中map 和collect同义:
以及grep:
当然Ruby中也有grep,不过在这里用select比较方便:
push/pop
shift/unshift
还有很多,都比较简单,这就不一一列举了。
Perl有很多C的遗迹,比如Perl没有Boolean型的true和false,所以在判断真假时就比较麻烦。在Perl中,0、空字串、一个内容为"0"的字串和一个undef的值都是假。
而在Ruby中除了false和nil,其它一切皆为真。
Perl中用if..else..来做分支判断。
在各种语言中的if语句几乎都一样。但注意Ruby中更喜欢像英语那样书写代码,所以不喜欢用{}。
与if相对的,还有unless。上面的程序用unless改写就成了这样:
当然,惜字如金的Perl程序员发明了后缀判断:
毫无疑问,这么好的东西Ruby当然要学过来。
让Ruby程序员骄傲地是,Ruby中有switch,
而Perl没有提供switch。
循环当然少不了while。
类似if/unless这对,while也有until。
可能是受C影响太大,Perl中居然可以像C一样写for!
不过Perl程序员更喜欢简洁的写法:
除了for,Ruby中用来表达循环的方式还有很多,参见
The Ruby Way的1.2.6节。
Perl中的散列变量以百分号(%)开头,用大括号来存取。
Ruby则使用中括号来存取。
如果需要一次指定大量的散列键值,可以用qw//。
等效于
如果键值数目不一致,Perl会把最后一个键对应的值赋为undef。
由于容易引起混乱,所以推荐用另一种等价的赋值方式:
如果希望一次取出所有的键值对,可以借用each函数。
each每次送回一个包含一对键值的数组。
有时候只需取出健集:
或者值集:
判断是否存在某个键值对。
Ruby中提供了has_key?来做这事(has_key?有很多别名,include?, key?, member?)
Ruby还提供了探测是否存在某值的函数has_value?(别名value?)
删除某个键值对。
Ruby还提供了clear, delete, delete_if, reject, reject!, shift等方法来删除键值对。(clear删除所有的键值对,相当于赋一个新的空散列,但是稍微快一点。)
Ruby提供了Perl能为散列提供的一切功能,甚至更多。
Perl在变量名前加&表示该变量是一个子程序。
Perl的子程序可以放在程序的任意位置,而Ruby必须先声明,后调用。
当把参数传给子程序时,参数会放在预设的数组@_里(好奇怪的传递方式!)。
遇到这种传入参数个数不定的情况,Ruby中可以在形参前加*,表示所有的参数都在该形参所指向的数组内。
Perl会把子程序中的最后一个运算的值当成预设的返回值。当然,你也可以显式地使用return。
这一招Ruby也学来了。
有人说如果Perl少了散列和正则表达式,就什么都不是了。
在Perl中用比对运算子"=~"来进行比对,用m//来括住样式(//也可换成其他成对出现的符合)。
Perl在完成比对之后会传回成功与否的数值。
Ruby几乎全部继承了Perl的正则表达式。
所不同的是,Ruby如果比对成功,返回的是匹配开始处的偏移位置。
Perl提供了六个常用的file handle:STDIN,STDOUT,STDERR,DATA,ARGV,ARGOUT
完整版:
$!是Perl的一个预设变量,存储系统产生的错误信息。
Perl在命名上使变量处于不同的名字空间,比如标量变量(数字、字符串)以$开头,数组变量以@开头,散列变量以%开头,子程序名以&开头等等。
(待续,学习中……)
总的来说,Ruby像个OO版的Perl。Ruby的的确确从Perl那学来了不少东西,但把我们拉向Ruby阵营的还因为Ruby自身的特色(至于是什么,我还有梳理梳理^_^)。
参考书目:
Perl 學習手札,引用了里面的很多Perl代码。这本书是簡信昌写的一本Perl入门教材,写得通俗易懂,力荐!