【问题标题】:Perl: How to pass and use a lexical file handle to a subroutine as a named argument?Perl:如何将词法文件句柄作为命名参数传递和使用子例程?
【发布时间】:2010-06-25 18:26:20
【问题描述】:

我想使用命名参数将词法文件句柄传递给子例程,但以下代码无法编译:

#!/usr/bin/perl -w
use strict;

my $log_fh;
my $logname = "my.log";

sub primitive {
   my ($fh, $m) = @_;
   print $fh $m;
}

sub sophisticated {
   my ($args) = @_;
   print $args->{m};
   print $args->{fh} $args->{m} ;
}

open $log_fh, ">", $logname;

print $log_fh "Today I learned ...\n";

primitive($log_fh,"... the old way works ...\n");

sophisticated({
   fh=>$log_fh, 
   m=>"... and the new way requires an intervention by SO.",
   });
close $log_fh;

投诉是:

Scalar found where operator expected at ./lexical.file.handle.pl line 15, near
} $args"
(Missing operator before  $args?)

$ perl --version

This is perl, v5.10.1

它工作正常。当我使用传递参数的原始技术时,命名参数散列技术适用于 message 部分,但不适用于 file handle 部分。我需要新版本的 print 吗?

【问题讨论】:

  • 你应该改掉预先声明变量的习惯(“my $log_fh;”是不必要的),你应该检查opens的状态。例如:open my $log_fh, ">", $logname or die "Error opening $logname: $!";

标签: perl subroutine


【解决方案1】:

当您有一个返回文件句柄的复杂表达式(如$args->{fh})时,您需要通过添加一些额外的花括号来消除语法歧义:

print { $args->{fh} } $args->{m};

这是由于 print 运算符的设计方式很奇怪,文件句柄和要打印的内容列表之间没有逗号。

或者,您可以先从参数 hashref 中获取文件句柄,例如

my $fh = $args->{fh};
print $fh $args->{m};

【讨论】:

  • 那是因为您使用了带有print 的间接对象语法。奇怪的是,如果您执行$args{fh}->print( 'blah' );,则必须执行use IO::Handle;,否则会出现错误。但是使用间接符号就没有必要了。请参阅perldoc.perl.org/perlobj.html#Indirect-Object-Syntax 了解更多信息。
【解决方案2】:

friedo's answer 涵盖了您的问题,但我想指出一个风格问题。您无需将所有内容包装在匿名哈希中即可模拟命名参数。哈希初始化器只是一个解释为键/值对的列表。将这样的列表传递给 sub 为调用者提供了更简洁的语法:

sub sophisticated {
   my %arg = @_;
   print $arg{m};
   print {$arg{fh}} $arg{m};
}

sophisticated(fh => $log_fh, m => "Hello, world!\n");

【讨论】:

  • 这应该是评论,而不是答案。
  • 对命名参数使用匿名哈希有一个主要优势。如果您不小心传递了奇数个值,则警告将出现在调用代码中,而不是被调用的函数中。
猜你喜欢
  • 1970-01-01
  • 2015-05-10
  • 1970-01-01
  • 2015-09-27
  • 1970-01-01
  • 2016-11-22
  • 1970-01-01
  • 1970-01-01
  • 2021-03-09
相关资源
最近更新 更多