Oop `在Raku中将角色混合到对象中时是否使用`vs`but`运算符
如果我的Oop `在Raku中将角色混合到对象中时是否使用`vs`but`运算符,oop,mixins,raku,composition,rakudo,Oop,Mixins,Raku,Composition,Rakudo,如果我的角色定义为: role R { method answer { 42 } } 这两条线之间有什么区别(如果有): my $a = 'question' does R; my $b = 'question' but R; 它们看起来非常相似: say $a.answer; # OUTPUT: «42» say $b.answer; # OUTPUT: «42» say $a.WHAT; # OUTPUT: «(Str+{R})» say $b.WHAT; # OU
角色定义为:
role R { method answer { 42 } }
这两条线之间有什么区别(如果有):
my $a = 'question' does R;
my $b = 'question' but R;
它们看起来非常相似:
say $a.answer; # OUTPUT: «42»
say $b.answer; # OUTPUT: «42»
say $a.WHAT; # OUTPUT: «(Str+{R})»
say $b.WHAT; # OUTPUT: «(Str+{R})»
这是不是一种不止一种的方法™, 这两个词的意思是一样的?还是我忽略了一个细微的差别
注意:
我知道确实
是,因此可以用于编译时混合(例如,类C确实{}
),而但是
仅用于运行时混合。我也理解但是
可以是(例如,我的$c='question'但是False
),而可以
只能与角色一起使用。我不是在问这些差异中的任何一个;我唯一的问题是,当两者在运行时与角色一起使用时,是否存在差异。我已经看过了,但没有看到答案。简单地说:
确实
在适当的位置修改对象(应谨慎使用值类型,请参见下面的注释)
但是
返回一个新对象
当根据文字创建时,它可能不那么明显,但当与另一个对象一起使用时,我认为它非常清楚:
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
这是因为确实
,因为操作符在概念上类似于+
或+=
,也就是说,设计为在独立上下文中使用,例如
my $foo = …;
given $bar {
when 'a' { $foo does A }
when 'b' { $foo does B }
when 'c' { $foo does B }
}
使用但在概念上更接近于使用$foo+1
——除非分配给或传递给其他对象,否则基本上没有意义
针对does
和值类型的警告
如果对值类型(主要是字符串、数字)使用does
,则极有可能导致意外的副作用。这是因为值类型(例如字符串)应该是不可变的,并且可以相互替换。注意以下几点:
role Fooish { }
my $foo = 'foo';
$foo does Fooish;
say 'foo'.WHAT; # (Str+{Fooish})
这是一种在编译时发生的替换(因此它不会影响运行时发生的,例如,'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})
应用多个转鼓需要的时间越来越长,因此如果将其更改为^100000,请准备等待一段时间。OTOH,使用但是
可以为您提供很好的恒定时间,并且不会污染文字。这种行为似乎完全正确,但肯定会出乎意料地抓住你。谢谢!这是一个巨大的(令人惊讶的)区别。特别是,我不会仅仅因为我的$does=$question.answer==42而期望。我现在明白了为什么会发生这种情况,但我很高兴我在这里学到了这一点,而不是在调试时!事实上,这让我感到非常惊讶,可能值得在你的答案中明确地添加这一点。你写的很清楚,但是如果略读的话,也有人可能会错过它。@codesections是的,这个想法是你可以有一句话,它说,$foo Dos Bar
来应用这个角色,而不需要说$foo=$foo but Bar
。我想大概是用+$foo
和$foo+1
来比较。另外,FWIW,我过去总是用但是
来做运行时的东西。一旦我意识到了差异,我就开始使用does
(我应该在DateTime::Timezones
上更新我的降临节帖子,以反映这一点)@jubilatious1它最近被禁止了。
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})