试图理解ruby语法的具体位

时间:2013-07-04 19:24:47

标签: ruby-on-rails ruby syntax

我是Ruby和Rails的新手,当我浏览各种教程时,我偶尔会遇到一些我无法理解的Ruby语法。

例如,这实际上是做什么的?

root to: "welcome#index"

我可以认为这可能是一个名为“root”的方法,但在那之后我就迷失了。 “To”不是象征,是吗?结肠将在之前,如果在“:to”中。这是利用哈希的某种形式的关键字参数吗?在irb with ruby​​1.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”的行。所以无括号和“冒号后”语法只在调用方法的上下文中有效吗?

5 个答案:

答案 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还是解释为关键字,但大部分规则都会按照您期望的方式解决。