当我创建一个以a开头的类方法^,并尝试调用它时,它会给我一个错误.
class C {
method ^test () {
"Hi"
}
}
dd C.new.test;
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
如果我在没有前导的情况下使用相同的方法^,它可以正常工作.
class C {
method test () {
"Hi"
}
}
dd C.new.test;
Run Code Online (Sandbox Code Playgroud)
"Hi"
Run Code Online (Sandbox Code Playgroud)
我已经看到模块使用以a开头的方法公开类^,这导致了我的问题.当我定义以a开头的方法名称时,为什么会出现此错误^?
TL; DR正确调用该方法.将^在foo.^bar表示"元方法".这既不是实例方法也不是类方法.Metamethods既是一个调用者,也是所有方法的情况,另一个是 "原始调用者"对象作为第一个参数.
大多数用户永远不需要考虑这些东西.但是你问过,所以让我们深入研究......
引用元对象协议(MOP) P6文档页面:
Perl 6构建在元对象层上.
此MOP层定义了您可以使用的各种内置"元方法".
例如:
say .^attributes given class bar { has Int $!foo }
Run Code Online (Sandbox Code Playgroud)
这显示(Int $!foo).该.^attributes方法的调用是一个元方法.它被称为(通常是不可见的)元对象,它决定了P6类型在幕后的工作方式.在这种情况下,它返回类的属性(has变量).
但也可以有用户定义的元方法.声明这些的一种方法是在另一个普通的类中:
say .^attributes given class baz { has Int $!foo; method ^attributes ($arg) { self, $arg } }
Run Code Online (Sandbox Code Playgroud)
上面的baz类包含一个^attributesmetamethod声明,它覆盖了内置的元方法.特别值得注意的是,我添加了一个参数.所有metamethods至少得到一个参数(除了常规的调用者).
使用此声明,而不是(Int $!foo)响应.^attributes调用,而是self, $arg从类中的.^attributes方法获取列表baz.
注意如何self既不是一个baz实例对象,也不是一个baz类型的对象-而不是它的Perl6::Metamodel::ClassHOW+{<anon>}.new-而$arg 为一baz(类型)的对象.
这个答案的其余部分更详细地解释了正在发生的事情.
首先,让我们回顾一下典型的方法调用.
语法foo.bar导致调度到"bar"方法(消息)foo.
如果foo是类的实例,则将"bar"分派给该实例.这种方法调用有时被称为"实例方法".
如果foo是对应于类的类型对象,则将"bar"分派给该类型对象.这种方法调用有时被称为"类方法".
在这两种情况下,都会发送"bar" foo.
foo.^bar语法foo.^bar不同.
阅读^为指向到那个无形以上徘徊另一个对象foo,或者实际上涉及到什么样的类型foo是.
这些对象是HOW确定对象如何工作的对象.这些HOW对象通常保持隐形,使事情很好地工作,用户幸福地不知道它们的存在和它们正在做的工作.1
形式的方法调用foo.^bar通常导致P6分派元方法调用foo的HOW对象.
这些元方法需要两个类似调用的参数.有HOW对象.这是作为常规调用者传递的.那就是foo对象.这是作为metamethod的第一个普通参数传递的.
这就是你调用时通常会发生的事情foo.^bar- 一个metamethod调用被调度到foo一个HOW对象,并foo作为一个普通的参数传递,存储可以说是"原始的调用者".
foo.^bar什么时候没有内置的 .^bar metamethod如果你foo.^bar在没有这种方法时打电话,你会收到一个错误:
42.^bar
Run Code Online (Sandbox Code Playgroud)
收益率:
No such method 'bar' for invocant of type 'Perl6::Metamodel::ClassHOW'
Run Code Online (Sandbox Code Playgroud)
请注意,调用类型是元模型类,而不是42或Int.
如果用户定义的类声明了a ^.bar,则P6调用它,将实例/类的HOW对象作为调用者传递,将"原始foo调用者"()作为第一个普通参数传递:
class foo {
method ^bar ($arg) { self, $arg }
}
say foo.^bar; # (Perl6::Metamodel::ClassHOW+{<anon>}.new (foo))
Run Code Online (Sandbox Code Playgroud)
1调用.HOW一个对象返回HOW:
say .HOW given class {} # Perl6::Metamodel::ClassHOW
Run Code Online (Sandbox Code Playgroud)
HOW对象是MOP的一部分,是P6内部的一层.
大多数开发人员永远不需要明确地挖掘到这个级别.
如果你挖得更深,你就会离开指定的P6.在Rakudo中.HOW,HOW对象通常是NQP对象:
say ((.HOW.new given class {}).HOW).^name; # NQPClassHOW
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
108 次 |
| 最近记录: |