我什么时候应该使用子程序属性?

Zai*_*aid 22 perl subroutine

我根本没有grol Perl子程序属性.

我从未在实际代码中看到它们perldoc perlsub而且perldoc attributes未能回答我的问题:

  • 什么属性有用?
  • 他们为Perl最佳实践中尚未提供的内容带来了什么?
  • 是否有任何使用属性的CPAN模块(众所周知的或其他方式)?

如果有人能够以他们应该的方式使用属性的详细示例,那将会很棒.


对于那些和我一样无能为力的人,属性是attributes SYNOPSIS下面例子中冒号后面的参数:

sub foo : method ;
my ($x,@y,%z) : Bent = 1;
my $s = sub : method { ... };

use attributes ();  # optional, to get subroutine declarations
my @attrlist = attributes::get(\&foo);

use attributes 'get'; # import the attributes::get subroutine
my @attrlist = get \&foo;
Run Code Online (Sandbox Code Playgroud)

JRi*_*out 14

属性允许您注释变量以在幕后执行自动魔术.类似的概念是java注释.这是一个可能有用的小例子.它用于Attribute::Handlers创建loud属性.

use Attribute::Handlers;

sub UNIVERSAL::loud : ATTR(CODE) {
    my ( $pkg, $sym, $code ) = @_;
    no warnings 'redefine';
    *{$sym} = sub {
        return uc $code->(@_);
    };
}

sub foo : loud {
    return "this is $_[0]";
}

say foo("a spoon");
say foo("a fork");
Run Code Online (Sandbox Code Playgroud)

每当使用loud属性声明sub时,UNIVERSAL::loud回调触发器就会触发sub上的元信息.我重新定义了实际调用匿名子函数的函数,后者又调用原始子函数并将其传递给uc

这输出:

THIS IS A SPOON
THIS IS A FORK
Run Code Online (Sandbox Code Playgroud)

现在让我们看一下SYNOPSIS中的变量示例:

my ($x,@y,%z) : Bent = 1;
Run Code Online (Sandbox Code Playgroud)

在不考虑我们拥有的属性的情况下将其分解为小的perl语句

my $x : Bent
$x = 1;

my @y : Bent
@y = 1;

my %Z : Bent
%z = 1;
Run Code Online (Sandbox Code Playgroud)

我们现在可以看到每个变量都以简洁的方式归因于Bent注释,同时还为所有变量赋值1.这里有一个更有趣的例子:

use Attribute::Handlers;
use Tie::Toggle;

sub UNIVERSAL::Toggle : ATTR(SCALAR) {
    my ($package, $symbol, $referent, $attr, $data, $phase) = @_;
    my @data = ref $data eq 'ARRAY' ? @$data : $data;
    tie $$referent, 'Tie::Toggle', @data;
}

my $x : Toggle;

say "x is ", $x;
say "x is ", $x;
say "x is ", $x;
Run Code Online (Sandbox Code Playgroud)

哪个输出:

x is 
x is 1
x is 
Run Code Online (Sandbox Code Playgroud)

您可以使用它来进行日志记录,创建测试注释,向变量添加类型详细信息,语法糖,做驼鹿角色组合以及许多其他很酷的事情.

另请参阅此问题:Perl方法属性如何工作?.


kat*_*hos 8

  • 什么属性有用?

这是一种传递关于变量或子例程的一些附加信息(属性)的方法.

您可以将此信息(属性)作为字符串(在COMPILE TIME!)捕获并随意处理它.您可以生成其他代码,修改存储空间.... 它是由你决定.

  • 他们为Perl最佳实践中尚未提供的内容带来了什么?

有时它会让生活更轻松.见下面的例子.

有些人使用它.做一个:找到.-name*.p [ml] | xargs grep'使用属性;' 在perl安装路径中使用属性查看包.Catalyst广泛使用属性来处理基于给定路径的请求.

示例:

假设您希望按特定顺序执行子例程.并且您想要告诉子程序何时必须执行(通过运行号RUNNR).使用属性实现可以是:

#!/usr/bin/env perl

use strict;
use warnings;

use Runner;     # immplements the attribute handling

# some subroutines to be scheduled :
# attibutes automatically filling @$Runner::schedule 
sub func_a : RUNNR(2) {return "You called func_a !"};
sub func_b : RUNNR(1) {return "You called func_b !"};
sub func_c : RUNNR(3) {return "You called func_c !"};

# run the subroutines according to the their RUNNR
sub run {
    # @$Runner::schedule holds the subroutine refs according
    # to their RUNNR
    foreach my $func (@$Runner::schedule) {
       if ( defined $func ) {
         print "Running : $func --> ", $func->(), "\n";
       }
    }
}

print "Starting ...\n\n";
run();
print "\nDone !\n";
Run Code Online (Sandbox Code Playgroud)

属性处理使用MODIFY_CODE_ATTRIBUTES挂钩在Runner包中.

package Runner;

use strict;
use warnings;

use attributes;

BEGIN {
    use Exporter ();                                                                 
    our (@ISA, @EXPORT);       

    @ISA         = qw(Exporter);                 
    @EXPORT      = qw(&MODIFY_CODE_ATTRIBUTES);    # needed for use attributes;    
}

# we have subroutines with attributes : <type> is CODE in MODIFY_<type>_ATTRIBUTES
# MODIFY_CODE_ATTRIBUTES is executed at COMPILE TIME ! try perl -c <prog_name> to prove it :-)

sub MODIFY_CODE_ATTRIBUTES {
    # for each subroutine of a package we get
    # the code ref to it and the attribute(s) as string
    my ($pckg, $code_ref, @attr) = @_;

    # whatever you like to do with the attributes of the sub ... do it
    foreach my $attr (@attr) {
        # here we parse the attribute string(s), extract the number and 
        # save the code ref of the subroutine
        # into $Runner::schedule array ref according to the given number
        # that is how we 'compile' the RUNNR of subroutines into 
        # a schedule
        if ( $attr =~ /^RUNNR\((\d+)\)$/ ) {    
            $Runner::schedule->[$1] = $code_ref;     
        }
    }
    return(); # ERROR if returning a non empty list
}

1;
Run Code Online (Sandbox Code Playgroud)

输出将是:

Starting ...

Running : CODE(0x129c288) --> You called func_b !
Running : CODE(0x129c2b8) --> You called func_a !
Running : CODE(0x12ed460) --> You called func_c !

Done !
Run Code Online (Sandbox Code Playgroud)

如果你真的想要了解什么属性做什么,什么时候发生什么,你必须'perldoc属性',一步一步阅读它并玩它.界面很麻烦,但原则上你在编译时挂钩并处理提供的信息.