return - 如何从 raku sub 返回 2 个哈希?

标签 return raku subroutine

...

#!/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 ;
                  ^
    
  • 你错过了@p6steve 的回答。
    具体来说,您可以更改:
    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) ;
  • 绑定(bind)对 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 ),它会从 = 的右边贪婪地吞食一切。 .这称为“列表分配”。
    那么你的原始代码会发生什么 %HGetHashes 返回的第一个散列中的前五个元素吸起来,然后继续,所以 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/

    相关文章:

    scala - 仅当数组输入的大小为 1 时,函数才返回错误值

    c++ - 如何返回字符串数组?

    testing - "Can' t 打开 perl 脚本 "t/spec/fudgeall": File or directory not found"

    perl - 只能 'perl6'解析Perl 6吗?

    function - 如何创建一个接受多个 block 的 Perl 子例程?

    java - 为什么即使在 System.exit(0) 之后也需要返回;

    c - 当字符串相等时 strcmp() 不返回 0

    hash - 那是 Perl 6 哈希还是 block ?

    assembly - 6502 汇编程序 - RTS 命令和堆栈

    arrays - Perl中的子程序递归