在 perl 中调用子程序 plack return 没有

calling subroutines in perl plack return nothing

我是 perl 新手 plack/psgi。我想访问 perl plack/psgi 循环中的子例程,但看起来好像子例程没有被执行。每个像 $number 这样的父变量都应该像编写常规 perl 脚本时一样自动传递。我是不是漏掉了什么,可能吗?

..
my $app = sub {

  my $number = 10;

  &count_number;
  sub count_number {
    $number +=10;
  }


  return ['200',[  'Content-Type' => 'application/json' ],
  [ "{\"number\":$number} ]];     

}
.. 

返回的是 10 而不是 20 :(

如果我修复 return 语句中字符串的引号(您缺少结束双引号),那么我会收到警告

Variable "$number" is not available at source_file.pl line 7.

原因是词法值 $app$number 是在 运行 时定义的,而子例程 count_number 在编译期间定义得更早

解决方案是将 count_number 的定义推迟到 运行 时间,方法是将其设为 anonymous 子例程。调用 $count_number->() 也需要移动到 之后 定义

my $app = sub {

    my $number = 10;

    my $count_number = sub {
        $number +=10;
    };

    $count_number->();

    return [
        '200',
        [ 'Content-Type' => 'application/json' ],
        [ "{\"number\":$number}" ]
    ];     
};


use Data::Dumper;
print Dumper $app->();

输出

$VAR1 = [
            '200',
            [
                'Content-Type',
                'application/json'
            ],
            [
                '{"number":20}'
            ]
        ];

有一个相关警告

Variable "$number" will not stay shared

具有类似的解决方案。您可以在 perldoc perldiag。消息按字母顺序列出和描述

my 运算符有两个作用:

  • 在编译时,它引入了一个标量变量。
  • 在 运行 时,它为该变量创建一个新的标量对象。

本质上,这两个标量是不同的变量,尽管它们具有相同的名称。

sub name { ... } 运算符只有编译时作用。它在编译时将子例程分配给给定的名称。因此,当子程序被编译时,它看到的是原始编译时变量,而不是稍后创建的 运行 时间变量。

因此,您不应嵌套命名子程序。事实上,如果你 use warnings 你会收到一条警告:“变量“$number”将不会保持共享状态”。

您有两个选择:

  • 您可以使用可以看到 运行time 变量的闭包。这使用匿名子程序:

    ...
    my $number = 10;
    my $count_number = sub {
      $number += 10;
    };
    
    $count_number->();
    
    ...
    
  • 或者,您将值作为显式参数传递给单独的子例程。是的,这确实让事情变得有点复杂,但它也让不同的事情分开。清晰的数据流是好的设计的一个特征。