2010-08-06 13 views
23

He hecho esta pregunta antes o buscado y he visto otras preguntan: ¿por qué recibo la advertencia "Subrutina mySub redefinida en ../lib/Common.pm línea x"? y siempre obtienes la respuesta declaraste el subtítulo dos veces en el mismo código. He creado este conjunto de ensayos:Perl - Subrutina redefinida

todo el archivo ---------------

package MyCommonPkg; 

use strict; 

sub thisSubroutineIsNotDefinedAnywhereElse{ 
} 

1; 

archivo completo -------------- -

y utilizar este paquete desde un script perl, el cual utiliza otros paquetes que utilizan este paquete también, y me da la advertencia:

subrutina ThisSubroutineIsNotDefinedAnywhereElse redefinió en la línea ../lib/MyCommonPkg.pm 19.

Prometo que no declaro este submarino en otro lugar. Entonces, ¿esto es causado por una referencia circular? ¿Cómo puedo seguir la causa de esta advertencia y corregirla?

+5

¿Realmente declara 'paquete Common.pm'? Eso parece un error. – mob

+0

¿Tiene dos paquetes con el mismo nombre? Eso puede causar una colisión del espacio de nombres. Siempre nombre sus paquetes para el archivo en el que se encuentran (reemplazando '/' con '::', y eliminando '.pm'). Esto también puede ocurrir si tienes * no * namespace, lo que realmente significa que estás en 'main'. – Ether

+0

no, no lo declare Common.pm. Acabo de renombrar cosas para obtener un ejemplo de pseudo código up y typoed. Voy a editar – user210757

Respuesta

7

Si está en un sistema con un sistema de archivos insensible a mayúsculas y minúsculas (Windows, y muy a menudo OSX), y hace use Common en otro archivo y use common en otro, puede causar problemas como este.

+0

buscó apariciones de esto y no pudo encontrar ninguna. muy bueno saberlo, ¡gracias! – user210757

0

Intenté utilizar el "paquete Common.pm" como nombre de paquete. El compilador me dio errores. Muy amable, ¿eh? ¿Qué versión de Perl estás usando? Lo intenté en 5.10.0 y 5.12.1.

Incluso si puede compilar, es una buena práctica eliminar el archivo .pm. Por ejemplo;

Archivo: some_package.pm;

package some_package; 
use strict; 

sub yadayadayada { ... } 

1; 
+0

5.10.1 MS-win32-x86-mulithread – user210757

31

¿Tiene un ciclo de dependencia? Si Perl comienza la compilación de su guión y se encuentra una línea como esta:

use PackageA; 

Perl se detiene la compilación de la secuencia de comandos; localiza PackageA.pm y comienza a compilarlo. Si encuentra una línea como esta:

use PackageB; 

Perl pausa la compilación de PackageA; localiza PackageB.pm y comienza a compilarlo. Normalmente, eso se completaría con éxito, y Perl volvería a completar la compilación de PackageA y, cuando se complete con éxito, volvería a compilar su script y, cuando se complete con éxito, comenzaría a ejecutar los códigos de operación compilados.

Sin embargo, si PackageB.pm contiene esta línea:

use PackageA; 

Se podría esperar que no haría nada desde Perl ya ha procesado PackageA.pm pero el problema es que no ha terminado todavía. Así que Perl hará una pausa en la compilación de PackageB y comenzará a compilar PackageA.pm nuevamente desde el principio. Eso podría provocar que se redefina el mensaje que está viendo sobre las subrutinas en PackageA.

Como regla general, dos paquetes no deberían depender el uno del otro. A veces, sin embargo, el bucle es más difícil de localizar porque es causado por un tercer paquete.

+2

Creo que este es mi problema, ¿cómo solucionarlo? no es una referencia circular: vería una referencia circular ya que PackageA tiene "use PackageB;" y PackageB tiene "uso de PackageA;" En cambio, tengo un script "main.pl" que usa PackageA y usa PackageB, y PackageA también usa PackageB. No debería haber nada de malo con eso? – user210757

+0

Correcto, no debería haber nada de malo en eso. –

2

¿Por casualidad lo está ejecutando como un script cgi en un servidor web?

Me parece que necesito reiniciar el servidor web para evitar esta advertencia.

+1

no, simplemente ejecutándose desde la línea de comando – user210757

0

Asegúrese de que no se olvidó de esta línea al final de su módulo:

1;

Sé que ha sido incluido en algunos de los ejemplos aquí, pero lo menciono porque es fácil pasar por alto, y en mi caso resultó ser la única causa de los errores!

19

Cuando tiene dos subrutinas con el mismo nombre en diferentes paquetes, debe ver esta advertencia (cuando las advertencias están habilitadas) como "Subrutina nueva redefinida ....". La razón simple (que está muy cerca de lo que dijo Grant McLean, pero aún no exactamente) es que debe obtener sus paquetes omitir la fase de compilación y hacer que luego lo requiera. De esta forma, el administrador del espacio de nombres de Perl no encontrará ningún símbolo conflictivo con el mismo nombre en el momento de la compilación, y si los módulos no tienen ningún error, también funcionarán correctamente.

Sólo asegúrese de que implemente

requieren módulo;

comunicado en lugar de

uso del módulo;

No debería volver a aparecer esta advertencia.

+0

gracias, esto resolvió mi problema – Thariama

+0

Gracias. Esta fue información bastante útil –

4

Esto suena como un problema causado por dependencias circulares. Aquí es cómo rastrearlo. Si su clase problema es el siguiente:

package AlientPlanet; 
use Dinosaurs; 
sub has_dinosaurs {...} 
1; 

luego cambia de ejemplo para tener este aspecto:

package AlienPlanet; 
sub has_dinosaurs {...}  # <-- swap 
use Dinosaurs;    # <-- swap 
1; 

Ahora compila el código con Carp::Always así:

⚡ perl -MCarp::Always -c lib/AlienPlanet.pm                            
Subroutine has_dinosaurs redefined at lib/AlienPlanet.pm line 4. 
    require AlienPlanet.pm called at lib/Dinosaurs.pm line 4 
    Dinosaurs::BEGIN() called at lib/AlienPlanet.pm line 4 
    eval {...} called at lib/AlienPlanet.pm line 4 
    require Dinosaurs.pm called at lib/AlienPlanet.pm line 5 
    AlienPlanet::BEGIN() called at lib/AlienPlanet.pm line 4 
    eval {...} called at lib/AlienPlanet.pm line 4 
lib/AlienPlanet.pm syntax OK 

Ahora que ya tener un stacktrace, puedes ver dónde está el bucle. La solución rápida y sucia es usar Class::Load en Dinosaurs.pm.

Para una explicación más detallada prueba mi blog post.

1

Eche un vistazo al programa package MyCommonPkg.pm y vea lo que dice. ¿Tiene algo como esto?

package MyCommonPkg; 

use Exporter qw(import); # Might be "require" and not "use" 
our @EXPORT = qw(thisSubroutineIsNotDefinedAnywhereElse); 

La sintaxis puede ser un poco diferente. Las principales cosas que debería ver son la declaración package, que está usando Exporter y que la matriz @EXPORT tiene el nombre de su subrutina.

Lo que está pasando es un conflicto de espacio de nombres. Su paquete está definiendo la misma subrutina que está definiendo.

Para evitar que esto suceda, Perl usa namespaces. De forma predeterminada, su espacio de nombre es main. Sin embargo, se supone que los paquetes definen sus propios homónimos por separado usando el comando package.

El espacio de nombre completo de una subrutina o variable es el espacio de nombre seguido de dos puntos dobles, seguido de la subrutina o el nombre de la variable. Por ejemplo, si mira File::Find, verá referencias a las variables $File::Find::name y $File::Find::dir. Estas son las variables $name y $dir dentro del paquete File/Find.pm bajo el espacio de nombre File::Find.

Con el fin de facilitar las cosas para usted, los paquetes pueden exportación sus variables y subrutinas en su principal espacio de nombres. Por ejemplo, si uso File::Copy, O puede hacer esto:

... 
use File::Copy 
... 
copy ($file, $to_dir); 

En lugar de:

... 
use File::Copy 
... 
File::Copy::copy ($file, $to_dir); 

Si nos fijamos en File/Copy.pm, verá lo siguiente:

package File::Copy; 
... 
our(@ISA, @EXPORT, @EXPORT_OK, $VERSION, $Too_Big, $Syscopy_is_copy); 
... 
require Exporter; 
@ISA = qw(Exporter); 
@EXPORT = qw(copy move); 

El package File::Copy; define un espacio de nombres. El require Exporter; y el @ISA = qw(Exporter) permiten que el paquete exporte subrutinas y variables en el espacio de nombre principal. El @EXPORT automáticamente, sin que le diga nada, importa las subrutinas copy y move en el principal namespace si las quiere o no!

Ese último bit es muy importante. Ahora se considera malos modales para usar @EXPORT. En su lugar, debe usar @EXPORT_OK, que requiere que liste las subrutinas que desea usar. Los paquetes más modernos como Scalar::Util hacen esto.

Así que varias cosas. Primero, ¿su MyCommonPkg tiene una declaración package MyCommonPkg;? Si no, debería. Esto evita que las subrutinas y las variables de los paquetes afecten su programa de maneras desagradables. Luego, puede usar @EXPORT o @EXPORT_OK.

Si MyCommonPkg tiene una declaración package, ¿usa @EXPORT? De ser así, tiene varias formas de evitar este problema:

  • Ignore la advertencia. Es solo una advertencia. Como sabe que está redefiniendo la subrutina y desea usar su definición de la subrutina, ignórela.

Usted puede hacer esto para desactivar el aviso que se redefine la subrutina:

use MyCommonPkg; 

no warnings qw(redefine); 
sub thisSubroutineIsNotDefinedAnywhereElse { 
    ... 
} 
use warnings qw(redefine); 
  • Uso require MyCommonPkg; en lugar de use MyCommonPkg;.Esto evitará la importación de cualquier subrutina o variable en su espacio de nombres, incluidas las que desee utilizar. Digamos que MyCommonPkg define cuatro subrutinas: thisSubroutineIsNotDefinedAnywhereElse, foo, bar y barfoo. Para usar cualquiera de estas subrutinas.

que tiene que hacer esto:

my $answer = MyCommonPkg::foo($input); 
No

divertido.

  • Utilice otro nombre para su subrutina. Debería haberse documentado que esta subrutina se define en MyCommonPkg, y si desea usar MyCommonPkg, no debe usar nombres de subrutinas que se exportan.

  • Por último, si MyCommonPkg es bastante nuevo, y no se utiliza en docenas de programas, utilice @EXPORT_OK en lugar de @EXPORT, y asegurarse de que todos los programas que utilizan MyCommonPkg se modifican para exportar las subrutinas que quieren:

De esta manera:

use MyCommonPkg qw(foo bar); 

En este caso, sólo subrutinas foo y bar se exportan. Las subrutinas thisSubroutineIsNotDefinedAnywhereElse y barfoo no se exportan a su entorno.

0

Tuve el mismo problema; Fue porque el programa usaba un módulo y la subrutina estaba presente tanto en el programa como en el módulo perl;

Cuestiones relacionadas