Perl将函数作为参数传递-未定义的子引用

Perl将函数作为参数传递-未定义的子引用,perl,Perl,我正在读马克·杰森·多米努斯(MarkJason Dominus)的《高阶Perl》一书,我被第一个例子所困扰。它围绕递归地解决河内塔问题展开,我的程序做得很好。问题是,本书通过重构代码开发了这个示例,在这里,solution函数采用另一个参数,而不是简单地打印解决方案正在做什么。这是一个函数,在我的例子中,它只是做同样的事情 问题是,我已经定义了辅助函数,并试图通过引用传递它,然后从主函数调用它,但是我得到了以下错误 无法在main.pl第86行将未定义的值用作子例程引用 此版本不将函数作为参

我正在读马克·杰森·多米努斯(MarkJason Dominus)的《高阶Perl》一书,我被第一个例子所困扰。它围绕递归地解决河内塔问题展开,我的程序做得很好。问题是,本书通过重构代码开发了这个示例,在这里,solution函数采用另一个参数,而不是简单地打印解决方案正在做什么。这是一个函数,在我的例子中,它只是做同样的事情

问题是,我已经定义了辅助函数,并试图通过引用传递它,然后从主函数调用它,但是我得到了以下错误

无法在main.pl第86行将未定义的值用作子例程引用

此版本不将函数作为参数,并正确地解决了问题

#!/usr/bin/perl

use utf8;
use v5.26;

use strict;
use warnings;

sub SolveTowerOfHanoiProblem0 {
    my ($n, $start, $end, $extra) = @_;

    if ($n == 1) {
        say "Move disk #$n from $start to $end.";
    } else {
        SolveTowerOfHanoiProblem0($n - 1, $start, $extra, $end);

        say "Move disk #$n from $start to $end.";

        SolveTowerOfHanoiProblem0($n - 1, $extra, $end, $start);
    }
}

SolveTowerOfHanoiProblem0(3, 'A', 'C', 'B');
输出:

Move disk #1 from A to C.
Move disk #2 from A to B.
Move disk #1 from C to B.
Move disk #3 from A to C.
Move disk #1 from B to A.
Move disk #2 from B to C.
Move disk #1 from A to C.
我希望重构代码,使输出每个步骤中发生的事情的行独立于解决方案代码,因此目前我编写了另一个函数,它只做同样的事情,但作为参数由调用方传递:

sub SolveTowerOfHanoiProblem {
    my ($n, $start, $end, $extra, $moveDisk) = @_;

    if ($n == 1) {
        $moveDisk->($n, $start, $end);
    } else {
        SolveTowerOfHanoiProblem($n - 1, $start, $extra, $end);

        $moveDisk->($n, $start, $end);

        SolveTowerOfHanoiProblem($n - 1, $extra, $end, $start);
    }
}

sub PrintInstruction {
    my ($disk, $start, $end) = @_;

    say "Move disk #$disk from $start to $end.";
}


SolveTowerOfHanoiProblem(8, 'A', 'C', 'B', \&PrintInstruction);
我遇到以下运行时错误:无法在main.pl第86行使用未定义的值作为子例程引用。这是我第一次调用传入函数的地方

第86行:

if ($n == 1) {
        $moveDisk->($n, $start, $end); # <---- Here, Line 86
    } else {
        SolveTowerOfHanoiProblem($n - 1, $start, $extra, $end);

        $moveDisk->($n, $start, $end);
我不明白为什么子引用是未定义的。我已经定义了我引用的函数,从目前为止我发现的情况来看,我似乎正确地调用了该函数

我也看过了,但是我的PrintInstruction函数不是在模块中定义的,它是在本地定义的,所以如果我理解正确,我不需要引用中的$symbol


我遗漏了什么?

SolveTowerOfHanoipProblem函数需要一个code ref作为最后五个参数,但在«else»块中调用它时,您没有传递它:

SolveTowerOfHanoiProblem($n - 1, $start, $extra, $end);
应写为:

SolveTowerOfHanoiProblem($n - 1, $start, $extra, $end, $moveDisk);

您将代码引用传递给SolveTowerOfHanoipProblem的原始调用,而不是递归调用

您只需传递代码ref

SolveTowerOfHanoiProblem($n - 1, ..., $moveDisk);
或者可以消除反复传递相同值的需要

sub SolveTowerOfHanoiProblem {
    my $moveDisk = pop;

    local *helper = sub {
        my ($n, $start, $end, $extra) = @_;

        if ($n == 1) {
            $moveDisk->($n, $start, $end);
        } else {
            helper($n - 1, $start, $extra, $end);
            $moveDisk->($n, $start, $end);
            helper($n - 1, $extra, $end, $start);
        }
    };

    helper(@_);
}
相同,但使用Perl 5.16中引入的功能:

use feature qw( current_sub );

sub SolveTowerOfHanoiProblem {
    my $moveDisk = pop;

    sub {
        my ($n, $start, $end, $extra) = @_;

        if ($n == 1) {
            $moveDisk->($n, $start, $end);
        } else {
            __SUB__->($n - 1, $start, $extra, $end);
            $moveDisk->($n, $start, $end);
            __SUB__->($n - 1, $extra, $end, $start);
        }
    }->(@_);
}

哇,真不敢相信我错过了。非常感谢,我很感激哇,我没有遇到像这样的嵌套子例程,谢谢你的提醒只是不要嵌套命名的子例程