我需要将一些代码从外部程序传递到类中。
在通用模块中,我拥有(为简单起见,简化为愚蠢的)
class A {
has &.hl;
submethod BUILD( :&!hl ) {}
}
在程序的其他地方,我有use A;
my &hl = -> $st {
my $p = shell "hl $st", :in,:out;
$p.out.slurp
};
my $statement = 'my $raku-variable = "Helloooo";'
my $first = &hl($statement);
my A $a .= new(:&hl);
my $second = $a.hl( $statement );
$first
将被处理,并将包含预期的结果。在
$second
,我会收到一个运行时错误Too many positionals passed; expected 1 argument but got 2
显然,该类中的例程同时被提供了invocant和参数$s
。重写类以提供自定义访问器:
class A {
has &!hl;
submethod BUILD( :&!hl ) {}
method process-it( Str $s --> Str ) { &!hl( $s ) }
}
# elsewhere
my $second = $a.process-it( $statement );
然后,$first
和$second
都将运行且没有错误,并且将包含相同的结果。当在类内部访问
hl
时,不添加任何发起人,但是如果未将其声明为&.hl
,则在类外部不可见。因此,我的问题是:是否存在另一种创建公共(public)对象代码变量的方法,该变量不会自动将倡导者作为变量添加到代码中?除了创建单独的访问器方法外。
这是简短的bash脚本
hl
以供说明#! /bin/bash
echo '<div class="statement">'$1'</div>'
这是完整的Raku程序use v6.c;
class A {
has &!highlighter; # also tried with has &highlighter
submethod BUILD( :&!highlighter ) {}
method process-it( Str $s --> Str ) {
&!highlighter( $s )
}
}
sub MAIN() {
my @strings = 'my $v = "Hello World";', 'my $w = $v.raku;';
my $proc;
my $proc-supply;
my &highlighter = -> $s {
my $p = shell "./hl '$s' ", :in,:out;
$p.out.slurp
}
for @strings {
say .&highlighter
}
my A $a .= new(:&highlighter);
for @strings { say $a.highlighter($_) }
# own accessor
for @strings { say $a.process-it($_) }
}
最佳答案
has $!hl
声明一个私有(private)属性。 has $.hl
声明一个公共(public)属性。
公开的意思是,它创建了一个同名的方法并将其返回,并将其添加到BUILD
/gist
/perl
/Capture
[sub]方法中。
class A {
has &.hl;
}
这实际上与以下内容相同:
class A {
has &!hl;
submethod BUILD ( :&!hl ){}
method hl (){ &!hl } # return the code object
method perl (){
"A.new(hl => $!hl.perl())"
}
method gist (){ self.perl }
method Capture () {
\( :&!hl )
}
}
因此,当您调用
A.hl
时,它将返回存储在&!hl
中的代码对象。您可以通过几种方式来处理。
$a.hl()(42)
$a.hl().(42)
$a.hl.(42)
method call-it ( |C ){
&!hl( |C )
}
$a.call-it( 42 )
my &hl = $a.hl;
请注意,我使用
|C
来避免完全处理签名。对于您来说,签名并像对待签名一样处理可能是有意义的。
method hl ( |C ){
&!hl( |C )
}
$a.hl( 42 )
通过覆盖它,使它成为公共(public)属性的所有其他更改仍将为您完成。
因此,无需创建
BUILD
子方法。 覆盖它时,这意味着
is rw
不起作用。这也意味着外部代码无法检索代码对象本身。
如果需要,有一些方法可以解决。
如果您不需要返回
&!hl
中的值,则只需像上面一样保留它即可。multi method hl (){ &!hl }
multi method hl ( |C ){
&!hl( |C )
}
$a.hl; # returns the value in $!hl
$a.hl(); # returns the value in $!hl
$a.hl( 42 ); # calls &!hl(42)
注意,没有方法可以区分
.hl
和.hl()
。 multi method hl ( :code($)! ){ &!hl }
multi method hl ( |C ){
&hl( |C )
}
$a.hl(:code); # returns the value in &!hl
$a.hl; # calls &!hl()
$a.hl(); # calls &!hl()
$a.hl( 42 ); # calls &!hl(42)
(这就是为您创建
Capture
方法的原因)class A {
has &.hl;
method hl ( |C ){
&!hl( |C )
}
}
sub get-hl ( A $ ( :&hl ) ){ &hl }
my &hl = get-hl($a);
my &hl = -> A $ ( :&hl ){ &hl }( $a );
my &hl = $a.Capture{'hl'};