cod*_*ons 10 oop composition mixins rakudo raku
如果我有一个Role R定义为:
role R { method answer { 42 } }
Run Code Online (Sandbox Code Playgroud)
这两行之间有什么区别(如果有的话):
my $a = 'question' does R;
my $b = 'question' but R;
Run Code Online (Sandbox Code Playgroud)
它们看起来非常相似:
say $a.answer; # OUTPUT: «42»
say $b.answer; # OUTPUT: «42»
say $a.WHAT; # OUTPUT: «(Str+{R})»
say $b.WHAT; # OUTPUT: «(Str+{R})»
Run Code Online (Sandbox Code Playgroud)
这是一个有不止一种方法可以做到这一点的情况吗,这两者的意思是一样的?还是我遗漏了细微的差别?
注:
据我所知,does是既操作者和性状,因此当用于编译时混入(例如,可使用class C does R {}),而but仅仅是用于运行时混入。我也明白but可以与对象(例如,my $c = 'question' but False)does一起使用,而只能与Role. 我不是在问这些差异中的任何一个。我唯一的问题是在运行时使用Role. 我已阅读有关在 Role 中混合的文档部分,但没有看到答案。
use*_*601 10
简单地说:
does 就地修改对象(并且应谨慎使用值类型,请参阅下面的注释)
but 返回一个新对象。
当从文字创建时,它可能不那么明显,但是当与另一个对象一起使用时,我认为很清楚:
role R { method answer { 42 } }
my $question = 'question';
my $but = $question but R;
my $does = $question does R;
say $question.WHAT; # (Str+{R})
say $but.WHAT; # (Str+{R})
say $does.WHAT; # (Str+{R})
say $question.WHERE; # 129371492039210
say $but.WHERE; # 913912490323923
say $does.WHERE; # 129371492039210 <-- same as $question's
Run Code Online (Sandbox Code Playgroud)
通知我被骗了一下,交换的次序does和but。如果我保留了您的顺序,does则将$question在适当的位置修改,应用角色,这意味着but将克隆$question(及其角色)并应用角色(再次!):
my $does = $question does R;
my $but = $question but R;
say $does.WHAT; # (Str+{R})
say $but.WHAT; # (Str+{R}+{R})
Run Code Online (Sandbox Code Playgroud)
这是因为doesas 运算符在概念上类似于++or +=,也就是说,设计为在独立上下文中使用,例如
my $foo = …;
given $bar {
when 'a' { $foo does A }
when 'b' { $foo does B }
when 'c' { $foo does B }
}
Run Code Online (Sandbox Code Playgroud)
Usingbut在概念上更接近 using $foo + 1—— 除非分配给或传递给其他东西,否则几乎没有意义。
does和值类型的警告如果您does在值类型(主要是字符串、数字)上使用,则极有可能会导致意外的副作用。这是因为值类型(例如字符串)应该是不可变的并且可以相互替换。请注意以下事项:
role Fooish { }
my $foo = 'foo';
$foo does Fooish;
say 'foo'.WHAT; # (Str+{Fooish})
Run Code Online (Sandbox Code Playgroud)
这是在编译时发生的替换(因此它不会影响,例如,'foobar'.substr(0,3)在运行时发生的),但如果您将它们扔进循环中,则会导致一些真正奇怪的效果:
role Fooish { }
my @a;
@a.push('foo' does Fooish) for ^10;
say @a[0].WHAT; # (Str+{Fooish}+{Fooish}+{Fooish}+{Fooish}+{Fooish}
+{Fooish}+{Fooish}+{Fooish}+{Fooish}+{Fooish})
Run Code Online (Sandbox Code Playgroud)
应用多个卷需要的时间越长,越多,因此如果将其更改为 ^100000,请准备好等待一段时间。OTOH,这样做but会给你很好的恒定时间并且不会污染文字。AFAICT,这种行为似乎是完全有效的,但绝对可以意外地抓住你。