【问题标题】:Perl: What is the preferred way of evaluating expressions besides eval?Perl:除了 eval,评估表达式的首选方法是什么?
【发布时间】:2022-01-06 15:18:40
【问题描述】:

我正在尝试使用算术来评估写为字符串的 a 函数:

#!/usr/bin/env perl

use strict;
use warnings FATAL => 'all';
use feature 'say';
use autodie ':default';

my $str = '0.203580063041053 * $x + -0.0273785448865449';
my $x = 3;
my $ans = eval $str;
say $ans;

上述代码有效,并给出了正确答案。

然而,perlcritic 表示最好避免使用上述代码:Expression form of "eval" at line 10, column 11. See page 161 of PBP. (Severity: 5)

我已经阅读了 Perl 最佳实践的那部分,但它很长,我不明白它如何适用于我正在做的非常简单的情况。

那么什么是评估函数的好方法?

【问题讨论】:

  • 也许使用例如编写自定义解析器Marpa::R2Regexp::Grammars ?
  • 你如何得到这个字符串中的代码?整件事的目的是什么?
  • 它产生 Perl 代码?那么是的,eval是合适的
  • 那么这是一个 icky/hackish 的解决方案。特别是因为作为 Algorithm::CurveFit 基础的模块提供了编译后的 Perl subs 的方程。
  • 明确地说,被标记的问题不是使用eval 来评估 Perl 代码,而是首先将 Perl 代码作为数据处理。

标签: perl perl-critic


【解决方案1】:

用户 @ikegami 提到了 Algorithm::CurveFit 中的另一个包,大概是 Math::Symbolic。

我能想到的最简单的写法是

#!/usr/bin/env perl

use strict;
use warnings FATAL => 'all';
use feature 'say';
use autodie ':default';
use Math::Symbolic ':all';

# https://metacpan.org/pod/Math::Symbolic
my $str = '0.203580063041053 * x + -0.0273785448865449';
my $x = 3;
my $tree = Math::Symbolic->parse_from_string($str);
my ($sub) = Math::Symbolic::Compiler->compile_to_sub($tree);
my $ans = $sub->($x);
say $ans;

根据 perlcritic,这段代码是可以的,并且没有使用eval 循环。

我不知道为什么my ($sub) 有效,而my $sub 无效,我将不胜感激。

【讨论】:

  • compile_to_sub 返回多个值,因此上下文在这里很重要。 my ($sub) 在列表上下文中调用 compile_to_sub,所以你基本上是在说“我想要列表中的第一项”。当您在没有参数my $sub = ... 的情况下执行此操作时,您将在标量上下文中调用compile_to_sub,这将返回列表中的项目数。所以大概在这种情况下,如果你打印$sub,你会看到2
【解决方案2】:

$str = '0.203580063041053 * $x + -0.0273785448865449' 本质上是一个函数 所以我会使用'sub'来创建这样的函数:

#!/usr/bin/env perl

use strict;
use warnings FATAL => 'all';
use feature 'say';
use autodie ':default';

sub str{
       my $x = shift;
       0.203580063041053 * $x + -0.0273785448865449;
}
my $x = 3;
my $ans = eval { str($x) } ;
say $ans;

【讨论】:

  • 谢谢!但我正在寻找一种没有eval 的方法,因为perlcritic 说不要使用eval
  • 当我运行上述代码时,perl 评论家给了我“源代码 OK”。如果不需要,您当然可以删除 eval 块。
  • @con: Perl::Critic 抱怨将字符串传递给eval。它不会抱怨将带有 Perl 代码的大括号传递给 eval,这就是 @turtle 的答案。这是一个重要的区别。我不是在提倡这个答案,只是澄清一下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-21
  • 1970-01-01
  • 1970-01-01
  • 2017-11-26
  • 1970-01-01
相关资源
最近更新 更多