Вызовы методов модуля Perl: невозможно вызвать метод "X" для неопределенного значения в строке $ {SOMEFILE} $ {SOMELINE} - PullRequest
6 голосов
/ 30 августа 2010

Повсюду, особенно в DBI, я вижу, что это сообщение появляется постоянно.Это сбивает с толку, потому что первое, что приходит на ум, это то, что аргументы, которые я передаю функции, установлены в undef (или что-то подобное), но это явно не так.

Учитывая модуль и соответствующий емускрипт ...

Модуль: ./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;
}

Скрипт: ./test.pl

#!/usr/bin/perl

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

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

Я получаю сообщение об ошибке

Невозможно вызвать метод "trim" для неопределенного значения в строке 7./text.pl 7.

Фактически, если я вызываю $My::Module->notamethod( "hello world" );, выдается аналогичная ошибка.

Что не так с вышеуказанным скриптом / модулем?

Что на самом деле говорит эта ошибка Can't call method “X” on an undefined value at ${SOMEFILE} line ${SOMELINE}?Относится ли это к контексту вызова метода (переданного здесь для печати) или контексту аргументов?

Ответы [ 3 ]

13 голосов
/ 30 августа 2010

Вы объединяете несколько различных способов работы с модулями и объектами - и в итоге получаете один, который не работает.

Вот четыре подхода, которые работают:

1 / My :: Module - это библиотека. отделка не экспортируется.

$ 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 - это библиотека. отделка экспортируется.

$ 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 - это класс. отделка - это метод класса.

$ 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 - это класс, а trim - метод объекта.

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

Я думаю, что вы пытались выбрать вариант 1. В этом случае, я думаю, я бы рекомендовал вариант 2.

И чтобы ответить на ваш последний вопрос. Вы получаете эту ошибку, потому что вы пытаетесь вызвать метод для переменной ($ My :: Module), которая не определена.

6 голосов
/ 30 августа 2010

Этот синтаксис ищет объект или имя класса в переменной $My::Module и вызывает его метод усечения, но эта переменная не определена.

Вместо этого вы просто хотите сказать print My::Module::trim( " \t hello world\t \t" );, чтобы вызвать функцию My :: Module :: trim ().

Из строки использования выглядит, как будто вы пытаетесь импортировать trim () в локальный пакет, так что вы можете просто вызвать его без квалификации My::Module::, но ваш модуль не выглядит так, как будто он настроен на поддержку экспорт.

В ваших регулярных выражениях флаги / s и / m не имеют никакого эффекта - они изменяют только то, что., ^ И $ match, и вы не используете ни один из них.

0 голосов
/ 30 августа 2010

Это просто, как Perl делает OO.Разница заключается в том, как вы вызываете методы.

Это просто вызывает триммер sub в пакете My :: Module:

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

С другой стороны,

 My::Module->trim('foo)

автоматически становится вызовом сабвуфера в пакете My :: Module со строкой «My :: Module» в качестве первого аргумента.Объекты работают одинаково:

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

Превращается в вызов той же подпрограммы, но на этот раз со ссылкой на объект $ m в качестве первого аргумента.

То, что вы пытаетесьсделать это:

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

, что означает разыменование переменной $ My :: Module (которая не существует), то есть сообщение об ошибке «Невозможно вызвать метод X с неопределенным значением».Если бы $ My :: Module была фактической ссылкой на объект, это привело бы к вызову trim () для этого объекта со ссылкой в ​​качестве неявного первого аргумента.

Редактировать: оба комментария верны.Этот ответ изначально задумывался как комментарий к принятому ответу.(Есть ли способ это исправить?)

Извините за путаницу.Я добавил здесь немного больше деталей, так что, надеюсь, станет понятнее, как это связано с исходным вопросом (разыменование неопределенной переменной).

...