为什么子类不继承其父类的常量?

发布于 2024-12-10 16:43:19 字数 472 浏览 5 评论 0原文

所以我正在处理我的 Moosey 业务,我想在我使用数字的这些地方使用常量可能会很好,以明确这些数字的含义或以防它们稍后发生变化

所以在父类中我添加了标准“使用常量”

package Parent;
    use constant {
        NO_LEVEL => 0,
        MY_LEVEL => 1,
        YOUR_LEVEL => 2,
    };

package Child;
extends 'Parent';

#just to demonstrate that child can or cannot access the constant
sub printMyLevel{
 print MY_LEVEL;
}

,但子类不知道父类中设置的常量!哦!

我猜我必须施展一些驼鹿魔法才能让它正常工作,或者完全是别的东西。我对这个问题的搜索没有得到任何结果=/

So I was going about my Moosey business and I thought hey might be nice to use a constant in these places where I'm using numbers, to make it clear what these numbers mean or in case they change later

So in the parent class I added the standard 'use constant'

package Parent;
    use constant {
        NO_LEVEL => 0,
        MY_LEVEL => 1,
        YOUR_LEVEL => 2,
    };

package Child;
extends 'Parent';

#just to demonstrate that child can or cannot access the constant
sub printMyLevel{
 print MY_LEVEL;
}

but the child class is not aware of the constants set in the parent! doh!

I'm guessing I have to do some Moose magic to get this to work right, or something else entirely. My searching on this issue didnt pull up any results =/

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

难得心□动 2024-12-17 16:43:19

常量是子例程。

{
    package Parent;
    use Moose;
    use namespace::autoclean;

    use constant {
        NO_LEVEL => 0,
        MY_LEVEL => 1,
        YOUR_LEVEL => 2,
    };
    __PACKAGE__->meta->make_immutable;
};

{
    package Child;
    use Moose;
    use namespace::autoclean;

    extends 'Parent';

    sub printMyLevel {
        my $self = shift;
        my $class = ref $self;

        print $class->MY_LEVEL;
    }
    __PACKAGE__->meta->make_immutable;
}

package main;

my $child = Child->new;
$child->printMyLevel;

请记住,常量是具有空原型的子例程。 perl 利用这一点在编译期间内联它们。但是,方法调用忽略原型,因此以这种方式访问​​的可继承常量不会被内联。

Constants are subroutines.

{
    package Parent;
    use Moose;
    use namespace::autoclean;

    use constant {
        NO_LEVEL => 0,
        MY_LEVEL => 1,
        YOUR_LEVEL => 2,
    };
    __PACKAGE__->meta->make_immutable;
};

{
    package Child;
    use Moose;
    use namespace::autoclean;

    extends 'Parent';

    sub printMyLevel {
        my $self = shift;
        my $class = ref $self;

        print $class->MY_LEVEL;
    }
    __PACKAGE__->meta->make_immutable;
}

package main;

my $child = Child->new;
$child->printMyLevel;

Keep in mind that constants are subroutines with an empty prototype. perl takes advantage of this to inline them during compilation. However, method calls disregard prototypes, and therefore inheritable constants accessed this way would not be inlined.

枕头说它不想醒 2024-12-17 16:43:19

这实际上在文档中提到过,如果只是顺便说一下:

“常量属于定义它们的包。要引用另一个包中定义的常量,请指定完整的包名称,如 Some::Package::CONSTANT 中。常量可以是由模块导出,也可以作为类或实例方法调用,即作为 Some::Package->CONSTANT 或作为 $obj->CONSTANT在哪里$objSome::Package 的实例。子类可以定义自己的常量来覆盖其基类中的常量。”

This is actually mentioned in the documentation, if only in passing:

"Constants belong to the package they are defined in. To refer to a constant defined in another package, specify the full package name, as in Some::Package::CONSTANT. Constants may be exported by modules, and may also be called as either class or instance methods, that is, as Some::Package->CONSTANT or as $obj->CONSTANT where $obj is an instance of Some::Package. Subclasses may define their own constants to override those in their base class."

謸气贵蔟 2024-12-17 16:43:19

由于常量是子例程,并且您可以通过将它们作为方法调用来获得继承位已经被覆盖到了,这里有一个不同的旋转。

如果您知道您只在单个文件中工作,则可以使用词法常量来桥接包:

package Parent;
    our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL);
    *NO_LEVEL   = \0;  # this split declaration installs aliases to numbers
    *MY_LEVEL   = \1;  # into the lexicals.  since numbers are constants
    *YOUR_LEVEL = \2;  # to perl, the aliased names are also constants

package Child;

# just to demonstrate that anything below can access the constants
sub printAll {
    print "$NO_LEVEL $MY_LEVEL $YOUR_LEVEL\n";
}

Child->printAll; # 0 1 2

eval {$NO_LEVEL = 3} or print "error: $@\n";
# error: Modification of a read-only value attempted at ...

如果您在分配给常量时不需要 Perl 死机,则 our 声明会变得更简单一些(并且可以是 my):

our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2);

您可以恢复常量性质,同时仍然使用简洁的语法,并带有一点魔力:

my $constant = sub {Internals::SvREADONLY($_[$_], 1) for 0 .. $#_};

package Parent;
    $constant->(our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2));

package Child;

# just to demonstrate that anything below can access the constants
sub printAll {
    print "$NO_LEVEL $MY_LEVEL $YOUR_LEVEL\n";  # interpolates :)
}

Child->printAll; # 0 1 2

eval {$NO_LEVEL = 3} or print "error: $@\n";
# error: Modification of a read-only value attempted at ...

您当然可以省略 $constant coderef 和内联魔法:

package Parent;
    Internals::SvREADONLY($_, 1)
        for our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2);

Since the constants are subroutines and you can get inheritance by calling them as methods bit has been covered to death already, here is a different spin on things.

If you know you are only working in a single file, you can use lexical constants to bridge packages:

package Parent;
    our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL);
    *NO_LEVEL   = \0;  # this split declaration installs aliases to numbers
    *MY_LEVEL   = \1;  # into the lexicals.  since numbers are constants
    *YOUR_LEVEL = \2;  # to perl, the aliased names are also constants

package Child;

# just to demonstrate that anything below can access the constants
sub printAll {
    print "$NO_LEVEL $MY_LEVEL $YOUR_LEVEL\n";
}

Child->printAll; # 0 1 2

eval {$NO_LEVEL = 3} or print "error: $@\n";
# error: Modification of a read-only value attempted at ...

If you don't need perl to die when assigning to the constant, the our declaration gets a bit simpler (and could be a my):

our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2);

You can bring back the constant nature while still using the terse syntax with a little magic:

my $constant = sub {Internals::SvREADONLY($_[$_], 1) for 0 .. $#_};

package Parent;
    $constant->(our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2));

package Child;

# just to demonstrate that anything below can access the constants
sub printAll {
    print "$NO_LEVEL $MY_LEVEL $YOUR_LEVEL\n";  # interpolates :)
}

Child->printAll; # 0 1 2

eval {$NO_LEVEL = 3} or print "error: $@\n";
# error: Modification of a read-only value attempted at ...

You can of course omit the $constant coderef and inline the magic:

package Parent;
    Internals::SvREADONLY($_, 1)
        for our ($NO_LEVEL, $MY_LEVEL, $YOUR_LEVEL) = (0, 1, 2);
风情万种。 2024-12-17 16:43:19

将它们称为方法。

sub printMyLevel{
    my ( $self, ) = $_;
    print $self->MY_LEVEL;
}

Call them as a method.

sub printMyLevel{
    my ( $self, ) = $_;
    print $self->MY_LEVEL;
}
笑饮青盏花 2024-12-17 16:43:19

继承会影响方法调用 ($x->m),句号。

Inheritance affects methods calls ($x->m), period.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文