我正在尝试从dbix :: class resultset构建一个类似树的嵌套数据结构。问题在于,当涉及到超过1级的元素时,我得到例外:
在使用“严格参考”时,不能使用字符串(“”)作为HASH参考 /home/romel/apps/myapp/script/../lib/MyApp/Products.pm第38行
代码包含两个子程序:
sub _findparent {
my ($tree, $pid) = @_;
if (my ($parent) = grep { $_->{'id'} == $pid } @$tree) {
say "found parent $parent->{'id'} = $pid ($parent->{'name'})";
$parent->{'children'} = [] if (ref $parent->{'children'} ne 'ARRAY');
return $parent;
} else {
for my $i (@$tree) {
say "traversing $i->{'name'} $i->{'id'}";
_findparent($i->{'children'}, $pid) if (ref $i->{'children'} eq 'ARRAY');|
}
}
}
sub index {
my $self = shift;
my @data = $self->db->resultset('Category')->search();
my @tree;
for my $i (@data) {
my $i = $i->get_column_data;
if (my $parent_id = $i->{'parent_id'}) {
say "--- $i->{'name'} has parent (id $parent_id), searching";
#if (my $parent = _findparent(\@tree, $parent_id)) {
# push ($parent->{'children'}, $i);
#}
push (_findparent(\@tree, $parent_id)->{'children'}, $i);
} else {
$i->{'children'} = [];
push (@tree, $i);
say "adding \"$i->{name}\" to tree as root";
}
}
$self->render(menudata => [@tree]);
}
使用Data :: Printer转储@tree:
[
[0] {
children [
[0] {
children [],
created_on undef,
id 2,
modified_on undef,
name "children 1 level",
parent_id 1,
position undef,
user_id undef
}
],
created_on undef,
id 1,
modified_on undef,
name "parent category one",
parent_id undef,
position undef,
user_id undef
},
[1] {
children [
[0] {
children [],
created_on undef,
id 4,
modified_on undef,
name "children 1 level 2",
parent_id 3,
position undef,
user_id undef
},
[1] {
children [],
created_on undef,
id 5,
modified_on undef,
name "children 1 level 3",
parent_id 3,
position undef,
user_id undef
},
[2] {
created_on undef,
id 12,
modified_on undef,
name "children 1 level 4",
parent_id 3,
position undef,
user_id undef
}
],
created_on undef,
id 3,
modified_on undef,
name "parent category two",
parent_id undef,
position undef,
user_id undef
}
]
最后是表结构:
+-------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(45) | YES | | NULL | |
| user_id | int(11) | YES | MUL | NULL | |
| created_on | datetime | YES | | NULL | |
| modified_on | datetime | YES | | NULL | |
| position | varchar(45) | YES | | NULL | |
| parent_id | varchar(45) | YES | | NULL | |
+-------------+-------------+------+-----+---------+----------------+
第38行是
push (_findparent(\@tree, $parent_id)->{'children'}, $i);
因此_findparent
不会为深度超过一个级别的嵌套元素返回任何内容。
答案 0 :(得分:3)
如果在第1级找不到ID,则问题是_findparent
没有return
可用值。我们来看看else
分支:
sub _findparent {
my ($tree, $pid) = @_;
if (my ($parent) = grep { $_->{'id'} == $pid } @$tree) {
...
} else {
for my $i (@$tree) {
say "traversing $i->{'name'} $i->{'id'}";
_findparent($i->{'children'}, $pid) if (ref $i->{'children'} eq 'ARRAY');|
}
}
}
如果不使用显式return
,则返回最后一个语句的值 - 这是一个循环。循环没有有用的返回值,所以你不应该使用它。
相反,从较低级别传递有用的返回值:
sub _findparent {
my ($tree, $pid) = @_;
if (my ($parent) = grep { $_->{'id'} == $pid } @$tree) {
...
} else {
for my $i (@$tree) {
say "traversing $i->{'name'} $i->{'id'}";
next if not ref $i->{children} eq 'ARRAY';
my $parent = _findparent($i->{'children'}, $pid);
return $parent if defined $result;
}
return; # return undef if nothing was found
}
}
...
# put the return value in a variable
my $parent = _findparent(...);
# check if the operation was successful
if (not defined $parent) {
die "Tried to find the parent for $id, but there was no matching parent";
}
# if so use the value
push @$parent, ...;
支票可缩写为:
my $parent = _findparent(...) // die "...";
使用//
已定义或运算符。