5

我有以下代码:

#!/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;

我只是在测试一些东西,而不是真正的生产代码......我bignum的机器上确实有编译指示(完全可以使用 加载use),我想知道为什么require不能正常工作(我得到的是指数数字而不是“大数字”)在这种情况下?

谢谢,

4

3 回答 3

3

bignum 的 import 需要在编译它打算生效的代码之前调用,否则它不起作用。在这里,BEGIN 在您实际的 compute_factorial 调用之前调用它,但不是在关键my $factorial = 1;编译之前调用。

对于这种情况,更好的方法是直接使用 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;
} 
于 2012-07-25T17:29:40.803 回答
2
BEGIN {
   require bignum;
   import bignum;
   my $x = 1;
}

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

是相同的,因为require和在已经编译import之后执行my $x = 1;,所以 bignum 永远没有机会my $x = 1;编译成my $x = Math::BigInt->new(1);. 请记住,

use bignum;
my $x = 1;

实际上是

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

并不是

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

解决方案是

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;
}

当然,既然您可以简单地消除杂注,那将是最好的。

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;
}
于 2012-07-25T20:21:55.613 回答
0

与许多其他 pragma 一样,在新版本的 Perlbignum中,仅在您导入它的范围内有效。但是,与许多不同的是,它还会在升级范围内的数字时造成一些时髦的混乱,而这些数字并不完全适用于require. 您将不得不中断检查它的存在并在两个不同的文件中使用以隔离范围并仍然让它发挥它的魔力。

大.pl

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

print big_loader::big_num_returner();

print "still ok\n";

big_loader.pm

package big_loader;
use bignum;

sub big_num_returner {
    return 2**512
}

1;
于 2012-07-25T17:24:59.513 回答