Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop `在Raku中将角色混合到对象中时是否使用`vs`but`运算符_Oop_Mixins_Raku_Composition_Rakudo - Fatal编程技术网

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})