访问Perl中Template Toolkit中的匿名哈希数组项

时间:2017-05-03 07:49:34

标签: arrays perl template-toolkit

我将这段代码作为控制器中foreach循环的一部分:

my $gr = My::Model::Group->new(id => $gra->gr_id);
$gra = My::Model::Group::Admin->new(id => $gra->id);
push(@$groups, {$gr => $gra});

在@ $ groups数组中,我想存储匿名哈希,其中key元素是group对象,value元素是该group对象的admin。然后在模板中我想显示管理员可以登录的不同组的列表,为此我有这个代码:

[%- FOREACH  gr IN groups -%]
  <li><input type="radio" name="group" value="[% gr.id %]">[% gr.name %]</input></li>
[%- END -%]

我知道p IN合作伙伴不对,但是要向您展示我想要实现的目标。有关模板代码的任何建议吗?

2 个答案:

答案 0 :(得分:3)

您需要重新修改代码才能实现这一目标。

Perl哈希中的键是字符串,而不是标量。使用非字符串作为哈希中的键的任何东西(例如,$gr中的{ $gr => $gra }将导致它被字符串化,就像您将其插入字符串或打印它一样除非你明确重载了""对象上的My::Model::Group运算符,否则该键最终将被存储为以下行的文字字符串:

"My::Model::Group=HASH(0x1234567890)"

此字符串无法转换回原始对象 - 事实上,原始对象一旦超出范围就可能被垃圾收集,因此它根本不存在。

考虑将该对存储为数组引用,例如

push @$groups, [$gr, $gra];

答案 1 :(得分:3)

duskwuff already explains in their answer您无法将对象用作哈希键,因为它们被序列化并且您将失去对象。我的答案建立在此基础上。

让我们假设你有一个数组数组,其中每个内部数组都包含一对对象。我已经创建了Moo课程来说明。

package My::Model::Group;
use Moo;
has [qw/id name/] => ( is => 'ro' );

package My::Model::Group::Admin;
use Moo;
has [qw/id name/] => ( is => 'ro' );

package main;

my $groups = [
    [
        My::Model::Group->new( id => 1, name => 'group1' ) =>
            My::Model::Group::Admin->new( id => 1, name => 'foo' )
    ],
    [
        My::Model::Group->new( id => 2, name => 'group2' ) =>
            My::Model::Group::Admin->new( id => 1, name => 'foo' )
    ],
    [
        My::Model::Group->new( id => 3, name => 'group3' ) =>
            My::Model::Group::Admin->new( id => 1, name => 'bar' )
    ],
    [
        My::Model::Group->new( id => 4, name => 'group4' ) =>
            My::Model::Group::Admin->new( id => 1, name => 'foo' )
    ],
];

有四对。两名管理员,四组。其中三个组属于 foo admin,另一个属于 bar 。现在让我们看看模板。

use Template;

my $tt = Template->new();
$tt->process( \*DATA, { groups => $groups }, \my $output )
   or die $tt->error;

print $output;
__DATA__
[%- FOREACH item IN groups -%]
    [%- DEFAULT by_admin.${item.1.name} = [] -%]
    [%- by_admin.${item.1.name}.push(item.0) -%]
[%- END -%]

[%- FOREACH admin IN by_admin.keys.sort -%]
    [%- FOREACH group IN by_admin.$admin -%]
        [%- admin %] -> [% group.id %]

    [%- END -%]
[%- END -%]

相关部分显然是DATA部分。我们需要将数组数据结构重组为具有管理员的哈希,然后将每个组分类到一个管理槽中。

我们不需要创建by_admin变量。它将全局隐式创建。但我们确实需要为$by_admin->{$item[0]->name}设置一个默认值(我现在使用Perl语法,以便更容易理解)。似乎Template Toolkit不知道autovivification,而the DEFAULT keyword//= assignment operator in Perl类似。

我们可以itemitem.1.name的第一个元素放入我们刚刚创建的数组引用中(如果它还没有存在),并使用键{{1}在哈希引用元素中} by_name

一旦我们做好准备,其余的只是一个简单的循环。我们迭代by_admin的{​​{3}} push,然后迭代该键后面的数组引用。

这是输出:

bar -> 3
foo -> 1
foo -> 2
foo -> 4

不是在模板中进行预处理,而是在控制器中进行预处理是有意义的。作为普通的Perl代码,它应该更容易阅读。

my %by_admin;
for my $group (@$groups) {
    push @{ $by_admin{ $group->[1]{name} } }, $group->[0];
}

请注意,为简洁起见,我省略了use strictuse warnings