如何从rakusub返回2个哈希?

...

#!/usr/bin/env raku
# -*-perl6-*-
# 2021-5-30: Example of how a sub does not seem to be able to return 2 Hashes...


sub GetHashes 
{
    my %H =  100 => 2149, 101 => 2305, 102 => 2076, 103 => 1767, 104 => 1743 ;
    my %G =  100 => 21493, 101 => 23053, 102 => 20763, 103 => 17673, 104 => 17433 ;
    return( %H, %G );
}

my ( %H, %G ) = GetHashes ;

%H.say;
%G.say;

...

我是一个老的 FORTRAN/perl5 程序员,他决定尝试学习 raku。上面的代码不起作用。我错过了什么?在 perl5 中,我会将 ref 返回到散列,并在调用者中取消 ref。这里是什么?

回答

我错过了什么?

许多可能的答案中有两个答案是:

  1. 你少了一个冒号。

    具体来说,您可以更改:

    my ( %H, %G ) = GetHashes ;
    
    my ( %H, %G ) = GetHashes ;
    

    到:

    my ( %H, %G ) := GetHashes ;
                  ^
    

  1. 你错过了@p6steve 的回答。

    具体来说,您可以更改:

    到:

    my ( $H, $G ) = GetHashes ;
    

总而言之,Raku 支持多种方式来使某些存储位置“包含”某些数据或“引用”某些数据。您正在使用“列表分配”,但需要使用其中一种替代方法,例如我们的答案。

分配 ( =)

分配意味着数据复制到一些最终“包含”复制数据的存储位置。[1]

如果您使用列表分配,则列表中的项目越多,复制的字节就越多。如果您有一百万个项目,则不太可能使用列表分配来分配它们。正如您所发现的,可能还有其他原因不想使用赋值。


例如,考虑my @array1 = 1, 2. 这段代码:

  1. 构造List两个元素的 a -- (1, 2)-- 作为要分配/复制的数据;

  2. 构造一个新的空Array并将这个新数组“绑定”到“符号”(变量名)@array1

  3. 迭代List的元素,对于每个元素:

    3.1Scalar在目标数组中添加一个新的对应的空“容器”(a ),准备接收一些标量数据;

    3.2 将一个标量(单个)值从 复制ListScalar数组中的新容器中。

请注意这最终如何在运行时创建三个存储位置:一个数组和两个单独的Scalars 作为该数组的前两个可索引元素。所有这三个存储位置都会更新,数组中Scalar添加了两个Scalars ,两个s 接收从列表中复制的两个值。

绑定 ( :=)

绑定意味着将引用(指针)复制数据。数据本身不会被复制。如果有,比如说,对数据的两次引用,那么无论数据有多大,都不会被复制。坚持复制引用而不是被引用的数据的一种方法是使用绑定。


考虑,例如my @array2 := 1, 2。这段代码:

  1. 构造List两个元素的 a (1, 2)

  2. 将对 的引用绑定List到“符号”(变量名)@array2

请注意,与上面的赋值示例不同,此绑定示例在被更新的左侧只有一个存储位置 ( @array2) :=,对应于右侧被视为单个值 (a List)。


绑定操作的左侧可以有多个存储位置。考虑你的例子,my ( %H, %G ) := GetHashes;。这段代码:

  1. 求值GetHashes,返回List两个散列中的一个;

  2. 迭代对值/引用列表正确:=,对每个反过来结合目标存储位置的列表中留下:=

请注意,与前面的绑定示例不同的是,这个绑定示例最终会更新两个存储位置(与符号%H和关联%G),对应于调用List返回的两个散列GetHashes

原始代码中列表赋值的效果

使用您的代码,您右侧的所有数据/值=逐项复制到与左侧第一个变量 ( %H)绑定的哈希中.

这是由于赋值的精确语义(使用 of =)由 左侧的各个目标确定=,从第一个开始,直到填充完毕,然后是第二个,依此类推。

如果分配目标是Associative(eg %H),它会贪婪地从=. 这称为“列表分配”。

因此,您的原始代码发生的情况是将%H返回的第一个散列中的前五个元素吸满GetHashes,然后继续前进,因此sub 返回的第二个散列中的五个元素分配给%H

并且因为第二批对的密钥与第一批的密钥相同,所以第二批会覆盖前五个。

所以%H最终只有第二批对,并%G保持空,结果你看到了。


类似的交易适用于Positional赋值目标,例如名为 的变量@array

标准 Raku 中唯一以这种方式贪婪的分配目标Scalar$bar. 因此,您可以有效地编写、说my ($bar, @bam) = 1, 2, 3;并以$bar分配的方式结束1,并@bam[2 3]. 因此@p6steve 的回答。

脚注

[1]如果=在某些代码中使用,但左侧的容器赋值不是该表达式的意思,Raku 会按照作者可能的意思来代替。例如:

  • constant list = 1, 2, 3;没有暂时分配List (1, 2, 3)到符号list在运行时,而是永久地结合在编译时它。换句话说,它与constant list := 1, 2, 3;. (大多数人只是写constant list = 1, 2, 3;。)

  • my int @list = 1, 2, 3;不会Scalar向本机数组添加任何容器,@list而是直接写入本机整数。


以上是如何从rakusub返回2个哈希?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>