Perl 6 documenthtml
翻译前端
本翻译意在帮助理解原文,因我的水平有限,不免会有翻译不当,若是疑惑请在评论中指出。node
原文git
简而言之,之前作什么如今怎么作 吾欲以 Perl 6行 Perl 5之所为,当何如?
这个页面尝试去索引从 Perl 5到 Perl 6的语法以及语义上的变化。那些在 Perl 5中正常工做的,在 Perl 6中却要换一种写法的语法应该被列出在这里(而许多 Perl 6的新特性以及风格就不会)。
所以,这个页面并非针对 Perl 6初学者的手册或者进阶文章,它是为有着 Perl 5知识背景的 Perl 6学习者以及移植 Perl 5 代码到 Perl 6的人员准备的技术文档(虽然Automated Translation可能会更方便一些)。
注意当文档中咱们说“如今”时,更多的意思是“你如今正在学习的 Perl 6”,并无暗示说 Perl 5忽然过期了,偏偏相反,大多数的咱们都深爱 Perl 5,咱们但愿 Perl 5能再继续使用好多年,事实上,咱们的重要目标之一就是让 Perl 5和 Perl 6之间顺利交互。不过,咱们也喜欢 Perl 6的设计目标,相比 Perl 5中的设计目标,更新颖,更好。因此,咱们中的大多数人都但愿在下一个十年或者两个十年,Perl 6能成为更流行的语言,若是你想把“如今”看成将来,那也是很好的,但咱们对致使争论的非此即彼的思想不感兴趣。程序员
参见Perl 6模块列表
若是你使用的模块尚未被移植到 Perl 6,并且在列表中没有替代品,可能在 Perl 6中的使用问题尚未解决。
有不少目标是为了在 Perl 6中use
Perl 5模块的工程:
v5模块意在让Rakudo自身解析 Perl 5的代码,而后编译成和 Perl 6一样的字节码。
Inline::Perl5模块使用一个内嵌的perl
解释器运行 Perl 6脚本中调用到的Perl 5代码。
其中,Inline::Perl5更完善,更有前途。github
若是你有读过 Perl 6的代码,一个最明显的地方就是方法调用语法如今使用点替代了箭头:web
$person->name; # Perl 5 $person.name; # Perl 6
点符号即容易书写又更加符合行业标准,不过咱们也想赋予箭头别的使命(字符串链接如今使用~
运算符)。
对于直到运行时期才知道名字的方法调用:正则表达式
$object->$methodname(@args); # Perl 5 $object."$methodname"(@args); # Perl 6
若是你省略了双引号,那么 Perl 6会认为$methodname
包含一个Method
对象,而不是简单的方法名字字符串。shell
Perl 5在容许空白的使用上有着惊人的灵活性,即便是在严格模式(strict mode)而且打开警告(warnings)环境下:编程
# 不符合习惯,可是在 Perl 5是能够的 say "Hello".ucfirst ($people [$ i] -> name)."!"if$greeted[$i]<i;
Perl 6也支持程序员书写自由和代码的创造性,可是权衡语法灵活性和其一致性、肯定性、可扩展的grammar,支持一次解析以及有用的错误信息,集成如自定义运算符的特性,而且不会致使程序员误用的设计目标,而且,“code golf”的作法也很重要,Perl 6的设计在概念上更简洁而不是击键上。
所以,在 Perl 5的语法的许多地方空白都是可选的,但在 Perl 6里多是强制的或者禁止的,这些限制中的许多不太可能关系到现实生活中的 Perl 代码(举例来讲,sigil 和变量名字之间的空格被禁止了),可是有一些可能不太幸运的和一些 Perl hacker的编程习惯风格相冲突:
参数列表的开括号以前不容许包含空白
substr ($s, 4, 1); # Perl 5 (这在 Perl 6 意味着传递了一个列表参数) substr($s, 4, 1); # Perl 6 substr $s, 4, 1; # Perl 6 替代括号的风格
关键字后面要紧跟空白
my($alpha, $beta); # Perl 5,这在 Perl 6里面将尝试调用例程my() my ($alpha, $beta); # Perl 6 if($a < 0) { ... } # Perl 5,在 Perl 6将会停止执行 if ($a < 0) { ... } # Perl 6 if $a < 0 { ... } # Perl 6,更符合习惯 while($x-- > 5) { ... } # Perl 5,在 Perl 6将会停止执行 while ($x-- > 5) { ... } # Perl 6 while $x-- > 5 { ... } # Perl 6,更符合习惯
前缀运算符后面或者后缀运算符、后缀环绕运算符(包含数组、哈希下标运算符)的前面不容许包含空白。
$seen {$_} ++; # Perl 5 %seen{$_}++; # Perl 6
方法调用运算符周围不容许出现空白:
$customer -> name; # Perl 5 $customer.name; # Perl 6
中缀运算符在可能和存在的后缀运算符或者后缀环绕运算符冲突时前面要包含空白:
$n<1; # Perl 5 (在 Perl 6里面可能和后缀环绕运算符 < > 冲突) $n < 1; # Perl 6
然而,你可使用unspace在 Perl 6的不容许使用空白的代码那增长空白:
# Perl 5 my @books = $xml->parse_file($file) # 一些注释 ->findnodes("/library/book"); # Perl 6 my @books = $xml.parse-file($file)\ # 一些注释 .findnodes("/library/book");
参见 Perl 6设计文档中的S03#Minimal whitespace DWIMmery和S04#Statement parsing。
在 Perl 5中,数组和哈希使用的 sigil 取决于怎样访问它们,在 Perl 6里面,不论变量怎样被使用,sigil 是不变的 - 你能够把他们做为变量名字的一部分(参见 Dereferencing)。
sigil $
如今老是和“标量”变量一块儿使用(好比$name
),再也不用于数组索引以及哈希索引。这就是说,你仍然可使用$x[1]
和$x{"foo"}
,可是它们是做用在$x
上,并不会对类似名字的@x
和%x
有影响,它们如今能够经过@x[1]
和%x{"foo"}
来访问。
sigil @
如今老是和“数组”变量一块儿使用(好比@month
,@month[2]
,@month[2, 4]
),再也不用于哈希值切片。
sigil %
如今老是和“哈希”变量一块儿使用(好比%calories
,%calories<apple>
,%calories<pear plum>
),再也不用于数组键值切片。
sigil &
如今始终(而且再也不须要反斜杠了)引用一个命名子例程/运算符的函数对象并不会执行它们,换句话说,把函数名字看成“名词”而不是“动词”:
my $sub = \&foo; # Perl 5 my $sub = &foo; # Perl 6 callback => sub { say @_ }; # Perl 5 - 不能直接传递内建过程 callback => &say; # Perl 6 - & 给出任何过程的“名词”形式
由于 Perl 6一旦完成编译就不容许在做用域内添加/删除符号,因此 Perl 6并无与 Perl 5中undef &foo;
等效的语句,而且最接近 Perl 5的defined &foo;
是defined &::("foo")
(这使用了“动态符号查找(dynamic symbol lookup)”语法)。然而,你可使用my &foo;
声明一个可修更名字的子例程,而后在运行过程当中向&foo
赋值改变它。
在 Perl 5中,sigil &
还能够用来以特定的方式调用子例程,这和普通的过程调用有些许不一样,在 Perl 6中这些特殊的格式再也不可用:
&foo(...),使函数原型失效
在 Perl 6中再也不有原型了,对你来讲,这和传递一个代码块或者一个持有代码对象的变量做为参数没有什么不一样:
# Perl 5 first_index {$_ > 5} @values; &first_index($coderef, @values); # 禁止原型而且传递一个代码块做为第一个参数 # Perl 6 first {$_ > 5}, @values, :k; # :k 副词使第一个参数返回下标 first $coderef, @values, :k;
&foo,还有 goto &foo; 用来重用调用者的参数列表或者替换调用栈的调用者
sub foo { say "before"; &bar; say "after" } # Perl 5 sub foo { say "before"; bar(|@_) say "after" } # Perl 6 - 须要显式传递 # 建议使用Rakudo中的 .callsame sub foo { say "before"; goto &bar } # Perl 5 # 建议使用Rakudo中的 .nextsame 或者 .nextwith
在 Perl 5中,sigil *
指向一个 GLOB 结构,继而 Perl 可使用它存储非词法变量,文件句柄,过程,还有格式(?formats)(不要和 Perl 5的用来读取目录中的文件名的内建函数 glob()
混淆了)。
你最可能在不支持词法文件句柄,但须要传递文件句柄到过程时的早期 Perl 版本代码中与 GLOB 邂逅:
# Perl 5 - 古法 sub read_2 { local (*H) = @_; return scalar(<H>), scalar(<H>); } open FILE, '<', $path or die; my ($line1, $line2) = read_2(*FILE);
在翻译到适合 Perl 6的代码前,你可能须要重构你的 Perl 5代码以移除对 GLOB的依赖:
# Perl 5 - 词法文件句柄的现代用法 sub read_2 { my ($fh) = @_; return scalar(<$fh>), scalar(<$fh>); } open my $in_file, '<', $path or die; my ($line1, $line2) = read_2($in_file);
而后这是可能的一个 Perl 6翻译代码:
# Perl 6 sub read-n($fh, $n) { return $fh.get xx $n; } my $in-file = open $path or die; my ($line1, $line2) = read-n($in-file, 2);
如今,数组的索引和切片再也不改变变量的sigil,而且在还可使用副词控制切片的类型:
索引
say $months[2]; # Perl 5 say @months[2]; # Perl 6 - @ 替代 $
值切片
say join ',', @months[6, 8..11]; # Perl 5, Perl 6
键值切片
say join ',', %months[6, 8..11]; # Perl 5 say join ',', @months[6, 8..11]:kv; # Perl 6 - @ 替代 %,而且使用 :kv 副词
如今,哈希的索引和切片再也不改变变量的sigil,而且在还可使用副词控制切片的类型。还有,花括号中的单词下标再也不自动引用(即自动在两边加上双引号),做为替代,老是自动引用其内容的新的尖括号版本是可用的(使用和qw//
引用构造相同的规则):
索引
say $calories{"apple"}; # Perl 5 say %calories{"apple"}; # Perl 6 - % 替代 $ say $calories{apple}; # Perl 5 say %calories<apple>; # Perl 6 - 尖括号,% 替代 $ say %calories«$key»; # Perl 6 - 双尖括号内插做为一个 Str 列表
值切片
say join ',', @calories{'pear', 'plum'}; # Perl 5 say join ',', %calories{'pear', 'plum'}; # Perl 6 - % 替代 @ say join ',', %calories<pear plum>; # Perl 6 - (更漂亮的版本) my $key = 'pear plum'; say join ',', %calories«$key»; # Perl 6 - 在内插以后完成切分
键值切片
say join ',', %calories{'pear', 'plum'}; # Perl 5 say join ',', %calories{'pear', 'plum'}:kv; # Perl 6 - 使用 :kv 副词 say join ',', %calories<pear plum>:kv; # Perl 6 - (更漂亮的版本)
还有注意下标花括号如今再也不是一个特殊的语法形式,而是一个普通的后缀环绕运算符,所以检测键是否存在和键移除使用副词完成。
在 Perl 5中,引用一个匿名数组和哈希以及过程的在它们建立的时候返回,引用一个存在的命名变量和过程使用\
运算符完成。
在 Perl 6中,匿名数组和哈希以及过程依然在它们建立的时候返回,引用一个命名的过程需在它们的名字前面加一个 sigil &
,引用一个存在的命名变量使用item
上下文:
my $aref = [1, 2, 9]; # 同时适用于 Perl 5&6 my $href = {A => 98, Q => 99 }; # 同时适用于 Perl 5&6 my $aref = \@aaa; # Perl 5 my $aref = item(@aaa); # Perl 6 my $href = \%hhh; # Perl 5 my $href = item(%hhh); # Perl 6 my $sref = \&foo; # Perl 5 my $sref = &foo; # Perl 6
在 Perl 5中,对一整个引用解引用的语法是使用 类型-sigil 和花括号,引用放在花括号里面,在 Perl 6中,由花括号变为了圆括号:
# Perl 5 say ${$scalar_ref}; say @{$array_ref}; say keys %{$hash_ref}; say &{$sub_ref}; # Perl 6 say $($scalar_ref); say @($array_ref); say %($hash_ref); say &($sub_ref);
注意在 Perl 5和 Perl 6中,围绕的花括号或者括弧都常常被省略,虽然省略下降了易读性。
在 Perl 5中,箭头运算符->
,用来单次访问复合引用或者经过引用调用一个过程,在 Perl 6中,咱们使用点运算符.
完成这一任务:
# Perl 5 say $array_ref->[7]; say $hash_ref->{'fire bad'}; say $sub_ref->($foo, $bar); # Perl 6 say $array_ref.[7]; say $hash_ref.{'fire bad'}; say $sub_ref.($foo, $bar);
在最近的 Perl 5版本(5.20或者之后),一个新的特性容许使用箭头运算符解引用,参见实验性的后缀解引用,这个新特性和 Perl 6中的.list
以及.hash
方法对应:
# Perl 5.20 use experimental qw < postref >; my @a = $array_ref->@*; my %h = $hash_ref->%*; my @slice = $array_ref->@[3..7]; # Perl 6 my @a = $array_ref.list; # 或者 @($array_ref) my %h = $hash_ref.hash; # 或者 %($hash_ref) my @slice = $array_ref[3..7];
“Zen”切片能够有一样的效果:
# Perl 6 my @a = $array_ref[]; my %h = $hash_ref{};
参见 S32/Containers。
更多运算符细节请参见S03-operators。
未改变的:
, 列表运算符
\+ 数值加法
\- 数值减法
* 数值乘法
/ 数值除法
% 数值求余
** 数值求幂
++ 数值自增
-- 数值自减
! && || ^ 逻辑运算符,高优先级
not and or xor 逻辑运算符,低优先级
== != < > <= >= 数值比较
eq ne lt gt le ge 字符串比较
在 Perl 5,这些运算符返回 -1,0 或者 1,而在 Perl 6,它们返回值对应的是 Order::Less
, Order::Same
和 Order::More
。cmp
如今叫作 leg
(字符串比较),它只适用于字符串上下问比较。<=>
仍然只适用于数值上下文。cmp
在 Perl 6中同时具有<=>
和leg
的功能,这依赖于参数的类型。
运算符自己没有改变,实际匹配的内容规则依赖于参数的类型,不过 Perl 6中的这些规则跟 Perl 5有很大不一样。参见S03/Smart matching。
在 Perl 5中,$
|
^
的行为依赖于参数的内容,好比,31 | 33
的返回值和"31" | "33"
是不一样的。
在 Perl 6中,这些单字符运算符都被移除了,替代它们的是能够强制把参数转换到须要的内容的双字符运算符。
# 中缀运算符 (两个参数,左右各一个) +& +| +^ 按位和 按位或 按位异或 :数值 ~& ~| ~^ 按位和 按位或 按位异或 :字符串 ?& ?| ?^ 按位和 按位或 按位异或 :逻辑 # 前缀运算符 (一个参数,在运算符后) +! 非:数值 ~! 非:字符串 ?! 非:逻辑 (做用和 ! 运算符同样)
被+<
和+>
取代。
say 42 << 3; # Perl 5 say 42 +< 3; # Perl 6
在 Perl 5里面,=>
的行为就想一个逗号,可是会自动引用(即加上双引号)左边的参数。
在 Perl 6里面,=>
是 Pair 运算符,这是最主要的不一样,可是在许多状况下行为都和 Perl 5里面相同。
在哈希初始化时,或者向一个指望哈希引用的方法传递一个参数时,=>
的用法就是相同的:
# 同时适用于 Perl 5&6 my %hash = (AAA => 1, BBB => 2); get_the_loot('diamonds', {quiet_level => 'very', quantity => 9}); # 注意花括号
在为了避免再引用(两边加上双引号)列表的一部分而使用=>
做为一种便利的方式时,或者向一个指望键,值,键,值这样的平坦列表的方法传递参数时,继续使用=>
可能会破坏你的代码,最简单的解决方法就是将胖逗号改成普通的逗号,而后在引用左边的参数。或者,你能够将方法的接口改成接受一个哈希,一个比较好的解决方式就是将方法的接口改成指望 Pair,然而,这须要你当即改动全部的方法调用代码。
# Perl 5 sub get_the_loot { my $loot = shift; my %options = @_; # ... } # 注意 这个方法调用中没有使用花括号 get_the_loot('diamonds', quiet_level => 'very', quantity => 9); # Perl 6,原始接口 sub get_the_loot($loot, *%options) { # * 意味着接受任何东西 # ... } get_the_loot('diamonds', quiet_level => 'very', quantity => 9); # 注意 这个方法调用中没有使用花括号 # Perl 6中,接口改成指定有效的选项 # sigil 前面的冒号表明指望一个 Pair # 参数的键名字和变量相同 sub get_the_loot($loot, :$quiet_level?, :$quantity = 1) { # 这个版本会检查未指望的参数 # ... } get_the_loot('diamonds', quietlevel => 'very'); # 参数名字拼写错误,将会抛出一个错误
如今使用两个问号替代了本来的一个问号,冒号被两个叹号替代了。
my $result = ($score > 60) ? 'Pass' : 'Fail'; # Perl 5 my $result = ($score > 60) ?? 'Pass' !! 'Fail'; # Perl 6
被波浪线替代。
小贴士:想象一下使用针和线“缝合”两个字符串。
$food = 'grape' . 'fruit'; # Perl 5 $food = 'grape' ~ 'fruit'; # Perl 6
在 Perl 5,x
是重复运算符。
在标量上下文,x
将会重复一个字符串,在 Perl 6里,x
会在任何上下文重复字符串。
在列表上下文,x
当且仅当将列表括入圆括号中时重复当前列表,在 Perl 6,新的运算符xx
将会在任何上下文重复列表。
小贴士:xx相对于x是比较长的,因此xx适用于列表。
# Perl 5 print '-' x 80; # 打印出一行横杠 @ones = (1) x 50; # 一个含有80个1的列表 @ones = (5) x ones; # 把全部元素设为5 # Perl 6 print '-' x 80; # 无变化 @ones = 1 xx 80; # 再也不须要圆括号 @ones = 5 xx @ones; # 再也不须要圆括号
在 Perl 5,..
依赖于上下文是两个彻底不一样的运算符。
在列表上下文,..
是熟悉的范围运算符,范围运算在 Perl 6有许多新的改变,不过 Perl 5的范围运算代码不须要翻译。
在标量上下文,..
和...
是不为人知的翻转运算符,在 Perl 6中它们被ff
和fff
取代了。
在 Perl 5,"${foo}s"
将变量名从普通的文本中分离出来,在 Perl 6中,简单的将花括号扩展到 sigil 外便可:"{$foo}s"
。
除了条件语句两边的括号如今是可选的,这些关键字几乎没有变化,可是若是要使用括号,必定没关系跟着关键字,不然这会被看成普通的函数调用,绑定条件表达式到一个变量也稍微有点变化:
if (my $x = dostuff()) { ... } # Perl 5 if dostuff() -> $x { ... } # Perl 6
在 Perl 6中你能够继续使用my
格式,可是它的做用域再也不位于语句块的内部,而是外部。
在 Perl 6中unless
条件语句只容许单个语句块,不容许elsif
或者else
子语句。
given-when
结构相似于if-elsif-else
语句或者 C 里面的switch-case
结构。它的普通样式是:
given EXPR { when EXPR { ... } when EXPR { ... } default { ... } }
根据这个最简单的样式,有以下代码:
given $value { when "a match" { do-something(); } when "another match" { do-something-else(); } default { do-default-thing(); } }
这是在when
语句中简单的使用标量匹配的场景,更广泛的实际状况都是利用如正则表达式通常的复杂的实体等替代标量数据对输入数据进行智能匹配。
同时参阅文章上面的智能匹配操做。
除了循环条件两边的括号如今是可选的,这些关键字几乎没有变化,可是若是要使用括号,必定没关系跟着关键字,不然这会被看成普通的函数调用,绑定条件表达式到一个变量也稍微有点变化:
while (my $x = dostuff()) { ... } # Perl 5 while dostuff() -> $x { ... } # Perl 6
在 Perl 6中你能够继续使用my
格式,可是它的做用域再也不位于语句块的内部,而是外部。
注意对文件句柄按行读取发生了变化。
在 Perl 5,这能够利用钻石运算符在while
循环里面完成,若是使用for
替代while
则会有一个常见的bug,由于for
致使文件被一次性读入,使程序的内存使用变的糟糕。
在 Perl 6,for
语句是缓式的(lazy),因此咱们能够在for
循环里面使用.lines
方法逐行读取文件:
while (<IN_FH>) { ... } # Perl 5 for $IN_FH.lines { ... } # Perl 6
首先注意这有一个常见的对for
和foreach
关键字的误解,许多程序员认为它们是把 C-风格for 和列表迭代方式区分开来,然而并非!实际上,它们是可互换的,Perl 5的编译器经过查找后面的分号来决定解析成哪种循环。
C-风格的for循环如今使用loop
关键字,其它都没有变化,两边的括号是必须的:
for (my $i = 1;$i <= 10;$i++) { ... } # Perl 5 loop (my $i = 1;$i <= 10;$i++) { ... } # Perl 6
for
或者foreach
的循环迭代样式如今统一叫作for
,foreach
再也不是一个关键字,括号是可选的。
迭代变量,若是有的话,已经从列表的前部移动到列表的后面,变量以前还有加上箭头运算符。
迭代变量,如今是词法变量,my
已经再也不须要并且不容许使用。
在 Perl 5里,迭代变量是当前列表中元素的可读写别名。
在 Perl 6,这个别名默认是只读的(为了安全),除非你将->
改成<->
。当翻译的时候,检查循环变量的使用来决定是否须要可读写。
for my $car (@cars) { ... } # Perl 5,可读写 for @cars -> $car { ... } # Perl 6,只读 for @cars <-> $car { ... } # Perl 6,可读写
若是使用默认的变量$_
,可是又须要可读写,那么须要使用<->
并显示指定变量为$_
。
for (@cars) { ... } # Perl 5,默认变量 for @cars { ... } # Perl 6,$_ 是只读的 for @cars <-> $_ { ... } # Perl 6,$_ 可读写
这是 Perl 6中和 Perl 5 while...each(%hash)
或者while...each(@array)
(遍历数据结构的键或者索引和值)等同的用法:
while (my ($i, $v) = each(@array)) { ... } # Perl 5 for @array.kv -> $i, $v { .... } # Perl 6 while (my ($k, $v) = each(%hash)) { ... } # Perl 5 for %hash.kv -> $k, $v { ... } # Perl 6
无变化的:
next
last
redo
continue
语句块已经被去掉了,做为替代,在循环体中使用NEXT
语句块:
# Perl 5 my $str = ''; for (1..5) { next if $_ % 2 == 1; $str .= $_; } continue { $str .= ':'; } # Perl 6 my $str = ''; for 1..5 { next if $_ % 2 == 1; $str ~= $_; NEXT { $str ~= ':'; } }
内建函数以前接受一个裸露的代码块,没有逗号在其余参数以前,如今须要在块和参数之间插入一个逗号,好比map
,grep
等等。
my @result = grep { $_ eq "bars" } @foo; # Perl 5 my @result = grep { $_ eq "bars" }, @foo; # Perl 6
my $deleted_value = delete $hash{$key}; # Perl 5 my $deleted_value = %hash{$key}:delete; # Perl 6,使用 :delete 副词 my $deleted_value = delete $array[$i]; # Perl 5 my $deleted_value = @array[$i]:delete; # Perl 6,使用 :delete 副词
say "element exists" if exists $hash{$key}; # Perl 5 say "element exists" if %hash{$key}:exists; # Perl 6,使用 :exists 副词 say "element exists" if exists $array[$i]; # Perl 5 say "element exists" if @array[$i]:exists; # Perl 6,使用 :exists 副词
在 Perl 5对变量的匹配和替换是使用=~
正则绑定运算符完成的。
在 Perl 6中使用智能匹配运算符~~
替代。
next if $line =~ /static/; # Perl 5 next if $line ~~ /static/; # Perl 6 next if $line !~ /dynamic/; # Perl 5 next if $line !~~ /dynamic/; # Perl 6 $line =~ s/abc/123/; # Perl 5 $line ~~ s/abc/123/; # Perl 6
一样的,新的.match
方法以及.subst
方法能够被使用。注意.subst
是不可变操做,参见S05/Substitution。
将全部的副词的位置从尾部移动到了开始,这可能须要你为普通的匹配好比/abc/
添加可选的m
。
next if $line =~ /static/i; # Perl 5 next if $line ~~ m:i/static/; # Perl 6
若是实际的正则表达式比较复杂,你可能不想作修改直接使用,那么就加上P5
副词吧。
next if $line =~ m/[aeiou]/; # Perl 5 next if $line ~~ m:P5/[aeiou]/; # Perl 6,使用 :P5 副词 next if $line ~~ /<[aeiou]>/; # Perl 6,新的风格
Perl 5的正则语法支持不少特殊的匹配语法,它们不会所有列在这里,可是通常在断言中做为()
的替代的是<>
。
对于字符类,这意味着:
Perl 5 Perl 6 [abc] <[abc]> [^abc] <-[abc]> [a-zA-Z] <[a..zA..Z]> [[:upper:]] <:Upper> [abc[:upper:]] <[abc]+:Upper>
对于环视(look-around)断言:
Perl 5 Perl 6 (?=[abc]) <?[abc]> (?=ar?bitray* pattern) <before ar?bitray* pattern> (?!=[abc]) <![abc]> (?!=ar?bitray* pattern) <!before ar?bitray* pattern> (?<=ar?bitray* pattern) <after ar?bitray* pattern> (?<!=ar?bitray* pattern) <!after ar?bitray* pattern> (跟<>语法无关,环视语法`/foo\Kbar/`变成了`/foo<(bar)>/` (?(?{condition})yes-pattern|no-pattern) [ <?{condition}> yes-pattern | no-pattern ]
在 Perl 6的正则中,|
用于LTM,也就是根据一组基于模糊匹配规则从结果中选择一个最优的结果,而不是位置优先。
对于 Perl 5代码最简单解决方案就是使用||
替代|
。
对于更多的规则,同时使用来自Blue Tiger的translate_regex.pl
。
严格模式如今是默认的。
警告如今默认是开启的。no warnings
目前仍是NYI状态,可是把语句放到quietly {}
块以内就能够避免警告。
这个功能可让程序在发生错误抛出异常,如今 Perl 6默认抛出异常,除非你显式的测试返回值。
# Perl 5 open my $i_fh, '<', $input_path; # 错误时保持沉默 use autodie; open my $o_fh, '>', $output_path; # 错误时抛出异常 # Perl 6 my $i_fh = open $input_path, :r; # 错误时抛出异常 my $o_fh = open $output_path, :w; # 错误时抛出异常
如今use base
和use parent
已经被 Perl 6中的is
关键字取代,在类的声明中。
# Perl 5 package Cat; use base qw (Animal); # Perl 6 class Cat is Animal;
再也不相关。Int
如今是无限精度的,是Rat
类型的分子(分母最大能够是2**64,出于性能考虑以后会自动转换为Num
类型)。若是你想使用无限精度分母的Rat
,那么FatRat
显然是最适合的。
constant
在 Perl 6用来变量声明,这相似与my
,不过变量会锁定保持第一次初始化的值不变(在编译时期求值)。
因此,将=>
改成=
,并加上一个 sigil。
use constant DEBUG => 0; # Perl 5 constant $DEBUG = 0; # Perl 6 use constant pi => 4 * atan2(1, 1); # Perl 5 # pi, e, i都是 Perl 6的内建变量
容许使用非ASCII或者非UTF8编码编写代码。
Perl的编译指示,使用整数运算替代浮点。
在编译时期操做 @INC。
再也不相关。
在 Perl 6中,方法调用如今使用 C3 方法调用顺序。
再也不相关。
在 Perl 6中,源代码将使用utf8编码。
在 Perl 5中被取代,参见vars。
在翻译到 Perl 6代码以前,你可能须要重构你的代码移除对use vars
的使用。
参见S19/commandline。
未变化的:
-c -e -h -I -n -p -S -T -v -V
在Spec中没有变化,可是在Rakudo中没有实现。
如今你须要手动调用.split
。
在Spec中没有变化,可是在Rakudo中没有实现。
如今你须要手动调用.split
。
如今默认提供此行为。
只有-M
还存在,还有,你们能够再也不使用“no Module”语法了,-M
的“no”模块操做再也不可用。
由于全部的特性都已经开启,请使用小写的-e
。
被++BUG
元语法替代。
开关选项解析如今被MAIN
子方法的参数列表替代。
# Perl 5 #!/usr/bin/perl -s if ($xyz) { print "$xyz\n" } ./example.pl -xyz=5 5 # Perl 6 sub MAIN(Int :$xyz) { say $xyz if $xyz.defined; } perl6 example.p6 --xyz=6 6 perl6 example -xyz=6 6
如今尚未指定。
移除,参见S19/commandline。
如今默认开启。
在 Perl 5,读取文本文件的行一般是这样子:
open my $fh, '<', "file" or die "$!"; my @lines = <$fh>; close $fh;
在 Perl 6,这简化成了这样:
my @lines = "file".IO.lines;
不要尝试一次读入一个文件,而后使用换行符分割,由于这会致使数组尾部含有一个空行,比你想象的多了一行(它实际更复杂一些)。好比:
# 初始化要读的文件 spurt "test-file", q:to/END/; first line second line third line END # 读取 my @lines = "test-file".IO.slurp.split(/\n/); say @lines.elems; # 输出 4
鉴于 Perl 5你可能这么作:
my $arg = 'Hello'; my $captured = \`echo \Q$arg\E\`; # 注意反引号\` my $captured = qx(echo \Q$arg\E);
或者使用String::ShellQuote(由于\Q...\E不是彻底正确的):
my $arg = shell_quote 'Hello'; my $captured = 'echo $arg'; my $captured = qx(echo $arg);
在 Perl 6中你可能不想经过shell运行命令:
my $arg = 'Hello'; my $captured = run('echo', $arg, :out).out.slurp-rest; my $captured = run(«echo "$arg"», :out).out.slurp-rest;
若是你想也可使用shell:
my $arg = 'Hello'; my $captured = shell("echo $arg", :out).out.slurp-rest; my $captured = qqx{echo $arg};
可是小心这种状况彻底没有保护,run
不使用shell执行命令,因此不须要对参数进行转义(直接进行传递)。若是你使用shell
或者qqx
,那么全部东西都会做为一个长长的字符串传给shell,除非你当心的验证你的参数,颇有可能由于这样的代码引入shell注入漏洞。
在 Perl 5中能够指定 Perl 模块的额外的搜索路径的一个环境变量是PERL5LIB
:
$ PERL5LIB="/some/module/lib" perl program.pl
在 Perl 6中也相似,仅仅须要改变一个数字,正如你想的那样,你只需使用PERL6LIB
:
$ PERL6LIB="/some/module/lib" perl6 program.p6
就 Perl 5来讲,若是你不指定PERL5LIB
,你须要使用use lib
编译指示来指定库的路径:
use lib '/some/module/lib'
注意PERL6LIB
在 Perl 6中更多的是给开发者提供便利(与 Perl 5中的PERL5LIB
相对应),模块的用户不要使用由于将来它可能被删除,这是由于 Perl 6的模块加载没有直接兼容操做系统的路径。
不像 Perl 5,一个只包含('0')的字符串是 True
,做为 Perl 6的核心类型,它有着更多的意义,这意味着常见的模式:
... if defined $x and length $x; # 或者现代 Perl 的写法 length($x)
在 Perl6里面变的更为简化:
... if $x;
被移除。
Perl 6的设计容许自动的保存加载编译的字节码。
Rakudo目前只支持模块。
在 Perl 5你能够像这样有选择性的导入一个给定模块的函数:
use ModuleName qw{foo bar baz};
在 Perl 6,一个想要被导出的函数须要对相关的方法使用is export
,全部使用is export
的方法都会被导出,所以,下面的模块Bar
导出了方法foo
和bar
,没有导出baz
:
unit module Bar; sub foo($a) is export { say "foo $a" } sub bar($b) is export { say "bar $b" } sub baz($z) { say "baz $z" }
使用模块时,简单的use Bar
便可,如今函数foo
和bar
都是可用的:
use Bar; foo(1); # 输出 "foo 1" bar(2); # 输出 "bar 2"
若是你尝试调用baz
函数,会在编译时报出“未定义的例程”错误。
因此,如何像 Perl 5那样可选择性的导入一个模块的函数呢?支持这个你须要在模块中定义EXPORT
方法来指定导出和删除module Bar
的声明(注意在Synopsis 11中并无module
语句,然而它能够工做) 。
模块Bar
如今仅仅是一个叫作Bar.pm
的文件并含有如下内容:
use v6; sub EXPORT(*@import-list) { my %exportable-subs = '&foo' => &foo, '&bar' => &bar,; my %subs-to-export; for @import-list -> $sub-name { if grep $sub-name, %exportable-subs.keys { %subs-to-export{$sub-name} = %exportable-subs{$sub-name}; } } return %subs-to-export; } sub foo($a) { say "foo $a" } sub bar($b) { say "bar $b" } sub baz($z) { say "baz $z" }
注意如今方法已再也不使用is export
显式的导出,咱们定义了一个EXPORT
方法,它指定了模块能够被导出的方法,而且生成一个包含实际被导出的方法的哈希,@import-list
是调用代码中使用set
语句设置的,这容许咱们可选择性的导出模块中可导出的方法。
因此,为了只导出foo
例程,咱们能够这么使用:
use Bar <foo>; foo(1); # 输出 "foo 1"
如今咱们发现即便bar
是可导出的,若是咱们没有显式的导出它,它就不会可用,所以下面的代码在编译时会引发“未定义的例程”错误:
use Bar <foo>; foo(1); bar(5); # 报错 "Undeclared routine: bar used at line 3"
然而,咱们能够这样:
use Bar <foo bar>; foo(1); # 输出 "foo 1" bar(5); # 输出 "bar 5"
注意,baz
依然是不可导出的即便使用use
指定:
use Bar <foo bar baz>; baz(3); # 报错 "Undeclared routine: baz used at line 2"
为了使这个能正常工做,显然须要跨越许多的障碍,在使用标准use的状况下,经过使用is export
指定某一个函数是导出的,Perl 6会自动以正确的方式建立EXPORT
方法,因此你应该仔细的考虑建立一个本身的EXPORT
方法是否值得。
在 Perl 5,Data::Dumper模块被用来序列化,还有程序员调试的时候用来查看程序数据结构的内容。
在 Perl 6中,这个任务彻底被存在于每个对象的.perl
方法替代。
# 给定 my @array_of_hashes = ( {NAME => 'apple', type => 'fruit'}, {NAME => 'cabbage', type => 'no, plese no'}, ); # Perl 5 use Data::Dumper; $Data::Dumper::Useqq = 1; print Dumper \@array_of_hashes; # 注意反斜杠 # Perl 6 say @array_of_hashes.perl; # .perl会做用在数组而不是引用上面
在 Perl 5,Data::Dumper有着更复杂的可选的调用约定,它支持对变量命名。
在 Perl 6,将一个冒号放在变量的 sigil 前面转换它为 Pair,Pair 的键是变量的名字,值是变量的值。
#给定 my ($foo, $bar) = (42, 44); my @baz = (16, 32, 64, 'Hike!'); # Perl 5 use Data::Dumper; print Data::Dumper->Dump( [$foo, $bar, \@baz], [qw(foo bar *baz )], ); # 输出 $foo = 42; $bar = 44; @baz = ( 16, 32, 64, 'Hike!' ); # Perl 6 say [ :$foo, :$bar, :@baz ].perl; # 输出 ["foo" => 42, "bar" => 44, "baz" => [16, 32, 64, "Hike!"]]
开关选项解析如今被MAIN
子方法的参数列表替代。
# Perl 5 use 5.010; use Getopt::Long; GetOptions( 'length=i' => \(my $length = 24), # 数值 'file=s' => \(my $data = 'file.data'), # 字符串 'verbose' => \(my $verbose), # 标志 ) or die; say $length; say $data; say 'Verbosity', ($verbose ? 'on' : 'off') if defined $verbose; perl example.pl 24 file.data perl example.pl --file=foo --length=42 --verbose 42 foo Verbosity on perl example.pl --length=abc Value "abc" invalid for option length (number expected) Died at c.pl line 3. # Perl 6 sub MAIN (Int :$length = 24, :file($data) = 'file.data', Bool :$verbose) { say $length if $length.defined; say $data if $data.defined; say "Verbosity", ($verbose ?? 'on' !! 'off'); } perl6 example.p6 24 file.dat Verbosity off perl6 example.p6 --file=foo --length=42 --verbose 42 foo Verbosity on perl6 example.p6 --length=abc Usage: example.p6 [--length=<Int>] [--file=<Any>] [--verbose]
注意 Perl 6会在命令行解析出错时自动生成一个完整的用法信息。
一个快速的将 Perl 5代码翻译为 Perl 6代码的途径就是经过自动化翻译。
注意:这些翻译器都尚未完成。
本项目的目致力于自动现代化 Perl 代码,它没有一个 web 前端,因此必须本地安装使用,它还含有一个单独的程序用来将 Perl 5的正则转换为 Perl 6的版本。
https://github.com/Util/Blue_Tiger/。
在线翻译器。
本项目是一套 Perl 跨平台编译器,包含 Perl 5到 Perl 6的翻译,它有一个 web 前端,因此能够在不安装的前提下使用,它目前只支持 Perl 5语法的一个子集。
http://www.perlito.org/perlito/perlito5to6.html。
Larry Wall 本身用来翻译 Perl 5到 Perl 6的代码已经太老了,在目前的 Perl 5版本中已经不可用了。
MAD(Misc Attribute Definition)是一个经过源码构建 Perl 的时候可用的配置选项, perl\
执行程序分析并翻译你的 Perl 代码到 op-tree,经过遍历 op-tree执行你的程序。一般,这些分析的细节会在处理的时候丢掉,当MAD开启的时候,`perl`执行程序会把这些细节保存成XML文件,而后MAX解析器即可以读取它并进一步处理成 Perl 6的代码。
为了进行你的MAD实验,请前去 #perl6 频道请教最适合的 Perl 5 版本。
Jeff Goff的围绕 Perl::Critic 框架的用于 Perl 5的模块 Perl::ToPerl6 ,目标是最最小的修改并将 Perl 5的代码转换成可编译的 Perl 6代码,代码的转换器是可配置和插件化的,你能够经过它建立本身的转换器,根据你的需求自定义存在的转换器。你能够从CPAN上面获取最新的版本,或者 follow 发布在 GitHub 的工程,在线转换器可能在某一天会可用。