【问题标题】:Access an array item that is an anonymous hash in Template Toolkit in Perl在 Perl 的 Template Toolkit 中访问作为匿名哈希的数组项
【发布时间】:2017-09-30 22:33:17
【问题描述】:

我将这段代码作为控制器中 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 数组中,我想存储匿名哈希,其中键元素是组对象,值元素是该组对象的管理员。然后在模板中我想显示管理员可以登录的不同组的列表,因为我有这个代码:

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

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

【问题讨论】:

  • FOREACH item IN list 是正确的。但是你想重新组合他们,对吧?这就像 Excel 中的枢轴。你有类似{ 1 =&gt; 'foo', 2 =&gt; 'bar', 3 =&gt; 'foo' } 的东西,你想显示用户foo1, 3bar2。我明白了吗?
  • 是的,没错。你说的完全正确
  • 是否有多个管理员?我还不明白预期的输出。
  • 管理员将是相同的,我的意思是,它将是多个组的相同管理员。但我想以哈希形式捕获组和管理员。稍后我将与管理员一起做更多的事情,但暂时不会。所以现在希望输出的是组名和 id。
  • 我现在正在为 TT 语法苦苦挣扎。

标签: arrays perl template-toolkit


【解决方案1】:

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 管理员,一个属于 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-&gt;{$item[0]-&gt;name} 设置一个默认值(我现在使用Perl 语法,以便于理解)。 Template Toolkit 似乎不知道autovivification,而the DEFAULT keyword//= assignment operator in Perl 类似。

然后我们可以将push 的第一个元素item 放入我们刚刚在哈希引用元素中创建的数组引用中(如果它还不存在的话),键为item.1.nameby_name 内。

一旦我们完成准备,剩下的只是一个简单的循环。我们迭代 by_adminsorted keys,然后迭代该键后面的数组 ref。

这是输出:

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

【讨论】:

  • 用那个sn-p的代码我得到了它。非常感谢!你们让我很开心
  • @Albert 真正重要的部分是DEFAULT。这就是我花了一段时间才弄清楚的原因。
  • 正如你所说,这最好在 Perl(不是 TT)中完成,所以我添加了 Perl 代码来完成它。
  • 谢谢@ikegami。
【解决方案2】:

您需要大量修改代码才能实现这一点。

Perl 哈希中的键是字符串,而不是标量。使用不是字符串的任何内容作为哈希中的键(例如,表达式{ $gr =&gt; $gra } 中的$gr 将导致它被字符串化,就像您已将其插入字符串或打印它一样。除非您有在My::Model::Group 对象上显式重载"" 运算符,键最终将被存储为文字字符串,如下所示:

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

这个字符串不能转换回原来的对象——事实上,原来的对象很可能一超出范围就被垃圾回收了,所以它根本不存在了。

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

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

【讨论】:

  • 好的,但是我如何访问模板中 $gr 中的 id?
猜你喜欢
  • 1970-01-01
  • 2014-04-16
  • 1970-01-01
  • 2015-06-26
  • 2016-12-12
  • 1970-01-01
  • 2013-02-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多