Function 如何创建接受多个块的Perl子例程?

Function 如何创建接受多个块的Perl子例程?,function,perl,parameter-passing,subroutine,Function,Perl,Parameter Passing,Subroutine,使用原型,您可以创建一个子例程,该子例程接受一个代码块作为其第一个参数: sub example (&) { my $code_ref = shift; $code_ref->(); } example { print "Hello\n" }; 我如何才能做同样的事情,但有一个以上的代码块?我想使用代码块,而不是变量或sub{…} 这不起作用: sub example2 (&&) { my $code_ref = shift; my $co

使用原型,您可以创建一个子例程,该子例程接受一个代码块作为其第一个参数:

sub example (&) {
   my $code_ref = shift;
   $code_ref->();
}
example { print "Hello\n" };
我如何才能做同样的事情,但有一个以上的代码块?我想使用代码块,而不是变量或
sub{…}

这不起作用:

sub example2 (&&) {
   my $code_ref = shift;
   my $code_ref2 = shift;
   $code_ref->();
   $code_ref2->();
}
example2 { print "One\n" } { print "Hello\n" };
它给出了以下错误:

Not enough arguments for main::example2
为我工作

sub example2  {
   my $code_ref = shift;
   my $code_ref2 = shift;
   $code_ref->();
   $code_ref2->();
}
example2 ( sub { print "One\n" }, sub { print "Hello\n" });
仅出于TMTOWTDI的目的,这里有一个方法,其工作方式与OP请求的方式类似

首先,制作一个源过滤器

package poop;

use Filter::Util::Call;

sub import {
    my ($type) = @_;
    my ($ref)  = [];
    filter_add( bless $ref );
}

sub filter {
    my ($self) = @_;
    my ($status);
if (( $status = filter_read() ) > 0) { 
        if(!/sub/ && /example2/) {
            s/\{/sub \{/g;
            }
        }

    $status;
}
1;
其次,必须使用过滤器

use poop;

sub example2  {
   my $code_ref = shift;
   my $code_ref2 = shift;
   $code_ref->();
   $code_ref2->();
}
example2 ( { print "One\n" }, { print "Hello\n" });
附言:这太可怕了,没有人希望在制作中看到这一点

这对我有用:

     example { print "One\n" } sub { print "Hello\n" };

我希望您认识到,这只是代码的调味品,您所要实现的只是以牺牲清晰度为代价的更整洁的语法

Perl不允许您将多个裸块传递给子例程,但第二个实际参数可以是对子例程的调用,该子例程也接受单个块并仅返回代码引用

这个程序演示了。注意,我选择了
作为子例程的名称。但是,您必须使用既适合自己代码功能又不太可能与即将推出的核心语言扩展冲突的东西

use strict;
use warnings;

sub please(&$) {
  my ($code1, $code2) = @_;
  $code1->();
  $code2->();
}

sub also(&) {
  $_[0];
}

please { print "aaa\n" } also { print "bbb\n" };
输出

aaa
bbb

您可以
eval

use experimental 'signatures';
use feature 'say'; 

sub doublethecode ($block1, $block2) { eval { $block1; }; eval { $block2;} } ;
doublethecode \&{ print "OH " }, \&{ say for qw/HAI YOU LOLCAT :-P/  }; 
输出

OH, HAI
YOU
LOLCAT
:-P
perl6
然后忽略
\&
,你就在那里了

v5.20开始
您可以同时使用签名和
:prototype
属性。
signatures
功能提供了一种更“通用”的语法和一种最低限度的参数检查。也许有一天,未来的perl将拥有某种“内置”(可选的,高度灵活的)类型的系统,但目前原型并不是这样的。比如:

sub doublethecode :prototype(\&\&) ($cr1, $cr2) { $cr1 ; $cr2 ; }
不是看起来的那样。由于原型、
signatures
和带有
:prototype(&&&&
的签名可能无法提供您认为得到的信息,这可能足够好了:

sub doublethecode { eval { shift };  eval{ shift } } ;
doublethecode &{ print "perl" }, &{ print "6" }
输出

OH, HAI
YOU
LOLCAT
:-P
perl6
为了确保perl不认为
{}
是散列,有必要使用
&
。但实际上。。。这里使用匿名子例程
sub{}
有什么错?

Fwiw,在Perl 6中:

sub doublecode (&foo, &bar) { foo(), bar() }
doublecode { print 1 }, { print 2 } # prints 12

但是请看。

您所谓的“代码块”正是
sub{…}
的意思,只是您不键入
sub
keyword@TLP你是说像这样<代码>示例2子{…},子{…}我意识到,我只想不使用
子关键字或变量。我猜这是不可能的。那也是我的猜测。原型不容易使用,一般的建议是:不要使用它们。我会猜测他们没有得到很好的维护和/或开发,因为大多数Perl程序员认为它们是死胡同,不使用它们。随着原型的发展,(&)和(& @)是相当无害的。你不觉得你欠我们一个为什么的答案吗?你有没有试过,看看它是否有效?不适合我。我更新了我的答案。。。也许你可以告诉我们为什么通过障碍物而不是匿名潜水艇很重要。这是Ruby,不是吗?问题不在于Ruby,而在于Perl(如标题和标签所示)。@LenJaffe:像这样的想法——尽管我承认,不是这个想法——构成了编程语言概念的核心。OP的左手边有一个必须完成的作业,右手边有一个可靠地遵守规则的实体。你应该为他们做些什么?带着他去见犀牛。你认为
次双重编码($block1,$block2)
有什么作用?@borodin噢,我想我们是同时编辑的对不起。。。我认为
sub-doublethecode($block1,$block2){…}
只是一种分配
@
的新方法,将其与属性
一起使用:原型(&&&)
似乎并没有使这个练习变得更好:-)请查看。这相当于
无警告“实验性”;使用特征“签名”。即使这样,您的代码也会随着消息而消亡,例如
未知警告类别“实验性”
功能“签名”不受支持
,除非您有前面的
使用5.020
。是的,要运行您的解决方案,您需要运行最新版本的Perl,该版本仅在今年5月发布。有人走在最前沿,有人炫耀关于新设施的所有警告。“你知道你在哪里。”博罗丁,说得对——我很熟悉布拉格语的用法,我应该指出它,我的错。我认为使用
sub{}
是一个非常清晰且使用良好的perl习惯用法。在越来越严肃的ECMA/Javascript世界中,匿名函数(更加冗长)风靡一时。在perl
sub{…}中,sub{…}
实际上是一种自文档特性,我们有它。OP应该解释他们为什么不使用它。我想你的意思是“更加严肃的ECMAScript/JavaScript世界”?JavaScript现在的地位与FORTRAN在几十年前以及之后的C一样:有无数的缺点,但受欢迎程度高于一切。之所以被接受,是因为答案是:“Perl不允许您将多个裸块传递给子例程”。
也是
的东西很聪明,但在本例中它的行为与
sub
完全相同,所以我也可以使用
sub
,但为什么会这样呢?Perl似乎将下一个块视为哈希引用,原因我不知道。是否Perl中的块不是数据类型(与sub相反)?考虑这一点:<代码> $x= {打印“FoBaar \n”} /代码> -它执行代码并创建哈希引用<代码> 1 = > UNDEF。