我想创建下一个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运算符或语法糖。有人可以解释这个更详细的(如果可能的话)提供解决方案来解决我的问题吗?
答案 0 :(得分:5)
那是不可能的。有些方法在没有显式接收器的情况下根本无法调用,因为否则它们会模糊不清。特别是,在你同时拥有一元前缀和二元中缀运算符的每种情况下,都不可能区分这两种情况:
+ 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强制为所有二进制中缀运算符使用两个操作数,而不仅仅是语法不明确的操作符。
同样,如果没有显式接收器,则无法调用[]
,因为它会与数组的文字语法冲突。
另一个众所周知的没有显式接收器就无法调用的方法示例是setters:
self.foo = bar # setter
foo = bar # local variable
对于private
setter,private
方法的规则实际上有一个例外,它允许使用显式接收器调用它们,只要该显式接收器是文字伪变量即可关键字self
。但是,调用私有二进制运算符或[]
之类的方法不存在此类异常。 (尽管如此,仍有提案。)
答案 1 :(得分:2)
JörgWMittag回答为什么你的第一个表达式* 'Ruby'
(没有明确的接收者)会引发错误。
我将添加为什么你的第二个表达式self.*(1)
(带有显式接收器)会引发错误。这是因为该方法是在main
对象上定义的,默认情况下都是私有的。
这使得调用方法的唯一方法既没有显式接收器,也没有显式接收器,换句话说,你不能用普通方法调用的形式调用该方法。您只能以描述该方法的符号形式传递它,而让另一种方法(send
)执行它。