简体   繁体   English

perl'require'在开始块

[英]perl 'require' in begin block

I have the following code: 我有以下代码:

#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';

BEGIN {
       my $supported = undef;
       *compute_factorial = sub { if (eval { require bignum; bignum->import(); 1;}) {
                                    my $num       = shift;
                                    my $factorial = 1;
                                    foreach my $num (1..$num) {
                                        $factorial *= $num; 
                                    }
                                    return $factorial;
                                  }  else {
                                       undef;
                                     } };
       };

my $f = compute_factorial(25);
say $f;

I'm just testing something, not really a production code... I do have bignum pragma on my machine (perfectly loadable using use ), I was wondering why require doesn't work as it should be (I'm getting exponential numbers rather then "big numbers") in this case? 我只是在测试某种东西,而不是真正的生产代码……我的机器上确实有bignum pragma(可以使用use完全加载),我想知道为什么require不能正常工作(我正在获取指数数)而不是“大数字”)?

Thanks, 谢谢,

bignum's import needs to be called before compilation of the code it is intended to effect, or it doesn't work. bignum的导入需要在要实现的代码编译之前被调用,否则将不起作用。 Here, the BEGIN makes it called before your actual compute_factorial call, but not before the critical my $factorial = 1; 在这里,BEGIN使它在您实际的compute_factorial调用之前被调用,但在关键my $factorial = 1;之前调用my $factorial = 1; is compiled. 被编译。

A better approach for cases like this is just to directly use Math::Big*: 对于这种情况,更好的方法是直接使用Math :: Big *:

if (eval { require Math::BigInt }) {
    my $num = shift;
    my $factorial = Math::BigInt->new(1);
    foreach my $num (1..$num) {
        $factorial *= $num;                            
    }
    return $factorial;
} else {
    undef;
} 
BEGIN {
   require bignum;
   import bignum;
   my $x = 1;
}

and

require bignum;
import bignum;
my $x = 1;

are the same because require and import are executed after my $x = 1; 是相同的,因为在my $x = 1;之后执行了requireimport my $x = 1; is already compiled, so bignum never has a chance to make my $x = 1; 已被编译,因此bignum永远没有机会使my $x = 1; compile into my $x = Math::BigInt->new(1); 编译成my $x = Math::BigInt->new(1); . Keep in mind that 请记住

use bignum;
my $x = 1;

is actually 实际上是

BEGIN {
   require bignum;
   import bignum;
}
my $x = 1;

and not 并不是

BEGIN {
   require bignum;
   import bignum;
   my $x = 1;
}

The solution would be 解决方案是

BEGIN {
   my $sub;
   if (eval { require bignum; }) {
      $sub = eval(<<'__EOI__') or die $@;
         use bignum;
         sub {
            my ($num) = @_;
            my $factorial = 1;
            $factorial *= $_ for 2..$num;
            return $factorial;
         }
__EOI__
   } else {
      $sub = sub { croak "Unsupported" };
   }

   *factorial = $sub;
}

Of course, since you can simply eliminate the pragma, that would be best. 当然,由于您可以简单地消除实用性,所以最好。

BEGIN {
   my $sub;
   if (eval { require Math::BigInt; }) {
      require Math::BigInt;
      $sub = sub {
         my ($num) = @_;
         my $factorial = Math::BigInt->new(1);
         $factorial *= $_ for 2..$num;
         return $factorial;
      };
   } else {
      $sub = sub { croak "Unsupported" };
   }

   *factorial = $sub;
}

As many other pragmas, in newer versions of Perl bignum is only active in scope where you imported it. 与许多其他编译指示一样,在较新版本的Perl bignum它仅在导入它的作用域中处于活动状态。 However, unlike many it also does some funky messing up with upgrading scoped numbers that doesn't quite work with just require . 但是,与许多其他方法不同,它还与升级有作用域的数字做了一些时髦的混淆,而这仅与require不能完全配合。 You will have to break check for its existence and use in two different files to isolate scope and still let it do its magic. 您将不得不中断检查它的存在,并在两个不同的文件中使用以隔离作用域,并且仍然让它发挥作用。

big.pl big.pl

if (eval { require bignum; 1 }) {
    require big_loader;
}

print big_loader::big_num_returner();

print "still ok\n";

big_loader.pm big_loader.pm

package big_loader;
use bignum;

sub big_num_returner {
    return 2**512
}

1;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM