关于6的另外六件我喜欢的事情
The Perl Shop最近赞助我参加了一次关于Perl 6的会议,这次会议是在Boston Perl mongers的聚会上。他们支持了Learning Perl 6的Kickstarter项目。作为其中的一部分,我在Perl mongers小组中发表了关于我喜欢这个语言的演讲。这些不一定是最激动人心或最先进的功能,也不一定是最新计算机科学功能。它们只是我喜欢的事情。
许多这些功能散布在语言景观中,我长期以来都说,当我找到一个比Perl更好的语言时,我会很高兴地放弃Perl。现在,我正在获得一些我可能在其他语言中渴望的功能,而这些语言缺少一些我仍然喜欢Perl的东西。
糟糕
Perl 6可以通过将有理数作为比率而不是原生浮点数来保持尽可能的精度。这意味着我们不必处理依赖于底层存储的各种问题。
$ perl5 -le 'print 0.3 - 0.2 - 0.1'
-2.77555756156289e-17
这有点不对,但我们已经接受了(例如,将所有货币金额乘以整数,这样你只需要处理整数)。然而,Perl 6可以精确地存储它们,只要可能
$ perl6
To exit type 'exit' or '^D'
> my $rat = 0.3
0.3
> $rat.numerator
3
> $rat.denominator
10
> 0.3 - 0.2 - 0.1
0
重复小数仍然是有理数,尽管Perl 6还没有一个功能来在重复的部分上放置横线
> <1/3>
0.333333
软错误
Perl 6有Failure对象,它封装了一个异常。许多事情在出错时可能会返回这样的对象。在布尔上下文中,Failure总是False
,但Perl 6还标记它为已处理,当它被这样检查时。否则,如果我试图使用那个对象,就像一切都很成功一样,它立即抛出异常
my $file = 'not-there';
unless my $fh = open $file {
put "In unless: exception is {$fh.exception.^name}"
}
CATCH {
put "Caught {.^name}: {.message}";
}
输出显示我在unless
中处理了问题
In unless: exception is X::AdHoc
与不检查open
的结果并继续像文件句柄很好一样进行下去的代码进行比较
my $file = 'not-there';
my $fh = open $file;
$fh.lines;
CATCH {
put "Caught {.^name}: {.message}";
}
现在异常接管了,CATCH
块处理它。这会伴随着一个堆栈跟踪
Caught X::AdHoc: Failed to open file not-there: no such file or directory
Failed to open file not-there: no such file or directory
in any at ... CORE.setting.moarvm line 1
in block <unit> at ...
Actually thrown at:
in block <unit> at ...
我喜欢这个让我决定如何检查错误的功能。我一直认为,各种try
的语法(在任何语言中)强迫自己的方式进入语言,并接管了源代码。
而且,我对面向对象编程的想法非常着迷,以至于我有一个Perl 5模块可以做到类似的事情:ReturnValue。我使用它来返回值,调用者可以通过调用结果的方法来确定发生了什么。
可恢复异常
让我们来谈谈异常。我不喜欢人们试图在Perl 5中推给我的虚假异常。如果我不能真正处理它并继续程序,我认为它不是一个正确的异常。它只是返回值的不同方式。
CATCH {
default {
put "Problem with file: {.^name} --> {.message}";
.resume
}
}
my $line = read-a-line( 'not-there' );
sub read-a-line ( $file ) {
X::AdHoc.new( :payload<Oh no Mr Bill!> ).throw;
say "Hey, I can keep going!"
}
我看到CATCH
处理了异常,然后允许子程序中的代码继续
Problem with file: X::AdHoc --> Oh no Mr Bill!
Hey, I can keep going!
并非每个异常都可以恢复,但我看到了这个能力的大量前景。
更简单的插值
我对语言的评估主要基于我创建新字符串的难易程度。Perl 5在这方面做得相当不错,但Perl 6做得更好。
标量、数组、哈希(是的,哈希!)可以直接插值,尽管后两者需要添加索引字符
say "This one has a $scalar";
say "The array needs braces: @array[]";
say "The hash needs curlies: %hash{}";
不过,更好的是,我可以通过在字符串中将任何内容括在花括号中来对其进行插值。Perl 6会在花括号中评估代码,并用最后评估的表达式替换块。
say "There are { $scalar.elems } elements";
say "The object's name is { $object.^name }";
say "The sum is { 2 + 2 }";
say "The lowest is { @array.sort.[1] }";
say "The lowest is { @array.min }";
我可以用sprintf
做这件事,有时我觉得这样做更合适。但我经常在字符串中玩引用解引用游戏来完成我现在可以通过设计完成的事情。我真的喜欢这个(我想Ruby程序员也会喜欢)。
fmt
你有一个标量,想要以不同的方式格式化它?有相应的办法。这不是一个令人兴奋的新特性,因为printf
已经存在很长时间了。与插值类似,这看起来可能是一件小事,但在我使用它的那些时候,我非常高兴,尽管我脑后的声音在说:“你个傻瓜,这不过是sprintf
!”
my @buffer = Buf.new( ... );
@buffer.map( { .fmt: "%02x" } ).join( ' ' ).put;
我忽略了那里的括号,通过在方法名后放置冒号来将参数传递给.fmt
。由于我没有指定对象,这使用了主题(你称之为$_
)。
出于某种原因,我比这篇文章的所有读者想的更喜欢这个。
$buffer.map( { sprintf "%02x", $_ } ).join( ' ' )
列表的列表
Perl 6有列表的列表(自从大列表重构以来)。这对于习惯了Perl 5的“总是扁平”的列表的人来说可能会有些不安,但我相信你会习惯它们的。这对于将相关值放在一起非常有用。
而且,列表是一个对象,作为一个单一的事物,你可以将其存储在标量变量中。它知道它是一个列表。
my $scalar = ( 1, 2, 3 );
# my $scalar = 1, 2, 3; # Nope!
put "scalar: $scalar";
put "scalar: { $scalar.^name }";
scalar: 1 2 3
scalar: List
你可以有字面意义上的列表的列表。
my @array = ( ( 1, 2 ), qw/a b/ );
put "elems: { @array.elems }";
put "@array[]"; # the whole thing
put "@array[0]"; # the first thing
put "{ @array[0].^name }";
2
1 2 a b
1 2
List
但是,这里还有更好的。你可以反过来。我从这个缓冲区的扁平列表(在这种情况下是表示八位的数字列表)转换到可以迭代的两个元素列表。这对于处理二进制格式非常有用。
my Buf $buf =
Buf.new( 0xDE, 0xAD, 0xBE, 0xEF );
for $buf.rotor(2) -> $c {
put "c is $c";
put "word is ",
( $c[0] +< 8 + $c[1] )
.fmt( '%02X' );
}
c is 222 173
word is DEAD
c is 190 239
word is BEEF
我可以写更多关于列表的列表的内容,但这篇文章已经足够长了。我将把一些内容留到以后的文章中。你可以在https://www.learningperl6.com上看到我更多的Perl 6内容。
这篇文章最初发布在PerlTricks.com。
标签
brian d foy
brian d foy是一位Perl培训师和作家,同时也是Perl.com的高级编辑。他是《Mastering Perl》、《Mojolicious Web Clients》、《Learning Perl Exercises》的作者,也是《Programming Perl》、《Learning Perl》、《Intermediate Perl》和《Effective Perl Programming》的合著者。
浏览他们的文章
反馈
这篇文章有什么问题吗?请在GitHub上打开一个问题或拉取请求来帮助我们。