如果你在匿名子里面调用shift会怎么样?

时间:2018-01-25 15:34:41

标签: perl subroutine anonymous

首先,如果这个问题不合适,请道歉;我实际上并不知道很多perl。

我正在尝试调试一些现有的代码,这些代码应该从我们的在线作业系统WeBWorK发送成绩到LMS。我遇到了一个奇怪的错误,我认为某些东西没有被正确初始化,或者可能不是正确的类。我怀疑问题可能在这里:

sub go {
    my $self = shift;
    my $r = $self->r;
    my $ce = $r->ce;

    # If grades are begin passed back to the lti then we peroidically
    # update all of the grades because things can get out of sync if
    # instructors add or modify sets.
    if ($ce->{LTIGradeMode}) {

      my $grader = WeBWorK::Authen::LTIAdvanced::SubmitGrade->new($r);

      my $post_connection_action = sub {
        my $grader = shift;

        # catch exceptions generated during the sending process
        my $result_message = eval { $grader->mass_update() };
        if ($@) {
          # add the die message to the result message
          $result_message .= "An error occurred while trying to update grades via LTI.\n"
        . "The error message is:\n\n$@\n\n";
          # and also write it to the apache log
          $r->log->error("An error occurred while trying to update grades via LTI: $@\n");
        }
      };
      if (MP2) {
        $r->connection->pool->cleanup_register($post_connection_action, $grader);
      } else {
        $r->post_connection($post_connection_action, $grader);
      }
    }
... # a bunch of other stuff happens in the "go" sub

我有点怀疑问题出在$grader变量上;特别是,我不知道匿名子内部my $grader = shift;做了什么。就像,如果sub有一个名字,那么shift给出传递给sub的第一个参数就更清楚了。但由于它是匿名的,我不知道它认为它的论点是什么。

此外,我不确定为什么需要这条线。就像,从我的谷歌搜索,我被理解,匿名子的意义是保持范围内的周围环境的所有变量。那么为什么我们需要首先在匿名子内部重新定义$grader

感谢您帮助perl noob! :)

1 个答案:

答案 0 :(得分:4)

在这方面没有什么特别的关于anon潜艇。

my $cr = sub {
   my $arg = shift;
   say $arg;
};

$cr->("foo");   # Prints "foo"
$cr->("bar");   # Prints "bar"

在您的情况下,您将$post_connection_action$grader传递给cleanup_registerpost_connection,期望它会导致&$post_connection_action调用{ {1}}作为它的第一个参数。期望是否正确取决于$gradercleanup_register的实施,我对此一无所知。

请注意,另一种解决方案出现在这里。在评估post_connection运算符时,Subs可以访问范围内的词汇。

sub

即使被调用的词汇在被调用时不再存在,上述情况也是如此。

my $prefix = "> ";
my $cr = sub {
   my $arg = shift;
   say "$prefix$arg";   # Captures $prefix from sub{} scope.
};

$cr->("foo");           # Prints "> foo"

这意味着您不需要将my $cr; { my $prefix = "> "; $cr = sub { my $arg = shift; say "$prefix$arg"; # Captures $prefix from sub{} scope. }; } # $prefix would normally stop existing here. $cr->("foo"); # Prints "> foo" 作为参数传递。它可以简单地捕获。只需忽略$grader(并且不要将my $grader = shift;传递给 $gradercleanup_register)。