Как добавить пользовательскую функцию в качестве встроенной функции в Perl? - PullRequest
1 голос
/ 09 марта 2020

Одно время я думал о том, как можно создать пакет (или класс) в Perl для повторного использования кода. Исходя из опыта C ++, у меня были проблемы с пониманием того, как работают Perl подпрограммы и пакеты. Итак, я создал структуру данных Stack в Perl (которая на самом деле является просто массивом с LIFO-подходом), который требовал от меня записывать l oop каждый раз, когда я хочу распечатать его (что очень неэффективно)

@_ = (1, 8, 14, 45);

push(@_, 69);
push(@_, 55);
push(@_, 65536);
push(@_, 4294967296);

print "Print without newline: ";

$size = @_;
for my $i(1 .. ($size-1))
{
    print $_[$i]." ";
}

print "Print with newline: ";

for my $i(1 .. ($size-1))
{
    say scalar $_[$i];
}

pop(@_);
pop(@_);
pop(@_);

print "Print without newline: ";
# HERE WE GO AGAIN
$size = @_;
for my $i(1 .. ($size-1))
{
    print $_[$i]." ";
}

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

Printer.pm

use Modern::Perl;

package Printer;
sub new
{
    my $class = shift;
    my $self = {};

    bless $self, $class;

    return $self;
}

my $size;
sub println
{   
    my @userArray = @_;
    $size = @userArray;
    for my $i(1 .. ($size-1))
    {
        say scalar $userArray[$i];
    }
}

sub print
{   
    my @userArray = @_;
    $size = @userArray;
    for my $i(1 .. ($size-1))
    {
        print $userArray[$i]." ";
    }

}

1;

Псевдокод для Stack.pl

use lib ".\\";
use Array::Printer;

. . .

my $printer = new Printer();
print "Print without newline: ";
print $printer->print(@_);
print "\nPrint with newline: \n";
print $printer->println(@_);

say "";

# POPPING (LIFO)
pop(@_);
pop(@_);
pop(@_);

print $printer->print(@_);

И, как вы уже догадались, это работает как обаяние.

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

println(@_);

Поскольку println не существует в Perl, мне просто любопытно, возможно ли это сделать. Любые предложения о том, что мне делать дальше?

1 Ответ

6 голосов
/ 09 марта 2020

Если вы хотите эмулировать встроенный, то вам не нужен класс, вам просто нужна библиотека. Библиотеки также реализованы в виде пакетов в Perl, но подпрограммы в них не ожидают передачи имени класса или объекта в качестве первого параметра. Вы также можете использовать Exporter , чтобы вставить свои подпрограммы в таблицу символов вызывающей программы.

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

package Array::Printer;

use strict;
use warnings;
use feature 'say';

require Exporter;
our @ISA = qw[Exporter];
our @EXPORT = qw[println];

sub println {
  say for @_;
}

1;

И вы будете использовать это как this:

#!/usr/bin/perl

use strict;
use warnings;

use lib '.';
use Array::Printer;

# I've used @stack instead of @_ in my code as @_ is a
# special variable and it seems strange to use it in another way.

my @stack = (1, 8, 14, 45);
push(@stack, 69);
push(@stack, 55);
push(@stack, 65536);
push(@stack, 4294967296);

println(@stack);

pop(@stack);
pop(@stack);
pop(@stack);

println(@stack);

Обновление: Обратите внимание, что мой библиотечный модуль называется Array::Printer. Ваш оригинальный класс должен был использовать то же имя. Как правило, Perl имена пакетов (как библиотеки, так и классы) должны совпадать с именами файлов, в которых они хранятся. Вы назвали свой пакет Printer, но вы использовали Array::Printer. Это гарантированно запутает любого программиста по обслуживанию (даже вас!)

use lib '.' в моем коде добавляет текущий каталог в список каталогов, которые Perl ищет библиотеки и классы. Итак, мы предполагаем, что код для Array::Printer находится в файле с именем Printer.pm в каталоге с именем Array в вашем текущем каталоге (который также, по-видимому, где находится ваша основная программа. Двойное двоеточие в Perl имя библиотеки (::) преобразуется в разделитель каталогов (/) при поиске файла, содержащего библиотеку.

...