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

心不动则不痛 提交于 2019-11-29 02:29:02

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.

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.

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).

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!