perl - 子例程返回空字符串而不是哈希引用

标签 perl tree subroutine

我正在尝试从 dbix::class 结果集构建树状嵌套数据结构。问题是,当涉及到深度超过 1 层的元素时,我得到了异常:

Can't use string ("") as a HASH ref while "strict refs" in use at /home/romel/apps/myapp/script/../lib/MyApp/Products.pm line 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 不会返回任何内容。

最佳答案

您的问题是,如果在第一级中找不到 ID,_findparent 不会返回可用值。让我们看一下 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 "...";

它使用// 定义或运算符。

关于perl - 子例程返回空字符串而不是哈希引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21134838/

相关文章:

xml - 查找两个元素之间的相对 XPath 的最有效方法是什么?

xml - 清除子处理程序中的 XML Twig

data-structures - AVL树删除规则

javascript - CSS/Javascript 中的树形图像布局

perl - 当调用的参数比预期的多时,子程序是否应该嘎嘎作响?

perl - 如何区分未传递的参数和传递错误值的参数?

regex - Perl 正则表达式更改容器中的所有模式

perl - 如何在 Perl 中处理配置文件?

algorithm - 3 的倍数的惰性传播线段树

java - 子例程返回字符串参数的所有大写字母,只能是首字母