使用相同散列的元素声明散列
Declaring a hash using elements of the same hash
愚蠢的 perl 问题。假设我正在准备一些 API 调用,为了整洁起见,我想在散列中声明所需的变量。我如何引用我正在声明的相同散列?
my %api_hash = (
'api_endpoint1' => {
'username' => 'foo',
'password' => 'bar',
'api_url' => 'https://192.168.1.10:9200',
'headers' => {Accept => 'application/json', Authorization => 'Basic ' . encode_base64($username . ':' . $password)}
},
'api_endpoint2' => {
'username' => 'bah',
'password' => 'wizz',
'api_url' => 'https://192.168.1.20:9182',
'headers' => {Accept => 'application/json', Authorization => 'Basic ' . encode_base64($username . ':' . $password)}
}
);
而不是 $api_hash{<endpoint name>}{'headers'}
中的 $username
和 $password
,我如何在同一声明语句中将它们设置为 $api_hash{<endpoint name>}{'username'}
和 $api_hash{<endpoint name>}{'password'}
?
您可以在散列中声明除 headers 之外的所有内容,然后在声明后使用 for 循环添加它们:
use warnings;
use strict;
my %api_hash = (
'api_endpoint1' => {
'username' => 'foo',
'password' => 'bar',
'api_url' => 'https://192.168.1.10:9200',
},
'api_endpoint2' => {
'username' => 'bah',
'password' => 'wizz',
'api_url' => 'https://192.168.1.20:9182',
}
);
for my $ep (keys %api_hash) {
my $auth = 'Basic ' . encode_base64($api_hash{$ep}{username} . ':' . $api_hash{$ep}{password});
$api_hash{$ep}{headers} = {Accept => 'application/json', Authorization => $auth}
}
您可以使用一个函数从您的三个输入构建四个键值对。
sub api_endpoint {
my ($user,$pw,$url) = @_;
return { username => $user, password => $pw, api_url => $url,
headers => { Accept => 'application/json',
Authorization => 'Basic ' . encode_base64($user . ':' . $pw)} }
}
my %api_hash = (
api_endpoint1 => api_endpoint('foo','bar','https://192.168.1.10:9200'),
api_endpoint2 => api_endpoint('bah','wizz','https://192.168.1.20:9182'),
...
);
或者为了保留散列声明的更多外观和感觉,让函数接受尽可能多的散列引用和return带有第四个参数的散列引用
sub api_endpoint {
my ($ep) = @_;
$ep->{headers} = {
Accept => 'application/json',
Authorization => 'Basic '
. encode_base64($ep->{username} . ':' . $ep->{password}
};
return $ep;
}
my %api_hash = (
'api_endpoint1' => api_endpoint({
'username' => 'foo',
'password' => 'bar',
'api_url' => 'https://192.168.1.10:9200',
}),
'api_endpoint2' => api_endpoint({
'username' => 'bah',
'password' => 'wizz',
'api_url' => 'https://192.168.1.20:9182',
})
);
对于一次性申请,你所做的就很好了。如果您要经历使某些代码可重用的麻烦,最好花更少的时间,而不是编写额外的“蓬松”代码。如果您在哈希中手动写入用户名和密码,也只需在第二个位置手动写入即可。
如果没有关于您正在做的其他事情的更多信息,很难说什么是做您想做的事的正确方法[TM]。您可以使用 mob 显示的生成器。 “最正确”的方法可能是使它成为一个对象并使headers
键成为一个方法调用。
{ package MyEndpoint;
sub new {
my $class = shift;
my $self = { @_ };
return bless $self, $class;
}
sub get_headers {
my self = shift;
my %headers = %{$self->{-headers}};
if ($self->{-auth} eq "basic") {
$headers{Authorization} = sprintf "Basic %s",
encode_base64(join ":", @{$self}{qw/-username -password/});
}
return %headers;
}
my %api_hash = (
api_endpoint1 => MyEndpoint->new(
-username => 'foo',
-password => 'bar',
-api_url => 'https://192.168.1.10:9200',
-auth => 'basic',
-headers => {Accept => 'application/json'},
},
...
);
## Later on when using the endpoint
foreach my $endpoint (values %api_hash) {
my @headers = $endpoint->get_headers;
...
}
但是要直接回答您的问题,要在定义数据结构时使用数据结构中的值,您必须滥用解析器。
my %api_hash;
for (1, 2) {
%api_hash = (
'api_endpoint1' => {
'username' => 'foo',
'password' => 'bar',
'api_url' => 'https://192.168.1.10:9200',
'headers' => {Accept => 'application/json',
Authorization => 'Basic ' . encode_base64(
$api_hash{api_endpoint1}{username} . ':' . $api_hash{api_endpoint1}{password}
)}
},
'api_endpoint2' => {
'username' => 'bah',
'password' => 'wizz',
'api_url' => 'https://192.168.1.20:9182',
'headers' => {Accept => 'application/json',
Authorization => 'Basic ' . encode_base64(
$api_hash{api_endpoint2}{username} . ':' . $api_hash{api_endpoint2}{password}
)}
}
);
}
没错,你用循环执行了两次赋值。第一遍设置所有普通值;此时所有的自引用都是undef
。在第二遍中,所有普通键和值现在都存在,因此自引用将解析为实际值。你明白为什么它是解析器滥用。您正在定义和覆盖整个事物两次以获得这些自我引用。对于一些又小又快又脏的东西来说很好。这是 Perl。然而,它对于 Real Code[TM] 来说也是浪费和蹩脚的。
最好从离散变量构建它或使它成为一个对象。这是对象很棒的主要原因之一。您可以将所有样板文件放入一个模块中,并仅在您真正需要它们时才生成它们。
HTH
愚蠢的 perl 问题。假设我正在准备一些 API 调用,为了整洁起见,我想在散列中声明所需的变量。我如何引用我正在声明的相同散列?
my %api_hash = (
'api_endpoint1' => {
'username' => 'foo',
'password' => 'bar',
'api_url' => 'https://192.168.1.10:9200',
'headers' => {Accept => 'application/json', Authorization => 'Basic ' . encode_base64($username . ':' . $password)}
},
'api_endpoint2' => {
'username' => 'bah',
'password' => 'wizz',
'api_url' => 'https://192.168.1.20:9182',
'headers' => {Accept => 'application/json', Authorization => 'Basic ' . encode_base64($username . ':' . $password)}
}
);
而不是 $api_hash{<endpoint name>}{'headers'}
中的 $username
和 $password
,我如何在同一声明语句中将它们设置为 $api_hash{<endpoint name>}{'username'}
和 $api_hash{<endpoint name>}{'password'}
?
您可以在散列中声明除 headers 之外的所有内容,然后在声明后使用 for 循环添加它们:
use warnings;
use strict;
my %api_hash = (
'api_endpoint1' => {
'username' => 'foo',
'password' => 'bar',
'api_url' => 'https://192.168.1.10:9200',
},
'api_endpoint2' => {
'username' => 'bah',
'password' => 'wizz',
'api_url' => 'https://192.168.1.20:9182',
}
);
for my $ep (keys %api_hash) {
my $auth = 'Basic ' . encode_base64($api_hash{$ep}{username} . ':' . $api_hash{$ep}{password});
$api_hash{$ep}{headers} = {Accept => 'application/json', Authorization => $auth}
}
您可以使用一个函数从您的三个输入构建四个键值对。
sub api_endpoint {
my ($user,$pw,$url) = @_;
return { username => $user, password => $pw, api_url => $url,
headers => { Accept => 'application/json',
Authorization => 'Basic ' . encode_base64($user . ':' . $pw)} }
}
my %api_hash = (
api_endpoint1 => api_endpoint('foo','bar','https://192.168.1.10:9200'),
api_endpoint2 => api_endpoint('bah','wizz','https://192.168.1.20:9182'),
...
);
或者为了保留散列声明的更多外观和感觉,让函数接受尽可能多的散列引用和return带有第四个参数的散列引用
sub api_endpoint {
my ($ep) = @_;
$ep->{headers} = {
Accept => 'application/json',
Authorization => 'Basic '
. encode_base64($ep->{username} . ':' . $ep->{password}
};
return $ep;
}
my %api_hash = (
'api_endpoint1' => api_endpoint({
'username' => 'foo',
'password' => 'bar',
'api_url' => 'https://192.168.1.10:9200',
}),
'api_endpoint2' => api_endpoint({
'username' => 'bah',
'password' => 'wizz',
'api_url' => 'https://192.168.1.20:9182',
})
);
对于一次性申请,你所做的就很好了。如果您要经历使某些代码可重用的麻烦,最好花更少的时间,而不是编写额外的“蓬松”代码。如果您在哈希中手动写入用户名和密码,也只需在第二个位置手动写入即可。
如果没有关于您正在做的其他事情的更多信息,很难说什么是做您想做的事的正确方法[TM]。您可以使用 mob 显示的生成器。 “最正确”的方法可能是使它成为一个对象并使headers
键成为一个方法调用。
{ package MyEndpoint;
sub new {
my $class = shift;
my $self = { @_ };
return bless $self, $class;
}
sub get_headers {
my self = shift;
my %headers = %{$self->{-headers}};
if ($self->{-auth} eq "basic") {
$headers{Authorization} = sprintf "Basic %s",
encode_base64(join ":", @{$self}{qw/-username -password/});
}
return %headers;
}
my %api_hash = (
api_endpoint1 => MyEndpoint->new(
-username => 'foo',
-password => 'bar',
-api_url => 'https://192.168.1.10:9200',
-auth => 'basic',
-headers => {Accept => 'application/json'},
},
...
);
## Later on when using the endpoint
foreach my $endpoint (values %api_hash) {
my @headers = $endpoint->get_headers;
...
}
但是要直接回答您的问题,要在定义数据结构时使用数据结构中的值,您必须滥用解析器。
my %api_hash;
for (1, 2) {
%api_hash = (
'api_endpoint1' => {
'username' => 'foo',
'password' => 'bar',
'api_url' => 'https://192.168.1.10:9200',
'headers' => {Accept => 'application/json',
Authorization => 'Basic ' . encode_base64(
$api_hash{api_endpoint1}{username} . ':' . $api_hash{api_endpoint1}{password}
)}
},
'api_endpoint2' => {
'username' => 'bah',
'password' => 'wizz',
'api_url' => 'https://192.168.1.20:9182',
'headers' => {Accept => 'application/json',
Authorization => 'Basic ' . encode_base64(
$api_hash{api_endpoint2}{username} . ':' . $api_hash{api_endpoint2}{password}
)}
}
);
}
没错,你用循环执行了两次赋值。第一遍设置所有普通值;此时所有的自引用都是undef
。在第二遍中,所有普通键和值现在都存在,因此自引用将解析为实际值。你明白为什么它是解析器滥用。您正在定义和覆盖整个事物两次以获得这些自我引用。对于一些又小又快又脏的东西来说很好。这是 Perl。然而,它对于 Real Code[TM] 来说也是浪费和蹩脚的。
最好从离散变量构建它或使它成为一个对象。这是对象很棒的主要原因之一。您可以将所有样板文件放入一个模块中,并仅在您真正需要它们时才生成它们。
HTH