我是Ruby和Rails的新手,当我浏览各种教程时,我偶尔会遇到一些我无法理解的Ruby语法。
例如,这实际上是做什么的?
root to: "welcome#index"
我可以认为这可能是一个名为“root”的方法,但在那之后我就迷失了。 “To”不是象征,是吗?结肠将在之前,如果在“:to”中。这是利用哈希的某种形式的关键字参数吗?在irb with ruby1.9.3中尝试使用时,我无法使这种语法有效。
我知道这可能是一个RTFM问题,但我甚至无法想到谷歌要做什么。
谢谢!
我还在玩这种语法,
def func(h)
puts h[:to]
end
x = { :to => "welcome#index" }
y = :to => "welcome#index"
z = to: "welcome#index"
func to: "welcome#index"
我看到这个例子只适用于定义“y”和“z”的行。所以无括号和“冒号后”语法只在调用方法的上下文中有效吗?
答案 0 :(得分:5)
首先,这是正确的 - root
是方法调用。
现在
to: 'welcome#index'
相当于
:to => 'welcome#index'
并且它是Hash
,其中键是:to
符号,值是'welcome#index'
字符串。您可以在定义自Ruby 1.9
以来的哈希值时使用此语法。
答案 1 :(得分:4)
相当于
root(:to => "welcome#index")
我无法找到有关新哈希语法的官方文档,但是当您看到foo: bar
时,这意味着foo
是用作哈希中的键的符号,并且具有值bar
。
答案 2 :(得分:3)
以下是定义函数foo
的示例,该函数采用哈希值并打印到屏幕上。
def foo(hash)
puts hash.inspect
puts hash[:to]
end
foo to: "wecome#index" #method call without paratheses
上面方法调用的输出:
{:to=>"welcome#index"}
welcome#index
等效声明:
h = {:to => "welcome#index"}
h = {to: "wecolme#index"}
此外,您可以使用Ripper(Ruby标准库的一部分)来了解Ruby如何解析代码。在下面的示例中,我已经如上所述定义了foo
。现在,我在不使用Ripper的情况下调用foo
。然后我使用Ripper来看看Ruby如何解析方法调用。
[2] pry(main)> foo to: "welcome#index"
{:to=>"welcome#index"}
welcome#index
=> nil
[3] pry(main)> require 'ripper'
=> true
[4] pry(main)> Ripper.sexp 'foo to: "welcome#index"'
=> [:program,
[[:command,
[:@ident, "foo", [1, 0]],
[:args_add_block,
[[:bare_assoc_hash,
[[:assoc_new,
[:@label, "to:", [1, 4]],
[:string_literal,
[:string_content, [:@tstring_content, "welcome#index", [1, 9]]]]]]]],
false]]]]
答案 3 :(得分:2)
在ruby括号中,方法调用是可选的,因此可以重写为:
root(to: "welcome#index")
并且可以再次重写为
root(:to => "welcome#index")
哈希作为关键字参数(ruby 1.9)也在这里解释:hash-constructor-parameter-in-1-9
P.S。顺便提一下轨道新手的一般规则是“首先学习红宝石,然后学习铁轨”;)
答案 4 :(得分:1)
正确收集后,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
字面语法。与原始语法相比,这种文字语法非常有限,因为它只能表示其键为Hash
的{{1}},它们也是有效的Ruby标识符,而使用原始语法,您可以写下来Symbol
以任意对象作为键。但是,对于那个有限的用例,它非常易读:
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
。
这些功能通常用于模拟其他语言中的关键字参数。长期以来,Ruby社区一直希望获得对真正的关键字参数的支持。这个支持分两步实现:首先,在Ruby 1.9中引入了新的Hash
文字语法,它允许您使用关键字参数进行看起来像的消息发送,即使他们真的只是一个Hash
。然后在第二步中,在Ruby 2.0中引入了真正的关键字参数。修改后的方法签名如下所示:
Hash
请注意,目前,无法拥有必需的关键字参数,始终需要具有默认值,因此始终是可选的。但是,您可以使用默认值可以是任意表达式的事实,并执行以下操作:
def foo.bar(baz: nil, quux: nil) p baz, quux end
在Ruby的未来版本中(它实际上已经在2月实现,可能在2.1中),可以通过省略默认值来指定必需的关键字参数:
def foo.bar(baz: raise ArgumentError '`baz` must be supplied!',
quux: raise ArgumentError '`quux` must be supplied!') p baz, quux end
请注意,现在存在语法歧义:
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编写的旧客户端代码与使用关键字参数的新API一起工作。有一些半复杂的规则可以确定该语法是解释为Hash
还是解释为关键字,但大部分规则都会按照您期望的方式解决。