How to pass optional parameters to a Perl function?

删除回忆录丶 提交于 2019-11-28 07:35:18

You can use a semicolon in the prototype to indicate the end of the required parameters:

sub someFunction($$;$) {
  my ( $oblig_param1, $oblig_param2, $option_param ) = @_;
  ...
}

The ; is optional before a @ or %, which, according to the docs, "gobbles up everything else".

EDIT: As DVK points out in a comment (and TLP emphasizes in another answer here), you are probably best off simply avoiding prototypes:

sub someFunction {
  my ( $oblig_param1, $oblig_param2, $option_param ) = @_;
  ...
}

Perl prototypes have their uses (mostly to supply implicit context coercion to arguments, as Perl's built-in functions do). They should not be used as a mechanism to check that function are called with the correct number and type of arguments.

Prototypes (the ($$@) part of your sub declaration) are optional themselves. They have a very specific use, and if you don't know what it is, it is better to not use it. From perlsub:

...the intent of this feature is primarily to let you define subroutines that work like built-in functions

Just remove the prototype from your sub declaration, and you can use whatever arguments you like.

sub someFunction {
    my ( $oblig_param1, $oblig_param2, $option_param ) = @_;
    if (defined $option_param) {
        # do optional things
    }
    $option_param //= "default optional value";
    ....
} 

It is a good idea to group parameters in a $parameter hashref. This is especially useful if several options (mandatory or optional) need to be provided.

To access any parameter, simply use $parameter->{oblig1} or $$parameter{option2}.

Passing hashrefs make it especially convenient when developing, so when the need for $oblig3 comes along, the ordering of the arguments changes neither at the caller nor the sub itself. Compare before and after:


# BEFORE $oblig3

--------------------------+-------------------------
# Caller                  | # Sub
--------------------------+-------------------------
someFunc( $oblig1,        | sub {
          $oblig2,        |   my ( $oblig1,
          $option1 );     |        $oblig2,
                          |        $option1 ) = @_;
                          | }
--------------------------+-------------------------

# AFTER $oblig3

--------------------------+-------------------------
# Caller                  | # Sub
--------------------------+-------------------------
someFunc( $oblig1,        | sub {
          $oblig2,        |   my ( $oblig1,
          $oblig3,        |        $oblig2,
          $option1 );     |        $oblig3,
                          |        $option1 ) = @_;
                          | }
--------------------------+-------------------------

The argument order changes at both caller and sub, so order needs to be maintained and respected.

Using hashrefs, there is no need to worry about argument order:

--------------------------+-------------------------
# Caller                  | # Sub
--------------------------+-------------------------
someFunc({ oblig1  => 1   | sub {
           oblig2  => 2   |   my ( $params ) = @_;
           option1 => 1   |   # No changes to    
           oblig3  => 7   |   # argument passing
         });              |  }    
                          | 
--------------------------+-------------------------

Depending on the design needs of the subroutine, the following subroutine argument patterns could be utilized:

  1. my ( $mandatory_parameters, $optional_parameters ) = @_;

    This pattern is useful if there are several of each. The beauty of this approach is that $optional_parameters is undefined if not passed, so the default case could be executed if ! $optional_parameters;

    Note that the mandatory parameters will need to be checked subsequently:

    for ( qw/ a b c / ) { 
        die "Missing '$_' parameter\n"
          unless exists $mandatory_parameters->{$_};
    }
    
  2. my ( $parameters ) = @_;

    Useful if there are few or no mandatory parameters.

    It is also extremely effective if parameters are passed to simply modify default behavior. By defining $default_parameters in the scope of the package, the defaults can be loaded by a subsequent one-liner unless a parameter was explicitly passed:

    $parameters = { %$default_parameters, %$parameters };

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!