gpt4 book ai didi

perl - 如何在 perl 中动态创建包?

转载 作者:行者123 更新时间:2023-12-04 12:25:20 24 4
gpt4 key购买 nike

如果我可以动态创建包,我会遇到一种情况。下面的代码不会运行,但说明了我想做的事情的精神。

#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;

my $basename = "Xma";
my $len = 7;
my $newClass = sprintf("%s%d", $basename, $len);

printf("New class is %s\n", $newClass);

package $newClass {
# Early modules.
our @enum; BEGIN { @enum = qw( I_VAL I_SLOPE ); }

use parent qw(Exporter);
use enum::fields @enum;
our @EXPORT = (@enum);

our $classLen = $len;
our $classBasename = $basename;

sub new {
my $invocant = shift;
my $self = bless ([], ref $invocant || $invocant);
return($self);
}
}

1;

我在我的新类中包含了“额外”的东西,以说明新类是一个复杂的类,它将在继承链中。

我知道我可以用类似的东西做简单的包:
*{ "${class}::new" } = sub { return bless { }, $class };

但是我的新类/包会很大,所以我希望有一些更容易维护的东西。

你们中间的好奇者可能会问,“为什么?”好奇心很大。我需要在加载/编译时尽可能多地处理进程,并试图避免数百万运行时查找。我要换 $basename$len经常,但只在编译时。还有最重要的一点:好奇心。

最佳答案

我不想成为那个说它的人,但可变代码(?!)是 反模式对于我能想到的大多数用例,除了明显的代码生成工具或转译器之外,还有一个很大的危险信号。

最好只创建一个类或类层次结构,然后使用非元编程处理该类中的任何差异。

事实上,这就是 OOP 的总体思路。您创建的对象是您的类的"template"的实例或副本:

  package MyClass {
sub new {
my ( $class, %args ) = @_;
bless { name => sprintf('%s%d', $args{basename}, $args{len}) }, $class;
}
}

my $obj = MyClass->new( basename => 'Xma', len => 7 );
printf "New class is %s\n", $obj->{ name };

如果你真的需要动态创建包/类,我能想到的最明智的方法是动态创建从一个或多个基类继承的类。
package MyClass {  
sub new {
my ( $class, %args ) = @_;
bless \%args, $class;
}

sub foo {
my $self = shift;
return "instance of $self";
}
}

sub build_class {
my ( %args ) = @_;

my $classname = sprintf( '%s::%s%d', $args{ parent }, $args{ basename }, $args{ len } );
@{ "${classname}::ISA" } = ( $args{ parent } );

return $classname;
}

my $classname = build_class( parent => 'MyClass', basename => 'Xma', len => 7 );
my $obj = $classname->new();

printf "New class is %s\n", ref $obj; # is MyClass::Xma7
printf "Object is an %s\n", $obj->foo; # a MyClass::Xma7=HASH(...) object instance

如需更多面向 OOP 的元编程能力,请查看 Moose::Meta::ClassClass::MOP :
use Class::MOP;

my $basename = 'Xma';
my $len = 7;
my $classname = "MyClass::${basename}${len}";

Class::MOP::Class->create(
$classname,
attributes => [
Class::MOP::Attribute->new( 'foo', is => 'rw', isa => 'Str' )
],
methods => {}
);

$classname->new( foo => 'bar' );

另一方面,如果你真的需要在你的包中包含可变代码和/或你不需要/不想在每次程序运行时在运行时将所有包加载到内存中,我会说你可以使用 一组文件模板和一些模板语言您选择将新包输出到文件(即“MyClass/Xma7.pm”、“MyClass/Xma8.pm”)然后使用 use MyClasses::Xma7; 加载它们就像任何其他包一样。这里的优点是,考虑到元编程的错误倾向,您的代码将更容易调试和测试。

关于perl - 如何在 perl 中动态创建包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57385262/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com