2010-06-25 3 views
7

Ich möchte eine lexikalische Datei-Handle zu einem Unterprogramm übergeben ein benanntes Argument, aber die folgenden nicht kompiliert:Perl: Wie übergeben und verwenden Sie ein lexikalisches Datei-Handle zu einer Subroutine als benanntes Argument?

#!/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; 

Die Beschwerde ist:

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 

Es funktioniert O. K. Wenn ich die primitive Technik der Übergabe von Argumenten verwende, funktioniert die Named-Argument-Hash-Technik für die Nachricht Teil, nur nicht für die Datei behandeln Teil. Benötige ich eine neue Version von Drucken?

+0

Siehe auch: http://stackoverflow.com/questions/3027605/how-can-i-store-and-access-a- filehandle-in-a-perl-class – mob

+1

Sie sollten sich von der Angewohnheit der Vorerklärung von Variablen (das "my $ log_fh;" ist unnötig), und Sie sollten den Status von öffnet überprüfen. ZB: öffne meine $ log_fh, ">", $ logname oder stirb "Error opening $ logname: $!"; – runrig

Antwort

17

Wenn Sie einen komplexen Ausdruck haben, die eine Dateihandle zurückgibt (wie $args->{fh}) Sie müssen die Syntax ein wenig eindeutig zu machen, indem sie einige zusätzliche curlies Zugabe:

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

Dies ist aufgrund der seltsamen Art und Weise Der Operator print wurde entworfen, ohne Komma zwischen dem Dateihandle und der Liste der zu druckenden Objekte.

Alternativ könnten Sie das Dateihandle aus Ihrer Argumente hashref zuerst, z.

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

Super! Danke, friedo! –

+1

Das liegt daran, dass Sie die indirekte Objektsyntax mit 'print' verwenden. Das Seltsame ist, wenn Sie '$ args {fh} -> print ('blah');' Sie müssen 'IO benutzen: Handle;' oder Sie erhalten einen Fehler. Aber mit der indirekten Notation gibt es keine Notwendigkeit. Weitere Informationen finden Sie unter http://perldoc.perl.org/perlobj.html#Indirect-Object-Syntax. – daotoad

4

friedo's answer deckt Ihr Problem, aber es gibt eine stilistische Frage ich darauf hinweisen möchte. Sie müssen nicht alles in einen anonymen Hash einbinden, um benannte Argumente zu emulieren. Ein Hash-Initialisierer ist nur eine Liste, die als Schlüssel/Wert-Paare interpretiert wird. Vorbei an einer solchen Liste zu einem Sub bietet eine sauberere Syntax für den Anrufer:

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

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

Dies sollte ein Kommentar sein, keine Antwort. – fengshaun

+2

@fengshaun: Es ist zu groß, um (klar) in einen Kommentar zu passen. –

+1

Es gibt einen großen Vorteil, den Anon-Hash für benannte Parameter zu verwenden. Wenn Sie versehentlich eine ungerade Anzahl von Werten übergeben, liegt die Warnung im aufrufenden Code und nicht in der aufgerufenen Funktion. –

Verwandte Themen