简体   繁体   中英

How can I set a default file handle in a perl subroutine signature?

I have a subroutine,

use experimental "signatures";

sub foo {
  my $fh = +shift;
  open ($fh, '>', 'default_file') unless defined $fh;
}

I would like to port that to subroutine signatures. Is it possible to set $fh to default to a filehandle that points to default_file .

Something like this

sub foo ($fh=open($fh,">",foo")) {}

or even with a do{} block,

sub foo ($fh=do { open($fh,">",foo"), $fh } ) {}

I know I can get this syntax if I use or create a wrapper. But it just seems like there should be a way of some sort to get this done without invoking IO::File and the like.

Can also cheat, just a little, and use a name-less and value-less optional argument

use experimental "signatures";

sub foo ($=) {
    my $fh = shift;
    open $fh, '>', "foo.txt" or die $!  if not defined $fh;
    say $fh 42;
    return $fh;
}

This fakes it in the sense that it processes arguments "normally" (as it would without signatures). However, one of nice things with signatures is that the @_ is kept pristine and can also be used

When using a signature, the arguments are still available in the special array variable @_ , in addition to the lexical variables of the signature.

I don't see a good reason to not use that. Even as it pushes the argument processing back into the sub's body, you still get other benefits of signatures -- and an added measure of flexibility.


The stylistic point of handling arguments in the signature, including their defaults, is denied here anyway, merely by how much there is to do for this default.

Pending a better answer, I think the only method is to use a wrapper,

use IO::File;                                                              
sub foo ( $fh=IO::File->new("default_file", "w") ) {                                
  print $fh 42                                                             
}

The second attempt you showed is almost valid, you just need another variable to stand in since $fh doesn't exist yet when assigning the default; and to return it in a separate statement from where it's declared. You could abuse global variables to do this of course but that's ugly and leaky.

sub foo ($fh=do { open(my $d,">","foo"); $d } ) {}

This of course should have error handling.

sub foo ($fh=do { open(my $d,">","foo") or die "Failed to open 'foo': $!"; $d } ) {}

A proposed extension to signatures could be used to do it slightly differently, but I'm not sure if this is any better:

sub foo (?$d, $fh=(open($d,">","foo") || die "Failed to open 'foo': $!", $d) ) {}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM