【问题标题】:Perlcritic - Subroutine prototypesPerlcritic - 子程序原型
【发布时间】:2012-01-24 07:08:57
【问题描述】:

我在运行 Perlcritic 时遇到此错误:

第 xx 行第 x 列使用的子程序原型。参见 PBP 第 194 页。 (严重性:5)

子程序是:

sub zFormatDate() {
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = shift;
  return sprintf("%04d%02d%02d%02d%02d%02d",
    $year + 1900, $mon+1, $mday, $hour, $min, $sec);
}

如果我从函数中删除关键字“sub”,它就会消失。

这样可以吗,还是我应该寻找不同的解决方案?

【问题讨论】:

  • 上下文,请。包括一些代码,以便我们可以看到发生了什么。
  • 您可能想先开始阅读 Perl 教程或入门书籍。

标签: perl


【解决方案1】:

不,删除sub 关键字绝对是不是的解决方案。如果你改变这个:

sub func($@) {
    # ...
}

到这里:

func($@) {
    # ...
}

perlcritic 不再抱怨原型——但我认为这只是 perlcritic 的一个小故障。没有sub 关键字,这不再是子程序定义;这是一个语法错误,您会看到是否尝试运行它或使用perl -cw 检查它。检查你的代码是否是有效的 Perl 并不是 perlcritic 的工作。它显然假设它是,然后警告您有关样式问题。如果你喂给它无效的 Perl,所有的赌注都会被取消。

如今的普遍看法是,使用 Perl 原型通常不是一个好主意。

Perlcritic 改编自 Damian Conway 的书 "Perl Best Practices"。从第 194 页开始的部分标题为“不要使用子程序原型”。

这本书不是公开的,所以我不能在这里引用或链接到该部分,但 chromatic 有一个 blog entry“原型问题”,其中包括:

原型的主要问题是它们的行为不同于 大多数人在第一次遇到它们时会期待。原型可以改变 后续代码的解析,他们可以强制类型 论据。它们不能作为数量或类型的文档 参数子例程期望,也不会将参数映射到命名 参数。

很容易假设 Perl 的原型类似于 C 的原型,它们声明函数期望的参数的数量和类型(以及可选的名称)。事实上,它们完全不同。它们的主要目的是编写模仿内置函数行为的 Perl 子例程,例如不将数组扁平化为列表。

另见perldoc perlsub

当然,这一切都非常强大,并且应该只用于 适度让世界变得更美好。

【讨论】:

    【解决方案2】:

    正如消息所示,您使用了subroutine prototypes。你很可能不需要它们。

    目前您的子程序定义可能类似于:

    sub foo()
    

    改成:

    sub foo
    

    注意删除() 以及介于两者之间的任何内容。

    【讨论】:

      【解决方案3】:

      Perl::Critic 认为子程序原型不好。这与“sub”关键字无关,而是函数参数定义。删除“sub”会诱使 Perl::Critic 不报告错误,但您的代码无论如何都不会运行

      您可能希望在以下两种情况之一中使用子例程原型:

      1. 你想用你的函数参数执行一些“魔法”,例如:

        子乐趣1(\@) { 我的 ($ar_ref) = @_ }

      这样的电话

      fun1(@args)  
      

      不会将@args 吞入@_,但会将@args 作为数组引用传递给@_[0]

      1. 你想清楚地说明函数签名

        sub fun2($$\%) { }

      fun2 args 是一个标量,另一个标量和一个哈希引用

      Perl 最佳实践书提供了两种情况的使用场景,您很容易被自己的代码搞砸。 PBP 给出的修正是:不要使用原型。

      如果你仍然想使用它们,你可以告诉 Perl::Critic 不要报告原型的使用:

      ## no critic
      # Perl::Critic will ignore any problems it sees with your code
      sub func_With_prototypes ($$$)
      {
      return undef
      }
      ## use critic
      # Perl::Critic will report any problems it sees within your code
      

      【讨论】:

      • 这是子程序:sub zFormatDate() { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = shift; return sprintf("%04d%02d%02d%02d%02d%02d", $year + 1900, $mon+1, $mday, $hour, $min, $sec); } 并使用:$lSortDate = zFormatDate($lSortDate);代码中还有其他子程序不会引发错误,所以我需要用这个子程序进一步调查
      • 删除 (),无论如何它们都会误导您的函数原型。它应该是 sub zFormatDate { ... }
      • sub zFormatDate () {...} 也是一个原型,它说 zFormatDate 由于“()”而具有零参数,因此删除 () 将停止批评者抱怨它
      【解决方案4】:

      较新的 Perls 有一个签名功能,虽然它仍然被标记为实验性的,但它非常流行,它被这个规则标记了。签名是在这篇原始帖子之后引入的,可能是 En-Motion 想要的。

      由于 Catalyst 广泛使用原型,因此不能弃用原型。 Catalyst 破解原型以提供动态路由系统。

      如果您使用签名功能(或 Catalyst),最好的解决方案是通过 ~/.perlcriticrc 禁用规则。

      将以下内容添加到 ~/.perlcriticrc

      [-Subroutines::ProhibitSubroutinePrototypes]

      虽然签名在 PerlCritic 看来就像原型,但它们是现代 Perl 编程的基本元素。

      考虑:

      sub add2nums { 我的 $num1 = shift;我的 $num2 = 班次;返回 $num1 + $num2 ; }

      带签名:

      使用特征“签名”;

      sub add2nums ( $num1, $num2 ) { return $num1 + $num2 ; }

      【讨论】:

        【解决方案5】:

        我猜

        sub zFormatDate() {
          my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = shift;
          return sprintf("%04d%02d%02d%02d%02d%02d",
            $year + 1900, $mon+1, $mday, $hour, $min, $sec);
        }
        

        旨在阅读

        sub zFormatDate($$$$$$$$$) {
          my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = @_;
          return sprintf("%04d%02d%02d%02d%02d%02d",
            $year + 1900, $mon+1, $mday, $hour, $min, $sec);
        }
        

        即:提供9个参数的原型,并正确设置my变量。

        【讨论】:

          猜你喜欢
          • 2023-03-26
          • 2011-12-29
          • 1970-01-01
          • 2015-06-22
          • 2014-11-25
          • 1970-01-01
          • 2014-11-05
          • 2014-02-07
          • 1970-01-01
          相关资源
          最近更新 更多