我是Perl的新手,我正在努力更好地了解何时以及如何将引用传递给嵌套数据结构。以下是我正在做的事情的概述:
我正在尝试传递对子例程的引用并让它们返回引用。这是推荐的做事方式吗?
以下是代码以及我对 认为 所做的事情的评论。
# create normal list
my @list1 = qw(1 2 3);
# this passes a reference of list1 to sub1 and $result1 is
a reference to return value of sub1
my $result1 = sub1(\@list1)
# passes reference of result1 to sub2 and result2 is a reference
to return value of sub2
my $result2 = sub2($result1)
my %hash1;
# dereferences list1 to the largest index to iterate until
and creates a key value pair in hash1 using the current
index of the loop. Also dereference result2 to get the
hash at the index.
for my $i (0 .. $#list1) {
$hash1{$list1[$i]} = @{$result2}[$i];
}
my $result3 = sub3(\%hash1);
sub sub1 {
# dereference list passed in?
my ($list1) = @_;
my $result = {hash containing a list} from service call using $list1;
# dereferences result to return list2,
is this returning the list or a reference?
return $result->{list2};
}
sub sub2 {
# dereference list passed in?
my ($list2) = @_;
my $result = {hash containing a list} from service call using $list2;
# dereferences result to return list3, is
this returning the list or a reference?
return $result->{list3}
}
sub sub3 {
# dereference hash1 ?
my ($hash1) = @_
my %result3;
# loop over key value pairs of dereferenced hash1
while (my ($key, $value) = each %$hash1) {
my %hash2;
# loop over item list inside hash that is
the value of the current key in the outer loop
foreach my $item (@{ $value->{items} }) {
if( !(defined $hash2{flag1}) ) {
$hash2{flag1} = $item->{flags}->{flag1};
}
switch ($item->{costName}) {
case 'name1' {
$hash2{name1} += $item->{costName}->{value};
}
case 'name2' {
$hash2{name2} += $item->{costName}->{value};
}
# I want to also add a case where I compare the current value to two strings to see if it is not equal to both. Can this be done in a Perl switch.
}
# set the value for this key in result3 to reference of hash2
$result3{$key} = \%hash2;
}
# return reference to result3
return \%result3
}
如果我正确引用和解除引用,请告诉我。到目前为止,我有我期望的输出,但我不能告诉我是否以非常低效的方式处理这个问题,或者只是使用引用错误。感谢。
编辑:正在发生的一件事我无法理解当我何时
在for循环中运行此行:$hash1{$list1[$i]} = @{$result2}[$i];
,第二个键(i = 1)接收用于第一个键(i = 0)的值。我验证了正确的数据位于result2列表中的正确索引处。这里发生了什么?
答案 0 :(得分:3)
我将使用我的评论来注释您的代码,即我将重写# inline annotations
并在下面的纯文本中添加更多说明。
首先,你错过了
use strict;
use warnings;
您编写的每个Perl文件都应以此开头(或等效文件;例如use Moose
为您启用此功能。)
# create normal array
my @list1 = qw(1 2 3);
@list1
是一个数组。右侧的qw(1 2 3)
部分是一个列表。
# pass a reference to @list1 to sub1 and assign the return value of sub1 to $result1
my $result1 = sub1(\@list1);
您在本声明末尾遗漏了;
。 $result1
是sub1
的返回值(的副本),而不是对它的引用。
# pass $result1 to sub2; $result2 is the return value of sub2
my $result2 = sub2($result1);
(见上文。)
my %hash1;
# iterate over the indices of @list1. $#list1 is the last index of @list1.
# Initialize %hash1 with keys taken from @list1 and corresponding values from @{$result2}.
for my $i (0 .. $#list1) {
$hash1{$list1[$i]} = @{$result2}[$i];
}
$#list1
不会取消引用任何内容; @list1
不是参考。
@{$result2}[$i]
在技术上是一个列表切片。正如您使用$list1[$i]
从数组中获取单个元素一样,您应该使用${$result2}[$i]
从数组引用中获取单个元素。 @
恰好在这里工作(列表切片只包含一个元素),但最好是请求标量,如果这是你想要的。
此外,惯用Perl将$result2->[$i]
从数组引用中获取单个元素。
根本不需要这个循环:
@hash1{@list1} = @{$result2};
这是一个哈希切片。我们使用@list1
的元素作为键,使用@{$result2}
作为相应的值。
my $result3 = sub3(\%hash1);
sub sub1 {
# Parameter list (done manually). The first argument goes in $list1.
my ($list1) = @_;
这里没有解除引用。这只是列表赋值:我们将@_
(我们的参数)的元素列表分配给($list1)
,即我们的第一个参数获取本地名称$list1
。
my $result = {hash containing a list} from service call using $list1;
我不知道你在这做什么。这是语法错误。
# return the value stored under key 'list2' in the hash %{$result}
return $result->{list2};
返回标量值。如果这是存储在%{$result}
哈希中的内容,那么它可能是一个参考。
}
sub sub2 {
我正在跳过这个。请参阅上面的sub1
。
}
sub sub3 {
# put first argument in local variable called $hash1
my ($hash1) = @_;
您再次错过了;
。
my %result3;
# loop over key value pairs of dereferenced hash1
while (my ($key, $value) = each %$hash1) {
请注意,建议不要使用each
。它使用/修改您使用它的哈希中的隐藏状态,因此如果循环中的任何代码在您迭代的哈希上调用each
或keys
或values
,它将会中断
my %hash2;
# loop over item list inside hash that is
# the value of the current key in the outer loop
foreach my $item (@{ $value->{items} }) {
具体来说,此代码假定$value
(%{$hash1}
中的当前值)是对另一个哈希的引用,该哈希包含对密钥'items'
下的数组的引用。这个数组是我们正在迭代的。
if( !(defined $hash2{flag1}) ) {
$hash2{flag1} = $item->{flags}->{flag1};
}
switch ($item->{costName}) {
Perl没有switch
声明。您必须使用与Perl语法相混淆的模块。如果是use Switch
,请停止:此模块有几个问题。它会在Perl解析器看到之前重写程序的代码,但并不总是正确。这意味着Perl可能会执行与您编写的代码不同的代码。它也有相当复杂的行为,即使代码重写部分成功,也可能导致意外行为。
case 'name1' {
$hash2{name1} += $item->{costName}->{value};
}
case 'name2' {
$hash2{name2} += $item->{costName}->{value};
}
# I want to also add a case where I compare the current value to two strings to see if it is not equal to both.
# Can this be done in a Perl switch.
正如我所说,没有Perl开关这样的东西。 (从技术上讲,有given
/ when
,但那些遭受同样复杂/难以预测的行为问题。他们现在正式“实验性”(行为可能会在未来版本中发生变化)。
}
# set the value for this key in result3 to reference of hash2
$result3{$key} = \%hash2;
}
# return reference to result3
return \%result3
}
这就是代码注释。如果您对程序的实际行为有疑问,则需要发布Minimal, Complete, and Verifiable Example。