2010-06-25 12 views
7

Quiero pasar un identificador de archivo léxica a una subrutina utilizando un argumento con nombre, pero el siguiente no se compila:Perl: ¿Cómo pasar y usar un manejador de archivo léxico a una subrutina como argumento con nombre?

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

La queja es:

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 

¡sí funciona cuando uso la técnica primitiva de pasar argumentos, y la técnica de hash de argumento con nombre funciona para la parte del mensaje , simplemente no para el parte del archivo. ¿Necesito una nueva versión de print?

+0

Ver también: http://stackoverflow.com/questions/3027605/how-can-i-store-and-access-a- filehandle-in-a-perl-class – mob

+1

Debe dejar el hábito de predefinir variables (el "my $ log_fh;" es innecesario), y debe verificar el estado de las aperturas. P. ej .: abrir mi $ log_fh, ">", $ logname o morir "Error al abrir $ logname: $!"; – runrig

Respuesta

17

Cuando se tiene una expresión compleja que devuelve un gestor de archivo (como $args->{fh}) que necesita para eliminar la ambigüedad de la sintaxis un poco añadiendo algunos curlies adicionales:

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

Esto es debido a la forma extraña el operador print está diseñado, sin una coma entre el identificador de archivo y la lista de cosas para imprimir.

Como alternativa, puede quitar primero el identificador de archivos de sus argumentos hashref, p.

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

¡Impresionante! Gracias, friedo! –

+1

Eso es porque estás usando la sintaxis de objeto indirecto con 'print'. Lo extraño es que si haces '$ args {fh} -> print ('blah');' tienes que 'usar IO :: Handle;' o si obtienes un error. Pero con la notación indirecta no hay necesidad. Consulte http://perldoc.perl.org/perlobj.html#Indirect-Object-Syntax para obtener más información. – daotoad

4

friedo's answer cubre su problema, pero hay una cuestión de estilo que me gustaría señalar. No necesita envolver todo en un hash anónimo para emular argumentos con nombre. Un inicializador hash es solo una lista interpretada como pares clave/valor. Pasar una lista de este tipo a un sub proporciona una sintaxis más limpio para la persona que llama:

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

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

Esto debería haber sido un comentario, no una respuesta. – fengshaun

+2

@fengshaun: es demasiado grande para (claramente) encajar en un comentario. –

+1

Hay una gran ventaja en el uso del hash anon para los parámetros con nombre. Si accidentalmente pasa un número impar de valores, la advertencia estará en el código de llamada, no en la función llamada. –

Cuestiones relacionadas