← Perl EnglishChapter 05 of 13

Functions

## Learning Objectives - Create and call functions (subroutines) - Pass parameters and return values - Understand wantarray for context - Master closures and anonymous functions - Use prototyped functions ## Subroutines ### Declaration ```perl use strict; use warnings; sub greet { print "Hello!\n"; } greet(); # Call the subroutine ``` ### Naming ```perl sub say_hello { } sub say_hello_world { } sub with_underscore { } sub mixedCase { } # Perl convention is snake_case ``` ### Calling ```perl # With parentheses greet(); greet; # With arguments greet("Alice"); greet "Alice"; # Without parens ``` ## Parameters ### @_ Array ```perl use strict; use warnings; sub greet { my ($name) = @_; # Unpack parameters print "Hello, $name!\n"; } greet("Alice"); # Hello, Alice! ``` ### Multiple Parameters ```perl sub add { my ($a, $b) = @_; return $a + $b; } print add(5, 3); # 8 ``` ### Flexible Parameters ```perl sub sum { my $total = 0; foreach my $val (@_) { $total += $val; } return $total; } print sum(1, 2, 3, 4, 5); # 15 ``` ### Named Parameters ```perl sub create_user { my %params = @_; my $name = $params{name} // "Anonymous"; my $age = $params{age} // 0; return { name => $name, age => $age }; } my $user = create_user(name => "Alice", age => 30); ``` ### Default Parameters ```perl sub greet { my ($name, $greeting) = @_; $greeting //= "Hello"; print "$greeting, $name!\n"; } greet("Alice"); # Hello, Alice! greet("Bob", "Hi"); # Hi, Bob! ``` ## Return Values ### Explicit return ```perl sub max { my ($a, $b) = @_; if ($a > $b) { return $a; } return $b; } print max(5, 3); # 5 ``` ### Implicit Return ```perl sub get_values { my @values = (1, 2, 3); return @values; # List context } my @nums = get_values(); # (1, 2, 3) sub get_first { my ($a, $b) = @_; $a; # Last expression returned } my $first = get_first(5, 3); # 5 ``` ### Returning Multiple Values ```perl sub divide { my ($a, $b) = @_; return (int($a / $b), $a % $b); } my ($quotient, $remainder) = divide(10, 3); print "Q: $quotient, R: $remainder\n"; # Q: 3, R: 1 ``` ## Context Awareness ### wantarray ```perl sub get_values { if (wantarray) { return ("list", "context"); } elsif (defined wantarray) { return "scalar"; } else { return "void"; } } my @list = get_values(); # "list context" my $scalar = get_values(); # "scalar" get_values(); # "void" ``` ### Practical Example ```perl sub get_data { my @data = (1, 2, 3); if (wantarray) { return @data; } return \@data; # Return reference in scalar context } my @list = get_data(); # List my $ref = get_data(); # Reference ``` ## Passing References ### Array References ```perl sub process_array { my ($arr_ref) = @_; foreach my $elem (@$arr_ref) { print "$elem "; } print "\n"; } my @nums = (1, 2, 3); process_array(\@nums); ``` ### Hash References ```perl sub process_hash { my ($hash_ref) = @_; foreach my $key (keys %$hash_ref) { print "$key => $hash_ref->{$key}\n"; } } my %data = (a => 1, b => 2); process_hash(\%data); ``` ### Modify Original ```perl sub double_values { my ($arr_ref) = @_; for my $i (0 .. $#$arr_ref) { $arr_ref->[$i] *= 2; } } my @nums = (1, 2, 3); double_values(\@nums); print "@nums\n"; # 2 4 6 ``` ## Closures ### Basic Closure ```perl use strict; use warnings; sub create_counter { my $count = 0; return sub { $count++; return $count; }; } my $counter = create_counter(); print $counter->(); # 1 print $counter->(); # 2 print $counter->(); # 3 my $counter2 = create_counter(); print $counter2->(); # 1 (separate count) ``` ### Factory Function ```perl sub multiplier { my ($factor) = @_; return sub { my ($num) = @_; return $num * $factor; }; } my $double = multiplier(2); my $triple = multiplier(3); print $double->(5); # 10 print $triple->(5); # 15 ``` ### State Variables (Perl 5.10+) ```perl use strict; use warnings; use 5.010; sub counter { state $count = 0; # Persistent state return ++$count; } print counter(); # 1 print counter(); # 2 print counter(); # 3 ``` ## Anonymous Functions ### Closures as Callbacks ```perl use strict; use warnings; my @numbers = (1, 2, 3, 4, 5); my @squares = map { $_ * $_ } @numbers; print "@squares\n"; # 1 4 9 16 25 my @evens = grep { $_ % 2 == 0 } @numbers; print "@evens\n"; # 2 4 ``` ### Anonymous Subroutine ```perl my $add = sub { my ($a, $b) = @_; return $a + $b; }; print $add->(5, 3); # 8 # Or with dereferencing print &{ $add }(5, 3); # 8 ``` ## Prototypes ### Basic Prototypes ```perl use strict; use warnings; sub my_print($$) { # Expects two scalars my ($str1, $str2) = @_; print $str1, $str2; } my_print("Hello", " World"); ``` ### Prototype Characters | Char | Meaning | |------|---------| | `$` | Scalar | | `@` | Array | | `%` | Hash | | `&` | Subroutine | | `*` | Typeglob | | `\` | Reference | ### Problems with Prototypes ```perl # Prototypes don't work with method calls # and can be confusing. Use with caution. # Better: explicit parameters sub add { my ($a, $b) = @_; return $a + $b; } ``` ## Special Variables in Subroutines ### @_ Details ```perl sub inspect_args { print "Number of args: ", scalar(@_), "\n"; foreach my $i (0 .. $#_) { print " Arg $i: $_[$i]\n"; } } inspect_args(1, "hello", 3.14); ``` ### Shifting ```perl sub process { my $first = shift; # First element my $second = shift; # Second element my @rest = @_; # Remaining elements } ``` ## Recursion ```perl sub factorial { my ($n) = @_; return 1 if $n <= 1; return $n * factorial($n - 1); } print factorial(5); # 120 # Iterative version sub factorial_iter { my ($n) = @_; my $result = 1; for my $i (2 .. $n) { $result *= $i; } return $result; } ``` ## Summary - Subroutines defined with `sub name { }` - Parameters passed via `@_` array - Use `my` to localize and unpack parameters - Return values with `return` or implicit last expression - `wantarray` checks calling context - Closures capture lexical variables - Anonymous subroutines with `sub { }` - References passed for arrays/hashes to modify - `state` variables persist between calls (5.10+) - Prototypes are optional and can be problematic

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →