英文:
How to create a Capture dynamically (Raku)
问题
在以下示例中,我尝试通过将数组(@a)“转换”为一个Capture来动态创建一个Capture。
考虑以下代码:
sub f (|c){
say '';
say ' List : ' ~ do {c.list.gist if c.list.elems > 0};
say ' Hash : ' ~ do {c.hash.gist if c.hash.elems > 0};
say '';
}
my $c1 = \(1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9);
my @a = 1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9;
my $c2 = \(|@a);
f(|$c1);
f(|@a);
f(|$c2);
结果是:
List : (1 (2 3) 4 5 6 7 8 9)
Hash : Map.new((t1 => test1, t2 => test2))
List : (1 (2 3) 4 5 t1 => test1 6 7 t2 => test2 8 9)
Hash :
List : (1 (2 3) 4 5 t1 => test1 6 7 t2 => test2 8 9)
Hash :
第一次运行(使用Capture $c1)运行正常,产生了期望的行为。第二次和第三次尝试动态创建Capture失败(可能是因为在这些情况下子例程f的参数不是所需的Capture)。我观察到,包含在数组@a中的键值对被视为列表的成员,而不是我想要的命名参数。
我知道在传递给子例程f之前,数组中的键值对必须进行某种程度的“扁平化”,但我无法弄清楚如何做到这一点!有人能给我一些提示吗?
英文:
In the following example I try to create a Capture dynamically by "converting" an array (@a) to a Capture.
Consider the code:
sub f (|c){
say '';
say ' List : ' ~ do {c.list.gist if c.list.elems > 0};
say ' Hash : ' ~ do {c.hash.gist if c.hash.elems > 0};
say '';
}
my $c1 = \(1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9);
my @a = 1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9;
my $c2 = \(|@a);
f(|$c1);
f(|@a);
f(|$c2);
The result is:
List : (1 (2 3) 4 5 6 7 8 9)
Hash : Map.new((t1 => test1, t2 => test2))
List : (1 (2 3) 4 5 t1 => test1 6 7 t2 => test2 8 9)
Hash :
List : (1 (2 3) 4 5 t1 => test1 6 7 t2 => test2 8 9)
Hash :
The first run (with Capture $c1) is running as it should, producing the desired behaviour.
The second and third attempts, to create a Capture dynamically, are failing (probably because the argument of the subroutine f in those cases is NOT the desired Capture).
I observe that the pairs incorporated into array @a, are taken to be members of a list and NOT named parameters as I wanted them to be.
I know that there must be, sort of speak, a "flattening" of the pairs in the array going on, before passing to subroutine f, but i can NOT figure out the way to do that!
Can anyone give me a hint?
答案1
得分: 7
在List
类中有一个方法Capture
,它的工作方式与您想要的完全相同:
my $c = \(1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9);
my @a = 1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9;
my $c2 = @a.Capture;
f(|$c);
f(|$c2);
f(|@a);
sub f (|c){
say() ;
say ' List : ', c.List;
say ' Hash : ', c.Hash;
say();
}
您可以修改函数f
的定义,以直接使用列表@a
。
my $c = \(1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9);
my @a = 1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9;
f($c);
f(@a);
sub f (Capture(Any) \c){
say() ;
say ' List : ', c.List;
say ' Hash : ', c.Hash;
say();
}
Capture(Any)
是所谓的强制类型转换。它接受 Any
但将其强制转换为 Capture
,即(重复地)调用方法 Capture
来获取它。
此外,通过使用 Capture
,您可以使用模式匹配。因此,函数 f
的最后一个定义可以更改为:
sub f ( (**@list, *%hash) ) {
#或者甚至 sub f ( (*@list, :t1($t),*%hash) ) {
say() ;
say ' List : ', @list;
# say ' test1 : ', $t;
say ' Hash : ', %hash;
say();
}
英文:
In the class List
there is the method Capture
, which works exactly how you want:
my $c = \(1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9);
my @a = 1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9;
my $c2 = @a.Capture;
f(|$c);
f(|$c2);
f(|@a);
sub f (|c){
say() ;
say ' List : ', c.List;
say ' Hash : ', c.Hash;
say();
}
You could modify the definition of the function f
to work directly with the list @a
.
my $c = \(1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9);
my @a = 1,(2,3),4,5, :t1('test1'), 6,7, :t2('test2'), 8,9;
f($c);
f(@a);
sub f (Capture(Any) \c){
say() ;
say ' List : ', c.List;
say ' Hash : ', c.Hash;
say();
}
Capture(Any)
is so-called coercion type. It accepts Any
but coerces Capture
, i.e. it (repeatedly) calls method Capture
to get it.
In addition, by Capture
you can use pattern matching. Thus last definition of the function f
could be changed to:
sub f ( (**@list, *%hash) ) {
#or even sub f ( (*@list, :t1($t),*%hash) ) {
say() ;
say ' List : ', @list;
# say ' test1 : ', $t;
say ' Hash : ', %hash;
say();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论