为什么我的 Perl 函数原型“(&;+)”仍然需要“sub”?

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)

显然我不明白发生了什么,因为这些对我来说似乎都不一致。我很明显错过了一些东西,但我不知道是什么。

Sha*_*awn 2

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)