Perl:参考同一个哈希定义哈希,$ this-> {key}?

时间:2010-01-27 16:53:13

标签: perl

我如何创建如下的哈希:

my %hash = (key1=>"Something", key2=>$hash{key1} . "Else");

当我声明哈希时,这不能完成吗?到目前为止,我唯一想到的是:

my %hash = (key1=>"Something");
$hash{key2} = $hash{key1} . "Else";

7 个答案:

答案 0 :(得分:11)

为什么不使用中间变量?

my $common_value = 'Something';
my %some_hash = ( k1 => $common_value, k2 => $common_value.'Else' );

<强>更新

kemp问我们为什么需要一个中间变量。我可以用两种方式解释这个问题,我会努力回答这两种解释。

  1. 为什么不能my %hash = ( k1 => 'foo', k2 => $hash{k1}.'bar' );

    在左侧(lhs)之前评估表达式的右侧(rhs)。因此,当确定k2的值时,尚未对%hash进行任何分配。事实上,%hash甚至尚未创建并进入暂存区。 (%hash这里是一个词法变量,所以它不会进入符号表。)

  2. 为什么要使用变量而不是其他方法?

    嗯,有很多方法可以用这样的值初始化哈希。如果我有少量相关的键进行初始化,我会使用一个中间变量。

    my $cv1 = sub_result() * 5;
    my $cv2 = "Number: $cv1";
    
    my %h = (
        k1 => $cv1,  
        k2 => $cv2,
        k3 => "Numero: $cv1",
        k4 => "Big $cv2",
        k5 => "Round $cv2",
        k6 => "Whole $cv2",
        k7 => "-$cv1",
    );
    

    但是,如果我必须构建许多依赖于许多不同键的复杂值,我可能会使用数据驱动方法来初始化哈希。确切的实现将取决于我没有的细节,但它可能看起来像这样:

    use Scalar::Util qw(reftype);
    
    my @init = ( 
        [ key1 => $value                 ],
        [ key2 => \&make_a_value, 'key1' ],
        [ key3 => \&another_way,  'key2' ],
    );
    
    my %h; 
    for my $spec ( @init ) {
        my $key   = shift @$spec;
        my $value = shift @$spec;
        my @args  = @$spec;
    
        if( reftype $value eq reftype sub {} ) {
            $value = $value->( @h{ @args } );
        }
    
        $h{$key} = $value;
    }
    

    对于此问题所针对的任何情况,选择使用何种技术取决于该实例特有的许多细节。因此,我们必须做出通用陈述。中间变量是解决OP问题的一种好方法。是否应该在他的特定情况下使用它,我不能说。

答案 1 :(得分:9)

由于两个原因无法完成:

  1. 在Perl处理key2 => $hash{key1}时,它还没有将使用密钥1分配的内存与散列名称哈希相关联。换句话说,$hash{key1}在指定key2 => $hash{key1}之后才会指向内存中的正确位置。

  2. 之前的原因没有说明其他问题:在您处理%hash时,您还没有将key2 => $hash{key1}放入符号表中(再次解析/评估的顺序) ,所以编译器会像你一样use strict;进行barf。在前面的陈述中声明my %hash很容易解决这个问题,但#1不是。

答案 2 :(得分:4)

在您定义哈希的位置,$ hash {key1}不存在,因此您无法在一个语句中执行此操作。 您可以自己创建解决方案,并在定义密钥后使用密钥1。

答案 3 :(得分:1)

有什么问题
my %hash = ( key1 => "Something", key2 => "Something" . "Else" );

是的,我知道这些是占位符,但无论它们是什么,你在构建哈希时都知道它们(或者你根本不会构建它),那你为什么不加入它们呢? / p>

答案 4 :(得分:0)

首先,我会用中间值来做这件事。但是,您有两个单独的更高级选项。如果你是perl的新手,我不建议/其中任何一个 - 实际上我更喜欢中间价值解决方案,但是为了完整性:

  • 您可以使用Tie::Hash,它允许您使用哈希语法和散列样式解除引用(->{key1})来访问对象,您可以使用perldoc perltie找到有关此方法的更多信息,以及上面链接到Tie::Hash;
  • 的手册页
  • 你可以放弃使用哈希的想法;并使用一个对象,甚至Moose,它允许您从哈希初始化对象,共享相同的值。在这样做的实际例子中,我没有看到太多的目的。

这是一个Moose的例子。

package Class;
use Moose;
has [qw/key1 key2/] => ( isa => 'Str', is => 'rw', init_arg => 'key1' );

my $o = Class->new( { key1 => 'foobar' } );
print $o->key1, $o->key2;

答案 5 :(得分:0)

你可以相当接近,但我不确定它是否具有新颖性以外的价值:

$_->{key2} = $_->{key1} . "Else" for my $hash = { key1 => "Something" };

答案 6 :(得分:0)

如果在%hash中创建 之外的中间变量,那么使用do block可能会让它更美观:

my %hash = (
    do {
        my $s = 'Something';
        ( key1 => $s, key2 => $s . 'Else' );
    },
);

/ I3az /