Почему T::fn2 имеет только один параметр, когда он был вызван с двумя аргументами?

#perl

Вопрос:

У меня есть следующий сценарий:

 package T;
use strict;
use warnings;

sub fn1 {
    my( $var1, $var2 ) =  @_;
    T::fn2 $var1, $var2;
}

sub fn2 {
    print ">>@_<<"; # >>x1<<
}

package main;
use strict;
use warnings;

T::fn1 'x1', 'x2'; # >>x1<<

 

Здесь T::fn2 вызывается с двумя аргументами, но он получает только один параметр.

Я понимаю, что вызываю подпрограмму переадресации, которая не видна во время синтаксического анализа и считается пустым словом.

Но у меня есть use strict , use warnings поэтому я ожидаю, что будет выдано предупреждение или программа вообще не должна работать, вместо этого она работает неправильно.

Так почему же он все еще работает и T::fn2 вызывается фактически с одним аргументом?

версия perl-5.30.3

Комментарии:

1. Вы можете опустить только парены в списке параметров для объявленных вложенных элементов.

2. @ikegami: или когда объявлена переадресация 😉

3. С каких это пор прямая декларация не является декларацией? Мои комментарии стоят сами по себе.

Ответ №1:

Бежать

 perl -MO=Deparse,-p
 

чтобы увидеть, как компилятор понимает код:

 sub fn1 {
    (my($var1, $var2) = @_);
    ($var1->T::fn2, $var2);
}
 

Таким образом, вызов интерпретируется как косвенная объектная нотация вызова метода, и подпрограмма возвращает два значения: результат вызова метода и $var2 .


Чтобы заставить его работать правильно, у вас есть два варианта:

  1. Используйте круглые скобки вокруг аргументов подпрограммы

    T::fn2($var1, $var2);

  2. Убедитесь, что функция объявлена перед ее вызовом
 sub fn2 {
    print ">>@_<<";
}

sub fn1 {
    my ($var1, $var2) =  @_;
    T::fn2 $var1, $var2;
}
 
  1. Убедитесь, что функция объявлена до ее вызова (прямое объявление).
 sub fn2;

sub fn1 {
    my ($var1, $var2) =  @_;
    T::fn2 $var1, $var2;
}

sub fn2 {
    print ">>@_<<";
}
 

Комментарии:

1. Однако немного странно, что код принимает $var1 его в качестве законного объекта. Как new FOO и должно быть FOO->new , но здесь это строка.

2. method $obj тоже работает. Косвенные обозначения объектов должны быть запрещены!

3. @choroba, no indirect;

4. @ikegami: Я знаю. Но это должно быть по умолчанию 🙂

5. @choroba Обратная совместимость. Но предполагалось, что он будет включен-э-э, выключен — по умолчанию в Perl 7