Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 在Moose子例程中,$meta是如何进入@的?_Perl_Moose - Fatal编程技术网

Perl 在Moose子例程中,$meta是如何进入@的?

Perl 在Moose子例程中,$meta是如何进入@的?,perl,moose,Perl,Moose,让我对Moose子程序产生了好奇。我正在查看Moose源代码,注意到在has子例程中,有一个$meta变量从@解包。$meta来自哪里?我已经开始涉猎各种各样的Moose和Class::MOP模块。在许多子例程中,$meta似乎通常作为@中的第一个参数出现,即使它没有作为参数专门传递给它 编辑:以下是has子例程的原始源代码: sub has { my $meta = shift; my $name = shift; Moose->throw_error('Usa

让我对Moose子程序
产生了好奇。我正在查看Moose源代码,注意到在
has
子例程中,有一个
$meta
变量从
@
解包。
$meta
来自哪里?我已经开始涉猎各种各样的Moose和Class::MOP模块。在许多子例程中,
$meta
似乎通常作为
@
中的第一个参数出现,即使它没有作为参数专门传递给它

编辑:以下是
has
子例程的原始源代码:

sub has {
    my $meta = shift;
    my $name = shift;

    Moose->throw_error('Usage: has \'name\' => ( key => value, ... )')
        if @_ % 2 == 1;

    my %options = ( definition_context => Moose::Util::_caller_info(), @_ );
    my $attrs = ( ref($name) eq 'ARRAY' ) ? $name : [ ($name) ];
    $meta->add_attribute( $_, %options ) for @$attrs;
}

你正在寻找的特殊魔法就在这里。您可以通过Moose.pm从以下代码获得
has
方法:

Moose::Exporter->setup_import_methods(
    with_meta => [
        qw( extends with has before after around override augment )
    ],
    as_is => [
        qw( super inner ),
        \&Carp::confess,
        \&Scalar::Util::blessed,
    ],
);
注意
setup\u import\u methods
的“with\u meta”选项——它将这些方法导入调用方的名称空间,确保传递的第一个参数是元类对象


扩展Moose的各种MooseX模块使用Moose::Exporter将新符号导入调用方的名称空间。您可以在烹饪书中阅读更多有关此过程的信息,从开始。

实际导入到包中的不是命名的has()子例程,而是插入元对象的闭包。您可以清楚地看到这是如何发生的:

$ perl -we'use Data::Dump::Streamer; use Moose; Dump(\&has)'
my ($extra,$sub,@ex_args);
$extra = sub {
       package Moose::Exporter;
       use warnings;
       use strict 'refs';
       Class::MOP::class_of(shift @_);
     };
$sub = sub {
     package Moose;
     use warnings;
     use strict 'refs';
     my $meta = shift @_;
     my $name = shift @_;
     'Moose'->throw_error(q[Usage: has 'name' => ( key => value, ... )]) if @_ % 2 == 1;
     my(%options) = ('definition_context', Moose::Util::_caller_info(), @_);
     my $attrs = ref $name eq 'ARRAY' ? $name : [$name];
     $meta->add_attribute($_, %options) foreach (@$attrs);
   };
@ex_args = ( 'main' );
$CODE1 = sub {
       package Moose::Exporter;
       use warnings;
       use strict 'refs';
       my(@curry) = &$extra(@ex_args);
       return &$sub(@curry, @_);
     };

$CODE1
是闭包本身;上面是其中引用的变量。

分子
注释:

我不确定has子例程是如何转换为这个闭包的,但这肯定显示了导入has的curried性质

下面是一个(希望如此!)如何实现这一目标的简单示例(但我怀疑它是以更复杂、更好的方式实现的!)

Meta.pm

package Meta;

sub new {
    my $class = shift;
    bless { @_ }, $class;
}

sub has {
    my $meta = shift;
    print "Given => @_ \n";
    print "meta $_ => ", $meta->{$_}, "\n" for keys %$meta;
}

1;
package Import;
use strict;
use warnings;
use Meta;

# some arbitrary meta info!
our $Meta = Meta->new( a => 'A', b => 'B' );

sub import {
    my $caller = caller;

    # import 'has' into caller namespace
    no strict 'refs';
    *{$caller . '::has'} = sub { $Meta->has(@_) };
}

1;
导入.pm

package Meta;

sub new {
    my $class = shift;
    bless { @_ }, $class;
}

sub has {
    my $meta = shift;
    print "Given => @_ \n";
    print "meta $_ => ", $meta->{$_}, "\n" for keys %$meta;
}

1;
package Import;
use strict;
use warnings;
use Meta;

# some arbitrary meta info!
our $Meta = Meta->new( a => 'A', b => 'B' );

sub import {
    my $caller = caller;

    # import 'has' into caller namespace
    no strict 'refs';
    *{$caller . '::has'} = sub { $Meta->has(@_) };
}

1;
meta_有.pl

use strict;
use warnings;
use Import;

has name => ( is => 'rw', isa => 'Int' );
现在,如果运行
meta_has.pl
,您将得到:

# Given => name is rw isa Int 
# meta a => A
# meta b => B
希望有帮助


/I3az/

+1谢谢。我知道我需要花一点时间研究Moose::Exporter,然后才能真正理解它。我仍然不清楚
$meta
(或者更准确地说,
$meta
后面提到的引用)是如何进入
@
的,但您肯定为我指明了正确的方向。您可能特别想看看
中的私有方法
\u make\u wrapped\u sub\u with\u meta
。这个函数的返回值是Moose安装的
has
,我相信我把它改成了
perl-we'package X;使用数据::转储::拖缆;使用驼鹿;转储(\&has)
以使其在我的Debian Lenny机器上工作。+1谢谢。我不确定
has
子例程是如何转换为这个闭包的,但这肯定显示了导入的
has
的curried性质。对于希望看到输出稍微不那么混乱的人,请尝试将一行程序中的
转储(\&has)
替换为
转储(\&after)