2010-08-30 6 views
6

Partout, surtout dans DBI, je vois ce message venir tout le temps. C'est déroutant, parce que la première chose qui vient à l'esprit est que les arguments que je passe la fonction sont définis sur undef (ou quelque chose de similaire), mais ce n'est clairement pas le cas.

Compte tenu d'un module et un script correspondant ...

Module: ./lib/My/Module.pm

package My::Module; 

use strict; 
use warnings; 

sub trim { 
    my $str = shift; 
    $str =~ s{ \A \s+ }{}xms; # remove space from front of string 
    $str =~ s{ \s+ \z }{}xms; # remove space from end of string 
    return $str; 
} 

Script: ./test.pl

#!/usr/bin/perl 

use strict; 
use warnings; 
use My::Module qw(trim); 

print $My::Module->trim(" \t hello world\t \t"); 

je reviens le message d'erreur

Californie appeler la méthode « trim » sur une valeur non définie à la ligne de ./text.pl 7.

Enfait, si je l'appelle $My::Module->notamethod("hello world"); donne une erreur semblable.

Quel est le problème avec le script/module ci-dessus?

Qu'est-ce que cette erreur Can't call method “X” on an undefined value at ${SOMEFILE} line ${SOMELINE} dit vraiment? Est-ce que cela fait référence au contexte de l'appel de la méthode (passé ici pour imprimer), ou au contexte des arguments?

Répondre

6

Cette syntaxe recherche un objet ou un nom de classe dans la variable $My::Module et appelle sa méthode de découpage, mais cette variable n'est pas définie.

Au lieu de cela, vous voulez juste dire print My::Module::trim(" \t hello world\t \t"); pour appeler la fonction My :: Module :: trim(). À partir de la ligne d'utilisation, il semble que vous essayez d'importer trim() dans le package local, vous pouvez donc l'appeler sans la qualification My::Module::, mais votre module ne semble pas configuré pour prendre en charge l'exportation. . Dans vos expressions régulières, les indicateurs/s et/m n'ont aucun effet - ils ne modifient que ce qui est., ^, Et $ correspond, et vous n'utilisez aucun de ceux-ci.

+0

J'ai tendance à les mettre quand j'écris des regex parce que j'aime mettre des commentaires en ligne :). J'ai juste oublié de les sortir pour l'exemple. – heymatthew

+1

@The Daemons Advocate,/s et/m n'ont rien à voir avec les commentaires en ligne. C'est/x. – cjm

-1

C'est exactement ce que fait Perl OO. La différence est entre la façon dont vous appelez les méthodes.

Ce juste appelle la sous garniture dans le My :: package Module:

My::Module::trim('foo') 

D'autre part,

My::Module->trim('foo) 

devient automatiquement un appel à la sous garniture dans le My :: Module package avec la chaîne "My :: Module" comme premier argument. objets fonctionnent de la même façon:

my $m = My::Module->new; # Corrected. Thanks for pointing this out. 
$m->trim('foo'); 

Se transforme en un appel à la même sous, mais cette fois avec une référence à l'objet m $ comme premier argument.

Ce que vous essayez de faire est:

$My::Module->trim('foo'); 

Ce qui se traduit par un déréférencement de la variable $ Mon module :: (qui n'existe pas), donc le message d'erreur « Impossible d'appeler la méthode X sur une valeur indéfinie ". Si $ My :: Module était une référence réelle à un objet, cela entraînerait un appel à trim() sur cet objet, avec la référence comme premier argument implicite.

Modifier: Les deux commentaires sont corrects. Cette réponse était à l'origine destinée à commenter la réponse acceptée. (Y at-il un moyen de résoudre ce problème?)

Désolé pour la confusion. J'ai ajouté un peu plus de détails ici, donc j'espère qu'il devient plus clair comment il se rapporte à la question d'origine (déréférencement d'une variable indéfinie).

+1

Vous ne devez pas utiliser la syntaxe de méthode indirecte pour votre ligne 'new'. Voir ici pour pourquoi: http://stackoverflow.com/questions/429657/what-is-the-difference-between-new-someclass-and-someclass-new-in-perl/429798#429798 – friedo

+0

L'information dans ce post C'est vrai, mais cela n'a rien à voir avec la question. – jrockway

13

Vous associez plusieurs manières différentes de gérer des modules et des objets, et vous vous retrouvez avec une solution qui ne fonctionne pas.

Voici quatre approches qui fonctionnent:

1/Mon :: Module est une bibliothèque. la garniture n'est pas exportée.

$ cat My/Module.pm 
package My::Module; 

use strict; 
use warnings; 

sub trim { 
    my $str = shift; 

    $str =~ s{ \A \s+ }{}xms; # remove space from front of string 
    $str =~ s{ \s+ \z }{}xms; # remove space from end of string 
    return $str; 
} 

1; 
$ cat test 
#!/usr/bin/perl 

use strict; 
use warnings; 

use My::Module; 

# Note: No $ and :: not -> 
print My::Module::trim(" \t hello world\t \t"); 

2/Mon :: Module est une bibliothèque. la garniture est exportée.

$ cat My/Module.pm 
package My::Module; 

use strict; 
use warnings; 

use Exporter; 
our @ISA = qw(Exporter); 
our @EXPORT = qw(trim); 

sub trim { 
    my $str = shift; 

    $str =~ s{ \A \s+ }{}xms; # remove space from front of string 
    $str =~ s{ \s+ \z }{}xms; # remove space from end of string 
    return $str; 
} 

1; 
$ cat test 
#!/usr/bin/perl 

use strict; 
use warnings; 

use My::Module; 

print trim(" \t hello world\t \t"); 

3/MyModule est une classe. trim est une méthode de classe. My/MyModule est une classe, trim est une méthode d'objet.

$ cat My/Module.pm 
package My::Module; 

use strict; 
use warnings; 

# Need a constructor (but this one does nothing useful) 
sub new { 
    my $class = shift; 

    return bless {}, $class; 
} 

sub trim { 
    # Note: Object method is passed an object (which is ignored here) 
    my $self = shift; 
    my $str = shift; 

    $str =~ s{ \A \s+ }{}xms; # remove space from front of string 
    $str =~ s{ \s+ \z }{}xms; # remove space from end of string 
    return $str; 
} 

1; 
$ cat test 
#!/usr/bin/perl 

use strict; 
use warnings; 

use My::Module; 

my $trimmer = My::Module->new; 

print $trimmer->trim(" \t hello world\t \t"); 

Je pense que vous essayiez pour l'option 1. Dans ce cas, je pense que je vous recommande l'option 2.

Et pour répondre à votre dernière question. Vous obtenez cette erreur parce que vous essayez d'appeler une méthode sur une variable ($ Mon :: Module) qui n'est pas définie.

Questions connexes