如何在 Perl 中将用户定义的函数添加为内置函数?
How to add a user-defined function as a built-in function in Perl?
有一次,我在考虑如何在 Perl 中创建一个包(或 class)以实现代码的可重用性。我有 C++ 背景,很难理解 Perl 子例程和包的工作原理。所以,我在 Perl 中创建了一个 Stack 数据结构(它实际上只是一个采用 LIFO 方法的数组),每次我想打印它时都需要我写下循环(这是非常低效的)
@_ = (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(@_);
而且,正如您猜到的那样,它就像魅力一样。
不过有一天,我突然想到一件事。我想知道是否可以将我在 Printer 包中构建的 'println' 函数作为 'built-in' 函数。没有调用包的构造函数。我在想这样的事情:
println(@_);
由于 Perl 中不存在 println,我只是想知道是否可以这样做。对我接下来应该做什么有什么建议吗?
如果你想模拟一个内置的,那么你不需要 class,你只需要一个库。库在 Perl 中也作为包实现,但其中的子例程不希望将 class 名称或对象作为其第一个参数传递。您还可以使用 Exporter 将您的子程序插入调用程序的符号 table.
看起来像这样:
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;
你会像这样使用它:
#!/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
。您原来的 class 应该使用相同的名称。通常,Perl 包名称(包括库和 classes)应该与它们存储在其中的文件的名称相匹配。您将包命名为 Printer
,但您使用了 Array::Printer
。这肯定会让任何维护程序员(甚至你!)感到困惑
我代码中的 use lib '.'
将当前目录添加到 Perl 搜索库和 classes 的目录列表中。因此,我们假设 Array::Printer
的代码位于当前目录中名为 Array
的目录中名为 Printer.pm
的文件中(这也是您的主程序所在的位置。在查找包含库的文件时,Perl 库名称 (::
) 中的双冒号被转换为目录分隔符 (/
)。
有一次,我在考虑如何在 Perl 中创建一个包(或 class)以实现代码的可重用性。我有 C++ 背景,很难理解 Perl 子例程和包的工作原理。所以,我在 Perl 中创建了一个 Stack 数据结构(它实际上只是一个采用 LIFO 方法的数组),每次我想打印它时都需要我写下循环(这是非常低效的)
@_ = (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(@_);
而且,正如您猜到的那样,它就像魅力一样。
不过有一天,我突然想到一件事。我想知道是否可以将我在 Printer 包中构建的 'println' 函数作为 'built-in' 函数。没有调用包的构造函数。我在想这样的事情:
println(@_);
由于 Perl 中不存在 println,我只是想知道是否可以这样做。对我接下来应该做什么有什么建议吗?
如果你想模拟一个内置的,那么你不需要 class,你只需要一个库。库在 Perl 中也作为包实现,但其中的子例程不希望将 class 名称或对象作为其第一个参数传递。您还可以使用 Exporter 将您的子程序插入调用程序的符号 table.
看起来像这样:
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;
你会像这样使用它:
#!/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
。您原来的 class 应该使用相同的名称。通常,Perl 包名称(包括库和 classes)应该与它们存储在其中的文件的名称相匹配。您将包命名为 Printer
,但您使用了 Array::Printer
。这肯定会让任何维护程序员(甚至你!)感到困惑
我代码中的 use lib '.'
将当前目录添加到 Perl 搜索库和 classes 的目录列表中。因此,我们假设 Array::Printer
的代码位于当前目录中名为 Array
的目录中名为 Printer.pm
的文件中(这也是您的主程序所在的位置。在查找包含库的文件时,Perl 库名称 (::
) 中的双冒号被转换为目录分隔符 (/
)。