【问题标题】:How can I use "member" variables of a module inside a function?如何在函数内使用模块的“成员”变量?
【发布时间】:2013-09-18 12:16:10
【问题描述】:

我有这个代码:

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

当我运行测试脚本时它不起作用。我明白了:

in sub author=jim lang = eng​​p>

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

我该如何解决这个问题?

【问题讨论】:

  • 每当你使用一些奇怪的方法来动态创建一个命名变量时,你应该考虑使用散列。
  • -1。即使修复了编译错误,代码也无法提供该输出。
  • @ikegami:我不明白你的意思。如果你复制粘贴代码,你应该得到我提到的相同的错误/警告。我使用 Perl 5-14 Cygwin 以防万一
  • 尽管您进行了编辑,但一旦您修复了编译错误,它仍然无法编译或给出错误。但我知道你改变了什么。固定。
  • @ikegami: 你是什么意思它不能编译。在你的评论之后,我复制/粘贴代码并运行它。我唯一的问题是一个错误的变量名称(我的坏那里)。除此之外,这是我得到的错误

标签: perl perl-module


【解决方案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} );
    ...
}

【讨论】:

  • 如果你想将一个字符串插入到一个模板中,通常sprintf会是选择,而不是eval
  • 如何解决变量超出范围的问题?
  • 另外这不起作用。它给出:Can't find string terminator "ENG" anywhere before EOF
  • @hobbs:什么意思。我复制的完全一样
【解决方案2】:

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 使“无效上下文”警告静音。)


也就是说,您似乎正在尝试重新发明wheel。不要发明另一个半途而废的模板系统。

【讨论】:

  • 我不明白示例 1 与示例 2 有何不同,或者我如何在我的情况下使用它们
  • 在第一个 sn-p 中,$x 在调用 f() 时不再存在。在第二个 sn-p 中,$x 仍然存在。看看卷发。
  • 简而言之:我需要一种将模块中“封装”的变量插入字符串的方法。
  • @Jim,这就是所谓的模板。我已将您链接到适当的模板系统。
【解决方案3】:

我在看几件事:

  • 首先,$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 是用our 声明的,而不是my。这使得它在整个包中都可用,包括我包中的任何子例程。

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

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

我也更喜欢在我的程序头上使用#! /usr/bin/env perl,因为它与Perlbrew 之类的东西更兼容。您正在使用/usr/bin/env 来查找用户路径中的可执行 Perl 程序。这样,你就不必知道是/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.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 2012-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-08
    • 1970-01-01
    相关资源
    最近更新 更多