使用另一个哈希值定义一个哈希值。

发布于 2024-12-28 13:17:33 字数 322 浏览 0 评论 0原文

有没有办法在仅使用一种数据结构的情况下执行以下操作?

my %hash = (
  "key1" => "value1",
  "key2" => "value2",
  "key3" => $hash{key1},
);

所以基本上,我想将哈希的键值设置为另一个键值。我已经尝试了上述语法,但收到以下警告:

Global symbol "%hash" requires explicit package name at ...

我假设这是因为我试图在实际创建哈希之前引用它。

Is there a way to do the following while using only one data structure?

my %hash = (
  "key1" => "value1",
  "key2" => "value2",
  "key3" => $hash{key1},
);

So basically, I want to set a hash's key value to another key value. I've tried the above syntax but get the following warning:

Global symbol "%hash" requires explicit package name at ...

I'm assuming this is because I'm trying to reference the hash before it's actually been created.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

任谁 2025-01-04 13:17:33

这是因为,在使用 $hash{key1} 时,符号“hash”尚未添加到符号表中。您的包还不知道 %hash 是什么,因为直到解析结束的“)”之后它才会被添加到符号表中 - 但它会遇到前面 1 行的符号。

您需要提前预先声明%hash:

my %hash;

%hash = (
  "key1" => "value1",
  "key2" => "value2",
  "key3" => $hash{key1},
);

但是,虽然上面的代码可以编译,但是它不会按预期工作,因为尚未将任何内容分配给%hash $hash{key1} 被评估。您需要首先将其作为单独的语句进行分配:

my %hash;

%hash = (
  "key1" => "value1",
  "key2" => "value2",
);

%hash = %hash, (
  "key3" => $hash{key1},
); # Or simply $hash{key3} = $hash{key1};

请注意,上面仅将key1中的值复制到key3一次。此后它们就不再有任何联系/关联。如果您想为 key1key3 起别名(例如让它们指向相同的值,而不是包含该值的副本),则此是可能的,但并非那么微不足道。您需要将其放入绑定哈希并编写自定义绑定处理程序以使其正确,或者让每个键的值成为引用

This is because, at the moment of using $hash{key1}, the symbol "hash" was not yet added to the symbol table. Your package doesn't yet know what %hash is, because it won't be added to the symbol table until AFTER the closing ")" is parsed - yet it will encounter the symbol 1 line earlier.

You need to pre-declare %hash in advance:

my %hash;

%hash = (
  "key1" => "value1",
  "key2" => "value2",
  "key3" => $hash{key1},
);

However, while the above will compile, it will NOT work as expected, since nothing has been assigned to %hash yet when $hash{key1} is evaluated. You need to assign it first, as a separate statement:

my %hash;

%hash = (
  "key1" => "value1",
  "key2" => "value2",
);

%hash = %hash, (
  "key3" => $hash{key1},
); # Or simply $hash{key3} = $hash{key1};

Please note that the above merely copies the value from key1 into key3, once. They are in no way linked/associated after that. If you want to alias key1 and key3 (e.g. have them point to the same value, instead of contain a copy of the value), this is possible but not nearly as trivial. You need to make it into a tied hash and write custom tie handlers to get it right, or have each key's value be a reference.

深居我梦 2025-01-04 13:17:33

如果您希望 $hash{key1} 成为 $hash{key3} 的别名,那么可以使用 数据::别名

use Data::Alias;

my %hash = (
    key1 => 'value1',
    key2 => 'value2'
);

alias $hash{key3} = $hash{key1};

$hash{key1} 和 $hash{key3} 现在将引用单个值,并且对一个值的更新将在另一个值中可见。

If you want $hash{key1} to be an alias of $hash{key3}, then this can be accomplished easily using Data::Alias.

use Data::Alias;

my %hash = (
    key1 => 'value1',
    key2 => 'value2'
);

alias $hash{key3} = $hash{key1};

$hash{key1} and $hash{key3} will now refer to a single value, and updates to one will be visible in the other.

格子衫的從容 2025-01-04 13:17:33

您可以使用核心模块 Hash::Util 访问低级 hv_store 例程,该例程可以将哈希值别名在一起。它看起来不像使用 Data::Alias 那样干净,但它已经安装了。

use Hash::Util 'hv_store';

my %hash = (
  key1 => "value1",
  key2 => "value2",
);

hv_store %hash, key3 => $hash{key1};

say "$_: $hash{$_}" for sort keys %hash;
# key1: value1
# key2: value2
# key3: value1

$hash{key1} = 'new value';

say "$_: $hash{$_}" for sort keys %hash;
# key1: new value
# key2: value2
# key3: new value

如果您不希望别名在初始赋值之后持续存在,那么您可以

$hash{key3} = $hash{key1}

在初始声明之后编写以下行:并跳过使用 hv_store

You can use the core module Hash::Util to access the low level hv_store routine which can alias values of the hash together. It isn't quite as clean looking as using Data::Alias but it is already installed.

use Hash::Util 'hv_store';

my %hash = (
  key1 => "value1",
  key2 => "value2",
);

hv_store %hash, key3 => $hash{key1};

say "$_: $hash{$_}" for sort keys %hash;
# key1: value1
# key2: value2
# key3: value1

$hash{key1} = 'new value';

say "$_: $hash{$_}" for sort keys %hash;
# key1: new value
# key2: value2
# key3: new value

if you dont want the aliasing to persist past the initial assignment, then you can just write the line:

$hash{key3} = $hash{key1}

after your initial declaration and skip using hv_store.

木森分化 2025-01-04 13:17:33

为什么不创建自己的函数:

use strict;
use warnings;

sub make_hash (@) { 
    my %h;
    my @unresolved;
    while ( @_ ) {
        my ( $key, $value ) = splice( @_, 0, 2 );
        next unless defined $value;
        if (   not ref( $value ) 
           and my ( $ref ) = $value =~ /^ref:\s*(.*\S)\s*$/ 
           ) {
            if ( defined( my $v = $h{ $ref } )) {
                $h{ $key } = $v;
            }
            else {
                push @unresolved, [ $key, $ref ];
            }
        }
        else {
            $value =~ s/^lit://;
            $h{ $key } = $value;
        }
    }
    $h{ $_->[0] } = $h{ $_->[1] } foreach grep { exists $h{ $_->[0] }; } @unresolved;
    return wantarray ? %h : \%h;
} 

为了演示一些功能:

my %hash 
    = make_hash(
      'key1' => 'value1'
    , 'key2' => 'value2'
    , 'key3' => 'ref:key1'
    , 'key4' => 'lit:ref:key2'
    , 'key5' => 'lit:lit:ref:key3'
    );

lit: 前缀涵盖了“如果我真的想要传递一个非-reference as 'ref:so-and-so'? 它在回答时也是递归的,“如果我非常需要创建一个值 'lit:xzy' 怎么办?

我已经做到了这一点,并且我还祝福对 Lit 类或类似内容的传递数据的引用。

sub Ref ($) { bless \shift, 'Ref' }

然后在 make_hash 例程中,您只需检查 ref( $value ) eq 'Ref' 即可。并像下面这样指定它:

my %hash 
    = make_hash(
      'key1' => 'value1'
    , 'key2' => 'value2'
    , 'key3' => Ref 'key1'
    );

有很多方法可以让 Perl 表现得像你希望的那样。

Why not make your own function:

use strict;
use warnings;

sub make_hash (@) { 
    my %h;
    my @unresolved;
    while ( @_ ) {
        my ( $key, $value ) = splice( @_, 0, 2 );
        next unless defined $value;
        if (   not ref( $value ) 
           and my ( $ref ) = $value =~ /^ref:\s*(.*\S)\s*$/ 
           ) {
            if ( defined( my $v = $h{ $ref } )) {
                $h{ $key } = $v;
            }
            else {
                push @unresolved, [ $key, $ref ];
            }
        }
        else {
            $value =~ s/^lit://;
            $h{ $key } = $value;
        }
    }
    $h{ $_->[0] } = $h{ $_->[1] } foreach grep { exists $h{ $_->[0] }; } @unresolved;
    return wantarray ? %h : \%h;
} 

To demonstrate some of the power:

my %hash 
    = make_hash(
      'key1' => 'value1'
    , 'key2' => 'value2'
    , 'key3' => 'ref:key1'
    , 'key4' => 'lit:ref:key2'
    , 'key5' => 'lit:lit:ref:key3'
    );

The lit: prefix covers the case of "What if I really wanted to pass a value that is a non-reference as 'ref:so-and-so'? It also is recursive in answering, "What if I direly need to make a value 'lit:xzy'.

I've done this and I've also blessed a reference to a passed piece of data to a Lit class or something along those lines.

sub Ref ($) { bless \shift, 'Ref' }

And then in the make_hash routine you'd just check for ref( $value ) eq 'Ref'. And specify it like the following:

my %hash 
    = make_hash(
      'key1' => 'value1'
    , 'key2' => 'value2'
    , 'key3' => Ref 'key1'
    );

There are many ways to make Perl act like you wish it did.

婴鹅 2025-01-04 13:17:33

创建要分配给哈希的值列表时,%hash 不包含任何内容,因为您尚未将该列表分配给哈希。

事实上,在创建要分配给散列的值列表时,%hash 并不存在,因为分配先评估其右侧,然后再评估其左侧。这就是为什么你会收到严格错误。

您可能喜欢的一些解决方案:

my %hash = (
  key1 => "value1",
  key2 => "value2",
  key3 => "value1",
);


my $value1 = "value1";
my %hash = (
  key1 => $value1,
  key2 => "value2",
  key3 => $value1,
);


my %hash = (
  ( map { $_ => "value1" } qw( key1 key3 ) ),
  key2 => "value2",
);

%hash doesn't contain anything when creating the list of values to assign to the hash, since you haven't assigned the list to the hash yet.

In fact, %hash doesn't exist when creating the list of values to assign to the hash since assignments evaluate their RHS before their LHS. That's why you're getting a strict error.

Some solutions you might like:

my %hash = (
  key1 => "value1",
  key2 => "value2",
  key3 => "value1",
);


my $value1 = "value1";
my %hash = (
  key1 => $value1,
  key2 => "value2",
  key3 => $value1,
);


my %hash = (
  ( map { $_ => "value1" } qw( key1 key3 ) ),
  key2 => "value2",
);
浪推晚风 2025-01-04 13:17:33

您可以说

my %h; 
my $i = 0;
while (
    my ( $k, $v ) = ( 
        key1 => '"value1"',
        key2 => '"value2"',
        key3 => '$h{key1}',
    )[ $i, $i + 1 ] 
  )
{
    $h{$k} = eval $v; 
    $i += 2;
}

只要引用的任何键在引用之前出现在列表中即可。

You could say

my %h; 
my $i = 0;
while (
    my ( $k, $v ) = ( 
        key1 => '"value1"',
        key2 => '"value2"',
        key3 => '$h{key1}',
    )[ $i, $i + 1 ] 
  )
{
    $h{$k} = eval $v; 
    $i += 2;
}

as long as any keys referred to appear in the list before they are referenced.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文