【问题标题】:Make required script use variables from another required script使所需的脚本使用来自另一个所需脚本的变量
【发布时间】:2012-09-13 02:55:07
【问题描述】:

我有两个模块:test1 和 test2,我需要依次运行它们的子程序。他们需要修改相同的变量 $var 并且外部脚本需要打印最终结果。不幸的是,这不起作用,并且似乎与 S.O. Question 非常相似。

#test1.pm
use strict;
package test1;
my $var;
sub step1 {
  $var = "Hello";
}
1;

#test2.pm
use strict;
package test2;
my $var;
sub step1 {
    $var = $var." World!\n";
}
1;

#execTests.pl
use strict;
require test1;
require test2;
&test1::step1;
&test2::step1;
print $test2::var;

如何使 $var 包含在两个必需包的相同范围内?

【问题讨论】:

  • 糟糕糟糕糟糕糟糕糟糕糟糕的设计。 var 是做什么用的? “正确”的解决方案可能涉及充当代理的第三个模块。
  • 我想对一系列相互依赖的测试进行测试。东测试包含一个测试步骤(点)。请解释一下这个代理模块...它将如何管理变量?

标签: perl scope require


【解决方案1】:

AFAIK 不可能让两个变量总是共享相同的值。以下是一些可以帮助您的想法:

包变量:

{
   package test1;
   our $var;
   sub step1 {$var = "Hello"}
}
{
  package test2;
  our $var;
  sub step1 {$var .= " World!\n"}
}

test1::step1();
$test2::var = $test1::var;
test2::step1();

print $test2::var;

评论:丑

参考资料:

{
  package test1;
  our $varref;
  sub init {
    my ($ref) = @_;
    $varref = $ref;
  }
  sub step1 {$$varref = "Hello"}
}
{
  package test2;
  our $varref;
  sub init {
    my ($ref) = @_;
    $varref = $ref;
  }
  sub step1 {$$varref .= " World!\n"}
}

my $var = "";
test1::init(\$var);
test2::init(\$var);

test1::step1();
test2::step1();

print $var;

评论:更好,但需要更多代码。

一个额外的共享模块:

{
  package test::shared;
  our $var;
}
{
  package test1;
  sub step1 {$test::shared::var = "Hello"}
}
{
  package test2;
  sub step1 {$test::shared::var .= " World!\n"}
}

test1::step1();
test2::step2();
print $test::shared::var;

评论:有一些优势。

显式状态

{
  package test1;
  sub step1 {
    my $state = @_;
    $state->{var} = "Hello";
    return $state;  # superfluous, but helps understanding
  }
}
{
  package test2;
  sub step1 {
    my $state = @_;
    $state->{var} .= " World!\n";
    return $state;  # superfluous, but helps understanding
  }
}

my $state = {};

$state = test1::step1($state);  # equiv: test1::step1($state), because of references
$state = test2::step1($state);

print $state->{var};

评论:这几乎是面向对象的编程。我更喜欢这种模式,因为它明确说明了何时给出共享。就多线程和重入而言,显式状态可以轻松扩展您的应用程序。

成本:明确性。语法冗长。

好处:可重入性,通过明确性清晰思路。

【讨论】:

  • 我考虑了显式状态,只是它会阻止我从测试运行器中抽象代码。一个额外的共享模块:似乎是最接近的答案。为您的简洁 +1。
  • 继续使用一个共享模块,该模块充当存储对象状态和信息的缓存。感谢您的准确回答!
【解决方案2】:

明确声明这是 BAD BAD BAD DESIGN,您可以简单地使用 glob:

==> exec.pl <==
#!/usr/bin/perl
use strict;
use warnings;
# You can omit this line, but there will be a warning about $My::Var being used only once
$My::Var = undef;
require 's1.pl';
require 's2.pl';
print $My::Var . "\n";

==> s1.pl <==
$My::Var = "Hello";


==> s2.pl <==
$My::Var .= "World";

Glob 基本上是包存储中的条目。包变量和子程序存在于包存储中;存储条目称为 glob。

http://perldoc.perl.org/perlguts.html#Stashes-and-Globs

stash 和 glob 的相对简单性,以及易于操作它们是我认为 Perl 非常酷的原因之一。

【讨论】:

  • 我从另一个 SO 问题中意识到这个糟糕的设计选项......@ikegami 可能对管理器模块有一个好点。
【解决方案3】:

主要问题是使用my 声明的变量不是包变量,不能通过使用包名完全限定它来访问。但是,即使您使用 our 声明包变量,您仍然有 test1.pmexecTests,pl 引用 $test1::vartest2.pm 正在使用 $test2::var

我建议你改用主程序本地的变量,并将其传递给两个步骤进行修改

类似的东西(经过测试和工作)

test1.pm

use strict;
use warnings;

package test1;

use parent 'Exporter';
our @EXPORT = qw/step1/;

sub step1 {
  $_[0] = "Hello";
}

1;

test2.pm

use strict;
use warnings;

package test2;

use parent 'Exporter';
our @EXPORT = qw/step2/;

sub step2 {
    $_[0] .= " World!\n";
}

1;

execTests.pl

use strict;
use warnings;

use test1;
use test2;

my $var;

step1($var);
step2($var);

print $var;

输出

Hello World!

【讨论】:

  • 很干净;但是,如果你不知道会有多少变量呢?
猜你喜欢
  • 2013-08-21
  • 2019-01-08
  • 2011-11-24
  • 2016-06-01
  • 1970-01-01
  • 2012-04-25
  • 2021-09-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多