正如您正确收集的那样,root
是一个方法调用。或者更确切地说,它是一个消息发送。Ruby 与 Smalltalk 一样,建立在消息传递隐喻之上,其中对象向其他对象发送消息,而这些对象(称为接收器)响应这些消息。
在这种情况下,您将参数传递给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
引入了一种新的替代文字语法。与原始语法相比,这种文字语法非常有限,因为它只能表示Hash
键为 s 的 esSymbol
也是有效的 Ruby 标识符,而使用原始语法,您可以Hash
用任意对象作为键来写 a。但是,对于那个有限的用例,它是非常可读的:
{ :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 社区一直希望获得对真正关键字参数的支持。这种支持分两步实现:首先,Hash
在 Ruby 1.9 中引入了新的文字语法,它允许您发送看起来像是在使用关键字参数的消息发送,即使它们实际上只是一个Hash
. 然后在第二步中,在 Ruby 2.0中引入了真正的关键字参数。修改后的方法签名如下所示:
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?
这种歧义实际上是有意的,因为它允许针对使用参数的 API 编写的旧客户端代码Hash
与使用关键字参数的新 API 保持不变地工作。有一些半复杂的规则可以确定该语法是否将被解释为 aHash
或关键字,但大多数这些规则会按照您期望的方式运行。