在Raku中如何复制保留当前内部状态且独立的函数实例?
实现方案
Raku 目前可以通过闭包封装+状态快照的方式实现你要的效果,也可以直接通过对克隆后的函数的内部状态变量手动赋值来完成,以下是两种可运行的实现:
方法1:显式快照克隆
你可以先获取原函数当前的状态值,克隆原函数后手动将新函数的state变量初始化为快照值,代码示例如下:
sub f { state $n++ } say f; # OUTPUT: «0» say f; # OUTPUT: «1» say f; # OUTPUT: «2» my &f1 = &f; my &f2 = &f.clone; # 实现f3的逻辑 my $current-n = &f.ctx.lexical::<$n>; # 捕获当前state变量的值 my &f3 = &f.clone; &f3.ctx.lexical::<$n> = $current-n; # 给克隆后的函数初始化状态 say f; # OUTPUT: «3» say f; # OUTPUT: «4» say f1; # OUTPUT: «5» say f2; # OUTPUT: «0» say f3; # OUTPUT: «3» 和预期一致 say f; # OUTPUT: «6» say f3; # OUTPUT: «4» 二者状态完全独立
这里用到了Raku的运行时上下文内省能力,ctx方法可以获取子程序的执行上下文,lexical::<$n>可以访问到上下文中的词法变量$n也就是你定义的state变量。
方法2:封装为可克隆状态的函数结构
如果你需要频繁做这类带状态的函数复制,可以提前把函数的状态暴露为可访问的属性,用闭包或者类的方式封装,后续克隆会更方便:
sub make-counter($init = 0) { my $n = $init; sub { $n++ } } my &f = make-counter; say f; # 0 say f; # 1 say f; # 2 my &f1 = &f; # 别名,共享状态 my &f2 = make-counter; # 新实例,初始状态为0 my &f3 = make-counter(&f.ctx.lexical::<$n>); # 快照当前状态生成新实例 say f; # 3 say f; #4 say f1; #5 say f2; #0 say f3; #3 符合预期
这两种方案都可以实现你要的「保留当前状态+完全独立」的需求,不需要用到wrap方法。
内容的提问来源于stack exchange,提问作者codesections
相关产品推荐
相关产品推荐

