我试图找出绑定操作是如何在属性上工作的,以及是什么使它与nqp::bindattr有如此大的不同。请考虑以下示例:
class Foo {
has @!foo;
submethod TWEAK {
my $fval = [<a b c>];
use nqp;
nqp::bindattr( nqp::decont(self), $?CLASS, '@!foo',
#@!foo :=
Proxy.new(
FETCH => -> $ { $fval },
STORE => -> $, $v { $fval = $v }
)
);
}
method check {
say @!foo.perl;
}
}
my $inst = Foo.new;
$inst.check;它打印:
$["a", "b", "c"]
用注释中的绑定运算符替换nqp::bindattr可以得到正确的输出:
["a", "b", "c"]
类似地,如果foo是一个公共属性,并且使用了访问器,那么由于访问器内部发生反特化,输出也将是正确的。
我在AttrX::Mooish模块中使用类似的代码,其中使用:=会使实现过于复杂。到目前为止,nqp::bindattr为我做了很好的工作,直到上面的问题出现为止。
我试图跟踪Rakudo的内部元素,寻找:=实现,但到目前为止没有取得任何成功。我想在这里要求一个关于如何模拟操作符的建议,或者在源中寻找它的实现的位置。
发布于 2018-10-02 18:14:27
在我深入研究答案之前:这篇文章中的大部分内容都是由实现定义的,而且将来实现可以自由地以不同的方式定义它们。
要找出在Rakudo 6下编译的东西(天真地),请使用--target=ast选项(perl6 --target=ast foo.p6)。例如,绑定:
class C {
has $!a;
submethod BUILD() {
my $x = [1,2,3];
$!a := $x
}
}以下列形式出现:
- QAST::Op(bind) :statement_id<7>
- QAST::Var(attribute $!a) <wanted> $!a
- QAST::Var(lexical self)
- QAST::WVal(C)
- QAST::Var(lexical $x) $x在将其转换为@!a时,如下所示:
class C {
has @!a;
submethod BUILD() {
my $x = [1,2,3];
@!a := $x
}
}以下列形式出现:
- QAST::Op(bind) :statement_id<7>
- QAST::Var(attribute @!a) <wanted> @!a
- QAST::Var(lexical self)
- QAST::WVal(C)
- QAST::Op(p6bindassert)
- QAST::Op(decont)
- QAST::Var(lexical $x) $x
- QAST::WVal(Positional) decont指令是这里最大的区别,它将通过调用它的FETCH来获取Proxy的内容,因此容器化就消失了。因此,您可以通过在nqp::decont周围插入Proxy来复制行为,尽管这就回避了一个问题:如果没有正确的答案,Proxy在那里做什么!
:=和=都是使用案例分析(即通过查看左手边的内容)进行编译的。:=只适用于左侧的有限范围的简单表达式;它显然是一个低级操作符。相反,如果案例分析没有提供更有效的发出形式,那么=就回到了sub调用,尽管在大多数情况下它管理的更好。
:=的案例分析在目标是带有sigil @或%的词法或属性时插入decont,因为--在Perl 6级别--将项绑定到@或%没有意义。使用nqp::bindattr会降低Perl 6的语义,因此可以直接使用Proxy绑定。然而,这也违背了其他方面的期望。不要指望这样做会很顺利(但看来你无论如何都不想这么做)。
https://stackoverflow.com/questions/52613076
复制相似问题