正如您正确收集的那样,root 是一个方法调用。或者更确切地说,这是一个消息发送。与 Smalltalk 一样,Ruby 建立在消息传递隐喻之上,其中对象向其他对象发送消息,而这些对象(称为 receiver)响应这些消息。
在这种情况下,您将参数传递给root,这就是您知道它是消息发送的方式。消息发送是唯一可以接受参数的东西,如果你看到一个参数,那么它一定是一个消息发送。没有函数,没有静态方法,没有构造函数,没有过程,只有方法和消息发送。
那么,是的论点是什么?嗯,在 Ruby 中,许多其他语言在语法上需要的东西都是可选的。例如,参数列表周围的括号:
foo.bar(baz)
# can also be written as
foo.bar baz
如果消息发送的最后一个参数是 Hash 字面量,则可以省略花括号:
foo.bar({ :baz => 23, :quux => 42 })
# can also be written as
foo.bar(:baz => 23, :quux => 42)
将两者放在一起,你会得到:
foo.bar({ :baz => 23, :quux => 42 })
# can also be written as
foo.bar :baz => 23, :quux => 42
在 Ruby 1.9 中,引入了一种新的替代 Hash 文字语法。与原始语法相比,此文字语法非常有限,因为它只能表示 Hashes,其键为 Symbols,这也是有效的 Ruby 标识符,而使用原始语法,您可以写下 Hash 与任何任意对象作为键。但是,对于 有限的用例,它是非常可读的:
{ :baz => 23, :quux => 42 }
# can also be written as
{ baz: 23, quux: 42 }
如果我们将该功能与其他两个功能放在一起,我们会得到您所询问的消息发送语法:
foo.bar baz: 23, quux: 42
如果我们有这样的单个参数声明的方法:
def foo.bar(opts) p opts end
opts 将绑定到具有两个键值对的单个 Hash。
这些功能通常用于模拟其他语言中的关键字参数。长期以来,Ruby 社区一直希望获得对 real 关键字参数的支持。这种支持分两步实现:首先,Ruby 1.9 中引入了新的 Hash 文字语法,它允许您使用关键字参数发送消息,看起来像,即使它们是真的只是一个Hash。然后在第二步中,在 Ruby 2.0 中引入了 real 关键字参数。修改后的方法签名如下所示:
def foo.bar(baz: nil, quux: nil) p baz, quux end
请注意,目前不可能有必需的关键字参数,它们总是需要有一个默认值,因此总是可选的。但是,您可以利用默认值可以是任意表达式这一事实,并执行以下操作:
def foo.bar(baz: raise ArgumentError '`baz` must be supplied!',
quux: raise ArgumentError '`quux` must be supplied!') p baz, quux end
在未来的 Ruby 版本中(实际上已经在 2 月份实现,并且很可能在 2.1 中),可以通过省略默认值来指定所需的关键字参数:
def foo.bar(baz:, quux:) p baz, quux end
请注意,现在存在语法歧义:
foo.bar baz: 23, quux: 42
# is this sending the message `bar` to `foo` with *one* `Hash` or *two* keywords?
这种歧义实际上是有意的,因为它允许针对使用 Hash 参数的 API 编写的旧客户端代码与使用关键字参数的新 API 保持不变地工作。有一些半复杂的规则可以确定该语法是被解释为 Hash 还是关键字,但大多数这些规则都会按照您期望的方式运行。