How do closures in Perl work?

后端 未结 3 1398
花落未央
花落未央 2021-02-18 20:19

Newbie in Perl again here, trying to understand closure in Perl.

So here\'s an example of code which I don\'t understand:

sub make_saying  {         


        
相关标签:
3条回答
  • 2021-02-18 20:38

    Every time you call the subroutine 'make_saying', it:

    1. creates a DIFFERENT closure

    2. assigns the received parameter to the scalar '$salute'

    3. defines (creates but not execute) an inner anonymous subroutine: That is the reason why at that moment nothing is assigned to the scalar $target nor is the statement print "$salute, $target!\n"; executed .

    4. finally the subroutine 'make_saying' returns a reference to the inner anonymous subroutine, that reference becomes the only way to call the (specific) anonymous subroutine.

    Ever time you call each anonymous subroutine, it:

    1. assign the received parameter to the scalar $target

    2. sees also the scalar $salute that will have the value assigned at the moment in which was created the anonymous subroutine (when was called its parent subroutine make_saying

    3. finally executes the statement print "$salute, $target!\n";

    0 讨论(0)
  • 2021-02-18 20:45

    In Perl, scalar variables cannot hold subroutines directly, they can only hold references. This is very much like scalars cannot hold arrays or hashes, only arrayrefs or hashrefs.

    The sub { ... } evaluates to a coderef, so you can directly assign it to a scalar variable. If you want to assign a named function (e.g. foo), you have to obtain the reference like \&foo.

    You can call coderefs like $code->(@args) or &$code(@args).

    The code

    $f = \make_saying("Howdy")
    

    evaluates make_saying("Howdy"), and takes a reference to the returned value. So you get a reference that points to a coderef, not a coderef itself.

    Therefore, it can't be called like &$f("world"), you need to dereference one extra level: &$$f("world").


    A closure is a function that is bound to a certain environment.

    The environment consists of all currently visible variables, so a closure always remembers this scope. In the code

    my $x;
    sub foo {
      my $y;
      return sub { "$x, $y" };
    }
    

    foo is a closure over $x, as the outer environment consists of $x. The inner sub is a closure over $x and $y.

    Each time foo is executed, we get a new $y and therefore a new closure. Each time it is called, a different closure is returned.

    When we execute make_saying("Howdy"), the $salute variable is set to Howdy. The returned closure remembers this scope.

    When we execute it again with make_saying("Greetings"), the body of make_saying is evaluated again. The $salute is now set to Greetings, and the inner sub closes over this variable. This variable is separate from the previous $salute, which still exists, but isn't accessible except through the first closure.

    The two greeters have closed over separate $salute variables. When they are executed, their respective $salute is still in scope, and they can access and modify the value.

    0 讨论(0)
  • 2021-02-18 20:56

    If a variable is asigned to a function, is it automatically a reference to that function?

    No. In example the function make_saying return reference another function. Such closures do not have name and can catch a variable from outside its scope (variable $salute in your example).

    In that above code, can i write $f = \make_saying("Howdy") instead? And when can i use the & cause i tried using that in passing the parameters (&$f("world")) but it doesnt work.

    No. $f = \make_saying("Howdy") is not what you think (read amon post for details). You can write $f = \&make_saying; which means "put into $f reference to function make_saying". You can use it later like this:

    my $f = \&make_saying;
    my $other_f = $f->("Howdy");
    $other_f->("world");
    

    and lastly, In that code above how in he** did the words world and earthlings got appended to the words howdy and greetings.

    make_saying creating my variable which goes into lamda (my $newfunc = sub); that lambda is returned from make_saying. It holds the given word "Howdy" through "closing" (? sorry dont know which word in english).

    0 讨论(0)
提交回复
热议问题