【问题标题】:How to add a user-defined function as a built-in function in Perl?如何在 Perl 中将用户定义的函数添加为内置函数?
【发布时间】:2020-06-21 10:29:12
【问题描述】:

有一次,我在考虑如何在 Perl 中创建一个包(或类)以实现代码的可重用性。由于具有 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”函数作为“内置”函数。没有调用包的构造函数。我正在考虑这样的事情:

println(@_);

由于 Perl 中不存在 println,我只是好奇是否可以这样做。对我接下来应该做什么有什么建议吗?

【问题讨论】:

  • 一些笔记。 (1) @ary 的最后一个索引的语法是$#ary,这对于循环索引很有用,for my $i (0..$#ary) {...}(这很少需要——我认为您这样做的原因不仅仅是打印)。 (2) 只打印一个包含空格且没有新行的数组:print "@ary";,并通过带有新行的元素:say for @ary;。 (3) 当您在对象上调用方法时,调用者(对象本身)作为第一个元素传递。所以你需要sub print { my ($self, @userArray) = @_; ...。为什么不阅读它,例如 perlootut 对于初学者?

标签: perl oop reusability code-reuse


【解决方案1】:

如果你想模拟一个内置的,那么你不需要一个类,你只需要一个库。库在 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;

你会这样使用它:

#!/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 的代码在您当前目录中名为Array 的目录中的一个名为Printer.pm 的文件中(大概也是您的主程序所在的位置。a 中的双冒号在查找包含该库的文件时,Perl 库名称 (::) 被转换为目录分隔符 (/)。

【讨论】:

    猜你喜欢
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 2013-06-14
    • 2021-03-16
    • 2022-12-25
    • 2019-02-14
    • 2011-10-21
    • 1970-01-01
    相关资源
    最近更新 更多