【问题标题】:How can I rebless an object in Perl 6?如何在 Perl 6 中重新分配对象?
【发布时间】:2017-06-11 17:56:38
【问题描述】:

另一个问题可能是“我如何从内置类型继承?”。

我真的有两个问题,但它们都来自我正在玩的同一件事。

首先,当我想进一步限制类型时,我可以创建一个类型的子集。我用MyInt 做到这一点,它接受任何Int。我通过MyInt 声明了一个变量并分配给它,但是当我检查它的名称时,我得到了Int。那么,这是怎么回事?

subset MyInt where * ~~ Int;

my MyInt $b = 137;
put 'Name: ', $b.^name;  # Int, but why not MyInt?

但是,我真正想要的是一个名为MyInt 的类,它做同样的事情。我可能想添加方法

class MyInt is Int {}   # empty subclass

my MyInt $b = 137;
put 'Name: ', $b.^name;

这看起来几乎可以正常工作,但我收到一个错误:

Type check failed in assignment to $b; expected MyInt but got Int (137)

我明白它在说什么,但不明白为什么我在使用subset 时没有得到同样的错误。这是问题 1.5。

我真正想要的是分配 137 以在我分配它时自动将其自身变成 MyInt。我知道我可以显式构造它,但是父类仍然将它变成Int而不是使用更派生类型的类型,这有点烦人:

class MyInt is Int {}   # empty subclass

my MyInt $b = MyInt.new: 137;  # Still an Int
put 'Name: ', $b.^name;

我可以覆盖new(直接取自Int.pm),但我对更改类型不知所措:

class MyInt is Int {
    method new ( $value --> MyInt ) {
        my $v = callsame; # let superclass construct it
        # But, how do I make it the more specific type?
        }
    }

my MyInt $b = MyInt.new: 137;  # Still an Int
put 'Name: ', $b.^name;

我可以bless self,但这并没有保留价值(而且我认为它不会也认为不应该。看着Int.pm,我看不出它是如何存储值。看起来它依赖于内置类型,并且可能传统上不能子类化:

class MyInt is Int {
    method new ( $value --> MyInt ) {
        my $v = callsame; # let superclass construct it
        put "v is $v";
        # But, how do I make it the more specific type?
        # $v.bless (doesn't change the type, fails return type check)
        self.bless;  # doesn't retain value
        }
    }

my MyInt $b = MyInt.new: 137;  # Still an Int
put 'Name: ', $b.^name;
put 'Value: ', $b;  # 0

有一个rebless,但这不是IntClassHow 可用的东西链的一部分:

class MyInt is Int {
    method new ( $value --> MyInt ) {
        my $v = callsame; # let superclass construct it
        put "v is $v";
        put "self is " ~ self.^name;
        put "HOW is " ~ self.HOW.^name;
        # No such method 'rebless' for invocant
        # $v.rebless: self.^name;
        $v.HOW.rebless: self.^name;
        }
    }

my MyInt $b = MyInt.new: 137;  # Still an Int
put 'Name: ', $b.^name;
put 'Value: ', $b;  # 0

【问题讨论】:

  • 1 和 1.5 是因为 subset 不会创建子类意义上的新 type,而只是命名的 type constraint .至于如何正确创建核心内置类型的子类,这也是我想知道的...... :) 上次我尝试这样做时,我放弃并恢复使用组合而不是继承。
  • 还有nqp::box_i(42, MyInt),但这仅适用于适合原生int(即64位)的整数
  • 为了避免缺少 nqp::box_I,我们可以使用 nqp::add_I 或类似的东西:use nqp; class MyInt is Int { }; nqp::add_I(100000, 0, MyInt).^name.sayMyInt
  • @timotimo:好主意,简短而甜蜜的method new(Int:D $value) { nqp::add_I(0, $value, self) };我试图通过nqp::bindattr() 设置$!value,但那段错误oO

标签: inheritance raku


【解决方案1】:

这是一个可能的解决方案:

class MyInt is Int { };
my $x = 42;
Metamodel::Primitives.rebless: $x, MyInt;
dd $x;

产生:

MyInt $x = 42

可能有一种更清洁的方式来做你想做的事,但我不知道它是什么。

重要更新Raku rebless doesn't work with inhertited classes anymore

【讨论】:

  • 这是全球范围内的行为,例如perl6 -e'class MyInt is Int { }; my $x = 42; Metamodel::Primitives.rebless( $x, MyInt); note 42.WHAT',输出(MyInt)
  • Metamodel::Primitives.rebless 调用在 raku 2019.11 上失败:New type MyInt for Int is not a mixin type in block <unit> at <unknown file> line 1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多