Можно ли предотвратить прямые необъявленные вызовы функций в Perl? - PullRequest
3 голосов
/ 03 июня 2011

Perl имеет ограниченную поддержку статической проверки кода, в частности он может проверить, передаем ли мы соответствующее количество аргументов в функцию. Например, это приведет к ошибке:

use strict;
use warnings;
sub f($) {}
f(2, 3)

Too many arguments for main::f

Если мы попытаемся вызвать f слишком рано, мы получим еще одно полезное предупреждение:

use strict;
use warnings;
f(2, 3)
sub f($) {}

main::f() called too early to check prototype

Это приведет к ошибке:

use strict;
use warnings;
sub f($) {}
sub g() { f(2, 3) }

Too many arguments for main::f

И мой вопрос, можем ли мы получить такое сообщение для следующего сценария:

use strict;
use warnings;
sub g() { f(2, 3) }
sub f($) {}

Потому что я не получаю никакой ошибки или предупреждения здесь. Было бы хорошо, если бы я мог предотвратить компиляцию этого кода. Пожалуйста, сообщите.

Ответы [ 3 ]

11 голосов
/ 03 июня 2011

«Те, кто в курсе» (особенно Дамиан Конуэй в своей книге «Лучшие практики Perl»), советуют не использовать прототипы подпрограмм, поскольку они служат только для запутывания кода, «делая невозможным вывод поведения поведения передачи аргументов». вызов подпрограммы, просто глядя на вызов. "

2 голосов
/ 04 июня 2011

Не используйте прототипы для проверки аргументов по всем уже указанным причинам. Есть соблазн сделать это, потому что они предоставляют проверки во время компиляции, но их проверки ограничены глупыми ошибками, они не проверяют вызовы методов и имеют неожиданные побочные эффекты.

Используйте такой модуль, как Method :: Signatures , чтобы выполнять реальную проверку аргументов, а также предоставлять вам обработку аргументов.

use Method::Signatures;

use strict;
use warnings;

func g() { f(2, 3) }

func f($foo) {
    print "f got $foo\n";
}

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

2 голосов
/ 03 июня 2011

Да, вы можете предварительно объявить его перед тем, как фактически его использовать:

use strict;
use warnings;
sub f($);                     # prototype defined
sub g() { f(2, 3) }
sub f($) { print "hi\n"; }
...