变量中§

有关状态声明符,请参阅主要文档 上下文

state 声明词法作用域变量,就像 my 一样。但是,初始化仅发生一次,即在执行的正常流程中首次遇到初始化时。因此,状态变量将在封闭块或例程的多次执行中保留其值。

因此,子例程

sub a {
    state @x;
    state $l = 'A';
    @x.push($l++);
};
 
say a for 1..6;

每次调用时都会继续递增 $l 并将其附加到 @x。因此,它将输出

[A]
[A B]
[A B C]
[A B C D]
[A B C D E]
[A B C D E F]

由于它们具有词法作用域,因此它们与声明它们的块相关联。

sub foo () {
  for 0..1 {
    state $foo = 1;
    say $foo++;
  }
};
foo;  # OUTPUT: «1␤2␤» 
foo;  # OUTPUT: «1␤2␤» 

在这种情况下,每次进入运行 for 循环的块时都会创建一个新的状态变量,这就是为什么在每次调用 foo 时都会重置状态变量。

这适用于包含代码对象的每个“克隆”,如下例所示

({ state $i = 1$i++.say} xx 3).map: {$_(), $_()}# OUTPUT: «1␤2␤1␤2␤1␤2␤» 

请注意,当同一块的同一克隆由多个线程运行时,这不是一个线程安全结构。还要记住,方法每个类只有一个克隆,而不是每个对象。

my 一样,多个 state 变量的声明必须放在括号中,对于单个变量可以省略括号。

许多运算符带有隐式绑定,这会导致距离动作。

使用 .clone 或强制转换创建可以绑定的新容器。

my @a;
my @a-cloned;
sub f() {
    state $i;
    $i++;
    @a       .push: "k$i" => $i;
    @a-cloned.push: "k$i" => $i.clone;
};
 
f for 1..3;
say @a;        # OUTPUT: «[k1 => 3 k2 => 3 k3 => 3]␤» 
say @a-cloned# OUTPUT: «[k1 => 1 k2 => 2 k3 => 3]␤»

状态变量在所有线程之间共享。结果可能是意外的。

sub code(){ state $i = 0say ++$i$i };
await
    start { loop { last if code() >= 5 } },
    start { loop { last if code() >= 5 } };
 
# OUTPUT: «1␤2␤3␤4␤4␤3␤5␤» 
# OUTPUT: «2␤1␤3␤4␤5␤» 
# many other more or less odd variations can be produced