How to pass optional parameters to a Perl function?

前端 未结 3 1462
时光取名叫无心
时光取名叫无心 2020-12-09 03:45

I want to pass several parameters, one of which is optional, to a function. The only way to do it that I know is using a list (@) as a parameter. Thus, it contents nothing o

相关标签:
3条回答
  • 2020-12-09 04:24

    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 };

    0 讨论(0)
  • 2020-12-09 04:26

    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.

    0 讨论(0)
  • 2020-12-09 04:35

    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";
        ....
    } 
    
    0 讨论(0)
提交回复
热议问题