将参数传递给 Ruby 方法
Passing arguments to Ruby methods
似乎可以将参数传递给某些 Ruby 方法,方法是在方法后面附加参数,并用 space 将两者分开。我试图了解实现这种情况的机制。这就是在命令行中将参数传递给脚本的方式。为什么以下语句在 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
用 Ripper 检查 AST
在 Ruby 中,括号在很大程度上是可选的,除非需要避免歧义,例如将参数传递给采用块的方法时。在幕后,主线 Ruby 有很多可移动的部分,可以标记和解析您编写的代码。最有用的方法之一是 Ripper module (documented 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 将几乎所有内容都视为 returns 一个值的表达式,因此操作顺序会影响解析器如何形成表达式。三元运算符最终必须评估为三个表达式,如果您使用解析器认为有歧义的语法,则会导致问题。
另请参阅
似乎可以将参数传递给某些 Ruby 方法,方法是在方法后面附加参数,并用 space 将两者分开。我试图了解实现这种情况的机制。这就是在命令行中将参数传递给脚本的方式。为什么以下语句在 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
用 Ripper 检查 AST
在 Ruby 中,括号在很大程度上是可选的,除非需要避免歧义,例如将参数传递给采用块的方法时。在幕后,主线 Ruby 有很多可移动的部分,可以标记和解析您编写的代码。最有用的方法之一是 Ripper module (documented 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 将几乎所有内容都视为 returns 一个值的表达式,因此操作顺序会影响解析器如何形成表达式。三元运算符最终必须评估为三个表达式,如果您使用解析器认为有歧义的语法,则会导致问题。