【问题标题】:Passing arguments to Ruby methods将参数传递给 Ruby 方法
【发布时间】:2021-07-19 08:41:19
【问题描述】:

似乎可以通过在方法后面附加参数并用空格分隔两者来将参数传递给某些 Ruby 方法。我试图了解使这种情况发生的机制。这就是在命令行中将参数传递给脚本的方式。为什么以下语句在 Ruby 中有效?

item = 'orange'
fruits = ['orange', 'grapefruit', 'apple']
x = fruits.include? item
puts x

为什么下面的语句不起作用?

item = 'orange'
fruits = ['orange', 'grapefruit', 'apple']

x = fruits.include? item ? 'You picked a fruit' : 'You did not pick a fruit'

puts x

【问题讨论】:

  • 在 Ruby 中,调用方法时可以省略括号。 fruits.lengthfruits.length() 相同。同样,fruits.include? itemfruits.include?(item) 相同。
  • 有道理。我编辑了问题以添加第二个陈述。我想第二个语句没有按预期工作,因为三元语句作为参数传递给 include? 方法?
  • x = fruits.include? item ? 'You picked a fruit' : 'You did not pick a fruit' 被评估为 x = fruits.include? (item ? 'You picked a fruit' : 'You did not pick a fruit') -> x = fruits.include? "You picked a fruit" 返回 false。您可以使用x = fruits.include?(item) ? 'You picked a fruit' : 'You did not pick a fruit'x = (fruits.include? item) ? 'You picked a fruit' : 'You did not pick a fruit' 来消除歧义(我推荐前者)。
  • @ArunKumarMohan 谢谢,这是有道理的!您能否粘贴您的 cmets 作为答案,我会接受吗?
  • 类似地,在以单行格式传递块时,您必须使用括号,例如arr.each_slice 2 { |slice| puts slice } 无效但arr.each_slice(2) { |slice| puts slice } 有效

标签: ruby methods syntax


【解决方案1】:

使用 Ripper 检查 AST

在 Ruby 中,括号在很大程度上是可选的,除非需要避免歧义,例如将参数传递给采用块的方法时。在底层,主线 Ruby 有很多可移动的部分,用于标记和解析您编写的代码。其中最有用的是Ripper module(记录在here),它使您能够查看Ruby 从您的代码中生成的抽象语法树。

这是 Ruby 看到的两个版本的代码。您可以从 S 表达式中看到失败版本与非失败版本不同。在 irb 中:

Ripper.sexp %q{x = fruits.include?(item) ? 'You picked a fruit' : 'You did not pick a fru
it'}
#=> 
[:program,
 [[:assign,
   [:var_field, [:@ident, "x", [1, 0]]],
   [:ifop,
    [:method_add_arg,
     [:call,
      [:vcall, [:@ident, "fruits", [1, 4]]],
      [:@period, ".", [1, 10]],
      [:@ident, "include?", [1, 11]]],
     [:arg_paren, [:args_add_block, [[:vcall, [:@ident, "item", [1, 20]]]], false]]],
    [:string_literal, [:string_content, [:@tstring_content, "You picked a fruit", [1, 29]]]],
    [:string_literal, [:string_content, [:@tstring_content, "You did not pick a fruit", [1, 52]]]]]]]]
Ripper.sexp %q{x = fruits.include? item ? 'You picked a fruit' : 'You did not pick a frui
t'}
#=> 
[:program,
 [[:assign,
   [:var_field, [:@ident, "x", [1, 0]]],
   [:command_call,
    [:vcall, [:@ident, "fruits", [1, 4]]],
    [:@period, ".", [1, 10]],
    [:@ident, "include?", [1, 11]],
    [:args_add_block,
     [[:ifop,
       [:vcall, [:@ident, "item", [1, 20]]],
       [:string_literal, [:string_content, [:@tstring_content, "You picked a fruit", [1, 28]]]],
       [:string_literal, [:string_content, [:@tstring_content, "You did not pick a fruit", [1, 51]]]]]],
     false]]]]]

由于 Ruby 几乎将所有内容都视为返回值的表达式,因此操作顺序会影响解析器如何形成表达式。三元运算符最终必须计算为三个表达式,如果您使用解析器认为不明确的语法,则会导致问题。

另见

【讨论】:

  • 谢谢,这是一个非常全面的答案。我现在明白,在第二个示例中,三元语句作为参数传递给 include? 函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-12
相关资源
最近更新 更多