带有^的类方法名称未正确调用

时间:2019-01-11 08:46:15

标签: perl6 raku

当我创建一个以^开头的类方法并尝试调用它时,它给我一个错误。

class C {
  method ^test () {
    "Hi"
  }
}

dd C.new.test;
Too many positionals passed; expected 1 argument but got 2
  in method test at .code.tio line 1
  in block <unit> at .code.tio line 1

如果我使用相同的方法而不使用前导^,则效果很好。

class C {
  method test () {
    "Hi"
  }
}

dd C.new.test;
"Hi"

我已经看到模块使用以^开头的方法公开类,这引发了我的问题。定义以^开头的方法名称时,为什么会出现此错误?

1 个答案:

答案 0 :(得分:8)

TL; DR 该方法正在正确调用。 ^中的foo.^bar表示“元方法”。这既不是实例方法也不是类方法。像所有方法一样,元方法既传递给调用者,也传递和另一个“原始调用者”对象作为第一个参数。

大多数用户将永远不需要考虑这些东西。但是您已经问过,所以让我们深入...

元方法

引用Meta-object protocol (MOP) P6文档页面:

  

Perl 6构建在元对象层上。

此MOP层定义了各种可以使用的内置“元方法”。

例如:

say .^attributes given class bar { has Int $!foo }

这将显示(Int $!foo).^attributes方法调用是一种元方法。在(通常是不可见的)元对象上调用它,该元对象确定P6类型在幕后的工作方式。在这种情况下,它将返回类的属性(has变量)。

但是也可以有用户定义的元方法。声明它们的一种方法是在其他普通类中:

say .^attributes given class baz { has Int $!foo; method ^attributes ($arg) { self, $arg } }

上面的baz类包含一个^attributes元方法声明,该声明覆盖了内置的元方法。需要特别说明的是,我添加了一个参数。所有元方法(至少有一个常规倡导者)都至少有一个论点。

使用此声明,而不是通过(Int $!foo)来响应.^attributes调用,您可以从self, $arg类中的.^attributes方法获取列表baz

请注意,self既不是baz实例对象也不是baz类型的对象-而是Perl6::Metamodel::ClassHOW+{<anon>}.new-而$arg 一个baz(类型)对象。

此答案的其余部分将更详细地说明正在发生的事情。

普通方法调用的回顾

首先,让我们回顾一下典型的方法调用。

语法foo.bar导致将“栏”方法(消息)发送到foo

如果foo是一个类的实例,则将“ bar”调度到该实例。有时将这种方法调用称为“实例方法”。

如果foo是对应于一个类的type object,则“ bar”被分派到该类型对象。有时将这种方法调用称为“类方法”。

在这两种情况下,“ bar”都分派到foo

foo.^bar

语法foo.^bar不同。

^指向指向另一个悬在foo上方的物体,或者与foo类型的种类有关的任何物体。< / p>

此类对象是HOW对象,它们确定对象的工作方式。这些HOW对象通常保持不可见,使工作正常,用户非常高兴地不知道它们的存在及其正在做的工作。 1

形式为foo.^bar的方法调用通常会导致P6向foo的{​​{1}}对象分配元方法调用。

这些元方法需要两个倡导者般的论点。有HOW对象。这作为常规倡导者通过。然后是HOW对象。这作为第一个普通参数传递给元方法。

这就是调用foo时通常发生的情况–元方法调用被分派到foo.^bar的{​​{1}}对象,并且foo作为普通参数存储传递可以说是“原始的煽动者”。

当没有内置 HOW元方法时

foo

如果在没有这种方法的情况下调用foo.^bar,则会收到错误消息:

.^bar

产量:

foo.^bar

请注意,发起人类型是元模型类,而不是42.^bar No such method 'bar' for invocant of type 'Perl6::Metamodel::ClassHOW'

如果用户定义的类声明了42,则P6调用它,将实例/类的Int对象作为主诉者,将“原始参与者”(^.bar)作为主旨。第一个普通论点:

HOW

脚语

1 在对象上调用foo返回其class foo { method ^bar ($arg) { self, $arg } } say foo.^bar; # (Perl6::Metamodel::ClassHOW+{<anon>}.new (foo))

.HOW

HOW对象是MOP(位于P6内部的一层)的一部分。

大多数开发人员都不需要显式地深入到这一层次。

如果您进行更深入的挖掘,则将保留指定的P6。在Rakudo中,say .HOW given class {} # Perl6::Metamodel::ClassHOW 对象的HOW通常是NQP对象:

.HOW