Как я могу условно определить подпрограмму Perl?

Проблема в вашей функции getAge(), и это должно быть очевидно, если вы посмотрите на столбец возраста в вашей таблице. Ваш код:

function getAge($date) 
{ 
    return intval(substr(date('Ymd') - date('Ymd', strtotime($date)), 0, -4));
}

Функция date [) PHP возвращает строку в формате 'YYYMMDD'. У вас их два, и вы их вычитаете. Предположим, что это '20190414' и '20020321', вычитание их приведет к 170093, а если взять последние два символа с substr(), то вам будет 93 для кого-то, кто родился в 2002 году. Вы не заметили что?

Итак, давайте напишем лучшую getAge() функцию. Работать точно со временем сложно. Однако на самом деле внутри PHP есть функция для вычисления разницы дат:

https://www.php.net/manual/en/datetime.diff.php

Если мы используем это для создания функции, мы получим:

function getAge($dateStr) 
{ 
    $birthDate = new DateTime($dateStr); // check the valid formats in the manual!
    $currentDate = new DateTime();
    return $birthDate->diff($currentDate, true)->y; // return difference in years
}

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

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

9
задан brian d foy 26 February 2009 в 18:51
поделиться

7 ответов

Другие уже представили синтаксис, который Вы запросили, но я рекомендую использовать более явные ссылки подпрограммы для этого, так, чтобы можно было свободно управлять ссылкой, не управляя определением. Например:

sub square_difference { return ($_[0] - $_[1]) ** 2 }
sub constant_difference { return 1 }

my %lookup = (
    'square' => \&square_difference,
    'constant' => \&constant_difference,
);

my $difference = $lookup{$ARGV[0]} || die "USAGE: $0 square|constant\n";
print &$difference(4, 1), "\n";

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

24
ответ дан 4 December 2019 в 05:58
поделиться

То, что Вы хотите сделать, может быть достигнуто как это:

if ($ARGV[0] eq 'square') {
    *difference = sub { return ($_[0] - $_[1]) ** 2 };
}
elsif ($ARGV[0] eq 'constant') {
    *difference = sub { return 1 };
}
16
ответ дан 4 December 2019 в 05:58
поделиться

Нижние индексы определяются во время компиляции->, если бы у Вас были "предупреждения использования", включил, Вы видели бы сообщение об ошибке о переопределении подпрограммы.

6
ответ дан 4 December 2019 в 05:58
поделиться

Я лично не сделал большого количества этого, но Вы могли бы хотеть использовать переменную для содержания подпрограммы:

my $difference;
if ("square" eq $ARGV[0]) {$difference = sub {return ($_[0] - $_[1]) ** 2}}
elsif ("constant" eq $ARGV[0]) {$difference = sub {return 1}}

Звоните с:

&{ $difference }(args);

Или:

&$difference(args);

Или, как предложил Leon Timmermans:

$difference->(args);

Немного объяснения - это объявляет названную переменную $difference и, в зависимости от Ваших условий, наборы это для содержания ссылки на анонимную подпрограмму. Таким образом, необходимо разыменовать $difference как подпрограмма (следовательно & впереди) для него для вызова подпрограммы.

Править: Код протестирован и работы.

Еще одно РЕДАКТИРОВАНИЕ:

Jesus, я так привык к useлуг strict и warnings то, что я забываю, что они являются дополнительными.

Но серьезно. Всегда use strict; и use warnings;. Это поможет поймать вещи как это и дать Вам хорошие полезные сообщения об ошибках, которые объясняют что случилось. Я никогда не должен был использовать отладчик в своей жизни из-за strict и warnings - это - насколько хороший сообщения проверки ошибок. Они поймают все виды вещей как это и даже дадут Вам полезные сообщения относительно того, почему они неправы.

Таким образом, каждый раз, когда Вы пишете что-то, неважно, как маленький (если это не запутывается), всегда use strict; и use warnings;.

11
ответ дан 4 December 2019 в 05:58
поделиться

Спасибо за все предложения для того, как заставить код работать. Только для полноты, я дам высокоуровневые ответы на свой вопрос.

  1. Первая конструкция не работает, потому что функции определяются во время компиляции, но условия, и/или параметры командной строки оценены во времени выполнения. К тому времени, когда условие оценено, именованная функция была уже определена.

  2. Компилятор действительно дает предупреждение с "предупреждениями использования", хотя не один это очень полезно для программиста, не знающего 1 :-) Трудность с предоставлением значимого предупреждения состоит в том, что определение функций в, если оператор может иметь смысл, если Вы также делаете что-то с функцией в если оператор, как в предложении Leon Timmermans. Исходный код компилирует в вырожденное, если оператор и компилятор не установлены предупредить о них.

  3. Строго говоря не возможно условно определить функции, но возможно условно определить ссылки (rbright) или псевдонимы (Leon Timmermans) к функциям. Согласие, кажется, что ссылки лучше, чем псевдонимы, хотя я не совсем уверен почему.

Отметьте приблизительно 1: порядок оценки не очевиден, пока Вы на самом деле не столкнулись с проблемой как это; можно было предположить Perl, который оценит условия во время компиляции каждый раз, когда он мог быть сделан безопасно. По-видимому, Perl не делает этого, так как следующий код также дает предупреждение о переопределенной подпрограмме.

use warnings ;
if (1) {sub jack {}} else {sub jack {}}
0
ответ дан 4 December 2019 в 05:58
поделиться

Другие ответы корректны, с помощью или ссылки кода или псевдонима. Но примеры искажения представляют yicky typeglob синтаксис и забывают иметь дело со строгим.

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

use strict;
use Alias;

my $difference_method = $ARGV[0];
if( "square" eq $difference_method ) {
    alias difference => sub { return ($_[0] - $_[1]) ** 2 };
}
elsif( "constant" eq $difference_method ) {
    alias difference => sub { return 1 };
}
else {
    die "Unknown difference method $difference_method";
}

И теперь difference($a, $b) работы.

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

my $difference_method = $ARGV[0];

my $Difference;
if( "square" eq $difference_method ) {
    $Difference => sub { return ($_[0] - $_[1]) ** 2 };
}
elsif( "constant" eq $difference_method ) {
    $Difference => sub { return 1 };
}
else {
    die "Unknown difference method $difference_method";
}

$Difference->($a, $b);

Условно изменение, что делает функция, делает код тяжелее для следования и менее гибкий, точно так же, как изменяющееся поведение на любом глобальном. Становится более очевидно, когда Вы понимаете, что просто оптимизируете это:

my $Difference_Method = $ARGV[0];

sub difference {
    if( $Difference_Method eq 'square' ) {
        return ($_[0] - $_[1]) ** 2;
    }
    elsif( $Difference_Method eq 'constant' ) {
        return 1;
    }
    else {
        die "Unknown difference method $Difference_Method";
    }
}

Любое время у Вас есть подпрограмма формы...

sub foo {
    if( $Global ) {
        ...do this...
    }
    else {
        ...do that...
    }
}

У Вас есть проблема.

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

1
ответ дан 4 December 2019 в 05:58
поделиться

Еще один путь:

my $diffmode;
BEGIN { $diffmode = $ARGV[0] }
sub difference {
    if ($diffmode eq 'square') { ($_[0] - $_[1]) ** 2 }
    elsif ($diffmode eq 'constant')  { 1 }
    else { "It don't make no never mind" }
}
-2
ответ дан 4 December 2019 в 05:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: