描述§

这份文档试图列出 Perl 特殊变量及其在 Raku 中的等效项,并说明它们之间必要的差异。

注意§

这份文档旨在帮助读者从 Perl 的特殊变量过渡到 Raku 中的等效项。有关 Raku 特殊变量的完整文档,请参阅每个变量的 Raku 文档。

特殊变量§

通用变量§

$ARG, $_§

值得庆幸的是,$_ 在 Raku 中仍然是通用默认变量,就像在 Perl 中一样。Raku 中的主要区别在于你现在可以对它调用方法。例如,Perl 中的 say $_ 在 Raku 中可以写成 $_.say。此外,由于它是默认变量,你甚至不需要使用变量名。前面的例子也可以通过使用 .say 来实现。

@ARG, @_§

由于 Raku 现在有了函数签名,你的参数可以放在那里,而不是依赖 @_ 来传递它们。实际上,如果你使用函数签名,使用 @_ 会报错,因为它不能覆盖现有的签名。

但是,如果你没有使用函数签名,@_ 将包含你传递给函数的参数,就像在 Perl 中一样。同样,与 $_ 一样,你也可以对它调用方法。与 $_ 不同的是,你不能假设 @_ 是这些方法操作的默认变量(例如,@_.shift 可以工作,.shift 则不行)。

$LIST_SEPARATOR, $"§

目前,Raku 中没有列表分隔符变量的等效项。设计文档 S28 中说没有,所以你可能不要抱太大希望。

$PROCESS_ID, $PID, $$§

$$ 在 Raku 中被 $*PID 替换。

$PROGRAM_NAME, $0§

你可以在 Raku 中通过 $*PROGRAM-NAME 访问程序名称。

注意:Raku 中的 $0 是保存正则表达式匹配中第一个捕获值的变量(即捕获变量现在从 $0 开始,而不是 $1)。

$REAL_GROUP_ID, $GID, $(§

在 Raku 中,组信息由 $*GROUP 处理,它包含一个 IntStr 类型的对象,因此可以在字符串或数字上下文中使用。因此,组 ID 通过 +$*GROUP 获取,组名通过 ~$*GROUP 获取。

$EFFECTIVE_GROUP_ID, $EGID, $)§

有效组 ID 似乎目前没有在 Raku 中提供。

$REAL_USER_ID, $UID, $<§

在 Raku 中,用户信息由 $*USER 处理,它保存一个类型为 IntStr 的对象,因此可以在字符串或数字上下文中使用(这类似于组信息如何由 $*GROUP 对象处理)。因此,用户 ID 通过 +$*USER 获取,而用户名通过 ~$*USER 获取。

$EFFECTIVE_USER_ID, $EUID, $>§

Raku 不提供有效用户 ID。

$SUBSCRIPT_SEPARATOR, $SUBSEP, $;§

Raku 中不包含下标分隔符变量。坦率地说,如果你的 Perl 代码正在使用它,它几乎肯定非常非常旧了。

$a, $b§

$a$b 在 Raku 中没有特殊含义。sort() 不对它们进行任何特殊处理。它们只是普通的旧变量。

此功能已通过具有占位符参数的块扩展,这些块更加通用。占位符变量使用 ^ twigil 创建(例如 $^z)。它们可以在没有显式参数列表的裸块或子例程中使用。块的参数按其 Unicode 顺序分配给占位符变量。也就是说,即使变量在块中按 ($^q, $^z, $^a) 的顺序出现,它们也会按 ($^a, $^q, $^z) 的顺序分配。因此

sort { $^a cmp $^z }156423;
# OUTPUT: «(1 2 3 4 5 6)␤» 
sort { $^g cmp $^a }156423;
# OUTPUT: «(6 5 4 3 2 1)␤» 
for 1..9 { say $^c$^a$^blast }
# OUTPUT: «312␤» 

有关占位符变量的更多信息,请参阅 此页面

%ENV§

在 Raku 中,%ENV 已被 %*ENV 取代。请注意,此哈希的键在 Perl 和 Raku 之间可能不完全相同。例如,OLDPWD 在 Raku 的 %ENV 中缺失。

$OLD_PERL_VERSION, $]§

Raku 的运行版本由 $*RAKU 特殊变量保存,该变量是一个对象。运行版本通过 $*RAKU.version 获取,它返回类似于 v6.d 的内容;Raku 解释器的完整字符串化版本通过 $*RAKU.gist 获取,它返回类似于 Raku (6.d) 的内容。

$SYSTEM_FD_MAX, $^F§

在 Raku 中不再存在。

@F§

[需要进一步研究] 此时有点令人困惑。设计文档 S28 指出 Perl 中的 @F 在 Raku 中被 @_ 取代,但目前尚不清楚它是如何工作的。另一方面,这目前有点无关紧要,因为 Perl 到 Raku 翻译文档表明 -a-F 命令行开关尚未在 rakudo 中实现。

@INC§

在 Raku 中不再存在。请使用“use lib”来操作要搜索的模块存储库。最接近 @INC 的东西实际上是 $*REPO。但这与 @INC 的工作方式完全不同,主要是因为 Raku 的预编译功能。

# Print out a list of compunit repositories 
.say for $*REPO.repo-chain;

%INC§

在 Raku 中不再存在。因为每个存储库负责记住哪些模块已被加载。你可以获取所有已加载模块(编译单元)的列表,如下所示

use Test;
use MyModule;
say flat $*REPO.repo-chain.map(*.loaded); #-> (MyModule Test) 

$INPLACE_EDIT, $^I§

S28 建议 $*INPLACE_EDIT,但它尚不存在。

$^M§

S28 建议 $*EMERGENCY_MEMORY,但它尚不存在。

$OSNAME, $^O§

这有点不清楚。它可能取决于你对“操作系统名称”的理解,因为设计文档 S28 有三个不同的建议,它们都给出了不同的答案。

目前有三个主要对象包含有关“运行环境”的信息。

  • $*KERNEL 提供有关正在运行的操作系统内核的信息;

  • $*DISTRO 提供有关操作系统发行版的信息;

  • $*VM 提供有关 Raku 正在运行的后端机器的信息。

以上所有对象都具有共同的方法

  • version 提供该组件的版本号;

  • name 提供该组件的助记符名称;

  • auth 提供该组件的已知作者。

作为一个简短的示例,以下代码片段打印了有关所有上述组件的信息

for $*KERNEL$*DISTRO$*VM -> $what {
    say $what.^name;
    say 'version '  ~ $what.version
        ~ ' named ' ~ $what.name
        ~ ' by '    ~ $what.auth;
}
 
# Kernel 
# version 4.10.0.42.generic named linux by unknown 
# Distro 
# version 17.04.Zesty.Zapus named ubuntu by https://www.ubuntu.com/ 
# VM 
# version 2017.11 named moar by The MoarVM Team 

以上所有对象上的 Cool.Str 方法 会生成信息的简短版本,目前是 name

所有对象都有其他方法,这些方法在尝试识别确切的运行实例时可能很有用,有关更多信息,请使用 .^methods 来内省所有上述对象。

%SIG§

没有等效的变量。要让您的代码在接收到信号时执行,您可以调用 signal 子例程,它会返回一个可以被抽取的 Supply

$SIG{"INT"} = sub { say "bye"; exit }

signal(SIGINT).tap: { say "bye"exit }loop {}

或者,如果您有一个想要知道它收到了哪个信号的通用代码

signal(SIGINT).tap: -> $signal { say "bye with $signal"exit }loop {}

在事件驱动情况下使用信号的更惯用方式

react {
    whenever signal(SIGINT{
        say "goodbye";
        done
    }
}

$BASETIME, $^T§

在 Raku 中被 $*INIT-INSTANT 替换。与 Perl 不同,这不是自纪元以来的秒数,而是一个 Instant 对象,它以原子秒为单位进行测量,并带有小数部分。

$PERL_VERSION, $^V§

$] 一样,它已被 $*RAKU.version 替换。

${^WIN32_SLOPPY_STAT}§

在 Raku 中没有类似的东西。

$EXECUTABLE_NAME, $^X§

它已被 $*EXECUTABLE-NAME 替换。请注意,还有 $*EXECUTABLE,它是一个 Raku 中的 IO 对象。

性能问题§

如下所示,$`$&$' 已从 Raku 中删除,主要被 $/ 的变体替换,并且随着它们的消除,Perl 中相关的性能问题不再适用。

$<digits> ($1, $2, ...)§

这些现有变量在 Raku 中的作用与在 Perl 中的作用相同,只是它们现在从 $0 开始而不是 $1。此外,它们是匹配变量 $/ 中索引项的同义词。即 $0 等效于 $/[0]$1 等效于 $/[1],等等。

$MATCH, $&§

$/ 现在包含 Match 对象,因此 $& 的 Perl 行为可以通过将其字符串化来获得,即 ~$/

请注意,虽然 $/.Str 也应该可以工作,但 ~$/ 目前是更常见的习惯用法。

${^MATCH}§

由于以前的性能问题已消除,因此此变量在 Raku 中没有用处。

$PREMATCH, $`§

$/.prematch 替换。

${^PREMATCH}§

由于以前的性能问题已消除,因此此变量在 Raku 中没有用处。

$POSTMATCH, $'§

$/.postmatch 替换。

${^POSTMATCH}§

由于以前的性能问题已消除,因此此变量在 Raku 中没有用处。

$LAST_PAREN_MATCH, $+§

在 Raku 中不存在,但您可以使用 $/[*- 1].Str$/[*-1] 将是匹配对象,而不是实际字符串)获取相同的信息。

如果您想理解为什么它有效,您可以查看以下文档

[ ] routineWhatever历史设计文档

$LAST_SUBMATCH_RESULT, $^N§

S28 建议 $*MOST_RECENT_CAPTURED_MATCH,但似乎没有与 $^N 匹配的已实现变量。

@LAST_MATCH_END, @+§

与大多数与正则表达式相关的变量一样,此功能至少部分地转移到了 Raku 中的 $/ 变量。或者,在本例中,是别名为其索引的编号变量。偏移量是通过使用 .to 方法找到的。例如,第一个偏移量是 $/[0].to,它与 $0.to 同义。Perl 提供的 $+[0] 值由 $/.to 提供。

%LAST_PAREN_MATCH, %+§

我们再次转向 $/。以前的 $+{$match}$/{$match}

@LAST_MATCH_START, @-§

@+ 被使用 .to 方法替换类似,@- 被使用 $/ 及其变体上的 .from 方法替换。第一个偏移量是 $/[0].from 或等效的 $0.from。Perl 的 $- [0]$/.from

%LAST_MATCH_START, %-§

%+ 非常相似,%-{$match} 的使用将被 $/{$match} 替换。

$LAST_REGEXP_CODE_RESULT, $^R§

没有等效项。

${^RE_DEBUG_FLAGS}§

没有等效项。

${^RE_TRIE_MAXBUF}§

没有等效项。

$ARGV§

读取行时当前文件的名称可以通过 $*ARGFILES.path 获取。

@ARGV§

@*ARGS 包含命令行参数。

ARGV§

这已被 $*ARGFILES 替换。

ARGVOUT§

由于 -i 命令行开关尚未实现,因此还没有 ARGVOUT 的等效项。

$OUTPUT_FIELD_SEPARATOR, $OFS, $,§

目前没有明显的等效项。

$INPUT_LINE_NUMBER§

$NR, $.§

没有直接的替换存在。

当使用 lines 方法从 IO::PathIO::Handle 类型迭代时,您可以调用其 .kv 方法以获取索引和值的交错列表(然后每次循环迭代 2 次)

for "foo".IO.lines.kv -> $n$line {
    say "{$n + 1}$line"
}
# OUTPUT: 
# 1: a 
# 2: b 
# 3: c 
# 4: d 

对于 IO::CatHandle 类型(其中 $*ARGFILES 是其中之一),您可以使用 on-switch 钩子在句柄切换时重置行号,并手动递增它。另请参阅 IO::CatHandle::AutoLinesLN 模块,它们简化了此操作。

$INPUT_RECORD_SEPARATOR, $RS, $/§

可以通过文件句柄上的 .nl-in 方法访问它。例如 $*IN.nl-in

$OUTPUT_RECORD_SEPARATOR, $ORS, $\§

可以通过文件句柄上的 .nl-out 方法访问它。例如 $*OUT.nl-out

$OUTPUT_AUTOFLUSH, $|§

没有可用的全局替代方案。TTY 句柄默认情况下是非缓冲的,对于其他句柄,将 out-buffer 设置为零或使用 :!out-bufferopen 在特定 IO::Handle 上。

${^LAST_FH}§

在 Raku 中未实现。

Raku 中没有内置格式。

错误变量§

由于 Raku 中错误变量的改变方式,这里不会单独详细介绍它们。

引用 Raku 文档,“$! 是错误变量。”就是这样。所有错误变量似乎都被 $! 吞噬了。与 Raku 的其他部分一样,它是一个对象,它将根据错误类型或 Exception 返回不同的内容。

特别是,在处理 Exception 时,$! 提供有关抛出异常的信息,假设程序尚未停止

try {
    fail "Boooh";
    CATCH {
        # within the catch block 
        # the exception is placed into $_ 
        say 'within the catch:';
        say $_.^name ~ ' : ' ~ $_.message;
        $_.resume# do not abort 
    }
}
 
# outside the catch block the exception is placed 
# into $! 
say 'outside the catch:';
say $!.^name ~ ' : ' ~ $!.message;

并且上面的代码产生以下输出

within the catch:
X::AdHoc : Boooh
outside the catch:
X::AdHoc : Boooh

因此,如前所述,$! 变量保存异常对象。

$COMPILING, $^C, $^D, ${^ENCODING}, ${^GLOBAL_PHASE}§

$^H, %^H, ${^OPEN}§

$PERLDB, $^P§

${^TAINT}§

${^UNICODE}, ${^UTF8CACHE}, ${^UTF8LOCALE}§

在 Raku 中未实现。