为什么 Ruby 会“包含”?嵌套在 if/end 条件中时表现不同吗?

Tec*_*Cat 3 ruby ruby-on-rails

在我看来,以下三个示例在逻辑上是等效的,并且应该产生相同的结果。

print "Enter your string: "
my_string = gets.chomp

#Example 1
my_string.include? ("j" or "J")
puts "1. Your string includes a j or J." 

#Example 2
if
  my_string.include? ("j" or "J")
  puts "2. Your string includes a j or J." 
end

#Example 3
if
  my_string.include? ("j") or my_string.include? ("J")
  puts "3. Your string includes a j or J." 
end
Run Code Online (Sandbox Code Playgroud)

以下是大写 J 的结果。

Enter your string: Jack
1. Your string includes a j or J.
3. Your string includes a j or J. 
Run Code Online (Sandbox Code Playgroud)

以下是小写 j 的结果。

Enter your string: jack
1. Your string includes a j or J.
2. Your string includes a j or J.
3. Your string includes a j or J.
Run Code Online (Sandbox Code Playgroud)

由于我不明白的原因,只有示例 1 和示例 3 生成相同的结果。相比之下,在示例 2 中,仅评估括号中的第一项(小写 j)。

但为什么?如果示例 1 工作正常,为什么示例 2 会仅仅因为“include”而失败?方法嵌套在“if/end”中?

如果我们需要将代码包装在“if/elsif/end”条件中,是否有一种方法可以在“include”中列出要评估的多个值?方法而不需要像示例 3 那样单独写出它们?如果有很多值需要评估,这将是乏味的 - 几乎是“反 Ruby”!

换句话说,有没有办法让示例2正常工作?

Sam*_*Sam 5

以下是每个示例中发生的情况:

\n\n

第一个例子

\n\n

此示例的输出1. Your string includes a j or J.与前一行无关。该my_string.include?检查被忽略,因为它没有在任何地方的比较中使用,因此第二行只是一个常规的puts.

\n\n

第二个例子

\n\n

第二个例子更有趣一些。("j" or "J")是 Ruby 中的语法,它将输出所提供的第一个参数,其计算结果为true. "j"计算结果为 true,因为它不是 nil 或 false,因此它成为第二个include?方法的参数。include?区分大小写,因此它将返回false\xe2\x80\x93 该字符串Jack不包含小写字母j

\n\n

irb您可以通过运行并输入类似1 or 2或 的内容来尝试此操作false and 1;您很快就会看到第一个 true 参数被返回(或者false如果没有参数为 true)。

\n\n

include?除了更新检查以使用set intersections之类的东西之外,没有什么好方法可以按原样进行这项工作。一个更简单的解决方案可能是downcase在检查字符之前输入。

\n\n

Avdi Grimm发布了一个关于使用Ruby的精彩视频。andor

\n\n

第三个例子

\n\n

第三个示例对字符串调用include?两次,并在第二次调用时返回 true,因此 if 语句被评估。

\n\n

更新

\n\n

papirtiger 的回答让我思考,所以我使用以下脚本使用 Ripper 进行了一些挖掘:

\n\n
require \'ripper\'\nrequire \'pp\'\n\nexpression = <<-FOO\nif true\n  puts \'Hello\'\nend\nFOO\n\npp Ripper.sexp(expression)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是结果:

\n\n
[:program,\n [[:if,\n   [:var_ref, [:@kw, "true", [1, 3]]],\n   [[:command,\n     [:@ident, "puts", [2, 2]],\n     [:args_add_block,\n      [[:string_literal,\n        [:string_content, [:@tstring_content, "Hello", [2, 8]]]]],\n      false]]],\n   nil]]]\n
Run Code Online (Sandbox Code Playgroud)\n\n

将表达式更新为以下内容后:

\n\n
expression = <<-FOO\nif\n  true\n  puts \'Hello\'\nend\nFOO\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是新的输出:

\n\n
[:program,\n [[:if,\n   [:var_ref, [:@kw, "true", [2, 2]]],\n   [[:command,\n     [:@ident, "puts", [3, 2]],\n     [:args_add_block,\n      [[:string_literal,\n        [:string_content, [:@tstring_content, "Hello", [3, 8]]]]],\n      false]]],\n   nil]]]\n
Run Code Online (Sandbox Code Playgroud)\n\n

看起来 Ruby 确实忽略了任何空格并计算下一个表达式。我没有足够的专业知识来深入挖掘,但在尝试了更多示例(例如在语句后添加十几个换行符if)后,我确信了。

\n