0

我想要一个计数器数组的哈希值,初始值为 0。这是我对代码的第一次尝试:

my @names = ("", a, b, c);
my %hsh = ();
for $i (1..3)
{
 # I expected this line to give me a fresh new array each time - it did not.
 $hsh{$names[$i]} = (0, 0, 0);  # Assignment line #
 doprint($i); #see below
}
#output is: ARRAY(0x1501128) ARRAY(0x1501128) ARRAY(0x1501128)

我们看到它们都是同一个数组,这是不希望的。为了解决这个问题,我将 #Assignment 行更改为:

 $hsh{$names[$i]} = ( );
 push(@{$hash{$names[$i]}}, 0, 0, 0);
 # output is: ARRAY(0x1510c70) ARRAY(0x1510d18) ARRAY(0x1510dc0)

现在都是不同的阵法,生活还不错。

如果分配行使用 (0, 0, $i) 我得到不同的数组(至少在这里 - 它们可能会在其他地方重用)
但我无法通过使用 (0, 0, $i - $i) 或更复杂的公式来生成 0 值。

这是 Perl 的某种优化吗?为什么 (0, 0, 0) 不是每次都是一个新数组?(0, 0) 或 (0, 0, 0, 0) 会不同吗?

为了完整起见,这里是打印子例程:

sub doprint
{
 my $i = shift;
 print (\@{$hsh{$names[$i]}}, " ");
}

---- 以下编辑是在“没有数组注释”之后的 2 月 9 日上午 - 我想添加一些代码,但注释不允许这样做。

好的:$h{$i} = (0, 0, 0); 将其初始化为标量值 0。
但是,如下面的输出所示,某处有一个数组。
编写 $h{$i}[$i] 是否在标量旁边创建了 @-something?

my %h = ();
sub dotest
{
 my $desc = shift;
 print "    # $desc\n";
 for (0, 1, 2)
 {
  $h{$_}[$_] += 1 + $_;
 }

 for (0, 1, 2)
 {
  print "    # $_: $h{$_} ";
  print "# @{$h{$_}}" . " # $h{$_}[$_] \n";
 }
 print "\n";
}

%h = ( );
$h{0} = [0, 0, 0];
$h{1} = [0, 0, 0];
$h{2} = [0, 0, 0];
dotest("Initialize to [0, 0, 0]");

%h = ( );
$h{0} = (0, 0, 0);
$h{1} = (0, 0, 0);
$h{2} = (0, 0, 0);
dotest("Initialize to (0,0,0)");

%h = ( );
dotest("No initialization");

%h = ( );
$h{0} = \@{(0, 0, 0)};
$h{1} = \@{(0, 0, 0)};
$h{2} = \@{(0, 0, 0)};
dotest("Initialize to \\\@{(0, 0, 0)}");


# Initialize to [0, 0, 0] - Separate arrays, initialized to zeros.
# 0: ARRAY(0x10ca5e0) # 1 0 0 # 1 
# 1: ARRAY(0x10ca778) # 0 2 0 # 2 
# 2: ARRAY(0x2709da0) # 0 0 3 # 3 

# Initialize to (0,0,0) - scalars AND a shared array?
# 0: 0 # 1 2 3 # 1 
# 1: 0 # 1 2 3 # 2 
# 2: 0 # 1 2 3 # 3 

# No initialization  - separate arrays, initialized to null
# 0: ARRAY(0x2709e48) # 1 # 1 
# 1: ARRAY(0x10ca718) #  2 # 2 
# 2: ARRAY(0x2709da0) #   3 # 3 

# Initialize to \@{(0, 0, 0)} - reusing the shared array from previous?
# 0: ARRAY(0x2709d88) # 2 4 6 # 2 
# 1: ARRAY(0x2709d88) # 2 4 6 # 4 
# 2: ARRAY(0x2709d88) # 2 4 6 # 6 
4

2 回答 2

3

Dave Cross 已经向你展示了如何去做你想要完成的事情。但是,这里有血腥的细节。

对标量的赋值是在标量上下文中,对散列的单元素访问是标量。所以,这是在标量上下文中:

$hash{key} = ( 0, 0, 0 );

赋值右侧的运算符是逗号。在标量上下文中,逗号运算符评估其左侧,然后丢弃结果。它评估右侧并返回。请参阅perlfaq4,我也对此进行了解释。它是 C 语言的一个特性,并出现在其他几种语言中。

当值不特殊时更容易看出:

$hash{key} = ( 9, 56, 137 );

因此,开始在标量上下文中评估右侧:

$hash{key} = (   9, 56,   137 );
$hash{key} = ( ( 9, 56 ), 137 );

$hash{key} = ( 56, 137 );

$hash{key} = ( 137 );

您最终得到最右边评估的结果。这与以下内容相同:

$hash{key} = 137;

有些人(ab)使用它来组合两个语句,否则它们必须在不同的行中(不是在 Perl 中,真的,但在其他人中,可能是 JavaScript):

my $foo = (  ($sideeffect=$a), ($b = $c) );

或者,您可以在通常只使用一个的地方组合表达式(尽管 who 是一个表达式):

for( my $i = 0; $i < 10; $j++, $i++ ) { ... }

现在,有问题的第二部分。您对该键有一个非引用值,然后您尝试取消引用它以使用push. 那是行不通的,因为它从来都不是参考。

于 2021-02-06T21:05:43.463 回答
2

这条线不符合你的想法:

$hsh{$names[$i]} = (0, 0, 0);

(0, 0, 0)不是数组,而是列表。而且您不能将数组(或者实际上是列表)存储在哈希元素中。您只能将标量值存储在哈希中。

您可以通过在哈希中存储对数组的引用来解决此问题。最简单的方法是使用匿名数组构造函数 ( [ ... ])。

$hsh{$names[$i]} = [0, 0, 0];
于 2021-02-06T08:18:31.020 回答