Perl Module Method Calls: Can't call method “X” on an undefined value at ${SOMEFILE} line ${SOMELINE}

前端 未结 3 2011
时光取名叫无心
时光取名叫无心 2020-12-16 06:34

All over the place, especially in DBI, I see this message come up all the time. It\'s confusing, because the first thing that comes to mind is that the arguments I\'m passin

相关标签:
3条回答
  • 2020-12-16 06:46

    It is just how Perl does OO. The difference is in between the way you call the methods.

    This just calls the trim sub in the My::Module package:

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

    On the other hand,

     My::Module->trim('foo)
    

    automatically becomes a call to the trim sub in the My::Module package with the string "My::Module" as the first argument. Objects work the same way:

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

    Turns into a call to the same sub, but this time with a reference to the $m object as the first argument.

    What you are trying to do is:

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

    Which translates to a dereference of the variable $My::Module (which does not exist), thus the error message "Can't call method X on an undefined value". If $My::Module were an actual reference to an object, this would result in a call to trim() on that object, with the reference as an implicit first argument.

    Edit: Both commenters are correct. This answer was originally intended as a comment to the accepted answer. (Is there a way to fix that?)

    Sorry for the confusion. I've added a little more detail here so hopefully it becomes more clear how it relates to the original question (dereferencing an undefined variable).

    0 讨论(0)
  • 2020-12-16 06:51

    That syntax is looking for an object or classname in the variable $My::Module and calling its trim method, but that variable is undefined.

    Instead, you want to just say print My::Module::trim( " \t hello world\t \t" ); to call the My::Module::trim() function.

    From the use line, it looks like you are trying to import trim() into the local package so you can just call it without the My::Module:: qualification, but your module doesn't look like it is set up to support exporting.

    In your regexes, the /s and /m flags don't have any effect - they only change what ., ^, and $ match, and you don't use any of those.

    0 讨论(0)
  • 2020-12-16 07:07

    You're conflating several different ways to handle modules and objects - and ending up with one that doesn't work.

    Here are four approaches that do work:

    1/ My::Module is a library. trim is not exported.

    $ 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/ My::Module is a library. trim is exported.

    $ 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 is a class. trim is a class method.

    $ cat My/Module.pm 
    package My::Module;
    
    use strict;
    use warnings;
    
    sub trim {
      # Note class name passed as first argument
      my $class = 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;
    
    # Note: Not $ and -> not ::
    print My::Module->trim( " \t hello world\t \t" );
    

    4/ MyModule is a class, trim is an object method.

    $ 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" );
    

    I think that you were trying for option 1. In this case, I think I'd recommend option 2.

    And to answer your final question. You are getting that error because you are trying to call a method on a variable ($My::Module) which is undefined.

    0 讨论(0)
提交回复
热议问题