当有一个`&'原型时,如何使用coderefs代替literal subs?

时间:2017-04-17 12:53:03

标签: perl anonymous-function plack

我正在尝试Router::Resource工作 其中函数的参数不是字面上的匿名子,但是 前面定义的coderefs。我这样做是为了减少代码重复。

这是来自概要的代码,以最小但工作的方式。这很有效。

# app.psgi
use 5.024;
use Router::Resource qw(resource router GET POST);
my $app = sub {
    my ($env) = @_;
    my $router = router {
        resource '/' => sub {
            GET { [200, [], ['get /']] };
        };
        resource '/blog/{year}/{month}' => sub {
            GET  { [200, [], ['get /blog']] };
            POST { [200, [], ['post /blog']] };
        };
    };
    $router->dispatch($env);
}
__END__
$ plackup &
$ http -b :5000
127.0.0.1 - - [17/Apr/2017:14:25:28 +0200] "GET / HTTP/1.1" 200 5 "-" "HTTPie/0.9.2"
get /
$ http -b :5000/blog/2017/4
127.0.0.1 - - [17/Apr/2017:14:26:15 +0200] "GET /blog/2017/4 HTTP/1.1" 200 9 "-" "HTTPie/0.9.2"
get /blog
$ http -b POST :5000/blog/2017/4
127.0.0.1 - - [17/Apr/2017:14:26:28 +0200] "POST /blog/2017/4 HTTP/1.1" 200 10 "-" "HTTPie/0.9.2"
post /blog
$ pkill -f plackup

将内部PSGI代码从文字匿名更改为coderef后,因此:

my $get_root = sub { [200, [], ['get /']] };
⋮
        resource '/' => sub {
            GET $get_root;
        };

然后程序将不再编译:

$ perl -c app.psgi
Type of arg 1 to Router::Resource::GET must be block or sub {} (not private variable) at app.psgi line 8, near "$get_root;"

函数原型是GET(&)。当&是第一个位置时,它允许调用者使用缩写语法,类似于sort { … } @listmap { … }而不是sort sub { … }, @list等,请参阅{{3 }}:

  

&需要一个匿名子程序,如果作为第一个参数传递,则不需要sub关键字或后续逗号。

如果有原型,我如何使用coderefs代替literal subs?

2 个答案:

答案 0 :(得分:3)

GET \&$get_root似乎有效。

对于更复杂的表达方式,例如您在评论中引用的内容,您可以使用

GET \&{$get_generic->('get /')}

\&{...}操作将其内容强制转换为适合与&原型一起使用的代码引用。同样,您可以在contexts where you want to workaround a \@ or \% prototype中使用@{[...]}%{{...}}

答案 1 :(得分:3)

选项:

  • 绕过原型。

    &GET($get_root)
    
  • 根据错误消息的要求提供BLOCK

    GET { $get_root->(@_) }
    
  • 根据错误消息的要求提供sub { }

    GET(sub { $get_root->(@_) })
    
  • 使用以\&开头的内容。 (无证)

    GET(\&$get_root)