如何打印对象,输入 nqp
How to print an object, type in nqp
如何在 NQP 中打印对象? (用于调试目的)
在 Raku 中很容易:
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))
- NQP好像比较复杂
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);
Cannot stringify this object of type P6opaque (Titi)
当然,没有 .gist
方法,code 调用 nqp::encode
最后需要一个字符串。
目前,我拥有的是 list
和 hash
鉴别器。它不适用于对象。
sub print_something ($value, :$indent = 0, :$no-indent=0) {
if nqp::ishash($value) {
print_hash($value, :$indent);
} elsif nqp::islist($value) {
print_array($value, :$indent);
} else {
if $no-indent {
say($value);
} else {
say_indent($indent, $value);
}
}
}
在哪里
sub print_indent ($int, $string) {
my $res := '';
my $i := 0;
while $i < $int {
$res := $res ~ ' ';
$i := $i + 1;
}
$res := $res ~ $string;
print($res);
}
sub print_array (@array, :$indent = 0) {
my $iter := nqp::iterator(@array);
say_indent($indent, '[');
while $iter {
print_value(nqp::shift($iter), :indent($indent+1));
}
say_indent($indent, ']');
}
sub print_hash (%hash, :$indent = 0) {
my $iter := nqp::iterator(%hash);
say_indent($indent, '{');
while $iter {
my $pair := nqp::shift($iter);
my $key := nqp::iterkey_s($pair);
my $value := nqp::iterval($pair);
print_indent($indent + 1, $key ~ ' => ');
print_value($value, :indent($indent+1), :no-indent(1));
}
say_indent($indent, '}');
}
将问题简化为 MRE:
class foo {}
say(foo.new); # Cannot stringify ...
简化解决方案:
class foo { method Str () { 'foo' } }
say(foo.new); # foo
综上所述,增加一个Str
方法。
这听起来很简单,但是 consider/explain.
有很多幕后的东西
nqp 与 raku
上述解决方案与 raku 使用的技术相同;当 routine/operation 期望某个值是字符串但不是时,语言行为是尝试强制转换为字符串。具体来说,看看是否有一个 Str
方法可以在该值上调用,如果有,就调用它。
在这种情况下 NQP's NQPMu
, which is way more barebones than raku's Mu
,不提供任何默认的 Str
方法。所以一个解决办法就是手动加一个。
更一般地说,NQP 是一种非常敌对的语言,除非你相当了解 raku 并且已经通过 A course on Rakudo and NQP internals。
一旦您在该课程中加快了 material 的速度,我建议您考虑将 IRC 频道 #raku-dev and/or #moarvm 作为您的第一站而不是 SO(除非您的目标是专门用于增加 nqp/moarvm).
的 SO 覆盖率
调试编译器代码
如您所见,您链接的 NQP 代码在文件句柄上调用 .say
。
然后调用 this method。
该方法的主体是 $str ~ "\n"
。该代码将尝试将 $str
强制转换为字符串(就像在 raku 中一样)。这就是产生 "Cannot stringify" 错误的原因。
在 NQP 存储库中搜索 "Cannot stringify" 只匹配了一些 Java 代码。我敢打赌你不是 JVM 上的 运行 Rakudo。这意味着错误消息必须来自 MoarVM。
MoarVM 存储库中的相同搜索产生 this line in coerce.c
in MoarVM。
在包含该行的例程中向后看,我们看到 this bit:
/* Check if there is a Str method. */
MVMROOT(tc, obj, {
strmeth = MVM_6model_find_method_cache_only(tc, obj,
tc->instance->str_consts.Str);
});
这显示了用 C 编写的后端,寻找并调用名为 Str
的 "method"。 (它依赖于编译器的所有三层(raku、nqp 和后端)都遵循的内部 API (6model)。)
自定义 Str
方法
您需要根据需要自定义 Str
方法。例如,如果 class 是类型对象,则打印其名称,否则打印其 $!bar
属性的值:
class foo {
has $!bar;
method Str () { self ?? nqp::coerce_is($!bar) !! self.HOW.name(self) }
}
say(foo.new(bar=>42)); # 42
尽管有方法名称,nqp say
例程 不是 期待 raku Str
而是 nqp 本机字符串(最终成为MoarVM 后端上的 MoarVM 本机字符串)。因此需要 nqp::coerce_is
(我通过浏览 the nqp ops doc 找到的)。
self.HOW.name(self)
是 nqp 没有 raku 所具有的优点的另一个例子。您可以 在 raku 中编写相同的代码,但在 raku 中编写代码的惯用方式是 self.^name
.
如何在 NQP 中打印对象? (用于调试目的)
在 Raku 中很容易:
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))
- NQP好像比较复杂
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);
Cannot stringify this object of type P6opaque (Titi)
当然,没有 .gist
方法,code 调用 nqp::encode
最后需要一个字符串。
目前,我拥有的是 list
和 hash
鉴别器。它不适用于对象。
sub print_something ($value, :$indent = 0, :$no-indent=0) {
if nqp::ishash($value) {
print_hash($value, :$indent);
} elsif nqp::islist($value) {
print_array($value, :$indent);
} else {
if $no-indent {
say($value);
} else {
say_indent($indent, $value);
}
}
}
在哪里
sub print_indent ($int, $string) {
my $res := '';
my $i := 0;
while $i < $int {
$res := $res ~ ' ';
$i := $i + 1;
}
$res := $res ~ $string;
print($res);
}
sub print_array (@array, :$indent = 0) {
my $iter := nqp::iterator(@array);
say_indent($indent, '[');
while $iter {
print_value(nqp::shift($iter), :indent($indent+1));
}
say_indent($indent, ']');
}
sub print_hash (%hash, :$indent = 0) {
my $iter := nqp::iterator(%hash);
say_indent($indent, '{');
while $iter {
my $pair := nqp::shift($iter);
my $key := nqp::iterkey_s($pair);
my $value := nqp::iterval($pair);
print_indent($indent + 1, $key ~ ' => ');
print_value($value, :indent($indent+1), :no-indent(1));
}
say_indent($indent, '}');
}
将问题简化为 MRE:
class foo {}
say(foo.new); # Cannot stringify ...
简化解决方案:
class foo { method Str () { 'foo' } }
say(foo.new); # foo
综上所述,增加一个Str
方法。
这听起来很简单,但是 consider/explain.
有很多幕后的东西nqp 与 raku
上述解决方案与 raku 使用的技术相同;当 routine/operation 期望某个值是字符串但不是时,语言行为是尝试强制转换为字符串。具体来说,看看是否有一个 Str
方法可以在该值上调用,如果有,就调用它。
在这种情况下 NQP's NQPMu
, which is way more barebones than raku's Mu
,不提供任何默认的 Str
方法。所以一个解决办法就是手动加一个。
更一般地说,NQP 是一种非常敌对的语言,除非你相当了解 raku 并且已经通过 A course on Rakudo and NQP internals。
一旦您在该课程中加快了 material 的速度,我建议您考虑将 IRC 频道 #raku-dev and/or #moarvm 作为您的第一站而不是 SO(除非您的目标是专门用于增加 nqp/moarvm).
的 SO 覆盖率调试编译器代码
如您所见,您链接的 NQP 代码在文件句柄上调用 .say
。
然后调用 this method。
该方法的主体是 $str ~ "\n"
。该代码将尝试将 $str
强制转换为字符串(就像在 raku 中一样)。这就是产生 "Cannot stringify" 错误的原因。
在 NQP 存储库中搜索 "Cannot stringify" 只匹配了一些 Java 代码。我敢打赌你不是 JVM 上的 运行 Rakudo。这意味着错误消息必须来自 MoarVM。
MoarVM 存储库中的相同搜索产生 this line in coerce.c
in MoarVM。
在包含该行的例程中向后看,我们看到 this bit:
/* Check if there is a Str method. */
MVMROOT(tc, obj, {
strmeth = MVM_6model_find_method_cache_only(tc, obj,
tc->instance->str_consts.Str);
});
这显示了用 C 编写的后端,寻找并调用名为 Str
的 "method"。 (它依赖于编译器的所有三层(raku、nqp 和后端)都遵循的内部 API (6model)。)
自定义 Str
方法
您需要根据需要自定义 Str
方法。例如,如果 class 是类型对象,则打印其名称,否则打印其 $!bar
属性的值:
class foo {
has $!bar;
method Str () { self ?? nqp::coerce_is($!bar) !! self.HOW.name(self) }
}
say(foo.new(bar=>42)); # 42
尽管有方法名称,nqp say
例程 不是 期待 raku Str
而是 nqp 本机字符串(最终成为MoarVM 后端上的 MoarVM 本机字符串)。因此需要 nqp::coerce_is
(我通过浏览 the nqp ops doc 找到的)。
self.HOW.name(self)
是 nqp 没有 raku 所具有的优点的另一个例子。您可以 在 raku 中编写相同的代码,但在 raku 中编写代码的惯用方式是 self.^name
.