在隐式接收器上调用 * 方法

Call * method on implicit receiver

我想创建下一个 DSL 部分:

* 'Ruby'

下一个实验显示了可预测的结果:

def *(a)
  a
end

* 'Ruby'         #=> SyntaxError: (irb):4: syntax error, unexpected '\n', expecting :: or '[' or '.'
self.*(1)        #=> NoMethodError: private method `*' called for main:Object
self.send(:*, 1) #=> 'Ruby'

我想 Ruby 语法分析器将这样的表达式视为 splat 运算符或星号方法的语法糖。有人可以更详细地解释一下并(如果可能的话)提供解决方案来解决我的问题吗?

这不可能。有一些方法在没有显式接收者的情况下根本无法调用,否则它们会产生歧义。特别是,在同时具有一元前缀和二元中缀运算符的每种情况下,都不可能区分这两种情况:

+ a == a.+@()
- a == a.-@()
& a # interpreted as the unary prefix proc-block conversion operator
* a # interpreted as the unary prefix splat operator

或者在运算符与其他语法冲突的情况下:

/ a # interpreted as the start of a Regexp literal

为了保持一致性,Ruby 强制对 所有 二元中缀运算符使用两个操作数,而不仅仅是那些语法不明确的操作数。

同样,[] 不能在没有显式接收者的情况下调用,因为它会与数组的文字语法冲突。

另一个 well-known 没有显式接收器就无法调用的方法示例是设置器:

self.foo = bar # setter
foo = bar      # local variable

对于 private 设置器,private 方法的规则实际上有一个例外,允许使用显式接收者调用它们,只要该显式接收者是文字 pseudo-variable关键字self。但是,调用私有二元运算符或 [] 等方法不存在此类异常。 (不过,有这方面的建议。)

Jörg W Mittag 回答了为什么您的第一个表达式 * 'Ruby'(没有显式接收者)会引发错误。

我将补充为什么您的第二个表达式 self.*(1)(具有显式接收者)会引发错误。这是因为方法定义在main对象上,默认都是私有的

这告诉你调用该方法的唯一方法是既不带也不不带显式接收者,换句话说,你不能以普通方法调用的形式调用该方法。您只能以描述该方法的符号形式传递它,并让另一个方法(send)执行它。