【问题标题】:trying to understand specific bit of ruby syntax试图理解特定的 ruby​​ 语法
【发布时间】:2013-07-05 08:53:37
【问题描述】:

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

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

root to: "welcome#index"

我可以推测这可能是一个名为“root”的方法,但之后我就迷路了。 “到”不是一个符号,是吗?冒号应该在前面,如果是的话,就像在 ":to" 中一样。这是使用哈希的某种形式的关键字参数吗?在使用 ruby​​1.9.3 在 irb 中尝试时,我无法使此语法正常工作。

我知道这可能是一个 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”的行被注释掉了。那么无括号和“冒号后”语法只在调用方法的上下文中有效?

【问题讨论】:

  • Symbolhound.com 在谷歌搜索语法时有时很有用。

标签: ruby-on-rails ruby syntax


【解决方案1】:

首先,没错——root 是一个方法调用。 现在

to: 'welcome#index' 

等价于

:to => 'welcome#index'

它是一个Hash,其中键是:to 符号,值是'welcome#index' 字符串。从Ruby 1.9 开始,您可以使用此语法定义哈希。

【讨论】:

    【解决方案2】:

    相当于

    root(:to => "welcome#index")
    

    我在查找有关新哈希语法的官方文档时遇到了麻烦,但是当您看到 foo: bar 时,这意味着 foo 是用作哈希键的符号并且具有值 bar。

    【讨论】:

      【解决方案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]]]]
      

      【讨论】:

        【解决方案4】:

        方法调用中的大括号是可选的,所以可以重写为:

        root(to: "welcome#index")
        

        并且可以再次改写为

        root(:to => "welcome#index")
        

        哈希作为关键字参数(ruby 1.9)也在这里解释:hash-constructor-parameter-in-1-9

        附:顺便说一句,rails 新手的一般经验法则是“先学习 ruby​​,然后再学习 rails”;)

        【讨论】:

        【解决方案5】:

        正如您正确收集的那样,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 还是关键字,但大多数这些规则都会按照您期望的方式运行。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-06
          • 2016-03-17
          • 1970-01-01
          • 1970-01-01
          • 2012-03-03
          • 2017-11-11
          • 2021-12-01
          相关资源
          最近更新 更多