2

我对 Perl 很陌生,正在尝试解决 Llama 书中的一些练习问题。问题是编写一个子例程,如果他是第一个人,则欢迎他,或者告诉他之前在场的人的名字。我的代码看起来像:

#! perl

# This is the greeter problem .

sub greetPerson{
    state $previous = undef ;

    if($previous eq undef){
     print " Welcome ... u r the first \n";
    }
    else{
     print " Hi ... $previous was already here \n";
    }

    $previous = $_;
    return 0; 
}

@code = ("ravi" , "teja" , "chandu");
greetPerson($code[0]);
greetPerson($code[1]);
greetPerson($code[2]);

我收到一条错误消息

 "Can't call method state on undefined value in Line 6.  "

请帮助我了解这意味着什么,为什么会出现以及如何解决它..?我了解“状态”与其他语言(C / Java)中的“静态”同义。我错了吗?

4

2 回答 2

9

state是一个相当新的特性(自 Perl 5.10 起),默认情况下不启用。要启用它:

use feature 'state';

使用state有点相当于在 Java 中使用静态变量。另一种没有状态的方法是$previous使用简单my的外部声明greetPerson,这意味着它在整个脚本中的范围内。

顺便说一句,您还应该在所有脚本中包含这些行,以免在跟踪过程中遇到很多麻烦:

use strict;
use warnings;

此外,greetPerson你需要得到你的论点,你可以从@_. 例如

my ($name) = @_; # or
my $name = $_[0];
于 2012-05-30T01:15:12.440 回答
2

是的; 你搞错了(但我也搞错了)。 AFAIK,state在 Perl 中没有特定含义(但有人说这是必须启用的新功能)。


嗯...Perl 5.14.2 有一个函数state. 它是在 5.10.0 中引入的;我在我的机器上检查了一个 5.10.0 版本,它就在那里,尽管我不知道它。 DavidO 很有帮助地确认state了 5.8 系列的 Perl 版本中没有它。更改是在 5.10.0 中添加的。

因此,您需要一个足够现代的 Perl 版本,并且需要通过以下方式启用它:

use feature 'state';

未启用该state功能时,它看起来像一个方法调用,并且由于未定义该方法,因此您会看到您看到的错误。当然,即使启用它也是一个方法调用;或者,至少,它既被列为函数又被描述为函数,但它是具有特殊语义的内置函数。

万一您没有意识到,StackOverflow 的一大优点是您可以通过回答问题来学习。

您可能正在寻找my(或ourlocal,但这里不太可能)。

但是,子程序中的变量会在子程序退出时消失,所以甚至my不是您想要的。

在没有 的情况下state,您可能会使用全局变量(没有任何初始化,因此在第一次传递时其值为undef):

my $previous;

在函数之外,然后您只需在函数中引用它:

sub greetPerson{

    if ($previous eq undef){
     print " Welcome ... u r the first \n";
    }
    else{
     print " Hi ... $previous was already here \n";
    }

    $previous = $_[0];
    return; 
}

这也解决了$_与传递给函数的参数无关的问题。你最好写:

sub greetPerson{
    my($who) = @_;
    if ($previous eq undef){
        print " Welcome ... u r the first \n";
    }
    else{
        print " Hi ... $previous was already here \n";
    }

    $previous = $who;
    return; 
}

通常,您还应该使用use warnings;use strict;。专家使用它们来确保他们没有犯愚蠢的错误。新手也应该​​这样做。这确实意味着您必须声明所有变量。

好处之一state是它允许您隐藏一个变量,否则该变量必须是全局的(或者如果您正在使用模块,则在模块级别隐藏)在它真正属于的函数中。因此,这是一个有用的功能。


从评论中

我正在传递一个标量(@code[0])。那么,为什么我需要在@_[0]那里使用呢?是$_不是一个?但不知何故,@_[0]工作而不是$_......你能解释一下吗?

整个故事很复杂,但是 Perl 将参数传递给函数的方式是作为数组。在函数内部,参数在@_. 变量$_无关@_(除了其名称的最后一个字符相同)。

注意:我已将第一个示例修改为引用$_[0]而不是@_[0]. 那是访问数组的第零个元素,并且与标量@_无关。$_这是 Perl 确实会引起混淆的一个领域。(如果@_[0]真的有效,那么要么我很幸运,要么 Perl 6 关于 sigils 的一些想法正在悄悄进入 Perl 5.1x。)

随着时间的推移,你会习惯这种表示法:

sub some_name_or_other
{
    my($arg1, $name2, $obj3, $ref4, $hash5, @the_rest) = @_;
    ...
}

这会将前 5 个参数分配给标量变量,并将剩余的任何内容填充到本地数组@the_rest中。如果你用太少的参数调用它,你会得到undef值。列表中的括号my(...)很重要。他们提供列表上下文并使其工作。省略括号,事情就会出错。但是,列表上下文是一个比我想在这里详细讨论的更大的主题;有关详细信息,请查看 Llama 书(或 Camel 书,或在线)。

如果你打算只引用一次参数,保证不改变值,你可以使用$_[0]符号;如果您要更频繁地使用它,请使用my变量。最好还是使用my变量;更便于理解。

于 2012-05-30T01:15:44.927 回答