Reading — step 1 of 5
Learn
~1 min readClosures and Data
Perl closures capture lexical (my) variables by reference. The closure keeps the variable alive even after the enclosing scope exits.
use strict;
use warnings;
sub make_counter {
my $count = 0;
return sub {
return ++$count;
};
}
my $c1 = make_counter();
my $c2 = make_counter();
print $c1->(), "\n"; # 1
print $c1->(), "\n"; # 2
print $c2->(), "\n"; # 1 — separate $count
print $c1->(), "\n"; # 3
Each call to make_counter() creates a fresh $count. Each closure has its own.
Multiple closures sharing state — Perl's encapsulation pattern:
sub make_account {
my ($balance) = @_;
return {
deposit => sub { $balance += $_[0] },
withdraw => sub { $balance -= $_[0] },
balance => sub { return $balance },
};
}
my $a = make_account(100);
$a->{deposit}->(50);
$a->{withdraw}->(20);
print $a->{balance}->(), "\n"; # 130
The three closures share $balance. External code can't access it without going through them.
Currying — produce specialized functions:
sub adder {
my ($x) = @_;
return sub { $x + $_[0] };
}
my $add5 = adder(5);
my $add10 = adder(10);
print $add5->(7), "\n"; # 12
print $add10->(7), "\n"; # 17
@_ quirk: inside a closure, @_ is the closure's args, NOT the enclosing function's. Capture explicitly:
sub outer {
my @outer_args = @_; # capture
return sub { print "outer had @outer_args, inner has @_\n" };
}
Closure-based dispatch tables — Perl-idiomatic:
my %ops = (
add => sub { $_[0] + $_[1] },
sub => sub { $_[0] - $_[1] },
mul => sub { $_[0] * $_[1] },
);
my $result = $ops{add}->(3, 4); # 7
Beats long if/elsif chains.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…