Можно ли взять ссылку встроенной функции в Perl?

Редактирование web.config файл или обновление DLL в bin папка просто перерабатывает рабочий процесс для того приложения, не целый пул.

14
задан brian d foy 21 October 2009 в 15:41
поделиться

7 ответов

Нет, нельзя. Какую основную проблему вы пытаетесь решить? Возможно, есть какой-то способ сделать то, что есть.

Повторите добавленную часть вопроса «Ваш ответ может включать XS, если необходимо, но я бы предпочел этого не делать», вызывать встроенные команды из XS действительно сложно, так как встроенные команды настроены так, чтобы предполагать, что они работают как часть скомпилированного optree и имеют определенные глобальные переменные. Обычно гораздо проще вызвать некоторую базовую функцию, которую использует сама встроенная функция, хотя такая функция не всегда, поэтому вы видите такие вещи, как:

buffer = sv_2mortal(newSVpvf("(caller(%d))[3]", (int) frame));
caller = eval_pv(SvPV_nolen(buffer), 1);

(выполнение строки eval из XS вместо того, чтобы проходить через обручи, необходимые для непосредственного вызовите pp_caller).

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

Вы можете сделать это, если сначала пропатчите внутренний метод (который даст вам кодовую ссылку вашего патча):

use strict;
use warnings;

BEGIN {
    *CORE::GLOBAL::die = sub { warn "patched die: '$_[0]'"; exit 3 };
}

print "ref to patched die: " . \&CORE::GLOBAL::die . "\n";
die "ack, I am slain";

дает результат:

ref to patched die: CODE(0x1801060)
patched die: 'ack, I am slain' at patch.pl line 5.

BTW: Я бы признателен, если кто-нибудь может объяснить, почему переопределение должно выполняться как * CORE :: GLOBAL :: die , а не * CORE :: die . Я не могу найти никаких ссылок по этому поводу. Кроме того, почему переопределение должно выполняться в блоке BEGIN? Вызов die () выполняется во время выполнения, так почему нельзя выполнить переопределение непосредственно во время выполнения?

1
ответ дан 1 December 2019 в 14:44
поделиться

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

sub my_shift (\@) { my $ll = shift; return shift @$ll }

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

my @list = (1,2,3,4);

sub my_shift (\@) { my $ll = shift; return shift @$ll }

my $a = shift @list;
my $my_shift_ref = \&my_shift;
my $b = (&{$my_shift_ref}  (\@list) ); # see below

print "a=$a, b=$b\n";

for (my $i = 0; $i <= $#list; ++$i) { print "\$list[$i] = ",$list[$i],"\n"; }

Если это вызывается как просто @list , perl barfs, потому что он не может автоматически создавать ссылки, как это делает shift .

См. Также: [ http://www.perl.com/language/misc/ fmproto.html] [Статья Тома Кристенсена].

Конечно, для встроенных функций, которые не являются особенными, как shift, вы всегда можете сделать

sub my_fork { return fork; }

, а затем & my_fork все, что захотите.

1
ответ дан 1 December 2019 в 14:44
поделиться

Я экспериментировал с решениями общего назначения для этого и придумал следующий грязный прием с использованием eval. Он в основном использует прототип, чтобы отделить @_, а затем вызвать встроенный. Это было только слегка протестировано и использует строковую форму eval, поэтому некоторые могут сказать, что он уже сломан: -)

use 5.10.0;
use strict;
use warnings;

sub builtin {
    my ($sub, $my, $id) = ($_[0], '');
    my $proto = prototype $sub         //
                prototype "CORE::$sub" //
                $_[1]                  //
                ($sub =~ /map|grep/ ? '&@' : '@;_');
    for ($proto =~ /(\\?.)/g) { $id++;
        if (/(?|(\$|&)|.(.))/) {
            $my  .= "my \$_$id = shift;";
            $sub .= " $1\$_$id,";
        } elsif (/([@%])/) {
            $my  .= "my $1_$id = splice \@_, 0, \@_;";
            $sub .= " $1_$id,";
        } elsif (/_/) {
            $my  .= "my \$_$id = \@_ ? shift : \$_;";
            $sub .= " \$_$id,"
        }
    }
    eval "sub ($proto) {$my $sub}"
        or die "prototype ($proto) failed for '$_[0]', ".
               "try passing a prototype string as \$_[1]"
}

my $shift = builtin 'shift';
my @a = 1..10;
say $shift->(\@a);
say "@a";

my $uc = builtin 'uc';
local $_ = 'goodbye';
say $uc->('hello '), &$uc;

my $time = builtin 'time';
say &$time;

my $map = builtin 'map';
my $reverse = builtin 'reverse';
say $map->(sub{"$_, "}, $reverse->(@a));

my %h = (a=>1, b=>2);
my $keys = builtin 'keys';
say $keys->(\%h);

# which prints
# 1
# 2 3 4 5 6 7 8 9 10
# HELLO GOODBYE
# 1256088298
# 10, 9, 8, 7, 6, 5, 4, 3, 2, 
# ab

Исправлено с помощью ниже и отредактировано.

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

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

Если я прав, просто укажите встроенное в закрытие:

#!/usr/bin/perl -w
use strict;

my $coderef = \&test;
$coderef->( "Test %u\n", 1 );

$coderef = sub { printf @_ };
$coderef->( "Test %u\n", 2 );

exit;

sub test {
    print join(' ', map { "[$_]" } @_) . "\n";
}

Выполнение этого со сдвигом также возможно, но помните, что сдвиг без явного массива для работы работает с разными массивами в зависимости от того, где он был вызван.

1
ответ дан 1 December 2019 в 14:44
поделиться

Если вы хотите увидеть, что нужно для подделки в производственном коде качества, посмотрите код для autodie . Мясо находится в Fatal . Помогает, если вы безумный пират-джедай из Австралии.

1
ответ дан 1 December 2019 в 14:44
поделиться

Единственный способ заставить его работать - это сделать ссылку на sub {shift} .

perl -e '@a=(1..3); $f=sub{shift}; print($f->(@a), "\n");'

Функционально это эквивалентно:

perl -e '@a=(1..3); print(shift(@a), "\n");'

Что могло бы быть просто perl -e 'print 1, "\ n"' , но тогда мы не будем говорить о встроенной функции.

К вашему сведению, я удивлен, что нельзя ссылаться на встроенную команду, и теперь, когда мне стало ясно, я не могу не думать об этом как о недостатке Perl.

Update Эрик правильно указывает, что $ f = sub {shift}; $ f -> (@ a) оставляет @a без изменений. Это должно быть больше похоже на:

perl -e '@a=(1..3); $f=sub{shift @{+shift}}; print($f->(\@a), "\n");

Спасибо, Эрик.

0
ответ дан 1 December 2019 в 14:44
поделиться
Другие вопросы по тегам:

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