如何测试方法是否在 Perl 6 class 中定义?

How can I test if a method is defined in a Perl 6 class?

我经常想测试我是否在特定的 class 中定义了一个方法。这在我重命名方法或以其他方式重新安排体系结构中的内容时遇到了很多问题。

我知道我可以使用 .^lookup 但这对我来说仍然感觉很奇怪,就像我最终会 运行 进入一个 returns 顺序不同的情况我希望(暂时忽略签名)。这是我想出的:

use Test;

class Foo is Str {}
class Bar is Str { method Str { 'Hello' } }

can-ok Str, 'Str';
can-ok Foo, 'Str';
can-ok Bar, 'Str';

is Foo.^lookup( 'Str' ).package.^name, 'Foo', 'Foo defines Str';
is Bar.^lookup( 'Str' ).package.^name, 'Bar', 'Bar defines Str';

done-testing;

在这个简单的例子中它做了我想要的,到目前为止我还没有让它失败:

ok 1 - The type 'Str' can do the method 'Str'
ok 2 - The type 'Foo' can do the method 'Str'
ok 3 - The type 'Bar' can do the method 'Str'
not ok 4 -
ok 5 -
1..5
# Failed test at /Users/brian/Desktop/hello.p6 line 12
# expected: 'Foo'
#      got: 'Mu'
# Looks like you failed 1 test of 5

您不应该按名称比较类型。

my \Foo = anon class Foo {}
my \Bar = anon class Foo {}

say Foo.^name eq  Bar.^name; # True
say Foo       eqv Bar;       # False

事实上,如果您将类型对象作为第二个参数,is 会检查对象标识。

is Bar.^lookup( 'Str' ).package, Bar, 'Bar defines Str'

您可以随时添加子例程以增加清晰度。

sub defines-method (
  Mu:U $class,
  Str:D $method,
  Str:D $desc = "$class.^name() defines $method"
) {
  is $class.^lookup( $method ).?package, $class, $desc
}

defines-method Foo, 'Str';

你可以给它取一个运算符的别名

sub &infix:<defines-method> = &defines-method;

Bar defines-method 'Str';

(请注意,我使用 .?package 以防 .^lookup 没有 return 任何东西。)


.^lookup 为您提供将要调用的 Method 对象;所以我不知道你为什么要谈论它在只有一个值 returned 时以不同的顺序给你。如果有多个方法,它 return 是原型方法(可能是隐式创建的)。
如果你想要单独的 multi 方法,你可以调用 .candidates
(还有 .^find_method,我想不起来了)

我相信您正在考虑 .can,如果您使用 .*Str.+Str,它会按照调用顺序为您提供方法对象,这与方法解析顺序。这意味着它只会在您更改继承树时发生变化。

> class Bar is Str { method Str { 'Hello' } }

> quietly .perl.say for Bar.+Str;
"Hello"
""
""

> .perl.say for Bar.new.+Str
"Hello"
""
"Bar<80122504>"

> quietly .(Bar).perl.say for Bar.can('Str')
"Hello"
""
""

> .(Bar.new).perl.say for Bar.can('Str')
"Hello"
""
"Bar<86744200>"