Joe*_*nte 6 perl function-prototypes
我正在研究 Perl 原型来了解更多关于它们的信息;我知道它们不像大多数其他语言那样工作。我不想让他们这么做。我特别希望获得一个包装函数来使用裸块作为代码参考,我认为这两个部分暗示了这一点perlsub:
因为此功能的主要目的是让您定义像内置函数一样工作的子例程
我理解这意味着你可以删除括号,并且
& 需要一个匿名子例程,如果作为第一个参数传递,则不需要 sub 关键字或后续的逗号。
我还想将其他参数传递给包装函数(而不是 coderef)。这些都是语法糖,但这就是我所追求的。
我有以下我认为可行的代码:
#!/usr/bin/env perl
use strict;
use warnings;
use 5.014;
sub with_some_context (&;+)
{
my($coderef, $context) = @_;
{
local %ENV = %ENV;
foreach my $key (keys %$context) {
$ENV{$key} = $context->{$key};
}
$coderef->();
}
}
with_some_context {
foreach my $key (@ARGV) {
say("$key: ", (defined $ENV{$key} ? $ENV{$key} : "<undef>"));
}
} => { shift(@ARGV) => 10 };
Run Code Online (Sandbox Code Playgroud)
目的是{ shift(@ARGV) => 10 }hashref 是函数的第二个参数with_some_context,即$context。编译器抱怨并且不使用 hashref 作为第二个参数:
$ /tmp/foo SHLVL TERM SHLVL LANG
Useless use of anonymous hash ({}) in void context at /tmp/foo line 26.
SHLVL: 1
TERM: xterm-256color
SHLVL: 1
LANG: en_US.UTF-8
Run Code Online (Sandbox Code Playgroud)
但是,如果我输入单词sub,编译器会突然理解我的意图:
with_some_context sub {
foreach my $key (@ARGV) {
say("$key: ", (defined $ENV{$key} ? $ENV{$key} : "<undef>"));
}
} => { shift(@ARGV) => 10 };
Run Code Online (Sandbox Code Playgroud)
正如我运行它时所证明的那样:
$ /tmp/foo SHLVL TERM SHLVL LANG
TERM: xterm-256color
SHLVL: 10
LANG: en_US.UTF-8
Run Code Online (Sandbox Code Playgroud)
如果我删除sub并在两个参数周围放入显式括号:
with_some_context({
foreach my $key (@ARGV) {
say("$key: ", (defined $ENV{$key} ? $ENV{$key} : "<undef>"));
}
}, { shift(@ARGV) => 10 });
Run Code Online (Sandbox Code Playgroud)
编译器完全失去了它的作用:
$ /tmp/foo SHLVL TERM SHLVL LANG
"my" variable $key masks earlier declaration in same statement at /tmp/foo line 24.
"my" variable %ENV masks earlier declaration in same statement at /tmp/foo line 24.
"my" variable $key masks earlier declaration in same statement at /tmp/foo line 24.
"my" variable @ARGV masks earlier declaration in same statement at /tmp/foo line 26.
syntax error at /tmp/foo line 23, near "foreach "
Execution of /tmp/foo aborted due to compilation errors.
Run Code Online (Sandbox Code Playgroud)
但如果我把sub后面:
with_some_context(sub {
foreach my $key (@ARGV) {
say("$key: ", (defined $ENV{$key} ? $ENV{$key} : "<undef>"));
}
}, { shift(@ARGV) => 10 });
Run Code Online (Sandbox Code Playgroud)
或者删除逗号并将括号放在 hashref 周围:
with_some_context {
foreach my $key (@ARGV) {
say("$key: ", (defined $ENV{$key} ? $ENV{$key} : "<undef>"));
}
} ({ shift(@ARGV) => 10 });
Run Code Online (Sandbox Code Playgroud)
一切又开始工作:
$ /tmp/foo SHLVL TERM SHLVL LANG
TERM: xterm-256color
SHLVL: 10
LANG: en_US.UTF-8
Run Code Online (Sandbox Code Playgroud)
使用sub、不带括号、不带 hashref 运行:
with_some_context {
foreach my $key (@ARGV) {
say("$key: ", (defined $ENV{$key} ? $ENV{$key} : "<undef>"));
}
};
Run Code Online (Sandbox Code Playgroud)
不会产生任何错误,但也不会做任何非常有用的事情:
$ /tmp/foo SHLVL TERM SHLVL LANG
SHLVL: 1
TERM: xterm-256color
SHLVL: 1
LANG: en_US.UTF-8
Run Code Online (Sandbox Code Playgroud)
显然我不明白发生了什么,因为这些对我来说似乎都不一致。我很明显错过了一些东西,但我不知道是什么。
从perlref:
因为大括号(大括号)用于包括 BLOCK 在内的其他一些内容,所以您有时可能需要通过在前面放置“+”或“return”来消除语句开头的大括号的歧义,以便 Perl 意识到左大括号不是' t 开始一个BLOCK。使用卷曲的经济和助记价值被认为值得这种偶尔的额外麻烦。
前导+与您尝试的 hashref 周围的括号具有相同的效果。
with_some_context {
foreach my $key (@ARGV) {
say("$key: ", (defined $ENV{$key} ? $ENV{$key} : "<undef>"));
}
} +{ shift(@ARGV) => 10 };
Run Code Online (Sandbox Code Playgroud)
如果将 hash ref 的键设置为字符串,它也可以工作;有关函数调用的某些内容(甚至是裸标量)使其解析为其他内容,从而导致错误。
这失败了:
my $first_arg = shift @ARGV;
with_some_context {
foreach my $key (@ARGV) {
say("$key: ", (defined $ENV{$key} ? $ENV{$key} : "<undef>"));
}
} { $first_arg => 10 };
Run Code Online (Sandbox Code Playgroud)
但这有效
my $first_arg = shift @ARGV;
with_some_context {
foreach my $key (@ARGV) {
say("$key: ", (defined $ENV{$key} ? $ENV{$key} : "<undef>"));
}
} { "$first_arg" => 10 };
Run Code Online (Sandbox Code Playgroud)