类中公共与私有方法内部调用规则及原理疑问
这个问题问到了Perl 6(如今更名为Raku)里类方法调用的一个关键语法设计细节,我来拆解清楚背后的原因和规则:
为什么私有方法不能用$!b调用?
首先得明确几个核心语法符号的本质:
$!xxx是Raku中私有属性的直接访问语法,它只用来读取或修改类内部的私有属性,和方法调用完全是两个独立的语法体系。$.xxx是公共属性/方法的语法糖:对于属性,它是公共访问器;对于公共方法,编译器会自动把$.b($y)转换成self.b($y),本质还是调用对象的方法,而非访问属性。
当你把方法b设为私有后:
- 私有方法不对外暴露,编译器不会为它生成
$.b这样的公共访问语法糖,所以$.b($y)会直接报错。 - 如果尝试用
$!b($y),编译器会把$!b解析成一个名为$!b的私有属性,但你的类里只声明了$!a,自然会抛出“Attribute $!b not declared in class TEST”的错误——因为它根本没把$!b当成方法来处理。
类内部调用方法的具体规则
公共方法(method)的调用方式
在类内部,公共方法有三种合法调用形式:
- 显式调用
self.method(参数):最清晰的方式,明确指定调用当前对象的方法,支持方法重载、继承时的多态(子类重写方法后,会调用子类的实现)。 - 语法糖
$.method(参数):等价于self.method(参数),仅适用于公共方法,是为了简化外部访问而设计的语法糖,类内部也可以用。 - 直接写
method(参数):在类的方法内部,直接调用方法名时,编译器会自动补全self.,等价于self.method(参数)。不过这种方式可能和局部变量名冲突,所以推荐显式使用self.或$.。
比如你的示例代码里,self.b($y)和$.b($y)效果完全一致,都是调用公共方法b。
私有方法(!method)的调用方式
私有方法的定义和调用都需要用!前缀,规则非常明确:
- 定义时:用
method !b($x) { ... }的形式声明私有方法,标识它只能在类内部访问。 - 调用时:必须用
self!method(参数)的形式,没有其他语法糖可选。这是因为私有方法是类的专属内部实现,Raku的语法设计刻意限制了它的调用方式,避免和公共方法、属性混淆。 - 注意:私有方法是类私有的,不仅外部无法调用,子类也不能继承或访问。
用你的示例修改成私有方法的正确写法:
class TEST { has Int $.a; method !b($x) { # 私有方法定义,加!前缀 return $!a * $x; } method c($y) { return self!b($y) * 3; # 正确调用私有方法 # return $!b($y) * 3; # 错误:被解析为私有属性,未声明 # return $.b($y) * 3; # 错误:私有方法无$.语法糖 } } my $m = TEST.new(a => 10); say $m.c(2); # 输出60
核心总结
Raku的语法设计刻意区分了属性访问和方法调用的语法:
$!和$.是属性专属的访问符号,和方法无关;- 公共方法可以用
$.做语法糖,是因为编译器帮你映射到了self.method; - 私有方法因为是内部实现,没有语法糖,必须用
self!method明确调用,避免语法歧义。
内容的提问来源于stack exchange,提问作者Eugene Barsky
相关产品推荐
相关产品推荐

