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 or 1 element (will never be undef), so that I can use the following code:
sub someFunction($$@) {
my ( $oblig_param1, $oblig_param2, $option_param ) = @_;
...
}
This code works, but I feel that maybe it's not the best workaround.
Are there any other ways to do it?
Thank you.
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:
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 executedif ! $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->{$_}; }
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 };
来源:https://stackoverflow.com/questions/8124138/how-to-pass-optional-parameters-to-a-perl-function