【问题标题】:How can I share variables between a base class and subclass in Perl?如何在 Perl 中的基类和子类之间共享变量?
【发布时间】:2011-02-09 22:33:37
【问题描述】:

我有一个这样的基类:

package MyClass;

use vars qw/$ME list of vars/;
use Exporter;
@ISA = qw/Exporter/;
@EXPORT_OK = qw/ many variables & functions/;
%EXPORT_TAGS = (all => \@EXPORT_OK );

sub my_method {

}
sub other_methods etc {

}

--- more code---

我想继承MyClass,但只针对一种方法。

package MySubclass;

use MyClass;
use vars qw/@ISA/;
@ISA = 'MyClass';

sub my_method {

--- new method

}

我想调用这个MySubclass,就像我调用原来的MyClass一样,并且仍然可以访问Exporter中的所有变量和函数。但是,我在从原始类MyClass 中获取Exporter 变量以正确导出时遇到问题。我需要在子类中再次运行Exporter 吗?这似乎是多余且不清楚的。

示例文件:

#!/usr/bin/perl

use MySubclass qw/$ME/;

-- rest of code

但是当我尝试导入 $ME 变量时出现编译错误。有什么建议吗?

【问题讨论】:

  • 始终包含您收到的错误消息。
  • 好吧,在这种特殊情况下,当我尝试使用“使用 MySubclass qw/$ME/;”时,我会遇到内部服务器错误即使它在 eval 中:“eval { use MySubclass qw/$ME/; };”,但是如果我只是说“eval { use MySubclass; };”一切都找到了,花花公子
  • 类数据 + 继承 = 专业的秘诀,未来的主要故障。
  • 向我们显示错误消息。服务器的错误日志中有什么?你知道,我们不是通灵者。
  • 基本上我没有在 MYSubclass 中使用 Exporter,因此当我添加 $ME 时它无法找到它。我希望我能够自动执行此操作,但我现在明白我需要导入所有变量,然后在我的子类中再次将它们重新导出。

标签: perl class inheritance subclass exporter


【解决方案1】:

您应该通过方法访问所有内容。忘记传递变量。

您收到语法错误是因为您有语法错误:

 use MySubclass /$ME/; # syntax error - that's the match operator

你想要一个列表:

 use MySubclass qw/$ME/;

但是,不要那样做。通过方法提供对这些数据的访问。由于您将继承这些方法,因此您不需要(也不应该使用)Exporter:

 package MyClass;

 BEGIN {
 my $ME;
 sub get_me { $ME }
 sub set_me { $ME = shift }
 }

现在你的子类只是:

 package MySubclass;
 use parent( MyClass );
 sub my_method { ... }

如果您需要共享许多变量,有多种模块可以自动为您处理访问者详细信息。

【讨论】:

  • 我在编写示例时只是忘记包含“qw”。我意识到我可以通过方法导出任何变量,但我希望有一种方法可以导出所有变量,而无需为每个变量创建方法。如果我调用“使用 MyClass qw/:all/;”我可以访问我的所有变量。我希望它以相同的方式工作,但使用“使用 MySubclass qw/:all/;”
  • 那么,回去解决你的问题吧。不要输入新代码。向我们展示真正的代码。
  • 真正的代码是复杂和繁琐的发布方式。我只发布了我的问题所必需的内容。
  • @Jonathan:您认为与您的问题相关的代码和与您的问题实际上相关的代码通常是不相交的集合。 shadowcat.co.uk/blog/matt-s-trout/show-us-the-whole-code
  • Dave - 可以理解,但我的问题不是关于特定的错误消息,而是关于如何用 perl 完成某些事情......我只是用我的代码作为我正在尝试的示例完成。
【解决方案2】:

一般来说,OO Perl 和 Exporter 通常是分开的,而不是混合在一起。这也是原因之一。

就像布赖恩说的那样,如果你把导出的所有废话都拿出来,把它变成类属性/方法,你会更容易让它首先工作,并在未来进一步扩展它,并彻底摆脱 Exporter。您想要执行此操作的方式需要您导入和重新导出所有内容这一简单事实应该是一个重要的、闪烁的线索,表明可能有更好的方式来执行此操作(即,一种不涉及 Exporter 的方式)。

【讨论】:

  • 我意识到这不是最好的主意,我打算寻找另一种方法。然而,我确实假设 perl 在使用 OOP 时会自动导出变量,但我开始理解为什么这是一个坏主意。我会找到另一种方法,但至少现在我知道我该怎么做(导入而不是再次导出),但前提是完全必要。
【解决方案3】:

您实际上根本没有从MyClass 继承MySubclass -- MySubClass MyClass 的用户。你正在做的是覆盖MyClass 的一些行为,但如果你认为这是继承,你只会混淆自己,因为它不是(例如:你的构造函数在哪里?)我想不通找出你想要做的事情,直到我忽略了代码正在做的所有事情,然后阅读你对你想要发生的事情的描述。

好的,所以你有一个导入一些符号的类 - 一些函数和一些变量:

package MyClass;
use strict;
use warnings;

use Exporter 'import';    # gives you Exporter's import() method directly
our @EXPORT_OK = qw/ many variables & functions/;
our %EXPORT_TAGS = (all => \@EXPORT_OK );
our ($ME, $list, $of, $vars);

sub my_func {

}
sub other_func {

}
1;

然后你开始编写一个从 MyClass 导入 所有内容 的类,然后再次将其全部导入,但将一个函数换成另一个函数:

package MyBetterclass;
use strict;
use warnings;
use Exporter 'import';    # gives you Exporter's import() method directly
our @EXPORT_OK = qw/ many variables & functions /;
our %EXPORT_TAGS = (all => \@EXPORT_OK );
use MyClass ':all';

sub my_func {
    # new definition   
}
1;

就是这样!请注意,我启用了严格检查和警告,并更改了实际上是函数的“方法”的名称。 此外,我没有使用use varsdocumentation 表示它已过时,因此如果您仍想在不了解其机制的情况下使用它,这是一个很大的危险信号)。

【讨论】:

  • 您输入的代码会打印出很多错误消息并死掉: $ ./ether-test.pl 全局符号“@EXPORT_OK”需要在 EtherBetterClass.pm 第 5 行显示包名。全局符号“%EXPORT_TAGS”需要在 EtherBetterClass.pm 第 6 行显示包名称。全局符号“@EXPORT_OK”需要在 EtherBetterClass.pm 第 6 行显示包名称。错误后 BEGIN 不安全——编译在 EtherBetterClass.pm 第 7 行中止。编译在 ./ether-test.pl 第 4 行的要求中失败。开始失败--编译在 ./ether-test.pl 第 4 行中止。
  • 所以基本上答案是我必须导入所有变量,然后使用 Exporter 再次导出。显然没有办法自动做到这一点?正确的?我使用“use vars”而不是“our”,因为我计划将我的脚本分发给可能使用或不使用最新版本 perl 5 的人。
  • Kinopiko - 您收到该错误是因为必须声明变量,我再次使用“use vars qw(@EXPORT_OK %EXPORT_TAGS);”虽然新的方式只是用“我们的”声明它们,就像用“我的”或“本地”声明一样
  • @Kino:哦,我在完成最后一次编辑之前被叫走了。现已修复。
【解决方案4】:
        # use setters and getters the Perl's way 
        #
        # ---------------------------------------
        # return a field's value
        # ---------------------------------------
        sub get {

            my $self = shift;
            my $name = shift;
            return $self->{ $name };
        }    #eof sub get


        #
        # ---------------------------------------
        # set a field's value
        # ---------------------------------------
        sub set {

            my $self  = shift;
            my $name  = shift;
            my $value = shift;
            $self->{ $name } = $value;
        }
        #eof sub set


        #
        # ---------------------------------------
        # return the fields of this obj instance
        # ---------------------------------------
        sub dumpFields {
            my $self = shift;

            my $strFields = ();
            foreach my $key ( keys %$self ) {
                $strFields .= "$key = $self->{$key}\n";
            }

            return $strFields;
        }    #eof sub dumpFields

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-10
    • 2012-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多