2

我有这个代码:

#!/usr/bin/perl

package Modules::TextStuff;  

use strict;  
use warnings;  
use Exporter;  
our @ISA = qw(Exporter);  
our @EXPORT = qw(get_text);  

my $author;  

my $text_tmp1 =<<'ENG';  
This is a template text  
by $author.   
ENG


sub get_text {  
        my $tmp = shift @_;  
        $author = shift @_;  
        print "In sub author= $author lang = $tmp \n";  
        my $final_str = eval('$text_'.$tmp);  
        print "$final_str \n";  
        return $final_str;  
}  
1;  

测试脚本:

#!/usr/bin/perl  

use strict;  
use warnings;  

use Modules::TextStuff;  

my $str = get_text('tmp1','jim');  
print $str;  

当我运行测试脚本时它不起作用。我得到:

在子作者=jim lang = eng

变量“$text_tmp1”在 (eval 1) 第 2 行不可用。在连接 (.) 或字符串中使用未初始化的值 $final_str

我怎样才能解决这个问题?

4

3 回答 3

1

组合字符串来创建变量名称通常是一个坏主意。our $text_tmp1 = ...您可以使用而不是挽救您当前的程序my $text_tmp1 = ...,但我认为您应该考虑一种不同的方法,例如哈希:

my %templates = (

    tmp1 => <<ENG,
This is a template text
by \$author.
ENG

    tmp2 => <<ESP,
Esta es templata texta de \$author.
ESP
);

sub get_text {
    ...
    my $final_str = eval( $templates{$tmp} );
    ...
}
于 2013-09-16T22:22:04.513 回答
1

您询问的错误是在eval EXPR尝试获取确实存在但不再存在的变量的值时生成的。

>perl -wE"{ my $x = 123; sub f { eval '$x' } } say '<'.f().'>';"
Variable "$x" is not available at (eval 1) line 2.
Use of uninitialized value in concatenation (.) or string at -e line 1.
<>

请记住,执行文件(例如脚本或模块)是在其自身的词法范围内完成的,就像上面 curlies 创建的那样。


可以通过不让它超出范围来保持变量处于活动状态来修复它

>perl -wE"my $x = 123; sub f { eval '$x' } say '<'.f().'>';"
<123>

但这不是你的选择。

其他选项包括使变量成为全局变量。

>perl -wE"{ our $x = 123; sub f { eval '$x' } } say '<'.f().'>';"
<123>

或者强迫潜艇捕获它,这样它就不会不复存在。

>perl -wE"{ my $x = 123; sub f { $x if 0; eval '$x' } } say '<'.f().'>';"
<123>

if 0静音“无效上下文”警告。)


也就是说,看起来您正在尝试重新发明轮子。不要发明另一个半途而废的模板系统。

于 2013-09-17T00:54:20.323 回答
0

我在看几件事:

  • 首先,$text_tmp1不是包变量。自从你用my. 如果您需要它作为包变量并使其在所有或您的子例程中可见,则需要使用our.
  • 您的模块未按书面方式编译。您正在尝试来源$author,但未定义。
  • 你在做什么eval?这在很多层面上都是错误的。

这是我的做法:

#! /usr/bin/env perl

package Modules::TextStuff;  

use strict;  
use warnings;  
use Exporter qw(import);
use Carp;
our @EXPORT_OK = qw(get_text);

our %templates;                # This is now a package variable

#
# TEMPLATES
#

$templates{tmp1}=<<TEMPLATE;   # We'll use `%s` for replacements
This is a template text  
by %s.
TEMPLATE

$templates{tmp2}=<<TEMPLATE;
This is another template and we will substitute 
in %s in this one too.
TEMPLATE

sub get_text {  
    my $template = shift;  
    my $author   = shift;
    if ( not exists $templates{$template} ) {
        croak qq(Invalid template name "$template");
    }
    return sprintf $templates{$template}, $author;
}
1;

我会将这些模板中的每一个都作为我的%templates哈希中的一个条目。无需eval计算模板的变量名。另请注意,我现在可以使用exists实际测试用户是否传入了有效模板。

另请注意,%template声明为 withour和 not my。这使得它在整个包中都可用,包括我包中的任何子例程。

我也使用@EXPORT_OK而不是@EXPORT. 它被认为更有礼貌。您正在请求污染用户命名空间的权限。这就像敲别人的门并询问您是否可以喝啤酒,而不是闯入并在他们的冰箱中翻找啤酒。

请注意我如何使用sprintf来处理可替换参数。这再次消除了对评估的需要。

我也更喜欢在我的程序头上使用,因为它与Perlbrew#! /usr/bin/env perl之类的东西更兼容。您用于查找用户路径中的可执行 Perl 程序。这样,您不必知道它是, , , 还是/usr/bin/env/bin/perl/usr/bin/perl/usr/local/bin/perl$HOME/perl5/perlbrew/perls/perl-5.18.0/bin/perl

要使用您的模块,我会这样做:

#! /usr/bin/env perl

use strict;
use warnings;
use feature qw(say);

use Modules::TextStuff qw(get_text);

say get_text('tmp1','jim');

和你打的电话差不多。这打印出来:

This is a template text  
by jim.
于 2013-09-18T03:38:44.683 回答