...
#!/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。这里是什么?
最佳答案
What am I missing?
许多可能的答案中有两个答案是:
具体来说,您可以更改:
my ( %H, %G ) = GetHashes ;
到:my ( %H, %G ) := GetHashes ;
^
具体来说,您可以更改:
my ( %H, %G ) = GetHashes ;
到:my ( $H, $G ) = GetHashes ;
总而言之,Raku 支持多种方式来使某些存储位置“包含”某些数据或“引用”某些数据。您正在使用 "list assignment"但需要使用其中一种替代方法,例如我们的答案。
作业 (
=
)分配意味着将数据复制到一些最终“包含”复制数据的存储位置。 [1]
如果您使用列表分配,则列表中的项目越多,复制的字节就越多。如果您有一百万个项目,则不太可能使用列表分配来分配它们。正如您所发现的,可能还有其他原因不想使用赋值。
例如,考虑
my @array1 = 1, 2
.这段代码:List
两个元素 -- (1, 2)
-- 作为要分配/复制的数据;Array
并将这个新数组“绑定(bind)”到“符号”(变量名)@array1
;List
的元素,对于每个:3.1 在目标数组中添加一个新的对应的空“容器”(一个
Scalar
),准备接收一些标量数据;3.2 从
List
复制标量(单个)值进新Scalar
数组中的容器。请注意这最终如何在运行时创建三个存储位置:一个数组和两个单独的
Scalar
s 作为该数组的前两个可索引元素。所有这三个存储位置都得到更新,阵列得到两个 Scalar
s 添加到其中,还有两个 Scalar
s 接收从列表中复制的两个值。绑定(bind) (
:=
)绑定(bind)意味着将引用(指针)复制到数据。数据本身不会被复制。如果有,比如说,对数据的两次引用,那么无论数据有多大,都不会被复制。坚持复制引用而不是被引用的数据的一种方法是使用绑定(bind)。
例如,考虑
my @array2 := 1, 2
.这段代码:List
两个元素 (1, 2)
;List
的引用到“符号”(变量名)@array2
.请注意,与上面的赋值示例不同,此绑定(bind)示例在
@array2
的左侧只有一个存储位置( :=
)。正在更新,对应于被视为单个值的权限(a List
)。绑定(bind)操作的左侧可以有多个存储位置。考虑你的例子,
my ( %H, %G ) := GetHashes;
.这段代码:GetHashes
,返回 List
两个哈希值;:=
右侧的值/引用列表,依次将每个绑定(bind)到:=
左侧的目标存储位置列表.请注意,与前面的绑定(bind)示例不同的是,这个绑定(bind)示例最终会更新两个存储位置(与符号
%H
和 %G
相关联),对应于 List
中的两个哈希值。由 GetHashes
返回称呼。原始代码中列表赋值的效果
使用您的代码,您从
=
的右侧复制了所有数据/值。 ,逐项(因此总共 10 个复制行为),进入绑定(bind)到左侧第一个变量 ( %H
) 的散列。这是由于赋值的精确语义(使用
=
)由 =
左侧的各个目标决定。 ,从第一个开始,直到填满为止,然后是第二个,依此类推。如果分配目标是
Associative
(例如 %H
),它会从 =
的右边贪婪地吞食一切。 .这称为“列表分配”。那么你的原始代码会发生什么
%H
将 GetHashes
返回的第一个散列中的前五个元素吸起来,然后继续,所以 sub 返回的第二个散列中的五个元素也分配给 %H
.并且因为第二批对的 key 与第一批的 key 相同,所以第二批会覆盖前五个。
所以
%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
在运行时而是在编译时永久绑定(bind)它。换句话说,它与 constant list := 1, 2, 3;
的作用相同。 . (大多数人只写 constant list = 1, 2, 3;
。)my int @list = 1, 2, 3;
不添加任何 Scalar
容器到 native 数组 @list
而是直接写入 native 整数。关于return - 如何从 raku sub 返回 2 个哈希?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67766157/