首页 > 解决方案 > 将参数传递给 Ruby 方法

问题描述

似乎可以通过在方法之后附加参数并将两者用空格分隔来将参数传递给某些 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

标签: rubymethodssyntax

解决方案


使用 Ripper 检查 AST

在 Ruby 中,括号在很大程度上是可选的,除非需要避免歧义,例如将参数传递给采用块的方法时。在底层,主线 Ruby 有很多可移动的部分,用于标记和解析您编写的代码。最有用的模块之一是Ripper 模块在此处记录),它使您能够查看 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 将几乎所有内容都视为返回值的表达式,因此操作顺序会影响解析器如何形成表达式。三元运算符最终必须评估为三个表达式,如果您使用解析器认为不明确的语法,则会导致问题。

也可以看看


推荐阅读