为什么我的Moo对象继承自非Moo类,为某些模块添加到父包中?

hsr*_*srv 8 perl moo gobject-introspection

我正在尝试使用GObject IntrospectionMoo在Perl中创建一个Gtk3应用程序.有一个来自Gtk的非Moo类Gtk::ApplicationWindow,我通过Moo使用它进行子类化extends 'Gtk::ApplicationWindow'.问题是,当创建该子类的对象时,它仍然是父类的类型 - 即Gtk::ApplicationWindow.

我通过继承自己的非基于Moo的类来尝试相同的事情,并且从这个子类创建的对象具有正确的类型.造成这种差异的原因是什么?

use v5.10;
use strict;
use warnings;

# Import the Gtk classes (non-Moo)
use Glib::Object::Introspection;
Glib::Object::Introspection->setup(basename => 'Gtk', version => '3.0', package => 'Gtk');
Glib::Object::Introspection->setup(basename => 'Gio', version => '2.0', package => 'Gio');

#################################################
{
    # A dummy non-Moo class
    package ClassNonMoo;
    sub new { bless {}, shift; }
}

{
    # Moo class extending the dummy class
    package ClassMoo;
    use Moo;

    extends 'ClassNonMoo';

    sub FOREIGNBUILDARGS {
        my ($class, %args) = @_;
        return ($args{app});
    }
}
#################################################

{
    # Moo class extending Gtk::ApplicationWindow
    package ClassMooGtkAppWin;
    use Moo;

    extends 'Gtk::ApplicationWindow';

    sub FOREIGNBUILDARGS {
        my ($class, %args) = @_;
        return ($args{app});
    }
}

#################################################

# Create objects of ClassMoo and ClassMooGtkAppWin
sub create_objects {
    my ($app) = @_;

    my $o1 = ClassMoo->new( app => $app );
    my $o2 = ClassMooGtkAppWin->new( app => $app );

    say "o1 = $o1\no2 = $o2";
    # Output:
    # o1 = ClassMoo=HASH(0x2f7bc50)
    # o2 = Gtk::ApplicationWindow=HASH(0x2f7bd40)
    #
    # Shouldn't o2 be of the type ClassMooGtkAppWin ?

    exit(0);
}

# We can create a GtkApplicationWindow only after creating a GtkApplication and
# running it. This code just ensures that create_object() is called once the
# application is 'active'.
my $app = Gtk::Application->new('org.test', 'flags-none');
$app->signal_connect(activate => sub { create_objects($app) });
$app->run();
Run Code Online (Sandbox Code Playgroud)

jpl*_*rom 4

“新”构造函数需要以某种方式编写以观察调用者的实际类(与子类化一起使用),但它们也可以对它们创建对象的类进行硬编码。

比较:

package MyClass;

# Considerate of subclassing
sub new {
    my $class = shift;
    return bless {}, $class;
}

# Doesn't give a shit
sub new {
    my $class = shift;
    return bless {};
}
Run Code Online (Sandbox Code Playgroud)

Glib 看起来像是 C 库的 XS 模块包装器,并且可能会对该类进行硬编码。

您可能可以尝试将对象重新祝福(在构造的对象上再次调用祝福)到您的实际子类中。不确定这将如何与 Moo 一起工作,但可能在 BUILD 方法中。

您还可以跳过继承并使用委托。创建一个属性来保存原始 Window 对象,然后将所有方法委托给它,除了子类中您自己的方法。

在 Moose(不是 Moo)中,您可以使用正则表达式来执行此操作: https: //metacpan.org/pod/Moose#handles-ARRAY-HASH-REGEXP-ROLE-ROLETYPE-DUCKTYPE-CODE

不知道如何用 Moo 很好地做到这一点。