style> #Content { margin: 0; padding: 0px; padding-top: 10px; text-align: left; border-top: none; float: left; padding-left: 1px; width: 740px; } body { font-family : Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; line-height: 18px; } h1 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 28px; font-weight: bold; color: #FF8817; } h2 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 18px; font-weight: bold; color: #B82619; } h3 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 16px; font-weight: bold; color: green; } h4 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; font-weight: bold; color: green; } h5 { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 13px; font-weight: bold; color: #333; } a { color: #0066cc; } a:visited { color: #0066cc; } a:hover { color: #FA6F00; } a.img:hover { background-color:#fff; } li { margin-bottom: 7px } .topbanner { border-bottom:dashed 1px #d6d6d6; } pre { font-family: "Courier New"; padding:10pt; font-size: 9pt; background-color: #f6f6f6; border: solid 1px #d6d6d6; border-left: solid 3px #d6d6d6; } b { color: #FF8817; } td { font-size: 70%; font-family: Verdana, Arial, Helvetica, sans-serif; font-weight: normal; text-decoration: none; } style>
从现在开始装的傻B一下,告诉你自己其实你一点也不懂Perl。你隐约记得Perl有一些特别,所以你想证实你的想法。你考虑到Larry Wall可以解释你的疑虑,所以你来到书店买了一本”Perl语言编程”。这是最新版的书讲述了6.0.1版。它并未描述Perl6有那些新功能,而是从入门开始讲解,于是你开始为你的好奇心猛啃这本书,就象小孩在生日上得到他想要已久的望远镜。现在,这篇文章就是让你看到未来的望远镜。
在本章的以后时间里我们将分析Perl6的各种特色并且来评价那些是你喜欢的那些是你不喜欢的。好!现在开始暂退一步,放掉那些细节,我们从整体上开始讲。
变量几乎是所有计算机语言的基础部分,它把数据块吸入到自己身上使用在周围的环境,在不同的场合中变化,并且突然出现在一些新的位置。这个数据库块的值可能是:字符串、数字、其他的,或是复杂的数据结构。变量正好是找到这些数据的名字。Perl6有三种变量模式他们是:标量(Scalar),数组(Array),哈希(Hash)。他们三个每种都在变量的名字前有一个印记(符号):标量是$,数组是@,哈希是%。这个印记从视觉上可以清楚的告诉使用者变量的举止行为。其实,他们三种的差别非常小。从本质上来讲每种变只是一个装数据的罐子,不管这个变量是一种集合还是单独的一个(看看下面的内容吧,你就明白为什么上面要这么说了)。
标量是一个全能的罐子。他们可以存储字符串、整数、浮点数与各种对象的引用。举例:
$string = "欢迎参加perlchina的Perl中文化你可以得到奖励"; $int = 42; $float = 3.14159; $arrayref = [ "Perlchina", "Perl中文化", "奖励" ]; $hashref = { "Perlchina" => 362, "Perl中文化" => 1574, "奖励" => 28 }; $subref = sub { print $string }; $object = Android.new;
一个文件句柄也仅仅是一个普通标量模式的普通对象:
$filehandle = open $filename;
数组变量存储简单的一排标量数值。通过数组的数字索引可以得到这些变量。0表示第一个值。@符号是变量名字的一部分无论变量怎么使用@都不会被取下来:
@crew = ( "Perlchina", "Perl中文化", "奖励" ); $second_member = @crew[1]; # Perl中文化
获得一个数组有多少个元素你可以使用.elems方法。.last方法用来返回这个数组最后一个序列是哪个。
$count_elements = @crew.elems; $last_index = @crew.last;
对儿(Pairs)存储了单一的键/值。他们没有一个独立的印记,因为他们很少情况被使用,所以他们可以被存储在标量、数组、哈希中。对儿的结构使用=>来创造,”左面是键”=>“左面是值”。
$pair = 'key' => 'value';
改变选择语法也可以用来创造一个对儿,在一个冒号的后面填写“键”在括号的里面填写“值”:
$pair = :key('value');
这个选择语法是在子程序调用中经常使用的语法,你可以查看”骆驼与鹦鹉的本质第二版本”(Perl6 and Parrot Essentials,2nd Edition)的第五章5.3.1。
哈希中存放的是无序的标量值,使用”键”进行索引存储与调用。你可以轻松的产生一个哈希列表并存储匿名的对儿:
%hash = ( "Zaphod" => 362, "Ford" => 1574, "Trillian" => 28 );
每个”键”用来识别一个值,他们可以是字符串或对象,虽然对象”键”可能受到一些功能限制。为了性能”对象键”必须被声明才能使用。任何对象成为哈希结构的”键”必须有一个.id的方法,这个方法将一对一的返回对象实例的”值”这样可以避免哈希中冲突。这个方法在所有的基类中是默认的,所以你定义自己的.id方法时只需要担心唯一性就够了。
$age = %hash{"Zaphod"}; # 字符串 $age = %hash{$name}; # 字符串变量 $age = %hash{$person}; # 对象
在文字字符串键旁边必须要有引号,而当你调用一个子程序来获得一个键时,这个子程序名不用像字符串键一样(必须去掉引号):
$age = %hash{get_key}; # subroutine call
如果你特讨厌输入引号,可以在键旁用自动引用符(双尖括号)来代替常用引用符(波浪号):
$age = %hash«Zaphod»; # string $age = %hash<<Zaphod>>; # ASCII equivalent
在列表上下文中,一个哈希会返回一列有键/值的对儿(Pairs)对象。而.kv方法会从哈希返回一个”平整列表”。看把一个哈希直接给到一个数组:
译者注:一般的当你把(“Perlchina” =>“中文化”)变成(“Perlchina”,”中文化”)后者就属于平整列表,平整列表也是数组中存储数据的格式。后文中这个单词还会出现。@pairs = %hash;
看,产生了一个全是对儿的数组:
(pair1, pair2, pair3, etc . . . )
然而关系被变成平整列表:
@flat = %hash.kv;
就变成了这个样子:
(key1, value1, key2, value2, etc . . . )
.keys方法将返回在哈希中的所有“键”的列表。.values方法将返回在哈希中的所有“值”:
@keys = %hash.keys; @values = %hash.values;
引用的功能在Perl6中重要性更明确了。在引用与普通变量之间有一个很小的区别,并且在自动处理引用或解除引用的某些必要时才会被使用到。创造一个数组或哈希的引用并不需要什么特别语法,你只需要简单的把他们赋给一个变量就可以了:
$arrayref = @array; $hashref = %hash;
在很多上下文关系里引用将会偷偷的被接触,所以使用数组索引或哈希的“键”来访问他们的数值你只需要这样明白的做:
$arrayref[1] $hashref{"Zaphod"}
在数组引用或哈希引用中调用方法就象一直在操作哈希和数组一样。指出“引用后面的数据类型或对象”测试在这个特别的引用中哪个方法可以使用,那些方法做什么了,无论如何引用可以支持这种连接的访问:
$arrayref.elems $hashref.keys
通过引用可以很容易的执行带有参数的子程序。当然参数可以是空的,但是括号是必须有的:
$subref($arg);
数组引用与哈希引用有个特别语法 (@{ . . . } 和 %{ . . . }) 可以在上下文中解除他们的引用:
@array = @{$arrayref}; # or @array = @$arrayref;
通常一个数组引用如果赋给了另外一个数组将会产生只有这个单一数组引用的新数组。如果你想把所有的$arrayref内容都给到@array你必须先解除这个引用。
在:$、@、%印记开头的变量上下文有一个明显的区别。$开头使用标量上下文,@开头使用列表上下文,%开头使用哈希上下文[1]。
[1]Perl6里不仅仅只有这三种上下文。一个更为详细的讨论请参看”骆驼与英文的本质第二版4.2.7部分或以后的章节”。任何一个数组或列表被标量上下文求值将得到一个数组引用。这里有一个数组来说明这句话的含义:
@array = ( "Zaphod", "Ford", "Trillian" ); $arrayref = @array;
一个列表:
$arrayref = ( "Zaphod", "Ford", "Trillian" );
或是一个外部的匿名引用:
$arrayref = [ "Zaphod", "Ford", "Trillian" ];
在上面的这个标量变量将正确的输出相同的结构:一个数组引用也会有三个元素。
列表的结构符逗号的功能在这个标量上下文当中有同样的效果。小括号只表示一小群。当一个单独的元素被放在小括号内并且赋给了一个标量上下文,它将成为典型的标量值:
$value = (20);
如果你想建立一个只有一个元素的数组索引,使用方括号([ . . . ]) 来创造一个匿名数组的引用:
$arrayref = [20];
一个看起来象哈希的内容被赋给了一个标量变量,这样它就产生了一个排列整齐的对儿数组,下面这种方法就是:
$pair_list = ( "Zaphod" => 362, "Ford" => 1574, "Trillian" => 28 );
如果要使用哈希引用在标量上下文中,你必须使用{...}明确的表示出来这个结构:
$hashref = { "Zaphod" => 362, "Ford" => 1574, "Trillian" => 28 };
变量使用@作为印记将产生”平整列表”上下文。这个意思是如果你赋一个数组给另外一个数组,那么这些元素会很顺利的从原来的数组一个一个的复制到新数组中。这个结果就是两个不同结构的数组将包含有一样的值:
@copy = @original;
一个列表同样也使用平整列表上下文。把一个数组赋给一个平整的列表并且把数组中每个元素按照前后顺序给到列表。如果数组的元素比列表多,那么多余的部分将自动被抛弃:
($first, $second, $third) = @array;
在列表上下文中如果有一个单独值,那么它将产生一个单独元素的数组:
@array = (20); @array = 20; # same
当匿名数组引用使用[ . . . ]构造器并且内部存放平整列表作为内容时。它将不能被处理成为列表上下文,这是因为平整列表上下文不能平整引用。在标量上下文中,一个普通的列表与一个数组引用结构可以产生一样的结果。但是在列表上下文中,一个(...)构造的列表可以作为一个平整列表对待,可[...]这种只能作为列表单一元素对待,这个元素是一个引用它可以引用到[...]中:
@array = ( "Zaphod", "Ford", "Trillian" ); @array = [ "Zaphod", "Ford", "Trillian" ];
上面第一个例子会产生有三个元素的数组。上面第二个例子会产生有一个元素的数组并且这个元素是引用了另外一个有三个元素的数组。这对于创造一个复杂的数据结构来说很有用处。
@array = ( "Marvin", [ "Zaphod", "Ford", "Trillian" ], "Zarniwoop" );
同样的,在平整列表上下文中的一群数组变量列表可以平整成一个新的列表。一个标量变量列表也可以被处理成为新列表,即使这个标量变量列表中存储的是数组引用:
@array = ( @array1, @array2, @array3 ); # single flattened list @array = ( $arrayref1, $arrayref1, $arrayref3 ); # 3-element list
上面第一个例子产生一个包含他们三个数组所有元素的新数组,而第二个例子将产生包含他们三个引用的数组。
一个对独立的()表示将产生一个空列表。它将产生一个没有任何元素的数组结构,在标量里,和在列表上下文里均可:
$arrayref = ( ); # 0-element arrayref @array = ( ); # 0-element array
使用%印记的哈希列表上下文,期望得到对儿列表对象。这是一个典型的使用对儿构造器(=>)创造的匿名对儿列表:
%hash = ( "Zaphod" => 362, "Ford" => 1574, "Trillian" => 28 );
一个简单的值列表在哈希列表上下文中会被变为对儿列表。你可以在哈希列表中替代对儿书写那种方式:
%hash = ( "Zaphod", 362, "Ford", 1574, "Trillian", 28 );
{ . . . }用于构造匿名哈希引用,但是他们并不强制为哈希列表下上文。这是因为用 { } 包围一个普通结构并把它赋给一个标量,那它就是一个匿名子程序了:
# a sub reference that returns a list $subref = { "Zaphod", 362, "Ford", 1574, "Trillian", 28 };
哈希引用构造器实际上不是{...}而是{...=>...},所以当你把一个哈希引用赋给一个标量的时候你就不能使用逗号构造对儿结构。。我们用=>来标记这个结构是一个哈希结构。如果存在歧义,你可以在上下文的右边强制指定块是哈希(hash)还是一个子程序(sub):
$subref = sub { print "Lost luggage.\n"; } $hashref = hash { "Zaphod", 362, "Ford", 1574, "Trillian", 28 };
道具允许将说明补充到变量或值上。如同Damian需要解释一样,工具很象纸贴。你可以写一些注释,或是干脆把需要的信息乱写上去。之后就把它贴冰箱上,或是显示器,或是你汽车仪表盘上。当你不需要的时候就把它拿下来丢掉就可以了。
一些道具是在编译时才被贴上的。他们被称做特性。特性仍然属于道具,只是他有一些特别点而已。特性在变量声明的时候就会被固定在变量上,并且以后也无法修改。编译时特性设置使用 is 关键字:
my $pi is constant = 3.14159;
constant 特性指定这个变量的值不可以被改变。
其他特性被加载在运行时。他们只修改变量的值而不是变量。他们可以被增加或删除在代码执行的任何阶段。运行时工具使用 but 关键字:
$true_value = 0 but true;
true 道具指定这个值如果是在布尔(Boolean)上下文的时候将成为true,将不考虑真实值是什么。这个道具的特性含义是Perl6系统的呼叫将被一个简单的条件式检查。这个变量仍然返回数字值(成功的时候是0失败的时候其他数字值),但是它的值标记将在呼叫成功后返回成功或失败。
道具和特性同样也可以存储值。在constant和ture被设置的时候定义他们自己的值。一些道具存储值参数:
my @array is dim(2,5,42); # specify dimensions
你绝对不会相信道具有那么重要,并且还有更广阔的语法。你将在以后很多章节中看看到他的影子。道具不仅仅是对变量与值的设置,实际上他可以被设置在子程序、函数、类、词法、分析器并且存在参数列表中。
Perl6允许你指定变量的类型与值的功能要比Perl5强,但是请注意您并不一定需要指定他们。如果你使用他们你将获得一些性能上的好处与语言之间的接口。类型系统还未全部完成,但是基础已经完成。
Perl6在值类型与变量类型之间有一点小小区别。值 类型指定这个这个值所在的变量可以存储那种值。将一个 Int 值类型赋给一个标量后这个标量将只能存储整型值:
my Int $scalar;
将一个 Int 数值类型赋给一个数组后这个数组将只存储整型值:
my Int @array;
同样,将一个 Int 值类型赋给一个哈希这个哈希也将只存储整型值(但是不设置 键 的类型):
my Int %hash;
变量 类型指定这个变量是什么容器。这个看起来基本上跟Perl5里的 tie 差不多。变量类型定义跟特性一样,使用 is 关键字。这个标记将暗示变量的类习惯内,如果要设置无类型的变量只需要这样:
my $scalar is Scalar; my @array is Array; my %hash is Hash;
你同样可以定义你自己的类来实现变量类型:
my $scalar is FileHandle; my @array is Matrix; my %hash is BerkeleyDB;
分级数据结构可以使用一个综合值类型。一个哈希存储整型数组,数组将只包含值类型 Array of Int:
my Array of Int %hash;
类型语法是可以改变的,你同样也可以这么写:
my %hash is Hash of Array of Int; # or my %hash of Array of Int;
获得设置数据结构,这样将改进可读性,特别是在多级数据结构里:
my Array of Hash of Array of Int %hash; my %hash is Hash of Array of Hash of Array of Int;
操作符为值的操作提供了一条捷径,它用几个字符就可以完成一个函数或多个函数才能做到的事情。从乐观角度讲操作符提供了不可思议的方便,当然从相反角度来看操作符由于在一个很小的地方就包含非常做的含义所以学习起来要困难一些。许多Perl6的操作符都是大家熟知的,尤其是Perl5程序员们。新的操作符部分也为语言本身增加了新功能,或是让Perl的操作符同系统更一致了。
等于号(=)是最普通的操作符。它把值从右面复制并且赋给右面的变量或某种数据结构:
$copy = $original; @copies = @originals;
$copy和$original有相同的值;@copies拥有@originals所有的元素。
冒号等于号(:=)用来操作绑定赋值。使用创建别名的方式代替从一个变量或结构复制到其他。别名在符号表中表示对这个值容器的另外一个入口(译者注:就象给你家开一个后门一样,屋子都是同样的内容)。
$a := $b; # $a 是 $b 的别名 @c := @d; # @c 是 @d 别名在这个实里例中如果你修改变量$a那么变量$b也会有变化,反之也是。这是因为他们两个只是同一个容器的不同名字而已。绑定赋值要求在两边有相同数量的元素否则就会出错:
# ($a, $b) := ($c); # 错误 # ($a, $b) := ($c, $d, $e); # 错误
双冒号等于号(::=)是一个不同的绑定操作符,它在程序编译时才被执行。
算术操作符有:加法(+)、减法(-)、乘法(*)、除法(/)、系数(%)、求幕(**)。他们每个都有相应的赋值符表达方式(+=、-=、*=、/=、%=、**=):
$a = 3 + 5; $a += 5; # $a = $a + 5
一元算术操作符使用前缀和后缀的自增(++)自减(--),前缀符在赋值前完成计算,后缀符与其相反。
$a++; $a--; ++$a; --$a;
浪线(~)操作符用来连接字符串。连接符(~=)将右边的字符串赋到左面的结尾:
$line = "The quick brown " ~ $fox ~ jumps_over( ) ~ " the lazy " ~ $dog; $line ~= "Belgium"; # 追加到$line的结尾
X操作符(x)可以重复字符串。他将反复的返回字符串不管操作符左面是一个单元素的变量还是一个列表。下面的实例赋值"LintillaLintillaLintilla":
$triplet = "Lintilla" x 3;
相应的x=操作符重复原字符串并且返回给原变量:
$twin = "Lintilla"; $twin x= 2; # "LintillaLintilla"
XX操作符(xx)用来重复列表。它将返回一个列表而不管左面是一个列表还是一个单元素。下面的这个实例赋值了有三个元素的数组@array,其中每个元素都是"Lintilla":
@array = "Lintilla" xx 3; # ("Lintilla", "Lintilla", "Lintilla")
相应的xx=将产生有指定数量元素的列表,并且将其赋给一个数组变量:
@array = (4, 2); @array xx= 2; # 成为了 (4, 2, 4, 2) @array = (@array, @array); # 等价
范围操作符(..)返回一个值的列表,但是你要指定开始点和结束点:
@range = 3..7; # 3,4,5,6,7
范围操作符是惰性的,所以一个包含无穷值的范围将不会一次计算所有的数在赋值前。相反他将返回一个列表发生器,只有在你需要的时候才返回你需要的元素。
@range = 3..Inf; # 惰性
省略号操作符(...)同..Inf是一样的:
@range = 3 . . . ;
每个比较操作符都有两个样子,一个是数字比较另一个是字符串比较。比较操作符有大于(>,gt),小于(<,lt),大于等于(>=,ge),小于等于(<=,le),等于(==,eq),不等于(!=,ne)。身份操作符(=:=)用来测试两个参数是否相同对象的别名。如果表达式为真将返回真如果为假将返回假。标准操作符(<=>,cmp)在两个参数相同的情况下返回0,如果第一个大返回1,如果第二个大-1:
if ($age > 12) { . . . }
比较操作符允许被连接在一起。被连接在一起的比较操作符在执行的时候每个只执行一次:
if (24 < $age < 42) { . . . } # 24 < $age and $age < 42
二元逻辑操作符根据条件的真实性测试两个值,然后返回其中一个或另外一个。他们也被认为是缩短(short-circuit)操作符,这是因为总的真实性可以由左侧来确定的话,右侧的就不会被运算。这样以来他就可以有条件的赋值和执行代码了。
关系操作符与(AND)用&&和低优先级的and来表示。如果左侧运算结果为假,那么就返回他的值。如果左侧运算结果为真,那右侧就被运算并返回它的值:
$splat = $whale && $petunia; $splat = ($whale and $petunia);
关系操作符或(OR)用||和低优先级的or来表示。当左侧为真时返回左侧值,否则运算右侧返回右侧值:
$splat = $whale || $petunia; $splat = ($whale or $petunia);
一个不同的或(OR)关系是用来测试是否定义而不是真假。它使用//和低级的err作为操作符。如果左侧的值有定义就返回,否则运算右侧返回右侧的值:
$splat = $whale // $petunia; $splat = ($whale err $petunia);
关系异或(XOR)用^^操作符和低级的xor操作符表示。当任意一个操作数(aperand)为真时返回为真的操作码。如果两个都为真或都为假时返回假。xor与其他不同,他不是缩短操作符。因为他必须运算两个条件才能知道真假:
$splat = $whale ^^ $petunia; $splat = ($whale xor $petunia);perl 6 当然也有不同的布尔逻辑操作符:?& (AND), ?| (OR), 和 ?^ (XOR)。它们返回的值都是真或假。
$whale = 42; $petunia = 24; $value = $whale || $petunia # $value is 42 $truth = $whale ?| $petunia # $truth is 1
上下文表达式指定了将要输出的值的类型。一个数组希望同时被赋多个值,所以列表上下文正巧被赋到数组上了。一个标量变量希望得到一个单一的值,所以正好一个标量上下文来了。Perl的表达式常常适合这些上下文,产生他们需要的值。
上下文经证明是Perl5里非常有价值的工具,所以在Perl6中由为它的重要性增加了筹码。空上下文环境(void context)依然存在,标量上下文被细化到布尔(boolean),整型(integer),数字(numeric),字符串(string)和对象(object)上下文。列表上下文被细化到平整列表(flattening-list)上下文,不平整列表上下文,懒惰列表上下文,哈希列表上下文。
空上下文
不需要任何返回值。
标量上下文
需要单一值。如果一个合成值,返回它自己的引用。
布尔上下文
需要真或假。包括传统对真的定义"0","undef"空字符串代表假。也包括其他值所定义的真假"true"和"false"。
整型上下文
需要整型值。已经被处理成为数字的字符串和浮点数(floating-point)将被切掉多余的部分。
数字上下文
需要数字,不管是整型的还是浮点的。不管是不是十进制的,还是二进制,十六进制,八进制或其他什么类型。
字符串上下文
需要字符串,它将把所有经过它的信息统统格式化成为字符串。
对象上下文
需要对象或更多的特性,一个对象的引用。它同样需要一个详细类型的对象。
列表上下文
需要收集值。任何一个单值在列表上下文中都将成为这个列表上下文的一个元素。
平整列表
需要一个列表。从他们那里平整出数组或哈希。
不平整列表上下文
需要一个列表。邀请数组、哈希和其他组合值成为离散实。
懒惰列表上下文
需要一个列表。和不平整列表上下文很象,但是并不一次性的需要列表的所有元素。
哈希列表上下文
需要对儿列表。每个典型哈希上下文都是以对儿作为基础的。
当一元上下文操作符不受其他的影响时将会强制一个特殊的上下文。通常,默认的上下文总是对的,但是有些时候你需要对他们做些少许的控制。
一元操作符?和低优先级的等价符true强制布尔上下文。赋值一个标量给另外一个标量只是简单的利用标量上下文,所以$number的值只是简单的被复制。如果使用?操作符号,你可以强制赋真(true)给这个变量而不是$number的值。
$value = $number; $truth = ?$number;
一元操作符!和低优先级的等价符not同样也强制布尔上下文,但是他们会否定(给假值)值。他们常常被用在只有否定是可见的布尔上下文结构中。
$untruth = !$number;
一元操作符+强制数字上下文,并且-也强制数字上下文只不过它与+正好相反:
$number = +$string; $negnum = -$string;
一元操作符~强制字符串上下文:
$string = ~$number;
你同样可以建立标量,列表,哈希上下文使用$(...),@(...)和%(...)。
本段部分未完成......
三重操作符??::求它的第二个或第三个操作码,依赖条件是第一个操作码为真或是假。它基本上是一个if-then-else结构的符号表达式:
$form = ($heads = = 2) ?? "Zaphod" :: "ape-descended lifeform";
超连符(hyper operator)基本上是为列表而设计的。他们是标准的标量操作符的"修改版"。每个操作符都有超连版,甚至用户定义的。它们同标量版相比有相同的基本结构,但是他们明显使用的是字符用标记» 和 «[2](还有文本模式的>>和<<)。下面这个实例超连增加符就是>>+<<。
[2]这个符号是UNICODE左面是U+00BB右面是U+00AB字符。超连符使用列表上下文作为他们的操作码,并让操作符穿越操作码中所有元素进行分配。超连增加符从第一个列表中拿出每一个个元素并且增加第二个列表中对应的元素:
@sums = @first >>+<< @second;
这个结果包含每一对儿元素的总和。就象每对儿元素使用标量操作符增加的一样:
@sums = ( (@first[0] + @second[0]), (@first[1] + @second[1]), etc . . . );如果超连符的一边是一个标量,那这个标量将穿越列表中每个元素:
@sums = @numbers >>+<< 5; @sums ( (@numbers[0] + 5), (@numbers[1] + 5), etc . . . );一元操作符同样也可以在一边使用超连符(只要只有一个操作码):
@less = @numbers >>--; @nums = +<< @strings;
本段部分未完成......
二元操作符~~提供了两个值之间的聪明匹配(smart match)。如果匹配成功它将返回真,如果匹配失败他将返回假[3]。反向匹配!~符进行相反的匹配:如果结果为假,那么它将返回真。聪明匹配的匹配模式是由匹配参数决定的。如果两个参数的类型不能在编译时就被决定,那么将在运行时决定。聪明匹配通常是平衡的,所以A~~B与B~~A将得到相同的结果。
[3]这是理论上的。实际上,匹配可能返回更复杂的值。只有在纯粹的布尔上下文的时候才会只返回真和假。任意标量(或是一些代码,但是代码返回的结果是标量值)的匹配依靠一个一其等价的字符串。如果$string包含"Ford"下面的实例结果将返回真:
$string ~~ "Ford"在标量里如果要匹配数字,那么就使用数字去匹配。下面这个实例将获得结果42,如果$number是42的话。
$number ~~ 42一个表达式的结果是42也会成真:
( (5 * 8) + 2 ) ~~ 42
用一个未定义的值来匹配出一个标量是否定义。如果$value返回真说明他未定义,如果返回假说明他定义了。
$value ~~ undef $value ~~ $undefined_value
标量值依靠一定规则(正则)来进行模式匹配。如果"towel"在$string的任何地方被找到,那么将返回真:
$string ~~ /towel/
标量匹配一个替换模式,并且常识替换值内容。如果$string的值发生替换将返回真否返回假:
$string ~~ s/weapon/towel/
标量值匹配一个布尔将很简单的返回真或是假。下面这个实例将永远返回真,因为右面的布尔总是返回真[4]:
[4]有些时候这个表达式似乎没什么用。当你对switch声明了解程度象聪明匹配一样的时候,兴许会让你更深的理解。更多的信息请查看以后内容。$value ~~ (1 = = 1)
未完成部分......
The Boolean value on the right must be an actual Boolean: the result of a Boolean comparison or operation, the return value of a not or true function, or a value forced into Boolean context by ! or ?. The Boolean value also must be on the right; a Boolean on the left is treated as an ordinary scalar value.
标量将顺序性的匹配比较列表当中的每个元素。在表达式-到-表达式的匹配模式中,如果其中一个元素匹配结果为真,那么匹配就为真。下面的表达式将得到真,如果$value同他们三个字符串相同:
$value ~~ ( "Zaphod", "Ford", "Trillian" )
这是一个缩短匹配:第一个匹配成功后它将停止继续。它将有相同的真值,就象连续的匹配了所有or一样:
($value ~~ "Zaphod") or ($value ~~ "Ford") or ($value ~~ "Trillian")
一个聪明匹配的列表可以包含所有的元素:标量,规则(rules),布尔表达样式,数组,哈希,其他:
$value ~~ ( "Zaphod", 5, /petunias/ )一个列表聪明匹配同另外一个列表进行匹配。其中第一个列表的每个值将会同第二个列表对应的值分别匹配。如果全部匹配成功那么结果将得到真。下面的这个实例得到的结果是真,因为他们两个列表完全一样:
( "Zaphod", "Ford", "Trillian" ) ~~ ( "Zaphod", "Ford", "Trillian" )
这两个列表不相同,尽管他们有一样的长度,有接近的元素进行匹配:
( $zaphod, $ford, $trillian ) ~~ ( "Zaphod", /Ford/, /^T/ )
这个列表-到列表的匹配同样是缩短的。如果第一个匹配失败它将停止,他们将得到相同的真值,因为他们使用了and连接起几个聪明匹配:
($zaphod ~~ "Zaphod") and ($ford ~~ /Ford/) and ($trillian ~~ /^T/)
一个非数字的匹配表达式匹配数组时候将匹配值是否在这个数组中。如果值在数组中被找到将得到真的返回值。如果@array中的内容是"Zaphod","Ford"和"Trillian"并$value中包含他们其中的一个,那么返回值也将是真:
$value ~~ @array
一个整型值匹配数组,将检查数组对应这个值索引元素是否存在。下面这个实例如果@array[2]存在将返回真:
2 ~~ @array
一个整型匹配数组引用,同样也将检查索引的元素是否存在:
2 ~~ [ "Zaphod", "Ford", "Trillian" ]
这个匹配将返回真,因为第三个元素的引用是真。
如果使用*操作符(查看以后控制结构部分)平整后的数组去匹配,相当于拿一组标量值去匹配一样。所以,下面的实例将搜索数组中包含2的值,而不是数组的第二个元素:
2 ~~ *@array
一个数组通过规则(正则)匹配一个表达式将会把数组中每个元素都拿出来匹配。只要其中有一个被匹配成功那么就返回真。如果"Trillian","Milliways","million"是数组@array的元素,下面的匹配为真(不管其他的了):
@array ~~ /illi/
两个数组要是在一起匹配,那么他们两个会把所有的元素都拿出来进行对应的:
@humans ~~ @vogons
这个匹配返回真,如果两个数组有相同的长度并且@humans[0]匹配@vogons[0],@humans[1]匹配@vogons[1],等等。
哈系被标量匹配的时候将匹配hash第一个值是否为真(以标量作为键):
$key ~~ %hash
如果%hash{$key}存在,那么结果为真。
用一个正则表达式来匹配哈系的键:
%hash ~~ /blue/
只要在%hash中有一个包含blue,那么这个结果就将为真。
在两个哈系结构中检查他们共有的键:
%vogons ~~ %humans
所以,只要有一个键%vogons和%humans都有,就返回真。如果你想匹配是否有相同的键必须以列表形式来做:
%vogons.keys.sort ~~ %humans.keys.sort
哈系同数组进行匹配时将用数组部分的值去检查哈系。如果数组里任何一个值在是哈系的键,那么将返回真:
有待商议!!!
A hash matched against an array checks a slice of a hash to see if its values are true.
%hash ~~ @array
如果@array有一个元素是"blue"并且%hash有一个key是"blue",%hash{'blue'}有返回值就将为真,但是如果没有返回值就为假。
一个表达式匹配any连接符将递归分开(recursive disjunction)。在下面的实例中如果列表里任何一个元素被匹配将返回真,这是一个表达式-到-表达式的匹配:
$value ~~ any("Zaphod", "Ford", "Trillian")
这个表达式匹配$value同右面任意一个值匹配。这个效果跟列表比较差不多,只可惜它不保证比较的顺序是从那里开始。
聪明匹配all连接:只有连接中所有值都为真,才能得到真:
/illi/ ~~ all("Gillian", "million", "Trillian") # match succeeds /illi/ ~~ all("Zaphod", "Ford", "Trillian") # match fails
聪明匹配one连接符,只有一个值为真的时候表达式才为真:
/illi/ ~~ one("Zaphod", "Ford", "Trillian") # match succeeds /illi/ ~~ one("Gillian", "million", "Trillian") # match fails
聪明匹配none连接符,只有所有值都不为真的时候表达式才为真:
/illi/ ~~ none("Zaphod", "Ford", "Marvin") # match succeeds /illi/ ~~ none("Zaphod", "Ford", "Trillian") # match fails
一个any连接符匹配另外一个any连接符将会把所有值递归分开(recursive disjunction)。如果在第一个连接符的任何一个值等于第二个连接符的任何一个值,表达式将得到真:
any("Ford", "Trillian") ~~ any("Trillian", "Arthur")
这个表达式为真,因为"Trillian"在两个表达式里都存在。
对象匹配一个类名字,如果这个对象属于这个类或是继承自这个类。从本质上来讲他跟呼叫.isa方法差不多:
$ship ~~ Vogon::Constructor # $ship.isa(Vogon::Constructor)
任何一种表达式都可以匹配子程序的返回值。如果子程序没有参数,那么将会被处理成为布尔结构:
$value ~~ my_true
如果子程序有一个参数信号并且和这个表达式的变量类型兼容,那么这个表达式将以$value作为参数呼叫呼叫子程序:
$value ~~ &value_test # value_test($value) @array ~~ &array_test # array_test(@array) %hash ~~ &hash_test # hash_test(%hash)
子程序的返回值来决定匹配的真还是假。
一个块匹配匿名子程序。这个块的返回值将决定匹配是否为真。如果没有得到参数将被处理成为布尔结构,或在块中使用左边作为值(使用$_或占位符变量)(查看骆驼与鹦鹉的本质第二版第五章5.2.7节)。
$value ~~ { $_ + 5; } # $_ is $value %hash ~~ { $_.keys; } # $_ is \%hash @array ~~ { @^a.elems; } # @^a is @array
一元操作符\用来返回操作码的引用。因为标量上下文可以自动的产生数组,哈希,函数的引用。但是他仍然要使用在平整(平整列表)上下文或其他无法自动产生引用的地方。
@array_of_refs = ( \@a, \@b, \@c );
通常,一列的数组被赋给一个列表,这一列的数组元素要被平整成为一个单一数组。但,就引用操作符来讲,一个拥有三个数组引用的列表被赋值给@array_of_refs了。
一元操作符*(known as the splat operator未完成!!!)在上下文中平整一个列表时它通常被当作一个引用。在右值,*使数组转化成为一个简单的列表:
@combo = (\@array, \%hash); @a := @combo; # @a is @combo (@b, %c) := *@combo; # @b is @array, %c is %hash
因为@combo数组既包含数组引用又包含哈希引用。所以普通的捆绑赋值将@combo变成单一元素并且捆绑到@a中。而平整操作,@combo数组被转变成为一个简单的列表,所以其中每个元素都被分别的放到左面。@b就跳到了@array而@c就跳到了%hash。
在左值的时候*告诉数组吃掉所有可以吃的参数。如果一个普通的二对二绑定,就把他们分别的左一对右一,左二对右二形式完成了:
(@a, @b) := (@c, @d); # @a is @c, @b is @d
然而如果你使用*,那么左面第一个值将会平整右面所有元素成为一个列表然后在绑定赋值。所以,下面你看到的@a包含了@c和@d的所有元素:
*@a := (@c, @d); # @a contains @c and @d
关于*在子程序和方法参数中的用途,请查看以后的部分(如果以后还写Perl6子程序的话,记得告诉我们你需要看哦!)
压缩操作符|可以让两个列表或更多的列表(数组啊,哈希的键啊,等等)以交叉形式存放到一起并且返回一个新列表。它允在同一时间内使用循环反复的操作几个列表的元素。
@a = (1, 2, 3); @b = (4, 5, 6); @c = @a ¬| @b; # @c is (1, 4, 2, 5, 3, 6)
这个符号不是ASCII码,所以你没办法用键盘输入。你可以使用zip操作符来实现这个功能,他们两个功能是相同的。在之后的部分对这个zip有所描述。
最简单的流程控制是一个线性的。一个表达式跟随在一个直线在程序结束的时候。The simplest flow of control is linear—one statement follows the next in a straight line to the end of the program.Since this is far too limiting for most development tasks, languages provide ways to alter the control flow.
未完成!!!
选择在所有可能的地方执行一个动作的设置。选择控制结构有:if、unless和given/when。
If声明检查一个条件并且在条件为真的情况下窒息功能下面的块中代码。表达式可以被写成任何样子来取得需要的值。圆括号是表达式的可选参数:
if $blue { print "True Blue."; }
if表达式在获得失败之后同样可以有无限的 elsif 来检查附加的饿表达式。else作为最终模式等所有 if 和 elsif 表达式失败后执行:
if $blue { print "True Blue."; } elsif $green { print "Green, green, green they say . . . "; } else { print "Colorless green ideas sleep furiously."; }
unless 表达式的逻辑与 if 正好相反。如果条件得到失败的结果块中的代码才会被执行:
unless $fire { print "All's well."; }
还有一个 elsunless 声明,就象 unless 的 else 一样。
switch表达式采用比较 given 表达式(同别的语言 switch)与连续的 when 声明(同别的语言 cases)来执行选择动作。当一个条件匹配选择,这个条件的块就将执行:
given $bugblatter { when Beast::Trall { close_eyes( ); } when 'ravenous' { toss('steak'); } when .feeding { sneak_past( ); } when /grrr+/ { cover_ears( ); } when 2 { run_between( ); } when (3..10) { run_away( ); } }
If these comparisons are starting to look familiar, they should. The set of possible relationships between a given and a when are exactly the same as the left and right side of a smart match operator (~~). The given aliases its argument to $_. $_ is always the current topic (think "topic of conversation"), so the process of aliasing a variable to $_ is known as topicalization. The when is a defaulting construct that does an implicit smart match on $_. The result is the same as if you typed:
未完成!!!!
given $bugblatter { when $_ ~~ Beast::Trall { close_eyes( ); } when $_ ~~ 'ravenous' { toss('steak'); } when $_ ~~ .feeding { sneak_past( ); } when $_ ~~ /grrr+/ { cover_ears( ); } when $_ ~~ 2 { run_between( ); } when $_ ~~ (3..10) { run_away( ); } }
but more convenient. Generally, only one case is ever executed. Each when statement has an implicit break at the end. It is possible to fall through a case and continue comparing, but since falling through is less common, it has to be explicitly specified with a continue:
未完成!!!
given $bugblatter { when Beast::Trall { close_eyes( ); continue; } when 'ravenous' { toss('steak'); continue; } when 'attacking' { hurl($spear, $bugblatter); continue; } when 'retreating' { toss('towel'); } }
在所有的条件都失败后将执行default 条件块:
given $bugblatter { when Beast::Trall { close_eyes( ); } when 'ravenous' { toss('steak'); } default { run('away'); } }
所有在 given 中的代码都将被执行,但是如果一个 when 成功将停止在given中剩余的代码执行:
given $bugblatter { print "Slowly I turn . . . "; when Beast::Trall { close_eyes( ); } print "Step by step . . . "; when 'ravenous' { toss('steak'); } print "Inch by inch . . . "; }
这表示default 条件并不是必须的,因为把一些代码写在最后的 when 后将象 default 一样被执行。但是一个明确的 default条件可以更明确。只在诱捕异常的时候才有区别。更多的信息请查看以后的部分。
when声明同样可以被写在given的外面。当你这么写以后,将对$_ 进行简单的智能匹配。when statements also have a statement modifier form that doesn't have an implicit break:
print "Zaphod" when 'two heads'; # if $_ ~~ 'two heads'
循环结构允许你多次执行表达式。Perl6的循环表达式有while,until,loop和常见的for。
一个while循环在条件为真的情况下将永远循环。条件可以很复杂,但是结果永远都是一个单独的布尔值,因为while使用布尔上下文做为他自己的条件选择器:
while $improbability > 1 { print "$improbability to 1 against and falling."; $improbability = drive_status('power_down'); }
until 很象 while 循环但必须是条件为假才能一直循环下去:
until $improbability <= 1 { print "$improbability to 1 against and falling."; $improbability = drive_status('power_down'); }
loop 结构最简单,他将一直循环下去。除非在表达式中明确的终止循环,不然它将永远的下去。就象一个机器人老太太一样:
loop { print "One more of that Ol' Janx."; last if enough( ); }
loop同样支持循环记录数。象while似的,它在执行块中内容的每一次都不怕麻烦的测试表达式,但是它有更好的表达模式,在初始化和执行循环的时候可以为循环声明一些目标:
loop ($counter = 1; $counter < 20; $counter++) { print "Try to count electric sheep . . . "; }
loop表达式中的圆括号不是必须的。
for循环属于列表循环,它利用了懒散的列表上下文。他利用一个数组列表或表达式产生列表,并且每次循环取出列表中每个元素。在每一次循环的时候,for的别名$_将成为当前循环元素。这个意思是所有结构将默认的被放在$_中,象 print 和 when 可以默认循环值一样:
for @useful_things { print; # prints $_, the current loop variable print " You're one hoopy frood." when 'towel'; }
箭头操作符->可以产生当前元素的别名成为$_。[5]所有的别名的作用域只在块中。
[5]箭头不受for的限制;它同样也可以在given和其他流控制结构中使用。for %people.keys -> $name { print; # prints $_ (same as $name) print ":", %people{$name}{'age'}; }
箭头操作符同样可以在循环了每个元素后产生结束:
for %ages.kv -> $name, $age { print "$name is now $age"; }
你可以把几个独立的列表使用zip函数或zip操作符合并使用一个箭头操作符,并且在每次循环的时候取得相同指定数量的元素,代码如下:
# one from each array for zip(@people,@places,@things) -> $person, $place, $thing { print "Are you a $person, $place, or $thing?"; }
以上实例同时循环三个数组,从每个数组中获得元素并且产生三个元素的别名。
# two from each array for zip( @animals, @things, :by(2) ) -> $animal1, $animal2, $thing1, $thing2 { print "The animals, they came, they came in by twosies, twosies: "; print "$animal1 and $animal2"; print "Two things. And I call them, $thing1 and $thing2."; }
这个循环实例有两个数组,每次循环获得两个元素并且产生他们的别名。
# two from the first array and one from the second for zip(@colors=>2, @textures=>1) -> $color1, $color2, $texture { $mix = blend($color1, $color2); draw_circle($mix, $texture); }
这个循环实例有两个数组,每次从第一个数组取得二个元素同时从第二个数组取得一个元素并且产生他们的别名。
如果zip在数组或列表的长度不同情况下被呼叫了,那么他将为那个短的产生undef值别名。
关键字next,redo和last允许你破坏正在进行中的循环。next停止剩余部分的代码并且开始一次新的循环。redo停止剩余部分的代码并且重新开始这一次循环(在不增加记数或重新检查循环条件的基础上)。last停止剩余部分的代码并且完全终止循环。
for @useful_things -> $item { next when 'towel'; redo when .try_again; last when 'bomb'; print "Are you sure you need your $item?"; }
In Perl 6, every block is a closure, so you get consistent behavior throughout the language, whether the block is a control structure, an argument passed to a subroutine, an anonymous subroutine reference, or the definition of a named element such as a subroutine, method, or class. What is a closure? Closures are chunks of code that are tied to the lexical scope in which they're defined. When they're stored and later executed at some point far removed from their definition, they execute using the variables in their original scope, even if those variables are no longer accessible any other way. It's almost as if they package up their lexical scope to make it portable. This example creates a closure that prints a lexical variable. When the closure is executed (from some other lexical scope), it prints the variable from the scope where it was defined, not the scope where it's executed:
未完成!!!
my $person = "Zaphod"; $closure = { print $person; } . . . my $person = "Trillian"; $closure( ); # prints "Zaphod"
所有的闭合(closures)块都有相同的特点。所有的块能接受参数。这就是为什么for产生一个$_别名变量用于循环。每个块都定义一个自己的词语作用域(lexical scope)。所有的块都可能在以后去存储或执行它们。无论哪块存储还是执行它都依赖使用词语作用域的结构。在之前我们刚刚讨论过控制结构的执行都在他们所定义的块之内。一个赤裸的块可以自己立即执行,但是他存储的当参数上下文或是传递来的参数:
The fact that all blocks are closures has some implications. Every block can take arguments. This is how for creates a $_ alias for the iterator variable. Every block defines a lexical scope. Every block has the potential to be stored and executed later. Whether a block is stored or executed immediately depends on the structure that uses it. The control structures we've discussed so far all execute their blocks where they're defined. A bare block executes immediately when it's alone, but is stored when it's in an assignment context or passed as a parameter:
未完成!!!!
# executed immediately { print "Zaphod"; } # stored $closure = { print "Trillian"; }
my和our声明不同类的变量。my声明一个变量在当前的词语作用域(lexical scratchpad),而our声明一个词语别名在包的符号表:
my $lexical_var; our $package_var;
state声明词语变量同my差不多,state declares a lexical variable similar to my, but instead of reinitializing the value every time the block is executed it preserves the previous value:
state $static_var;
temp and let are not declarations; they are run-time commands to store the current value of a variable so it can be restored later. temp variables always restore their previous value on exiting the lexical scope of the temp, while let variables keep the temporary value, unless the lexical scope of the let is exited under an error condition (an undef or empty-list return value, or an exception):
temp $throwaway; let $hypothetical;
temp and let don't change the value of the variable, they only store it.
块可能赋有有连续的流控制句柄。These are called property blocks because they are themselves blocks (i.e., closures), attached as properties on the block that contains them. Property blocks are defined within the block they modify, by an uppercase keyword followed by a block (they're also sometimes called NAMED blocks):
NEXT { print "Coming around again." }
Property blocks aren't executed in sequential order with the other code in the enclosing block—they are stored at compile time and executed at the appropriate point in the control flow. NEXT executes between each iteration of a loop, LAST executes at the end of the final iteration (or simply at the end of an ordinary block). PRE executes before everything else—before all other properties and code in an ordinary block and before the first iteration of a loop. POST executes after everything else—after all code and properties in an ordinary block and after the last iteration of a loop. PRE and POST are intended for assertion checking and cannot have any side effects. CATCH, KEEP, and UNDO are related to exception handling. KEEP and UNDO are variants of LAST and execute after CATCH. KEEP executes when the block exits with no exceptions, or when all exceptions have been trapped and handled; UNDO executes when the block exits with untrapped exceptions. There can be only one CATCH in a block, but there's no limit on the other types of property blocks.
This example prints out its loop variable in the body of the block:
for 1..4 { NEXT { print " potato, "; } LAST { print "." } print; }
每次执行循环的时候,NEXT块都被执行,打印 "potato"。在最后一次循环的时候 LAST块打印一个句号。所以最后的结果是这个样子:
1 potato, 2 potato, 3 potato, 4.
Property blocks是属于词语作用域(lexically scoped)闭合块(enclosing block),所以他们可以访问词语变量象这样定义:
for 5..7 -> $count { my $potato = "$count potato, "; NEXT { print $potato; } LAST { print $potato, "more."; } }
这个实例词语变量$potato在每次循环都被重新定义并且在NEXT和LAST块中被打印,所以最后结果是这样:
5 potato, 6 potato, 7 potato, more.
异常一共有两种类型:一、错误异常 二、控制流异常。所有的异常都被存储在异常对象$!中。所有的异常都继承自Exception类。
错误异常使用die或(在use fatal的时候)fail抛出。任何块需要异常句柄的时候只需要内含一个CATCH块。CATCH块只讨论$!的话题,所以最简单的测试方法是使用when声明比较一个类的名字(查看操作符部分):
CATCH { when Err::Danger { warn "fly away home"; } }
$!对象同样stringify文字信息,如果你匹配一个表达式:
CATCH { when /:w I'm sorry Dave/ { warn "HAL is in the house."; } }
如果CATCH块因为一个明确的break表达式退出或隐含的break藏在when或default条件里,它将会把产生的异常清除掉。A when case with a continue statement leaves the exception unhandled, since continue skips the implicit break.如果一个异常标记在CATCH块中没有被清楚掉,CATCH将会被自己外部的块获得。
一旦一个异常被抛出,执行停止的部分一直到CATCH块的剩余代码会被停止。如果这个执行块中包含有 POST,KEEP或UNDO property blocks,他们将在CATCH块之后执行。
如果你想要限制一个异常的产生,你可以把错误抛出代码包围在一个try块中。一个try块写在CATCH块的外面并且提供了默认的CATCH用来捕抓所有的异常,清除标记并且在出现异常的时候尝试返回undef。try同样也是本文中随手可得的部分。
try { may_throw_exception( ); CATCH { when Error::Moof { warn "Caught a Moof error."; } } }
控制流程中的异常有时也会在控制流没有错误的时候发生。当你调用next去停止剩余部分的代码并且开始下一次循环,你实际上已经抛出一个控制异常。控制异常一般是由next和last在循环中抛出的。而一个return异常是由子程序或方法抛出的。
是的,截止现在还没有一个成品Perl6解析器(·#¥%……?)!!!
您可能认为,真正出来再说吧。难道您只愿意一辈子都使用别人设计的语言吗?您不愿意加入Perl6的开发吗?
您可能怀疑自己能否加入开发队伍。要告诉您的是,即使您只能测试1+1=2您也将为这个项目做出巨大的奉献。如果您希望能尽快的使用到Perl6参加我们的工作是最好的选择。
比较幸运的是Perl6一个重要的项目Pugs(用Haskell语言设计的)已经开始能运行Perl6代码了。这是向全世界推广Perl的台北电脑天才Autrijus Tang所带领的项目。他和我们Perlchina的所有人一样希望能有更多的人加入这个项目。
您可以为Perl6设计第一个配置文件读取器,第一个MYSQL连接程序,第一个Template系统,第一个CGI记数器等等,或是把现有的CPAN搬到Perl6上,这对你来说都不是难事。一切这些都可以用Pugs运行。当更多的人找到Pugs和Perl6的弱点,Perl6就已经快出现了。
最后告诉对Pugs有兴趣的人一个秘密,用IRC登陆irc.freenode.net的#perlchina房间你可以找到Autrijus Tang你可以用中文与他聊天哦:)
我真奇怪你能花那么久时间看这一篇翻译的糟