跳转至

Perl–关闭功能

原文:https://www.geeksforgeeks.org/perl-closure-function/

闭包是 Perl 中的重要概念之一。闭包是一个计算机术语,有着准确但难以解释的含义。它通常被称为一个可以存储为变量的函数,该函数具有访问其他变量的特殊能力,这些变量位于创建它的范围内。它用于引用任何外部函数的局部变量,当编译器检测到时,它会将这些变量从外部函数的堆栈空间移动到闭包的隐藏对象声明中。然后它生成一个闭包类型的变量。 所以基本上,一个捕捉创建它的词汇环境的函数——也就是说,它运行在收集当时环境中所有东西的周围——被称为闭包函数。

关于 Perl 语言的闭包意味着:子例程 1 返回一些其他的子例程 2,然后子例程 2 访问子例程 1 中存在的变量 x,当子例程 1 的执行结束时,用户不能再访问 x,但是子例程 2 因为也引用了指向数据对象的变量 x。它使子程序 2 在子程序 1 结束后继续访问这个数据对象。 因此,子程序 1 中的变量 x 必须是词法变量,否则,子程序 1 执行后,变量 x 仍可能被外界访问、修改,如果是这样,闭包和正常函数就没有意义了。

闭包是一种绑定到某个环境的函数,在另一个函数中被写成一个函数。

示例:

sub make_adder 
{
    my $addpiece = shift;
    return sub { shift() + $addpiece };
}

# Driver Code
my $f1 = make_adder(555);
my $f2 = make_adder(20);

现在\(f1(\)n)总是 555 加上你传入的任何\(n,而\)f2(\(n)总是 20 加上你传入的任何\)n。结尾中的$addpiece 仍然存在。

闭包的使用

闭包确实是有用的东西。例如,对于回调,不需要在函数中传递回调函数指针+参数,也不需要在该函数中计算出你被回调的内容,只需要使用闭包就可以了。当调用该函数时,它可以访问创建时的所有词法环境。

闭包的一些主要用途是:将它们用作“智能”回调,另一个用途是将它们用作迭代器。

  • 智能回调函数 例如:我们想创建一个按钮(使用 Tk 工具包)给它一个子程序引用。但是如果我们想给屏幕上的两个不同的按钮一个子程序,这将是一个问题。因此,为了做到这一点,我们将使用“智能”回调例程,即闭包。这将使闭包存储一些特定于该按钮的数据(比如它的名称),当调用该子例程时,它就可以访问这些数据。
  • 迭代器 迭代器通常是一个代码引用,当执行时,它计算列表中的下一项并返回。 例如:假设有一个偶数流,其上有一个迭代器,每当调用它时,它都会返回下一个偶数。显然不可能生成所有可能的偶数,但是如果它记得上一个生成的数字,它总是可以计算下一个偶数。迭代器会记住这条重要信息。
  • 闭包的另一个用途是它可以 使一个变量私有于一个命名的子程序。 例如:在子节点创建时初始化的计数器,只能在子节点内修改。这有时可以与包文件中的 BEGIN 块一起使用,以确保变量在包的生存期内不会干扰。

部分应用的使用

部分应用函数被认为是这样一种能力:取一个具有许多参数的函数,并将参数应用于其中的一些参数,以创建一个新的函数,该函数只需要应用剩余的参数,以产生将参数应用于原始函数的等价形式。 局部应用的反复出现的特点是应用到一个参数时,其他参数不应该明确提及。

示例:

sub fs(&) 
{ 
    my $func = shift;
    sub { map $func->($_), @_ }
}

sub double($) { shift() * 2 }
sub square($) { shift() ** 2 }

my $fs_square = fs(\&square);
my $fs_double = fs(\&double);

my @s = 0 .. 3;
print "fs_square(@s): @{[ $fs_square->(@s) ]}\n";
print "fs_double(@s): @{[ $fs_double->(@s) ]}\n";

@s = (2, 4, 6, 8);
print "fs_square(@s): @{[ $fs_square->(@s) ]}\n";
print "fs_double(@s): @{[ $fs_double->(@s) ]}\n";

输出:

fs_square(0 1 2 3): 0 1 4 9
fs_double(0 1 2 3): 0 2 4 6
fs_square(2 4 6 8): 4 16 36 64
fs_double(2 4 6 8): 4 8 12 16



回到顶部