如何在 NQP 中打印对象?(用于调试目的)
class Toto { has $.member = 42; }
class Titi { has $.member = 41; has $.toto = Toto.new }
my $ti = Titi.new;
say $ti;
# Titi.new(member => 41, toto => Toto.new(member => 42))
dd $ti;
# Titi $ti = Titi.new(member => 41, toto => Toto.new(member => 42))
Run Code Online (Sandbox Code Playgroud)
class Toto { has $!member; sub create() {$!member := 42}};
class Titi { has $!member; has $!toto; sub create() {$!member := 41; $!toto := Toto.new; $!toto.create; }}
my $ti := Titi.new;
say($ti);
Run Code Online (Sandbox Code Playgroud)
Cannot stringify this object of type P6opaque (Titi)
Run Code Online (Sandbox Code Playgroud)
当然,没有.gist
方法,代码调用nqp::encode
最终需要一个字符串。
将问题减少到MRE:
class foo {}
say(foo.new); # Cannot stringify ...
Run Code Online (Sandbox Code Playgroud)
简化解决方案:
class foo { method Str () { 'foo' } }
say(foo.new); # foo
Run Code Online (Sandbox Code Playgroud)
总之,添加一个Str
方法。
这听起来很简单,但有很多幕后的东西需要考虑/解释。
上述解决方案与 raku 使用的技术相同;当例程/操作期望值是字符串但不是字符串时,语言行为是尝试强制转换为字符串。具体来说,看看有没有Str
可以对该值调用的方法,如果有,就调用它。
在这种情况下,NQPNQPMu
比rakuMu
更准系统,不提供任何默认Str
方法。所以一个解决办法是手动添加一个。
更一般地说,NQP 是一种非常敌对的语言,除非您相当了解 raku 并且已经通过了 Rakudo 和 NQP 内部的课程。
一旦您掌握了该课程中的材料,我建议您考虑将 IRC 频道#raku-dev和/或#moarvm作为您的第一个停靠点,而不是 SO(除非您的目标是专门增加 SO 覆盖率) nqp/moarvm)。
正如您将看到的,您链接的 NQP 代码调用.say
了文件句柄。
然后调用这个方法。
该方法的主体是$str ~ "\n"
. 该代码将尝试强制$str
转换为字符串(就像在 raku 中一样)。这就是产生“无法字符串化”错误的原因。
在 NQP 存储库中搜索“Cannot stringify”仅匹配一些 Java 代码。而且我敢打赌你不是在 JVM 上运行 Rakudo。这意味着错误消息必须来自 MoarVM。
在MoarVM回购相同的搜索得到这条线coerce.c
在MoarVM。
在包含该行的例程中向后看,我们看到了这一点:
/* Check if there is a Str method. */
MVMROOT(tc, obj, {
strmeth = MVM_6model_find_method_cache_only(tc, obj,
tc->instance->str_consts.Str);
});
Run Code Online (Sandbox Code Playgroud)
这显示了用 C 编写的后端,寻找并调用名为Str
. (它依赖于编译器的所有三层(raku、nqp 和后端)都遵循的内部 API(6model)。)
Str
方法您需要根据需要自定义该Str
方法。例如,如果是类型对象,则打印类的名称,否则打印其$!bar
属性的值:
class foo {
has $!bar;
method Str () { self ?? nqp::coerce_is($!bar) !! self.HOW.name(self) }
}
say(foo.new(bar=>42)); # 42
Run Code Online (Sandbox Code Playgroud)
尽管有方法名称,nqpsay
例程并不期待 rakuStr
而是 nqp 本机字符串(最终成为 MoarVM 后端的 MoarVM 本机字符串)。因此需要nqp::coerce_is
(我通过浏览nqp ops doc 找到的)。
self.HOW.name(self)
是 nqp 没有 raku 的优点的另一个例子。您可以在 raku 中编写相同的代码,但在 raku 中编写它的惯用方法是self.^name
.