【问题标题】:Perl hash referencing itself at declarationPerl 哈希在声明时引用自身
【发布时间】:2014-11-29 07:34:50
【问题描述】:

在声明 Perl 哈希时,我想知道是否可以使用在声明之前分配的值。

我想一次性完成类似的操作:

my %H   = (something => generateString());
$H{foo} = $H{something} . "/FOO",
$H{bar} = $H{something} . "/BAR",

我可以想象这样的事情:

my %H = (
   something => generateString(),
   foo       => $_{something} . "/FOO",
   bar       => $_{something} . "/BAR",
);

编辑:需要明确的是,我不关心$H{something} 的实际引用(即稍后更改$H{something} 不应影响$H{foo})。我只想将它的值放入字符串连接中。

【问题讨论】:

  • (你的意思是“分配”。)是的,但你以前想要它。 $H{something} 中没有任何内容。所以问题是
  • 所以你想要my %H = ( something => generateString(), foo => stack(2) . "/FOO", bar => stack(4) . "/BAR" );。是的...不。
  • my %H = ( something => generateString(), foo => $STACK[-2] . "/FOO", bar => $STACK[-4] . "/BAR" ); 再好不过了。
  • 你问怎么做。我向你展示了它是可以做到的,我解释了为什么没有人这样做。我不推荐任何编码实践。至于想了解事情在后台是如何发生的,为什么你接受了根本没有解释任何事情的答案,而赞成确切解释了你声称想要理解的答案?
  • 哈希问题总是很好的问题,因为 - 嗯 - hashes are the "key" to perl 和 perl OO 和 Moose 等。为了记录,我不是那么“高级”,但它是 Sriram Srinivasan 的经典之作,高级Perl Programming, O'Reilly, 1997 帮助我在最短的时间内学到了最多的东西。好吧,这与@ikegami mpapec 和其他人在这里相结合。

标签: perl


【解决方案1】:

您似乎认为

中有两个赋值运算符
%H = ( a=>1, b=>$H{a} );

没有。请记住,上述内容与

相同
%H = ( 'a', 1, 'b', $H{a} );

有一个赋值运算符,在你执行赋值之前,你需要知道什么是赋值。

我的意思是%H = ( a=>1, b=>$H{a} ); 的真正问题不是范围之一;真正的问题是,当您执行 $H{a}[1] 时,没有任何内容分配给 %H。因此,$_{a}$H{a} 更有意义。

解决方法很简单:

my $something = generateString();
my %H = (
   something => $something,
   foo       => "$something/FOO",
   bar       => "$something/BAR",
);

  1. %H 还没有被创建!

【讨论】:

    【解决方案2】:
    my %H = (something => generateString());
    %H = (%H, 
       foo => $H{something} ."/FOO",
       bar => $H{something} ."/BAR",
    );
    

    看起来很合理,但如果您想不惜一切代价一次性完成,

    use strict;
    use warnings;
    
    %{ $_->{hash} } = (
       something => $_->{thing},
       foo       => "$_->{thing}/FOO",
       bar       => "$_->{thing}/BAR",
    )
    for {hash => \my %H, thing => generateString()};
    

    可以翻译成更详细的版本,

    my %H;
    local $_ = {hash => \%H, thing => generateString()};
    
    %{ $_->{hash} } = (
       something => $_->{thing},
       foo       => "$_->{thing}/FOO",
       bar       => "$_->{thing}/BAR",
    );
    

    【讨论】:

    • @ikegami 它将是可见的。
    • 这是最骇人听闻的代码,我建议不要这样做。 ANY 成本,应该更详细地说明。
    • 没有什么反对 mpapec 正确回答问题,但除非有特定原因您不能使用附加变量,否则我认为 Ikegami 对使用临时变量的回答将是关键。它不仅减少了用于保持简洁的字符数量,而且在发生的事情中更加清晰易读。您会看到变量的定义位置以及是否弹出错误,在哪里修复它。此外,我认为它的效率要高得多,但在此示例中可能可以忽略不计。
    • 是的,我问他们也很内疚,所以我不应该太虚伪。只要确保@ajwood 知道他在问什么。我确定我可能一次问过同样的事情,而我真正想知道的是如何在它的构造函数中引用哈希。在分配了第一个 key/val 对之后,我会认为对象会被创建,但即使它在内部,它也不会暴露,因此无法完成。
    • 我绝对不打算使用这个结构!我只是在写一个哈希,想知道它是否可以完成..
    【解决方案3】:

    正如 ikegami 所说,赋值操作只有一个;它在整个右侧被评估后执行。

    几个选择:

    my %H = map {;
        'something' => $_,
        'foo' => "$_/FOO",
        'bar' => "$_/BAR",
    } generateString();
    

    use Memoize;
    memoize('generateString');
    my %H = (
        'something' => scalar(generateString()),
        'foo' => generateString() . '/FOO',
        'bar' => generateString() . '/BAR',
    );
    

    (需要标量,否则,memoize 将对列表和标量上下文进行单独调用。)

    【讨论】:

    • 地图加 1,目前为止最好
    • @mpapec:不,到目前为止,绝对最好的方法是 ikegami 的回答;不过,我可以看到在稍微不同的情况下使用地图,这就是我展示它的原因。
    • map 最大的滥用,我喜欢它。不......不要使用它!我还考虑提到memoize,但它不会将生成随机字符串的函数变成静态函数吗?因此,要实现这一点,您必须传递某种参数,您希望函数始终为其返回相同的响应。在这种情况下,也许 null 参数就是它,但是你总是需要在其他地方包含一个参数。
    【解决方案4】:

    另一种方法是将定义作为分配的一部分:

    my %H = (
       something => ( local our $str=generateString() ),
       foo       => qq{$str/FOO},
       bar       => qq{$str/BAR}
    );
    

    有两点需要考虑:

    1. 注意使用local our 而不是my
    2. 我建议不要这样做。出于很多原因;如果不是为了最佳编码实践,而是为了可能引入的错误。

    我觉得在哈希定义之外定义一个变量(如 Ikegami 的回答所示)是最好的方法,原因有很多,但我意识到这也不是被问到的问题。问题的答案是哈希在创建之前不能被引用,并且在创建期间它不会在构造函数中公开。

    【讨论】:

    • @ikeagmi 我很好奇您使用local 是什么意思,因为如果不使用our,我无法看到它完成
    • local 不会创建变量,所以你是的,你仍然需要our。你注意到修改了吗?
    • 我想我对 local 的唯一需求是在覆盖已经定义的特殊变量时。一旦我看到 cmets 丢失,我就看到了你的变化。我希望您还将“构造函数”更改为更正确的内容。我想我的目标是分配值,或者用户可以实际控制的东西。
    猜你喜欢
    • 2019-09-04
    • 2014-10-24
    • 1970-01-01
    • 2012-08-14
    • 2020-09-06
    • 1970-01-01
    • 2017-01-06
    • 2011-10-11
    • 1970-01-01
    相关资源
    最近更新 更多