在赋值之前在 Perl 6 程序中使用变量

Using a variable in a Perl 6 program before assigning to it

我想用我的程序将文字分配给文件末尾的一些变量,但要更早地使用这些变量。我想出的唯一方法如下:

my $text;

say $text;

BEGIN {    
    $text = "abc";
}

有没有更好/更惯用的方法?

只要发挥作用。

改为创建子例程:

say text();

sub text { "abc" }


更新(感谢 raiph!合并您的反馈,包括对使用 term:<> 的参考):

在上面的代码中,我最初省略了调用 text 的括号,但始终包含它们以防止解析器误解我们的意图会更易于维护。例如,

say text();          # "abc" 
say text() ~ text(); # "abcabc"
say text;            # "abc", interpreted as: say text()
say text ~ text;     # ERROR, interpreted as: say text(~text())

sub text { "abc" };

为避免这种情况,您可以将 text 设为 term,这实际上使裸词 text 的行为与 text():

相同
say text;        # "abc",    interpreted as: say text() 
say text ~ text; # "abcabc", interpreted as: say text() ~ text()

sub term:<text> { "abc" };

对于compile-time优化和警告,我们还可以添加pure trait to it (thanks Brad Gilbert!). is pure asserts that for a given input, the function "always produces the same output without any additional side effects":

say text;        # "abc",    interpreted as: say text() 
say text ~ text; # "abcabc", interpreted as: say text() ~ text()

sub term:<text> is pure { "abc" };

与 Perl 5 不同,在 Perl 6 中,BEGIN 不必是一个块。但是词法定义必须先看才能使用,所以BEGIN块必须在say.

之前完成
BEGIN my $text = "abc";
say $text;

不确定这是否构成了对您问题的回答。

首先,重新表述一下你的问题:

What options are there for succinctly referring to a variable (or constant etc.) whose initialization code appears further down in the same source file?

Post 声明例程

say foo;
sub foo { 'abc' }

当 P6 编译器解析 identifier that has no sigil 时,它会检查是否已经看到该标识符的声明。如果没有,则它假定标识符对应于一个例程,该例程稍后将被声明为“listop”例程(它采用零个或多个参数)并继续前进。 (如果其假设被证明是错误的,则编译失败。)

因此您可以像 中描述的变量一样使用例程。

首次使用时自动声明变量

strict is a "pragma" that controls how a P6 compiler reacts when it parses an as yet undeclared variable/constant that starts with a sigil.

P6 在开启严格模式的情况下启动程序。这意味着编译器将坚持预先声明任何印记 variable/constant。 (我所说的预声明是指在使用 variable/constant 之前 明确 声明 文本 。)

但是你可以写 use strictno strict 来控制在给定的词法范围内是否打开或关闭严格的 pragma,所以这会起作用:

no strict;

say $text;

BEGIN {    
    $text = "abc";
}

警告 使 no strict 生效(不幸的是,这是大多数编程语言的工作方式)使得变量名称的意外拼写错误比 [=15] 更令人讨厌=]模式开启。

在变量首次使用时在同一语句中显式声明变量

您不必将声明写成单独的语句。您可以改为在同一语句或表达式中声明 使用变量:

say my $text;

BEGIN {    
    $text = "abc";
}

警告 如果您在 完全相同的 词法范围内重复 my $bar,编译器将发出警告。相反,say my $bar = 42; if foo { say my $bar = 99 } 创建两个不同的 $bar 变量而没有警告。

初始化于 run-time

上面显示的 BEGIN 移相器在 编译 时运行(在 my 声明之后,也发生在 compile-time,但是在 say 之前,发生在 run-time)。

如果您想在 run-time 处初始化 variables/constants,请改用 INIT

say my $text;

INIT {    
    $text = "abc";
}

INIT 代码在任何其他 run-time 代码之前运行,因此初始化仍然发生在 say 执行之前。

使用正电子 (ym) 变量

根据对您问题的字面解释,“正电子”或 ym 变量将是另一种解决方案。 (这个功能不是built-in。我把它包括在内主要是因为我在回答这个问题后遇到它并且认为它属于这里,至少有娱乐价值。)

此类变量的初始化和计算从使用它的 last 语句开始,并相对于代码的文本顺序向后发生。

这是达米安“疯狂科学家”康威在他 2011 年的演讲中讨论的几个听起来很疯狂但实际上有用的概念之一多个拓扑连接中的时间四元虚拟纳米机器编程Quantum-Relativistic平行时空...变得简单!.

这是 link 到 the bit where he focuses on these variables

(整个演示过程令人愉悦,特别是如果您对物理感兴趣;编程技术;观看极富创造力的神童;and/or享受出色的演示技巧和幽默感。)

创建 PS 编译指示?

就酷而言,与我刚刚介绍的 Damian 的正电子变量特征相比,以下内容相形见绌,但这是我在思考这个问题时产生的想法。

有人可能会实现类似于以下 pragma 的东西:

use PS;

say $text;

BEGIN $text = 'abc';

这个 PS 将在词法上应用 no strict 并且另外要求,以避免 compile-time 错误:

  • auto-declared variable/constant 必须与 BEGININIT 移相器中的 post 声明匹配;

  • 如果 variable/constant 的首次使用(文本)不是绑定或赋值,则声明必须包括初始化。